mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2025-08-06 18:24:26 +08:00
Introduce handling of stored functions in PostgreSQL: Displays functions in database browser, enables function editor and "run routine" button with argument handling.
This commit is contained in:
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: HeidiSQL\n"
|
"Project-Id-Version: HeidiSQL\n"
|
||||||
"POT-Creation-Date: 2012-11-05 21:40\n"
|
"POT-Creation-Date: 2012-11-05 21:40\n"
|
||||||
"PO-Revision-Date: 2014-10-13 20:39+0100\n"
|
"PO-Revision-Date: 2014-10-26 11:35+0100\n"
|
||||||
"Last-Translator: Ansgar Becker <anse@heidisql.com>\n"
|
"Last-Translator: Ansgar Becker <anse@heidisql.com>\n"
|
||||||
"Language-Team: English (http://www.transifex.com/projects/p/heidisql/"
|
"Language-Team: English (http://www.transifex.com/projects/p/heidisql/"
|
||||||
"language/en/)\n"
|
"language/en/)\n"
|
||||||
@ -5810,3 +5810,7 @@ msgstr "Skip"
|
|||||||
#. Displayed in the query log, when connecting. E.g.: "Characterset: utf8"
|
#. Displayed in the query log, when connecting. E.g.: "Characterset: utf8"
|
||||||
msgid "Characterset"
|
msgid "Characterset"
|
||||||
msgstr "Characterset"
|
msgstr "Characterset"
|
||||||
|
|
||||||
|
#. Error happening when facing unknown native column types, mainly in PostgreSQL
|
||||||
|
msgid "Unknown column type oid #%d."
|
||||||
|
msgstr "Unknown column type oid #%d."
|
||||||
|
@ -346,6 +346,7 @@ type
|
|||||||
function ExtractIdentifier(var SQL: String): String;
|
function ExtractIdentifier(var SQL: String): String;
|
||||||
procedure ClearCache(IncludeDBObjects: Boolean);
|
procedure ClearCache(IncludeDBObjects: Boolean);
|
||||||
procedure FetchDbObjects(db: String; var Cache: TDBObjectList); virtual; abstract;
|
procedure FetchDbObjects(db: String; var Cache: TDBObjectList); virtual; abstract;
|
||||||
|
function NativeToNamedColumnType(NativeType: Integer): TDBDatatype;
|
||||||
procedure SetObjectNamesInSelectedDB;
|
procedure SetObjectNamesInSelectedDB;
|
||||||
procedure SetLockedByThread(Value: TThread); virtual;
|
procedure SetLockedByThread(Value: TThread); virtual;
|
||||||
procedure KeepAliveTimerEvent(Sender: TObject);
|
procedure KeepAliveTimerEvent(Sender: TObject);
|
||||||
@ -2529,10 +2530,11 @@ end;
|
|||||||
|
|
||||||
function TDBConnection.GetCreateCode(Database, Schema, Name: String; NodeType: TListNodeType): String;
|
function TDBConnection.GetCreateCode(Database, Schema, Name: String; NodeType: TListNodeType): String;
|
||||||
var
|
var
|
||||||
Cols, Keys: TDBQuery;
|
Cols, Keys, ProcDetails: TDBQuery;
|
||||||
ConstraintName, MaxLen: String;
|
ConstraintName, MaxLen: String;
|
||||||
ColNames: TStringList;
|
ColNames, ArgNames, ArgTypes, Arguments: TStringList;
|
||||||
Rows: TStringList;
|
Rows: TStringList;
|
||||||
|
i: Integer;
|
||||||
|
|
||||||
// Return fitting schema clause for queries in IS.TABLES, IS.ROUTINES etc.
|
// Return fitting schema clause for queries in IS.TABLES, IS.ROUTINES etc.
|
||||||
// TODO: Does not work on MSSQL 2000
|
// TODO: Does not work on MSSQL 2000
|
||||||
@ -2666,6 +2668,31 @@ begin
|
|||||||
Result := implodestr('', Rows);
|
Result := implodestr('', Rows);
|
||||||
Rows.Free;
|
Rows.Free;
|
||||||
end;
|
end;
|
||||||
|
ngPgSQL: begin
|
||||||
|
Result := 'CREATE FUNCTION '+QuoteIdent(Name);
|
||||||
|
ProcDetails := GetResults('SELECT '+
|
||||||
|
QuoteIdent('p')+'.'+QuoteIdent('prosrc')+', '+
|
||||||
|
QuoteIdent('p')+'.'+QuoteIdent('proargnames')+', '+
|
||||||
|
QuoteIdent('p')+'.'+QuoteIdent('proargtypes')+', '+
|
||||||
|
QuoteIdent('p')+'.'+QuoteIdent('prorettype')+' '+
|
||||||
|
'FROM '+QuoteIdent('pg_catalog')+'.'+QuoteIdent('pg_namespace')+' AS '+QuoteIdent('n')+' '+
|
||||||
|
'JOIN '+QuoteIdent('pg_catalog')+'.'+QuoteIdent('pg_proc')+' AS '+QuoteIdent('p')+' ON '+QuoteIdent('p')+'.'+QuoteIdent('pronamespace')+' = '+QuoteIdent('n')+'.'+QuoteIdent('oid')+' '+
|
||||||
|
'WHERE '+
|
||||||
|
QuoteIdent('n')+'.'+QuoteIdent('nspname')+'='+EscapeString(Database)+
|
||||||
|
'AND '+QuoteIdent('p')+'.'+QuoteIdent('proname')+'='+EscapeString(Name)
|
||||||
|
);
|
||||||
|
ArgNames := Explode(',', Copy(ProcDetails.Col('proargnames'), 2, Length(ProcDetails.Col('proargnames'))-2));
|
||||||
|
ArgTypes := Explode(',', Copy(ProcDetails.Col('proargtypes'), 2, Length(ProcDetails.Col('proargtypes'))-2));
|
||||||
|
Arguments := TStringList.Create;
|
||||||
|
for i:=0 to ArgNames.Count-1 do begin
|
||||||
|
Arguments.Add(ArgNames[i] + ' ' + NativeToNamedColumnType(MakeInt(ArgTypes[i])).Name);
|
||||||
|
end;
|
||||||
|
Result := Result + '(' + implodestr(',', Arguments) + ') '+
|
||||||
|
'RETURNS '+NativeToNamedColumnType(MakeInt(ProcDetails.Col('prorettype'))).Name+' '+
|
||||||
|
'AS $$ '+ProcDetails.Col('prosrc')+' $$'
|
||||||
|
// TODO: 'LANGUAGE SQL IMMUTABLE STRICT'
|
||||||
|
;
|
||||||
|
end;
|
||||||
else begin
|
else begin
|
||||||
Result := GetVar('SELECT ROUTINE_DEFINITION'+
|
Result := GetVar('SELECT ROUTINE_DEFINITION'+
|
||||||
' FROM INFORMATION_SCHEMA.ROUTINES'+
|
' FROM INFORMATION_SCHEMA.ROUTINES'+
|
||||||
@ -4150,6 +4177,56 @@ begin
|
|||||||
end;
|
end;
|
||||||
FreeAndNil(Results);
|
FreeAndNil(Results);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Stored functions. No procedures in PostgreSQL.
|
||||||
|
// See http://dba.stackexchange.com/questions/2357/what-are-the-differences-between-stored-procedures-and-stored-functions
|
||||||
|
try
|
||||||
|
Results := GetResults('SELECT '+QuoteIdent('p')+'.'+QuoteIdent('proname')+' '+
|
||||||
|
'FROM '+QuoteIdent('pg_catalog')+'.'+QuoteIdent('pg_namespace')+' AS '+QuoteIdent('n')+' '+
|
||||||
|
'JOIN '+QuoteIdent('pg_catalog')+'.'+QuoteIdent('pg_proc')+' AS '+QuoteIdent('p')+' ON '+QuoteIdent('p')+'.'+QuoteIdent('pronamespace')+' = '+QuoteIdent('n')+'.'+QuoteIdent('oid')+' '+
|
||||||
|
'WHERE '+QuoteIdent('n')+'.'+QuoteIdent('nspname')+'='+EscapeString(db)
|
||||||
|
);
|
||||||
|
except
|
||||||
|
on E:EDatabaseError do;
|
||||||
|
end;
|
||||||
|
if Assigned(Results) then begin
|
||||||
|
while not Results.Eof do begin
|
||||||
|
obj := TDBObject.Create(Self);
|
||||||
|
Cache.Add(obj);
|
||||||
|
obj.Name := Results.Col('proname');
|
||||||
|
obj.Database := db;
|
||||||
|
obj.NodeType := lntFunction;
|
||||||
|
Results.Next;
|
||||||
|
end;
|
||||||
|
FreeAndNil(Results);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TDBConnection.NativeToNamedColumnType(NativeType: Integer): TDBDatatype;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
rx: TRegExpr;
|
||||||
|
TypeFound: Boolean;
|
||||||
|
begin
|
||||||
|
rx := TRegExpr.Create;
|
||||||
|
TypeFound := False;
|
||||||
|
for i:=0 to High(Datatypes) do begin
|
||||||
|
if Datatypes[i].NativeTypes = '' then
|
||||||
|
Continue;
|
||||||
|
rx.Expression := '\b('+Datatypes[i].NativeTypes+')\b';
|
||||||
|
if rx.Exec(IntToStr(NativeType)) then begin
|
||||||
|
Result := Datatypes[i];
|
||||||
|
TypeFound := True;
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if not TypeFound then begin
|
||||||
|
// Fall back to text type
|
||||||
|
Result := Datatypes[0];
|
||||||
|
Log(lcError, f_('Unknown column type oid #%d.', [NativeType]));
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -5070,7 +5147,7 @@ end;
|
|||||||
|
|
||||||
procedure TPGQuery.Execute(AddResult: Boolean=False; UseRawResult: Integer=-1);
|
procedure TPGQuery.Execute(AddResult: Boolean=False; UseRawResult: Integer=-1);
|
||||||
var
|
var
|
||||||
i, j, NumFields: Integer;
|
i, NumFields: Integer;
|
||||||
NumResults: Integer;
|
NumResults: Integer;
|
||||||
FieldTypeOID: POid;
|
FieldTypeOID: POid;
|
||||||
LastResult: PPGresult;
|
LastResult: PPGresult;
|
||||||
@ -5119,20 +5196,7 @@ begin
|
|||||||
FColumnOrgNames.Add(FColumnNames[FColumnNames.Count-1]);
|
FColumnOrgNames.Add(FColumnNames[FColumnNames.Count-1]);
|
||||||
FieldTypeOID := PQftype(LastResult, i);
|
FieldTypeOID := PQftype(LastResult, i);
|
||||||
TypeFound := False;
|
TypeFound := False;
|
||||||
for j:=0 to High(FConnection.Datatypes) do begin
|
FColumnTypes[i] := FConnection.NativeToNamedColumnType(FieldTypeOID);
|
||||||
if FConnection.Datatypes[j].NativeTypes = '' then
|
|
||||||
Continue;
|
|
||||||
rx.Expression := '\b('+FConnection.Datatypes[j].NativeTypes+')\b';
|
|
||||||
if rx.Exec(IntToStr(FieldTypeOID)) then begin
|
|
||||||
FColumnTypes[i] := FConnection.Datatypes[j];
|
|
||||||
TypeFound := True;
|
|
||||||
break;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
if not TypeFound then begin
|
|
||||||
// Fall back to text type
|
|
||||||
FColumnTypes[i] := FConnection.Datatypes[11];
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
rx.Free;
|
rx.Free;
|
||||||
FRecNo := -1;
|
FRecNo := -1;
|
||||||
|
@ -3793,6 +3793,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
ngMSSQL:
|
ngMSSQL:
|
||||||
Query := 'EXEC ';
|
Query := 'EXEC ';
|
||||||
|
ngPgSQL:
|
||||||
|
Query := 'SELECT ';
|
||||||
else
|
else
|
||||||
raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(Obj.Connection.Parameters.NetType)]);
|
raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(Obj.Connection.Parameters.NetType)]);
|
||||||
end;
|
end;
|
||||||
@ -3814,7 +3816,7 @@ begin
|
|||||||
Parameters.Free;
|
Parameters.Free;
|
||||||
ParamValues := '';
|
ParamValues := '';
|
||||||
case Obj.Connection.Parameters.NetTypeGroup of
|
case Obj.Connection.Parameters.NetTypeGroup of
|
||||||
ngMySQL:
|
ngMySQL, ngPgSQL:
|
||||||
ParamValues := '(' + ImplodeStr(', ', Params) + ')';
|
ParamValues := '(' + ImplodeStr(', ', Params) + ')';
|
||||||
ngMSSQL:
|
ngMSSQL:
|
||||||
ParamValues := ' ' + ImplodeStr(' ', Params);
|
ParamValues := ' ' + ImplodeStr(' ', Params);
|
||||||
|
Reference in New Issue
Block a user