253 lines
9.2 KiB
ObjectPascal
253 lines
9.2 KiB
ObjectPascal
unit uDAPostgresInterfaces;
|
|
|
|
{----------------------------------------------------------------------------}
|
|
{ Data Abstract Library - Core Library }
|
|
{ }
|
|
{ compiler: Delphi 6 and up, Kylix 3 and up }
|
|
{ platform: Win32, Linux }
|
|
{ }
|
|
{ (c)opyright RemObjects Software. all rights reserved. }
|
|
{ }
|
|
{ Using this code requires a valid license of the Data Abstract }
|
|
{ which can be obtained at http://www.remobjects.com. }
|
|
{----------------------------------------------------------------------------}
|
|
|
|
{$I DataAbstract.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
SysUtils,
|
|
uDAInterfaces, uDAEngine, uROClasses;
|
|
|
|
type
|
|
{ IDAPostgresConnection
|
|
For identification purposes Implemented by all Postgres connections }
|
|
IDAPostgresConnection = interface(IDAConnection)
|
|
['{D8EADB7E-7AA0-48FF-9E7D-34853F999BFC}']
|
|
end;
|
|
|
|
TDAPostgresDriver = class(TDAEDriver)
|
|
protected
|
|
function GetDefaultConnectionType(const AuxDriver: string): string; override; safecall;
|
|
public
|
|
end;
|
|
|
|
TDAEPostgresConnection = class(TDAEConnection, IDAPostgresConnection, IDACanQueryDatabaseNames, IDAUseGenerators)
|
|
protected
|
|
function DoGetLastAutoInc(const GeneratorName: string): integer; override;
|
|
procedure DoGetTableFields(const aTableName: string; out Fields: TDAFieldCollection); override;
|
|
// IDACanQueryDatabaseNames
|
|
function GetDatabaseNames: IROStrings;
|
|
// IDAUseGenerators
|
|
function GetNextAutoinc(const GeneratorName: string): integer; safecall;
|
|
end;
|
|
|
|
function Postgres_GetDatabaseNames(aConnection: TDAEConnection): IROStrings;
|
|
function Postgres_DoGetLastAutoInc(const GeneratorName: string; Query: IDADataset): integer;
|
|
function Postgres_GetNextAutoInc(const GeneratorName: string; Query: IDADataset): integer;
|
|
procedure Postgres_DoGetTableFields(const aTableName: string; Query: IDADataset; out Fields: TDAFieldCollection);
|
|
function PostgresDataTypeToDA(aDataType: string; Unicode: Boolean): TDADataType;
|
|
|
|
const
|
|
PostgreSQL_DriverType = 'PostgreSQL';
|
|
|
|
implementation
|
|
|
|
const
|
|
Postgres_MasterDatabase = 'template1';
|
|
Postgres_GetDatabaseNames_SQL = 'SELECT datname FROM pg_database ORDER BY datname';
|
|
|
|
function PostgresDataTypeToDA(aDataType: string; Unicode: Boolean): TDADataType;
|
|
begin
|
|
aDataType := LowerCase(aDataType);
|
|
if pos(' ', aDataType) <> 0 then Delete(aDataType, Pos(' ', aDataType), MaxInt);
|
|
if (aDAtaType = 'varchar') or (aDataType = 'charactervarying') or
|
|
(aDataType = 'character') or (aDataType = 'char') then begin
|
|
if Unicode then
|
|
Result := datWideString
|
|
else
|
|
Result := datString;
|
|
end else if aDataType = 'text' then begin
|
|
if Unicode then
|
|
Result := datWideMemo
|
|
else
|
|
Result := datMemo;
|
|
end else if (aDataType = 'blob') or (aDataType = 'binary') or (aDAtaType = 'varbinary') then
|
|
Result := datBlob
|
|
else if (aDataType = 'date') or
|
|
(aDataType = 'time') or (aDataType = 'timetz') or
|
|
(aDataType = 'datetime') or
|
|
(aDataType = 'timestamp') or (aDataType = 'timestamptz') or
|
|
(aDataType = 'year') then
|
|
result := datDateTime
|
|
else if (aDataType = 'single') or
|
|
(aDataType = 'real') or (aDataType = 'float4') then
|
|
Result := datSingleFloat
|
|
else if (aDataType = 'double') or
|
|
(aDataType = 'float') or
|
|
(aDataType = 'doubleprecision') or (aDataType = 'float8') then
|
|
Result := datFloat
|
|
else if (aDataType = 'bit') or (aDataType = 'boolean') or (aDataType = 'bool') then
|
|
Result := datBoolean
|
|
else if (aDataType = 'bigint') or (aDataType = 'int8') then
|
|
result := datLargeInt
|
|
else if (aDataType = 'decimal') or (aDataType = 'numeric') then
|
|
result := datDecimal
|
|
else if (aDataType = 'money') then
|
|
result := datCurrency
|
|
else if (aDataType = 'serial') or (aDataType = 'serial4') then
|
|
result := datAutoInc
|
|
else if (aDataType = 'bigserial') or (aDataType = 'serial8') then
|
|
result := datLargeAutoInc
|
|
else if (aDataType = 'smallint') or (aDataType = 'int2') then
|
|
result := datSmallInt
|
|
else if (aDataType = 'shortint') or (aDataType = 'int1') then
|
|
result := datShortInt
|
|
else if (aDataType = 'enum') or
|
|
(aDataType = 'int4') or (adatatype = 'int') or (adatatype = 'integer') or
|
|
(aDataType = 'tinyint') then
|
|
result := datInteger
|
|
else
|
|
result := datUnknown;
|
|
end;
|
|
|
|
function Postgres_GetDatabaseNames(aConnection: TDAEConnection): IROStrings;
|
|
begin
|
|
Result := Engine_GetDatabaseNames(aConnection, Postgres_MasterDatabase, Postgres_GetDatabaseNames_SQL);
|
|
end;
|
|
|
|
function Postgres_DoGetLastAutoInc(const GeneratorName: string; Query: IDADataset): integer;
|
|
begin
|
|
try
|
|
Query.SQL := 'SELECT currval(''' + GeneratorName + ''')';
|
|
Query.Open;
|
|
result := Query.Fields[0].Value;
|
|
finally
|
|
Query := nil;
|
|
end;
|
|
end;
|
|
|
|
function Postgres_GetNextAutoInc(const GeneratorName: string; Query: IDADataset): integer;
|
|
begin
|
|
try
|
|
Query.SQL := 'SELECT nextval(''' + GeneratorName + '''text)';
|
|
Query.Open;
|
|
result := Query.Fields[0].Value;
|
|
finally
|
|
Query := nil;
|
|
end;
|
|
end;
|
|
|
|
procedure Postgres_DoGetTableFields(const aTableName: string; Query: IDADataset; out Fields: TDAFieldCollection);
|
|
const
|
|
main_sql = 'SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT, CHARACTER_MAXIMUM_LENGTH, CHARACTER_SET_NAME ' +
|
|
'FROM INFORMATION_SCHEMA.COLUMNS ' +
|
|
'WHERE TABLE_NAME=''{tbl}'' and TABLE_SCHEMA=''{schem} ''' +
|
|
'ORDER BY ORDINAL_POSITION';
|
|
pk_sql = 'SELECT COLUMN_NAME ' +
|
|
'FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE ' +
|
|
'WHERE TABLE_NAME=''{tbl}'' and TABLE_SCHEMA=''{schem}'' AND CONSTRAINT_NAME like ''%_pkey''';
|
|
var
|
|
fld : TDAField;
|
|
lSchema, lTable : string;
|
|
p1 : integer;
|
|
s : string;
|
|
begin
|
|
Fields := TDAFieldCollection.Create(nil);
|
|
try
|
|
Query.SQL := 'SELECT * FROM ' + aTableName + ' WHERE 1=0';
|
|
Query.Open;
|
|
Fields.Assign(Query.Fields);
|
|
Query.Close;
|
|
Query.SQL := main_sql;
|
|
lTable := aTableName;
|
|
if pos('.', lTable) = 0 then begin
|
|
lSchema := 'public'
|
|
end else begin
|
|
lSchema := copy(lTable, 1, pos('.', lTable) - 1);
|
|
Delete(lTable, 1, pos('.', lTable));
|
|
end;
|
|
Query.SQL := StringReplace(Query.SQL, '{tbl}', lTable, []);
|
|
Query.SQL := StringReplace(Query.SQL, '{schem}', lSchema, []);
|
|
Query.Open;
|
|
while not Query.Eof do begin
|
|
fld := Fields.FieldByName(Query.Fields[0].AsString);
|
|
fld.Required := Query.Fields[2].AsString <> 'YES';
|
|
fld.DefaultValue := Query.Fields[3].AsString;
|
|
fld.Size := Query.Fields[4].AsInteger;
|
|
fld.DataType := PostgresDataTypeToDA(Query.Fields[1].asString, sametext(Query.Fields[5].AsString, 'utf8') or sametext(Query.Fields[5].AsString, 'utf16'));
|
|
if fld.DefaultValue <> '' then begin
|
|
if pos('nextval(', fld.DefaultValue) = 1 then begin
|
|
case fld.DataType of
|
|
datInteger: fld.DataType := datAutoInc;
|
|
datLargeInt: fld.DataType := datLargeAutoInc;
|
|
else
|
|
fld.DefaultValue := '';
|
|
end;
|
|
if fld.DefaultValue <> '' then begin
|
|
s := fld.DefaultValue;
|
|
p1 := pos('''', s);
|
|
Delete(s, 1, p1);
|
|
p1 := pos('''', s);
|
|
fld.GeneratorName := Copy(s, 1, p1 - 1);
|
|
fld.DefaultValue := '';
|
|
end;
|
|
end else if not TestDefaultValue(fld.DefaultValue, fld.DataType) then begin
|
|
fld.DefaultValue := '';
|
|
end;
|
|
end;
|
|
Query.Next;
|
|
end;
|
|
Query.Close;
|
|
Query.SQL := pk_sql;
|
|
Query.SQL := StringReplace(Query.SQL, '{tbl}', lTable, []);
|
|
Query.SQL := StringReplace(Query.SQL, '{schem}', lSchema, []);
|
|
Query.Open;
|
|
while not Query.Eof do begin
|
|
fld := Fields.FindField(Query.Fields[0].AsString);
|
|
if fld <> nil then
|
|
fld.InPrimaryKey := true;
|
|
Query.Next;
|
|
end;
|
|
finally
|
|
Query := nil;
|
|
end;
|
|
end;
|
|
|
|
{ TDAEPostgresConnection }
|
|
|
|
function TDAEPostgresConnection.DoGetLastAutoInc(
|
|
const GeneratorName: string): integer;
|
|
begin
|
|
Result := Postgres_DoGetLastAutoInc(GeneratorName, GetDatasetClass.Create(Self));
|
|
end;
|
|
|
|
procedure TDAEPostgresConnection.DoGetTableFields(const aTableName: string;
|
|
out Fields: TDAFieldCollection);
|
|
begin
|
|
Postgres_DoGetTableFields(aTableName, GetDatasetClass.Create(Self), Fields);
|
|
end;
|
|
|
|
function TDAEPostgresConnection.GetDatabaseNames: IROStrings;
|
|
begin
|
|
Result := Postgres_GetDatabaseNames(Self);
|
|
end;
|
|
|
|
function TDAEPostgresConnection.GetNextAutoinc(
|
|
const GeneratorName: string): integer;
|
|
begin
|
|
Result := Postgres_GetNextAutoInc(GeneratorName, GetDatasetClass.Create(Self));
|
|
end;
|
|
|
|
{ TDAPostgresDriver }
|
|
|
|
function TDAPostgresDriver.GetDefaultConnectionType(
|
|
const AuxDriver: string): string;
|
|
begin
|
|
Result:= PostgreSQL_DriverType;
|
|
end;
|
|
|
|
end.
|
|
|