mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2026-03-13 09:24:25 +08:00
725 lines
25 KiB
ObjectPascal
725 lines
25 KiB
ObjectPascal
unit dbstructures.postgresql;
|
|
|
|
{$mode delphi}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
dbstructures, StrUtils;
|
|
|
|
type
|
|
// PostgreSQL structures
|
|
TPQConnectStatus = (CONNECTION_OK, CONNECTION_BAD, CONNECTION_STARTED, CONNECTION_MADE, CONNECTION_AWAITING_RESPONSE, CONNECTION_AUTH_OK, CONNECTION_SETENV, CONNECTION_SSL_STARTUP, CONNECTION_NEEDED);
|
|
PPGconn = Pointer;
|
|
PPGresult = Pointer;
|
|
POid = Cardinal; // Object ID is a fundamental type in Postgres.
|
|
TPostgreSQLLib = class(TDbLib)
|
|
PQconnectdb: function(const ConnInfo: PAnsiChar): PPGconn cdecl;
|
|
PQerrorMessage: function(const Handle: PPGconn): PAnsiChar cdecl;
|
|
PQresultErrorMessage: function(const Result: PPGresult): PAnsiChar cdecl;
|
|
PQresultErrorField: function(const Result: PPGresult; fieldcode: Integer): PAnsiChar;
|
|
PQfinish: procedure(const Handle: PPGconn);
|
|
PQstatus: function(const Handle: PPGconn): TPQConnectStatus cdecl;
|
|
PQsendQuery: function(const Handle: PPGconn; command: PAnsiChar): Integer cdecl;
|
|
PQgetResult: function(const Handle: PPGconn): PPGresult cdecl;
|
|
PQbackendPID: function(const Handle: PPGconn): Integer cdecl;
|
|
PQcmdTuples: function(Result: PPGresult): PAnsiChar; cdecl;
|
|
PQntuples: function(Result: PPGresult): Integer; cdecl;
|
|
PQclear: procedure(Result: PPGresult); cdecl;
|
|
PQnfields: function(Result: PPGresult): Integer; cdecl;
|
|
PQfname: function(const Result: PPGresult; column_number: Integer): PAnsiChar; cdecl;
|
|
PQftype: function(const Result: PPGresult; column_number: Integer): POid; cdecl;
|
|
PQftable: function(const Result: PPGresult; column_number: Integer): POid; cdecl;
|
|
PQgetvalue: function(const Result: PPGresult; row_number: Integer; column_number: Integer): PAnsiChar; cdecl;
|
|
PQgetlength: function(const Result: PPGresult; row_number: Integer; column_number: Integer): Integer; cdecl;
|
|
PQgetisnull: function(const Result: PPGresult; row_number: Integer; column_number: Integer): Integer; cdecl;
|
|
PQlibVersion: function(): Integer; cdecl;
|
|
protected
|
|
procedure AssignProcedures; override;
|
|
end;
|
|
|
|
TPostgreSQLProvider = class(TSqlProvider)
|
|
public
|
|
function GetSql(AId: TQueryId): string; override;
|
|
end;
|
|
|
|
const InvalidOid: POid = 0;
|
|
|
|
var
|
|
PostgreSQLDatatypes: Array[0..38] of TDBDatatype =
|
|
(
|
|
(
|
|
Index: dbdtUnknown;
|
|
NativeTypes: '99999';
|
|
Name: 'UNKNOWN';
|
|
Description: 'Unknown data type';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcOther;
|
|
),
|
|
(
|
|
Index: dbdtSmallint;
|
|
NativeTypes: '21';
|
|
Name: 'SMALLINT';
|
|
Names: 'smallint|int2';
|
|
Description: 'Small-range integer. Range: -32768 to +32767. Storage Size: 2 Bytes.';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
ValueMustMatch: '^\d{1,5}$';
|
|
Category: dtcInteger;
|
|
),
|
|
(
|
|
Index: dbdtInt;
|
|
// 26 = oid, 28 = xid
|
|
NativeTypes: '23|26|28';
|
|
Name: 'INTEGER';
|
|
Names: 'integer|int4|int|oid|xid';
|
|
Description: 'Typical choice for integer. Range: -2147483648 to +2147483647. Storage Size: 4 Bytes.';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
ValueMustMatch: '^\d{1,10}$';
|
|
Category: dtcInteger;
|
|
),
|
|
(
|
|
Index: dbdtBigint;
|
|
NativeTypes: '20';
|
|
Name: 'BIGINT';
|
|
Names: 'bigint|int8';
|
|
Description: 'Large-range integer. Range: -9223372036854775808 to 9223372036854775807. Storage Size: 8 Bytes.';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
ValueMustMatch: '^\d{1,19}$';
|
|
Category: dtcInteger;
|
|
),
|
|
(
|
|
Index: dbdtSerial;
|
|
Name: 'SERIAL';
|
|
Names: 'serial|serial4';
|
|
Description: 'Autoincrementing integer. Range: 1 to 2147483647. Storage Size: 4 Bytes.';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcInteger;
|
|
),
|
|
(
|
|
Index: dbdtBigSerial;
|
|
Name: 'BIGSERIAL';
|
|
Names: 'bigserial|serial8';
|
|
Description: 'Large autoincrementing integer. Range: 1 to 9223372036854775807. Storage Size: 8 Bytes.';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcInteger;
|
|
),
|
|
(
|
|
Index: dbdtVarBit;
|
|
NativeTypes: '1562';
|
|
Name: 'BIT VARYING';
|
|
Names: 'bit varying|varbit';
|
|
Description: 'Variable-length bit string.';
|
|
HasLength: True;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: True;
|
|
LoadPart: False;
|
|
Category: dtcInteger;
|
|
),
|
|
(
|
|
Index: dbdtBit;
|
|
NativeTypes: '1560';
|
|
Name: 'BIT';
|
|
Names: 'bit';
|
|
Description: 'Fixed-length bit string.';
|
|
HasLength: True;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: True;
|
|
LoadPart: False;
|
|
Category: dtcInteger;
|
|
),
|
|
(
|
|
Index: dbdtNumeric;
|
|
NativeTypes: '1700';
|
|
Name: 'NUMERIC';
|
|
Names: 'numeric|float8|decimal';
|
|
Description: 'User-specified precision, exact. Range: no limit. Storage Size: variable.';
|
|
HasLength: True;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcReal;
|
|
),
|
|
(
|
|
Index: dbdtReal;
|
|
NativeTypes: '700';
|
|
Name: 'REAL';
|
|
Names: 'real|float4';
|
|
Description: 'Variable-precision, inexact. Range: 6 decimal digits precision. Storage Size: 4 Bytes.';
|
|
HasLength: True;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcReal;
|
|
),
|
|
(
|
|
Index: dbdtDoublePrecision;
|
|
NativeTypes: '701|1700';
|
|
Name: 'DOUBLE PRECISION';
|
|
Names: 'double precision|float8';
|
|
Description: 'Variable-precision, inexact. Range: 15 decimal digits precision. Storage Size: 8 Bytes.';
|
|
HasLength: True;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcReal;
|
|
),
|
|
(
|
|
Index: dbdtChar;
|
|
NativeTypes: '18|1042';
|
|
Name: 'CHAR';
|
|
Names: 'CHARACTER';
|
|
Description: 'Fixed-length, blank padded.';
|
|
HasLength: True;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: True;
|
|
Category: dtcText;
|
|
),
|
|
(
|
|
Index: dbdtVarchar;
|
|
NativeTypes: '18|19|24|1043|1043';
|
|
Name: 'VARCHAR';
|
|
Names: 'char|bpchar|varchar|name|enum|character varying';
|
|
Description: 'Variable-length with limit.';
|
|
HasLength: True;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: True;
|
|
Category: dtcText;
|
|
),
|
|
(
|
|
Index: dbdtText;
|
|
NativeTypes: '25|22|30|143|629|651|719|791|1000|1028|1040|1041|1115|1182|1183|1185|1187|1231|1263|1270|1561|1563|2201|2207|2211|2949|2951|3643|3644|3645|3735|3770';
|
|
Name: 'TEXT';
|
|
Names: 'text|int2vector|oidvector|bool';
|
|
Description: 'Variable unlimited length.';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: True;
|
|
Category: dtcText;
|
|
),
|
|
(
|
|
Index: dbdtCiText;
|
|
NativeTypes: '?';
|
|
Name: 'CITEXT';
|
|
Names: 'citext';
|
|
Description: 'A case-insensitive character string type. Essentially, it internally calls lower when comparing values. Otherwise, it behaves almost exactly like text.';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: True;
|
|
Category: dtcText;
|
|
),
|
|
(
|
|
Index: dbdtCidr;
|
|
NativeTypes: '650';
|
|
Name: 'CIDR';
|
|
Names: 'cidr';
|
|
Description: 'IPv4 and IPv6 networks. Storage size: 7 or 19 bytes';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcText;
|
|
),
|
|
(
|
|
Index: dbdtInet;
|
|
NativeTypes: '869';
|
|
Name: 'INET';
|
|
Names: 'inet';
|
|
Description: 'IPv4 and IPv6 hosts and networks. Storage size: 7 or 19 bytes';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcText;
|
|
),
|
|
(
|
|
Index: dbdtMacaddr;
|
|
NativeTypes: '829';
|
|
Name: 'MACADDR';
|
|
Names: 'macaddr';
|
|
Description: 'MAC addresses. Storage size: 6 bytes';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcText;
|
|
),
|
|
(
|
|
Index: dbdtMoney;
|
|
NativeTypes: '790';
|
|
Name: 'MONEY';
|
|
Description: 'Currency amount. Range: -92233720368547758.08 to +92233720368547758.07. Storage Size: 8 Bytes.';
|
|
HasLength: True;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcText;
|
|
),
|
|
(
|
|
Index: dbdtDate;
|
|
NativeTypes: '1082';
|
|
Name: 'DATE';
|
|
Description: 'Calendar date (year, month, day).';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Format: 'yyyy-mm-dd';
|
|
Category: dtcTemporal;
|
|
),
|
|
(
|
|
Index: dbdtTime;
|
|
NativeTypes: '1083';
|
|
Name: 'TIME';
|
|
Description: 'Time of day.';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Format: 'hh:nn:ss';
|
|
Category: dtcTemporal;
|
|
),
|
|
(
|
|
Index: dbdtDatetime;
|
|
NativeTypes: '1082|1114|702';
|
|
Name: 'TIMESTAMP';
|
|
Names: 'timestamp|datetime|abstime|timestamp without time zone';
|
|
Description: 'Date and time without timezone, e.g. "2020-06-27 16:24:41".';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Format: 'yyyy-mm-dd hh:nn:ss';
|
|
Category: dtcTemporal;
|
|
),
|
|
(
|
|
Index: dbdtDatetime2;
|
|
NativeTypes: '1184';
|
|
Name: 'TIMESTAMPTZ';
|
|
Names: 'timestamptz|timestamp with time zone';
|
|
Description: 'Date and time with time zone, e.g. "2020-06-27 16:24:41+02".';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Format: 'yyyy-mm-dd hh:nn:ss';
|
|
Category: dtcTemporal;
|
|
),
|
|
(
|
|
Index: dbdtDate;
|
|
NativeTypes: '1082';
|
|
Name: 'DATE';
|
|
Description: 'Calendar date (year, month, day).';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Format: 'yyyy-mm-dd';
|
|
Category: dtcTemporal;
|
|
),
|
|
(
|
|
Index: dbdtInterval;
|
|
NativeTypes: '1186';
|
|
Name: 'INTERVAL';
|
|
Description: 'time interval from -178000000 years to 178000000 years';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Format: 'yyyy-mm-dd hh:nn:ss';
|
|
Category: dtcTemporal;
|
|
),
|
|
(
|
|
Index: dbdtBlob;
|
|
NativeTypes: '17';
|
|
Name: 'BYTEA';
|
|
Description: 'Binary data ("byte array").';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: True;
|
|
Category: dtcBinary;
|
|
),
|
|
(
|
|
Index: dbdtPoint;
|
|
NativeTypes: '600';
|
|
Name: 'POINT';
|
|
Description: 'Point on a plane (x,y). Storage size: 16 bytes.';
|
|
HasLength: True;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcSpatial;
|
|
),
|
|
(
|
|
Index: dbdtLinestring;
|
|
NativeTypes: '628';
|
|
Name: 'LINE';
|
|
Description: 'Infinite line ((x1,y1),(x2,y2)). Storage size: 32 bytes.';
|
|
HasLength: True;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcSpatial;
|
|
),
|
|
(
|
|
Index: dbdtLineSegment;
|
|
NativeTypes: '601';
|
|
Name: 'LSEG';
|
|
Description: 'Finite line segment ((x1,y1),(x2,y2)). Storage size: 32 bytes.';
|
|
HasLength: True;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcSpatial;
|
|
),
|
|
(
|
|
Index: dbdtBox;
|
|
NativeTypes: '603';
|
|
Name: 'BOX';
|
|
Description: 'Rectangular box ((x1,y1),(x2,y2)). Storage size: 32 bytes.';
|
|
HasLength: True;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcSpatial;
|
|
),
|
|
(
|
|
Index: dbdtPath;
|
|
NativeTypes: '602';
|
|
Name: 'PATH';
|
|
Description: 'Closed path (similar to polygon) ((x1,y1),...). Storage size: 16+16n bytes.';
|
|
HasLength: True;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcSpatial;
|
|
),
|
|
(
|
|
Index: dbdtPolygon;
|
|
NativeTypes: '604';
|
|
Name: 'POLYGON';
|
|
Description: 'Closed path (similar to polygon) ((x1,y1),...). Storage size: 40+16n bytes.';
|
|
HasLength: True;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcSpatial;
|
|
),
|
|
(
|
|
Index: dbdtCircle;
|
|
NativeTypes: '718';
|
|
Name: 'CIRCLE';
|
|
Description: 'Circle <(x,y),r> (center point and radius). Storage size: 24 bytes.';
|
|
HasLength: True;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcSpatial;
|
|
),
|
|
(
|
|
Index: dbdtBool;
|
|
NativeTypes: '16';
|
|
Name: 'BOOLEAN';
|
|
Names: 'boolean|bool';
|
|
Description: 'State of true or false. Storage size: 1 byte.';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
ValueMustMatch: '^(true|false)$';
|
|
Category: dtcOther;
|
|
),
|
|
(
|
|
Index: dbdtRegClass;
|
|
NativeTypes: '2205';
|
|
Name: 'REGCLASS';
|
|
Names: 'regclass';
|
|
Description: 'Relation name';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcOther;
|
|
),
|
|
(
|
|
Index: dbdtRegProc;
|
|
NativeTypes: '24';
|
|
Name: 'REGPROC';
|
|
Names: 'regproc|regprocedure';
|
|
Description: 'Function name';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcOther;
|
|
),
|
|
(
|
|
Index: dbdtJson;
|
|
NativeTypes: '114';
|
|
Name: 'JSON';
|
|
Names: 'json';
|
|
Description: 'JavaScript Object Notation data';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcText;
|
|
),
|
|
(
|
|
Index: dbdtJsonB;
|
|
NativeTypes: '3802';
|
|
Name: 'JSONB';
|
|
Names: 'jsonb';
|
|
Description: 'JavaScript Object Notation data in a binary form';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
Category: dtcText;
|
|
),
|
|
(
|
|
Index: dbdtUniqueidentifier;
|
|
NativeTypes: '2950';
|
|
Name: 'UUID';
|
|
Names: 'uuid';
|
|
Description: 'The data type uuid stores Universally Unique Identifiers (UUID) as defined by RFC 4122, ISO/IEC 9834-8:2005, and related standards.';
|
|
HasLength: False;
|
|
RequiresLength: False;
|
|
HasBinary: False;
|
|
HasDefault: False;
|
|
LoadPart: False;
|
|
ValueMustMatch: '^\{?[a-f0-9]{8}-?[a-f0-9]{4}-?[a-f0-9]{4}-?[a-f0-9]{4}-?[a-f0-9]{12}\}?$';
|
|
Category: dtcText;
|
|
)
|
|
);
|
|
|
|
implementation
|
|
|
|
procedure TPostgreSQLLib.AssignProcedures;
|
|
begin
|
|
AssignProc(@PQconnectdb, 'PQconnectdb');
|
|
AssignProc(@PQerrorMessage, 'PQerrorMessage');
|
|
AssignProc(@PQresultErrorMessage, 'PQresultErrorMessage');
|
|
AssignProc(@PQresultErrorField, 'PQresultErrorField');
|
|
AssignProc(@PQfinish, 'PQfinish');
|
|
AssignProc(@PQstatus, 'PQstatus');
|
|
AssignProc(@PQsendQuery, 'PQsendQuery');
|
|
AssignProc(@PQgetResult, 'PQgetResult');
|
|
AssignProc(@PQbackendPID, 'PQbackendPID');
|
|
AssignProc(@PQcmdTuples, 'PQcmdTuples');
|
|
AssignProc(@PQntuples, 'PQntuples');
|
|
AssignProc(@PQclear, 'PQclear');
|
|
AssignProc(@PQnfields, 'PQnfields');
|
|
AssignProc(@PQfname, 'PQfname');
|
|
AssignProc(@PQftype, 'PQftype');
|
|
AssignProc(@PQftable, 'PQftable');
|
|
AssignProc(@PQgetvalue, 'PQgetvalue');
|
|
AssignProc(@PQgetlength, 'PQgetlength');
|
|
AssignProc(@PQgetisnull, 'PQgetisnull');
|
|
AssignProc(@PQlibVersion, 'PQlibVersion');
|
|
end;
|
|
|
|
|
|
{ TPostgreSQLProvider }
|
|
|
|
function TPostgreSQLProvider.GetSql(AId: TQueryId): string;
|
|
begin
|
|
case AId of
|
|
qDatabaseDrop: Result := 'DROP SCHEMA %s';
|
|
qEmptyTable: Result := 'DELETE FROM ';
|
|
qRenameTable: Result := 'ALTER TABLE %s RENAME TO %s';
|
|
qRenameView: Result := 'ALTER VIEW %s RENAME TO %s';
|
|
qCurrentUserHost: Result := 'SELECT CURRENT_USER';
|
|
qLikeCompare: Result := '%s ILIKE %s';
|
|
qAddColumn: Result := 'ADD %s';
|
|
qChangeColumn: Result := 'ALTER COLUMN %s %s';
|
|
qRenameColumn: Result := 'RENAME COLUMN %s TO %s';
|
|
qForeignKeyEventAction: Result := 'RESTRICT,CASCADE,SET NULL,NO ACTION,SET DEFAULT';
|
|
qSessionVariables: Result := 'SHOW ALL';
|
|
qGlobalVariables: Result := 'SHOW ALL';
|
|
qISSchemaCol: Result := '%s_schema';
|
|
qUSEQuery: Result := 'SET search_path TO %s';
|
|
qKillQuery: Result := 'SELECT pg_cancel_backend(%d)';
|
|
qKillProcess: Result := 'SELECT pg_cancel_backend(%d)';
|
|
qFuncLength: Result := 'LENGTH';
|
|
qFuncCeil: Result := 'CEIL';
|
|
qFuncLeft: Result := 'SUBSTRING(%s, 1, %d)';
|
|
qFuncNow: Result := 'NOW()';
|
|
qFuncLastAutoIncNumber: Result := 'LASTVAL()';
|
|
qLockedTables: Result := '';
|
|
qDisableForeignKeyChecks: Result := '';
|
|
qEnableForeignKeyChecks: Result := '';
|
|
qForeignKeyDrop: Result := 'DROP CONSTRAINT %s';
|
|
|
|
// This uses pg_attribute.attgenerated, which only exists starting in PostgreSQL 12
|
|
qGetTableColumns: Result := IfThen(
|
|
FServerVersion >= 120000,
|
|
'SELECT ' +
|
|
' n.nspname AS table_schema, ' +
|
|
' c.relname AS table_name, ' +
|
|
' a.attname AS column_name, ' +
|
|
' a.attnum AS ordinal_position, ' +
|
|
' pg_catalog.format_type(a.atttypid, a.atttypmod) AS data_type, ' +
|
|
// YES/NO like information_schema.is_nullable
|
|
' CASE ' +
|
|
' WHEN a.attnotnull THEN ''NO'' ' +
|
|
' ELSE ''YES'' ' +
|
|
' END AS is_nullable, ' +
|
|
// Character maximum length (in characters)
|
|
' CASE ' +
|
|
' WHEN (bt.typcategory = ''S'' OR (bt.oid IS NULL AND t.typcategory = ''S'')) ' +
|
|
' AND a.atttypmod <> -1 ' +
|
|
' THEN a.atttypmod - 4 ' +
|
|
' ELSE NULL ' +
|
|
' END AS character_maximum_length, ' +
|
|
// Numeric precision / scale (NULL for non-numeric)
|
|
' CASE ' +
|
|
' WHEN (bt.typcategory IN (''N'',''F'')) OR (bt.oid IS NULL AND t.typcategory IN (''N'',''F'')) ' +
|
|
' THEN ' +
|
|
' CASE ' +
|
|
' WHEN a.atttypmod = -1 THEN NULL ' +
|
|
' ELSE ((a.atttypmod - 4) >> 16)::integer ' +
|
|
' END ' +
|
|
' END AS numeric_precision, ' +
|
|
' CASE ' +
|
|
' WHEN (bt.typcategory IN (''N'',''F'')) OR (bt.oid IS NULL AND t.typcategory IN (''N'',''F'')) ' +
|
|
' THEN ' +
|
|
' CASE ' +
|
|
' WHEN a.atttypmod = -1 THEN NULL ' +
|
|
' ELSE ((a.atttypmod - 4) & 65535)::integer ' +
|
|
' END ' +
|
|
' END AS numeric_scale, ' +
|
|
// Datetime precision (for time/timestamp/interval)
|
|
' CASE ' +
|
|
' WHEN (bt.typcategory = ''D'' OR (bt.oid IS NULL AND t.typcategory = ''D'')) ' +
|
|
' AND a.atttypmod <> -1 ' +
|
|
' THEN a.atttypmod ' +
|
|
' ELSE NULL ' +
|
|
' END AS datetime_precision, ' +
|
|
// Character set name: PostgreSQL has one per DB; mimic information_schema
|
|
' CASE ' +
|
|
' WHEN (bt.typcategory = ''S'' OR (bt.oid IS NULL AND t.typcategory = ''S'')) ' +
|
|
' THEN current_database() ' +
|
|
' ELSE NULL ' +
|
|
' END AS character_set_name, ' +
|
|
// Collation name for collatable columns
|
|
' CASE ' +
|
|
' WHEN (bt.typcategory = ''S'' OR (bt.oid IS NULL AND t.typcategory = ''S'')) ' +
|
|
' THEN ' +
|
|
' CASE ' +
|
|
' WHEN a.attcollation <> t.typcollation ' +
|
|
' THEN coll.collname ' +
|
|
' ELSE NULL ' +
|
|
' END ' +
|
|
' ELSE NULL ' +
|
|
' END AS collation_name, ' +
|
|
// Default expression for non-generated columns
|
|
' CASE ' +
|
|
' WHEN a.attgenerated = '''' AND a.atthasdef ' +
|
|
' THEN pg_get_expr(ad.adbin, ad.adrelid) ' +
|
|
' ELSE NULL ' +
|
|
' END AS column_default, ' +
|
|
// Generation expression for generated columns
|
|
' CASE ' +
|
|
' WHEN a.attgenerated <> '''' AND a.atthasdef ' +
|
|
' THEN pg_get_expr(ad.adbin, ad.adrelid) ' +
|
|
' ELSE NULL ' +
|
|
' END AS generation_expression, ' +
|
|
' d.description AS column_comment ' +
|
|
'FROM pg_catalog.pg_class AS c ' +
|
|
'JOIN pg_catalog.pg_namespace AS n ON n.oid = c.relnamespace ' +
|
|
'JOIN pg_catalog.pg_attribute AS a ON a.attrelid = c.oid ' +
|
|
'JOIN pg_catalog.pg_type AS t ON t.oid = a.atttypid ' +
|
|
'LEFT JOIN pg_catalog.pg_type AS bt ON bt.oid = t.typbasetype ' +
|
|
'LEFT JOIN pg_catalog.pg_attrdef AS ad ' +
|
|
' ON ad.adrelid = a.attrelid ' +
|
|
' AND ad.adnum = a.attnum ' +
|
|
'LEFT JOIN pg_catalog.pg_description AS d ' +
|
|
' ON d.objoid = a.attrelid ' +
|
|
' AND d.objsubid = a.attnum ' +
|
|
'LEFT JOIN pg_catalog.pg_collation AS coll ' +
|
|
' ON coll.oid = a.attcollation ' +
|
|
'WHERE n.nspname = %s ' +
|
|
' AND a.attnum > 0 ' +
|
|
' AND NOT a.attisdropped ' +
|
|
' AND c.relname = %s ' +
|
|
'ORDER BY ordinal_position',
|
|
'' // ServerVersion < 12
|
|
);
|
|
|
|
qGetCharsets: Result := 'SELECT DISTINCT pg_encoding_to_char(enc) AS "Charset" FROM '+
|
|
'(SELECT conforencoding AS enc FROM pg_catalog.pg_conversion '+
|
|
' UNION '+
|
|
' SELECT contoencoding AS enc FROM pg_catalog.pg_conversion) AS x';
|
|
qGetRowCountApprox: Result := 'SELECT reltuples::bigint FROM pg_class'+
|
|
' LEFT JOIN pg_namespace ON pg_namespace.oid = pg_class.relnamespace'+
|
|
' WHERE pg_class.relkind=''r'''+
|
|
' AND pg_namespace.nspname=:EscapedDatabase'+
|
|
' AND pg_class.relname=:EscapedName';
|
|
else Result := inherited;
|
|
end;
|
|
end;
|
|
|
|
|
|
end.
|