📄 sdpgsql.pas
字号:
szErrMsg := PQerrorMessage( pgconn );
sMsg := HelperPtrToString( szErrMsg );
E := ESDPgSQLError.Create(-1, -1, sMsg, 0);
raise E;
end;
procedure TIPgDatabase.CheckRes(pgres: PPGresult);
var
E: ESDPgSQLError;
szErrMsg: TSDCharPtr;
sMsg: string;
rs: Integer;
begin
ResetIdleTimeOut;
rs := PQresultStatus( pgres );
if (rs = PGRES_EMPTY_QUERY) or (rs = PGRES_COMMAND_OK) or (rs = PGRES_TUPLES_OK) then
Exit;
ResetBusyState;
szErrMsg := PQresultErrorMessage( pgres );
sMsg := HelperPtrToString( szErrMsg );
E := ESDPgSQLError.Create(-1, -1, sMsg, 0);
raise E;
end;
procedure TIPgDatabase.ExecCmd(const sStmt: string; CheckRslt: Boolean);
var
res: PPGresult;
szCmd: TSDCharPtr;
begin
{$IFDEF SD_CLR}
szCmd := Marshal.StringToHGlobalAnsi( sStmt );
{$ELSE}
szCmd := TSDCharPtr( sStmt );
{$ENDIF}
res := PQexec( PgConnPtr, szCmd );
try
if CheckRslt then
CheckRes( res );
finally
PQclear( res );
{$IFDEF SD_CLR}
if Assigned( szCmd ) then
Marshal.FreeHGlobal( szCmd );
{$ENDIF}
end;
end;
function TIPgDatabase.GetClientVersion: LongInt;
begin
Result := dwLoadedFileVer;
end;
function TIPgDatabase.GetServerVersion: LongInt;
begin
Result := VersionStringToDWORD( GetVersionString );
end;
function TIPgDatabase.GetVersionString: string;
var
res: PPGresult;
szVer: TSDCharPtr;
szCmd: TSDCharPtr;
sCmd: string;
begin
sCmd := 'select version()';
{$IFDEF SD_CLR}
szCmd := Marshal.StringToHGlobalAnsi( sCmd );
{$ELSE}
szCmd := TSDCharPtr( sCmd );
{$ENDIF}
res := PQexec( PgConnPtr, szCmd);
try
CheckRes( res );
szVer := PQgetvalue( res, 0, 0 );
Result := HelperPtrToString( szVer );
finally
PQclear( res );
{$IFDEF SD_CLR}
if Assigned( szCmd ) then
Marshal.FreeHGlobal( szCmd );
{$ENDIF}
end;
end;
function TIPgDatabase.GetPgConnPtr: PPGconn;
begin
ASSERT( Assigned(FHandle), 'TIPgDatabase.GetPgConn' );
{$IFDEF SD_CLR}
Result := TIPgConnInfo( Marshal.PtrToStructure( FHandle, TypeOf(TIPgConnInfo) ) ).PgConnPtr;
{$ELSE}
Result := TIPgConnInfo(FHandle^).PgConnPtr;
{$ENDIF}
end;
function TIPgDatabase.GetHandle: TSDPtr;
begin
Result := FHandle;
end;
procedure TIPgDatabase.SetHandle(AHandle: TSDPtr);
{$IFDEF SD_CLR}
var
r1, r2: TIPgConnInfo;
{$ENDIF}
begin
LoadSqlLib;
AllocHandle;
{$IFDEF SD_CLR}
r1 := TIPgConnInfo( Marshal.PtrToStructure( FHandle, TypeOf(TIPgConnInfo) ) );
r2 := TIPgConnInfo( Marshal.PtrToStructure( AHandle, TypeOf(TIPgConnInfo) ) );
r1.PgConnPtr := r2.PgConnPtr;
Marshal.StructureToPtr( r1, FHandle, False );
{$ELSE}
TIPgConnInfo(FHandle^).PgConnPtr := TIPgConnInfo(AHandle^).PgConnPtr;
{$ENDIF}
end;
procedure TIPgDatabase.AllocHandle;
var
rec: TIPgConnInfo;
begin
ASSERT( not Assigned(FHandle), 'TIPgDatabase.AllocHandle' );
FHandle := SafeReallocMem(nil, SizeOf(rec));
SafeInitMem( FHandle, SizeOf(rec), 0 );
rec.ServerType := Ord( istPostgreSQL );
{$IFDEF SD_CLR}
Marshal.StructureToPtr( rec, FHandle, False );
{$ELSE}
TIPgConnInfo(FHandle^) := rec;
{$ENDIF}
end;
procedure TIPgDatabase.FreeHandle;
begin
if Assigned(FHandle) then
FHandle := SafeReallocMem( FHandle, 0 );
end;
procedure TIPgDatabase.DoConnect(const sRemoteDatabase, sUserName, sPassword: string);
var
sSrvName, sDbName, sPortNo: string;
szUser, szPwd, szSrv, szDb, szPortNo: TSDCharPtr;
rec: TIPgConnInfo;
begin
LoadSqlLib;
AllocHandle;
// sRemoteDatabase can be equal 'srv:port:db'
sSrvName := ExtractServerName(sRemoteDatabase);
sDbName := ExtractDatabaseName(sRemoteDatabase);
// gets the custom server port
sPortNo := ExtractServerName(sDbName);
if sPortNo = sDbName then
sPortNo := Params.Values[szSERVERPORT];
{$IFDEF SD_CLR}
rec := TIPgConnInfo( Marshal.PtrToStructure( FHandle, TypeOf(TIPgConnInfo) ) );
szSrv := Marshal.StringToHGlobalAnsi( sSrvName );
szDb := Marshal.StringToHGlobalAnsi( sDbName );
if Trim(sPortNo) <> '' then
szPortNo := Marshal.StringToHGlobalAnsi( sPortNo );
szUser:= Marshal.StringToHGlobalAnsi( sUserName );
szPwd := Marshal.StringToHGlobalAnsi( sPassword );
{$ELSE}
szSrv := TSDCharPtr( sSrvName );
szDb := TSDCharPtr( sDbName );
szPortNo:=TSDCharPtr( sPortNo );
szUser:= TSDCharPtr( sUserName );
szPwd := TSDCharPtr( sPassword );
{$ENDIF}
try
rec.PgConnPtr := PQsetdblogin( szSrv, szPortNo, nil, nil, szDb, szUser, szPwd );
{$IFDEF SD_CLR}
Marshal.StructureToPtr( rec, FHandle, False );
{$ELSE}
TIPgConnInfo(FHandle^) := rec;
{$ENDIF}
Check( PgConnPtr );
finally
{$IFDEF SD_CLR}
if Assigned( szSrv ) then
Marshal.FreeHGlobal( szSrv );
if Assigned( szDb ) then
Marshal.FreeHGlobal( szDb );
if Assigned( szPortNo ) then
Marshal.FreeHGlobal( szPortNo );
if Assigned( szUser ) then
Marshal.FreeHGlobal( szUser );
if Assigned( szPwd ) then
Marshal.FreeHGlobal( szPwd );
{$ENDIF}
end;
end;
procedure TIPgDatabase.DoDisconnect(Force: Boolean);
{$IFDEF SD_CLR}
var
rec: TIPgConnInfo;
{$ENDIF}
begin
if Assigned(FHandle) and Assigned( PgConnPtr ) then begin
if InTransaction then
ExecCmd( 'ROLLBACK', False );
PQfinish( PgConnPtr );
{$IFDEF SD_CLR}
rec := TIPgConnInfo( Marshal.PtrToStructure( FHandle, TypeOf(TIPgConnInfo) ) );
rec.PgConnPtr := nil;
Marshal.StructureToPtr( rec, FHandle, False );
{$ELSE}
TIPgConnInfo(FHandle^).PgConnPtr := nil;
{$ENDIF}
end;
FreeHandle;
FreeSqlLib;
end;
procedure TIPgDatabase.SetAutoCommitOption(Value: Boolean);
begin
end;
procedure TIPgDatabase.DoStartTransaction;
begin
ExecCmd( 'BEGIN', True );
end;
procedure TIPgDatabase.DoCommit;
begin
ExecCmd( 'COMMIT', True );
end;
procedure TIPgDatabase.DoRollback;
begin
ExecCmd( 'ROLLBACK', True );
end;
procedure TIPgDatabase.SetTransIsolation(Value: TISqlTransIsolation);
var
sStmt: string;
begin
sStmt := 'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL ';
if Value = itiRepeatableRead then
sStmt := sStmt + 'SERIALIZABLE'
else
sStmt := sStmt + 'READ COMMITTED';
ExecCmd( sStmt, True );
end;
function TIPgDatabase.TestConnected: Boolean;
var
cmd: TISqlCommand;
begin
Result := False;
cmd := CreateSqlCommand;
try
cmd.ExecDirect( SDummySelect );
if Assigned(cmd) then
Result := True;
finally
cmd.Free;
end;
end;
function TIPgDatabase.GetSchemaInfo(ASchemaType: TSDSchemaType; AObjectName: string): TISqlCommand;
const
SQueryPgStoredProcNamesFmt =
'select '''' as '+CAT_NAME_FIELD+', usename as '+SCH_NAME_FIELD+
', proname as '+PROC_NAME_FIELD+', CASE WHEN prorettype = 0 THEN 1 ELSE 2 END as '+PROC_TYPE_FIELD+
', pronargs as '+PROC_IN_PARAMS+', pronargs as '+ PROC_OUT_PARAMS+
', typname as RET_TYPE, proargtypes as ARG_TYPES'+
' from pg_proc, pg_shadow, pg_type st where proowner = usesysid and prorettype = st.oid %s order by usename, proname';
SQueryPgTableNamesFmt =
'select '''' as '+CAT_NAME_FIELD+', usename as '+SCH_NAME_FIELD+', relname as '+TBL_NAME_FIELD+
', CASE relkind WHEN ''r'' THEN 1 WHEN ''v'' THEN 2 END as '+TBL_TYPE_FIELD+
' from pg_class, pg_user where relowner = usesysid and relkind in (''r'', ''v'') %s order by usename, relname';
SQueryPgTableFieldNamesFmt =
'select '''' as '+CAT_NAME_FIELD+', usename as '+SCH_NAME_FIELD+
', relname as '+TBL_NAME_FIELD+', attname as '+COL_NAME_FIELD+
', attnum as '+COL_POS_FIELD+', 0 as '+COL_TYPE_FIELD+
', typname as '+COL_TYPENAME_FIELD+
', CASE attlen WHEN -1 THEN (CASE atttypmod WHEN -1 THEN 0 ELSE atttypmod END) ELSE CAST(attlen as integer) END as '+COL_LENGTH_FIELD+
', CASE WHEN attnotnull THEN 0 ELSE 1 END as '+COL_NULLABLE_FIELD+', '''' as '+COL_DEFAULT_FIELD+
' from pg_class so, pg_user, pg_attribute, pg_type st '+
'where relowner = usesysid and attrelid = so.oid and relkind in (''r'', ''v'') and'+
' attnum > 0 and UPPER(relname) like UPPER(''%s'') and atttypid = st.oid order by usename, relname, attnum';
// Note, CREATE INDEX command does not have ASC/DESC sort conditions (v.7.3.2)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -