pqconnection.pp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. unit pqconnection;
  2. {$mode objfpc}{$H+}
  3. {$Define LinkDynamically}
  4. interface
  5. uses
  6. Classes, SysUtils, sqldb, db, dbconst,
  7. {$IfDef LinkDynamically}
  8. postgres3dyn;
  9. {$Else}
  10. postgres3;
  11. {$EndIf}
  12. type
  13. TPQTrans = Class(TSQLHandle)
  14. protected
  15. TransactionHandle : PPGConn;
  16. end;
  17. TPQCursor = Class(TSQLCursor)
  18. protected
  19. Statement : string;
  20. tr : Pointer;
  21. nFields : integer;
  22. res : PPGresult;
  23. BaseRes : PPGresult;
  24. Nr : string;
  25. end;
  26. TPQConnection = class (TSQLConnection)
  27. private
  28. FCursorCount : word;
  29. FConnectString : string;
  30. FSQLDatabaseHandle : pointer;
  31. function TranslateFldType(Type_Oid : integer) : TFieldType;
  32. protected
  33. procedure DoInternalConnect; override;
  34. procedure DoInternalDisconnect; override;
  35. function GetHandle : pointer; override;
  36. Function AllocateCursorHandle : TSQLCursor; override;
  37. Procedure DeAllocateCursorHandle(var cursor : TSQLCursor); override;
  38. Function AllocateTransactionHandle : TSQLHandle; override;
  39. procedure PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams); override;
  40. procedure FreeFldBuffers(cursor : TSQLCursor); override;
  41. procedure Execute(cursor: TSQLCursor;atransaction:tSQLtransaction; AParams : TParams); override;
  42. procedure AddFieldDefs(cursor: TSQLCursor; FieldDefs : TfieldDefs); override;
  43. function Fetch(cursor : TSQLCursor) : boolean; override;
  44. procedure UnPrepareStatement(cursor : TSQLCursor); override;
  45. function LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer) : boolean; override;
  46. function GetTransactionHandle(trans : TSQLHandle): pointer; override;
  47. function RollBack(trans : TSQLHandle) : boolean; override;
  48. function Commit(trans : TSQLHandle) : boolean; override;
  49. procedure CommitRetaining(trans : TSQLHandle); override;
  50. function StartdbTransaction(trans : TSQLHandle; AParams : string) : boolean; override;
  51. procedure RollBackRetaining(trans : TSQLHandle); override;
  52. procedure UpdateIndexDefs(var IndexDefs : TIndexDefs;TableName : string); override;
  53. public
  54. constructor Create(AOwner : TComponent); override;
  55. published
  56. property DatabaseName;
  57. property KeepConnection;
  58. property LoginPrompt;
  59. property Params;
  60. property OnLogin;
  61. end;
  62. implementation
  63. ResourceString
  64. SErrRollbackFailed = 'Rollback transaction failed';
  65. SErrCommitFailed = 'Commit transaction failed';
  66. SErrConnectionFailed = 'Connection to database failed';
  67. SErrTransactionFailed = 'Start of transacion failed';
  68. SErrClearSelection = 'Clear of selection failed';
  69. SErrExecuteFailed = 'Execution of query failed';
  70. SErrFieldDefsFailed = 'Can not extract field information from query';
  71. SErrFetchFailed = 'Fetch of data failed';
  72. SErrNoDatabaseName = 'Database connect string (DatabaseName) not filled in!';
  73. SErrPrepareFailed = 'Preparation of query failed.';
  74. const Oid_Bool = 16;
  75. Oid_Text = 25;
  76. Oid_Name = 19;
  77. Oid_Int8 = 20;
  78. Oid_int2 = 21;
  79. Oid_Int4 = 23;
  80. Oid_Float4 = 700;
  81. Oid_Float8 = 701;
  82. Oid_bpchar = 1042;
  83. Oid_varchar = 1043;
  84. Oid_timestamp = 1114;
  85. oid_date = 1082;
  86. oid_time = 1083;
  87. oid_numeric = 1700;
  88. constructor TPQConnection.Create(AOwner : TComponent);
  89. begin
  90. inherited;
  91. FConnOptions := FConnOptions + [sqSupportParams];
  92. end;
  93. function TPQConnection.GetTransactionHandle(trans : TSQLHandle): pointer;
  94. begin
  95. Result := (trans as TPQtrans).TransactionHandle;
  96. end;
  97. function TPQConnection.RollBack(trans : TSQLHandle) : boolean;
  98. var
  99. res : PPGresult;
  100. tr : TPQTrans;
  101. begin
  102. result := false;
  103. tr := trans as TPQTrans;
  104. res := PQexec(tr.TransactionHandle, 'ROLLBACK');
  105. if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
  106. begin
  107. PQclear(res);
  108. result := false;
  109. DatabaseError(SErrRollbackFailed + ' (PostgreSQL: ' + PQerrorMessage(tr.transactionhandle) + ')',self);
  110. end
  111. else
  112. begin
  113. PQclear(res);
  114. PQFinish(tr.TransactionHandle);
  115. result := true;
  116. end;
  117. end;
  118. function TPQConnection.Commit(trans : TSQLHandle) : boolean;
  119. var
  120. res : PPGresult;
  121. tr : TPQTrans;
  122. begin
  123. result := false;
  124. tr := trans as TPQTrans;
  125. res := PQexec(tr.TransactionHandle, 'COMMIT');
  126. if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
  127. begin
  128. PQclear(res);
  129. result := false;
  130. DatabaseError(SErrCommitFailed + ' (PostgreSQL: ' + PQerrorMessage(tr.transactionhandle) + ')',self);
  131. end
  132. else
  133. begin
  134. PQclear(res);
  135. PQFinish(tr.TransactionHandle);
  136. result := true;
  137. end;
  138. end;
  139. function TPQConnection.StartdbTransaction(trans : TSQLHandle; AParams : string) : boolean;
  140. var
  141. res : PPGresult;
  142. tr : TPQTrans;
  143. msg : string;
  144. begin
  145. result := false;
  146. tr := trans as TPQTrans;
  147. tr.TransactionHandle := PQconnectdb(pchar(FConnectString));
  148. if (PQstatus(tr.TransactionHandle) = CONNECTION_BAD) then
  149. begin
  150. result := false;
  151. PQFinish(tr.TransactionHandle);
  152. DatabaseError(SErrConnectionFailed + ' (PostgreSQL: ' + PQerrorMessage(tr.transactionhandle) + ')',self);
  153. end
  154. else
  155. begin
  156. res := PQexec(tr.TransactionHandle, 'BEGIN');
  157. if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
  158. begin
  159. result := false;
  160. PQclear(res);
  161. msg := PQerrorMessage(tr.transactionhandle);
  162. PQFinish(tr.TransactionHandle);
  163. DatabaseError(sErrTransactionFailed + ' (PostgreSQL: ' + msg + ')',self);
  164. end
  165. else
  166. begin
  167. PQclear(res);
  168. result := true;
  169. end;
  170. end;
  171. end;
  172. procedure TPQConnection.RollBackRetaining(trans : TSQLHandle);
  173. var
  174. res : PPGresult;
  175. tr : TPQTrans;
  176. msg : string;
  177. begin
  178. tr := trans as TPQTrans;
  179. res := PQexec(tr.TransactionHandle, 'ROLLBACK');
  180. if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
  181. begin
  182. PQclear(res);
  183. DatabaseError(SErrRollbackFailed + ' (PostgreSQL: ' + PQerrorMessage(tr.transactionhandle) + ')',self);
  184. end
  185. else
  186. begin
  187. PQclear(res);
  188. res := PQexec(tr.TransactionHandle, 'BEGIN');
  189. if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
  190. begin
  191. PQclear(res);
  192. msg := PQerrorMessage(tr.transactionhandle);
  193. PQFinish(tr.TransactionHandle);
  194. DatabaseError(sErrTransactionFailed + ' (PostgreSQL: ' + msg + ')',self);
  195. end
  196. else
  197. PQclear(res);
  198. end;
  199. end;
  200. procedure TPQConnection.CommitRetaining(trans : TSQLHandle);
  201. var
  202. res : PPGresult;
  203. tr : TPQTrans;
  204. msg : string;
  205. begin
  206. tr := trans as TPQTrans;
  207. res := PQexec(tr.TransactionHandle, 'COMMIT');
  208. if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
  209. begin
  210. PQclear(res);
  211. DatabaseError(SErrCommitFailed + ' (PostgreSQL: ' + PQerrorMessage(tr.transactionhandle) + ')',self);
  212. end
  213. else
  214. begin
  215. PQclear(res);
  216. res := PQexec(tr.TransactionHandle, 'BEGIN');
  217. if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
  218. begin
  219. PQclear(res);
  220. msg := PQerrorMessage(tr.transactionhandle);
  221. PQFinish(tr.TransactionHandle);
  222. DatabaseError(sErrTransactionFailed + ' (PostgreSQL: ' + msg + ')',self);
  223. end
  224. else
  225. PQclear(res);
  226. end;
  227. end;
  228. procedure TPQConnection.DoInternalConnect;
  229. var msg : string;
  230. begin
  231. {$IfDef LinkDynamically}
  232. InitialisePostgres3;
  233. {$EndIf}
  234. inherited dointernalconnect;
  235. if (DatabaseName = '') then
  236. DatabaseError(SErrNoDatabaseName,self);
  237. FConnectString := '';
  238. if (UserName <> '') then FConnectString := FConnectString + ' user=''' + UserName + '''';
  239. if (Password <> '') then FConnectString := FConnectString + ' password=''' + Password + '''';
  240. if (HostName <> '') then FConnectString := FConnectString + ' host=''' + HostName + '''';
  241. if (DatabaseName <> '') then FConnectString := FConnectString + ' dbname=''' + DatabaseName + '''';
  242. FSQLDatabaseHandle := PQconnectdb(pchar(FConnectString));
  243. if (PQstatus(FSQLDatabaseHandle) = CONNECTION_BAD) then
  244. begin
  245. msg := PQerrorMessage(FSQLDatabaseHandle);
  246. dointernaldisconnect;
  247. DatabaseError(sErrConnectionFailed + ' (PostgreSQL: ' + msg + ')',self);
  248. end;
  249. end;
  250. procedure TPQConnection.DoInternalDisconnect;
  251. begin
  252. PQfinish(FSQLDatabaseHandle);
  253. {$IfDef LinkDynamically}
  254. ReleasePostgres3;
  255. {$EndIf}
  256. end;
  257. function TPQConnection.TranslateFldType(Type_Oid : integer) : TFieldType;
  258. begin
  259. case Type_Oid of
  260. Oid_varchar,Oid_bpchar,
  261. Oid_name : Result := ftstring;
  262. Oid_text : REsult := ftmemo;
  263. Oid_int8 : Result := ftLargeInt;
  264. Oid_int4 : Result := ftInteger;
  265. Oid_int2 : Result := ftSmallInt;
  266. Oid_Float4 : Result := ftFloat;
  267. Oid_Float8 : Result := ftFloat;
  268. Oid_TimeStamp : Result := ftDateTime;
  269. Oid_Date : Result := ftDate;
  270. Oid_Time : Result := ftTime;
  271. Oid_Bool : Result := ftBoolean;
  272. Oid_Numeric : Result := ftBCD;
  273. end;
  274. end;
  275. Function TPQConnection.AllocateCursorHandle : TSQLCursor;
  276. begin
  277. result := TPQCursor.create;
  278. end;
  279. Procedure TPQConnection.DeAllocateCursorHandle(var cursor : TSQLCursor);
  280. begin
  281. FreeAndNil(cursor);
  282. end;
  283. Function TPQConnection.AllocateTransactionHandle : TSQLHandle;
  284. begin
  285. result := TPQTrans.create;
  286. end;
  287. procedure TPQConnection.PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams);
  288. const TypeStrings : array[TFieldType] of string =
  289. (
  290. 'Unknown',
  291. 'text',
  292. 'int',
  293. 'int',
  294. 'int',
  295. 'bool',
  296. 'float',
  297. 'numeric',
  298. 'numeric',
  299. 'date',
  300. 'time',
  301. 'datetime',
  302. 'Unknown',
  303. 'Unknown',
  304. 'Unknown',
  305. 'Unknown',
  306. 'Unknown',
  307. 'Unknown',
  308. 'Unknown',
  309. 'Unknown',
  310. 'Unknown',
  311. 'Unknown',
  312. 'Unknown',
  313. 'Unknown',
  314. 'Unknown',
  315. 'int',
  316. 'Unknown',
  317. 'Unknown',
  318. 'Unknown',
  319. 'Unknown',
  320. 'Unknown',
  321. 'Unknown',
  322. 'Unknown',
  323. 'Unknown',
  324. 'Unknown',
  325. 'Unknown',
  326. 'Unknown',
  327. 'Unknown'
  328. );
  329. var s : string;
  330. i : integer;
  331. begin
  332. with (cursor as TPQCursor) do
  333. begin
  334. FPrepared := False;
  335. nr := inttostr(FCursorcount);
  336. inc(FCursorCount);
  337. // Prior to v8 there is no support for cursors and parameters.
  338. // So that's not supported.
  339. if FStatementType = stselect then
  340. statement := 'DECLARE slctst' + name + nr +' BINARY CURSOR FOR ' + buf
  341. else if FStatementType in [stInsert,stUpdate,stDelete] then
  342. begin
  343. tr := aTransaction.Handle;
  344. // Only available for pq 8.0, so don't use it...
  345. // Res := pqprepare(tr,'prepst'+name+nr,pchar(buf),params.Count,pchar(''));
  346. s := 'prepare prepst'+nr+' ';
  347. if Assigned(AParams) and (AParams.count > 0) then
  348. begin
  349. s := s + '(';
  350. for i := 0 to AParams.count-1 do
  351. begin
  352. s := s + TypeStrings[AParams[i].DataType] + ',';
  353. buf := stringreplace(buf,':'+AParams[i].Name,'$'+inttostr(i+1),[rfReplaceAll,rfIgnoreCase]);
  354. end;
  355. s[length(s)] := ')';
  356. end;
  357. s := s + ' as ' + buf;
  358. res := pqexec(tr,pchar(s));
  359. if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
  360. begin
  361. pqclear(res);
  362. DatabaseError(SErrPrepareFailed + ' (PostgreSQL: ' + PQerrorMessage(tr) + ')',self)
  363. end;
  364. FPrepared := True;
  365. end
  366. else
  367. statement := buf;
  368. end;
  369. end;
  370. procedure TPQConnection.UnPrepareStatement(cursor : TSQLCursor);
  371. begin
  372. with (cursor as TPQCursor) do if FPrepared then
  373. begin
  374. res := pqexec(tr,pchar('deallocate prepst'+nr));
  375. if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
  376. begin
  377. pqclear(res);
  378. DatabaseError(SErrPrepareFailed + ' (PostgreSQL: ' + PQerrorMessage(tr) + ')',self)
  379. end;
  380. pqclear(res);
  381. FPrepared := False;
  382. end;
  383. end;
  384. procedure TPQConnection.FreeFldBuffers(cursor : TSQLCursor);
  385. begin
  386. with cursor as TPQCursor do
  387. if (PQresultStatus(res) <> PGRES_FATAL_ERROR) then //Don't try to do anything if the transaction has already encountered an error.
  388. begin
  389. if FStatementType = stselect then
  390. begin
  391. Res := pqexec(tr,pchar('CLOSE slctst' + name + nr));
  392. if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
  393. begin
  394. pqclear(res);
  395. DatabaseError(SErrClearSelection + ' (PostgreSQL: ' + PQerrorMessage(tr) + ')',self)
  396. end
  397. end;
  398. pqclear(baseres);
  399. pqclear(res);
  400. end;
  401. end;
  402. procedure TPQConnection.Execute(cursor: TSQLCursor;atransaction:tSQLtransaction;AParams : TParams);
  403. var ar : array of pchar;
  404. i : integer;
  405. s : string;
  406. begin
  407. with cursor as TPQCursor do
  408. begin
  409. if FStatementType in [stInsert,stUpdate,stDelete] then
  410. begin
  411. if Assigned(AParams) and (AParams.count > 0) then
  412. begin
  413. setlength(ar,Aparams.count);
  414. for i := 0 to AParams.count -1 do
  415. ar[i] := pchar(AParams[i].asstring);
  416. res := PQexecPrepared(tr,pchar('prepst'+nr),Aparams.count,@Ar[0],nil,nil,0)
  417. end
  418. else
  419. res := PQexecPrepared(tr,pchar('prepst'+nr),0,nil,nil,nil,0);
  420. if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
  421. begin
  422. pqclear(res);
  423. DatabaseError(SErrExecuteFailed + ' (PostgreSQL: ' + PQerrorMessage(tr) + ')',self);
  424. end;
  425. end
  426. else
  427. begin
  428. tr := aTransaction.Handle;
  429. s := statement;
  430. //Should be altered, just like in TSQLQuery.ApplyRecUpdate
  431. if assigned(AParams) then for i := 0 to AParams.count-1 do
  432. s := stringreplace(s,':'+AParams[i].Name,AParams[i].asstring,[rfReplaceAll,rfIgnoreCase]);
  433. res := pqexec(tr,pchar(s));
  434. if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
  435. begin
  436. pqclear(res);
  437. DatabaseError(SErrExecuteFailed + ' (PostgreSQL: ' + PQerrorMessage(tr) + ')',self);
  438. end;
  439. end;
  440. end;
  441. end;
  442. procedure TPQConnection.AddFieldDefs(cursor: TSQLCursor; FieldDefs : TfieldDefs);
  443. var
  444. i : integer;
  445. size : integer;
  446. st : string;
  447. fieldtype : tfieldtype;
  448. begin
  449. with cursor as TPQCursor do
  450. begin
  451. // BaseRes := pqexecParams(tr,'FETCH 0 IN selectst' + pchar(name) ,0,nil,nil,nil,nil,1);
  452. st := pchar('FETCH 0 IN slctst' + name+nr);
  453. BaseRes := pqexec(tr,pchar(st));
  454. if (PQresultStatus(BaseRes) <> PGRES_TUPLES_OK) then
  455. begin
  456. pqclear(BaseRes);
  457. DatabaseError(SErrFieldDefsFailed + ' (PostgreSQL: ' + PQerrorMessage(tr) + ')',self)
  458. end;
  459. nFields := PQnfields(BaseRes);
  460. for i := 0 to nFields-1 do
  461. begin
  462. size := PQfsize(BaseRes, i);
  463. fieldtype := TranslateFldType(PQftype(BaseRes, i));
  464. if (fieldtype = ftstring) and (size = -1) then
  465. size := pqfmod(baseres,i)-3;
  466. if fieldtype = ftdate then
  467. size := sizeof(double);
  468. TFieldDef.Create(FieldDefs, PQfname(BaseRes, i), fieldtype,size, False, (i + 1));
  469. end;
  470. end;
  471. end;
  472. function TPQConnection.GetHandle: pointer;
  473. begin
  474. Result := FSQLDatabaseHandle;
  475. end;
  476. function TPQConnection.Fetch(cursor : TSQLCursor) : boolean;
  477. var st : string;
  478. begin
  479. with cursor as TPQCursor do
  480. begin
  481. st := pchar('FETCH NEXT IN slctst' + name+nr);
  482. Res := pqexec(tr,pchar(st));
  483. if (PQresultStatus(res) <> PGRES_TUPLES_OK) then
  484. begin
  485. pqclear(Res);
  486. DatabaseError(SErrfetchFailed + ' (PostgreSQL: ' + PQerrorMessage(tr) + ')',self)
  487. end;
  488. Result := (PQntuples(res)<>0);
  489. end;
  490. end;
  491. function TPQConnection.LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer) : boolean;
  492. var
  493. x,i : integer;
  494. li : Longint;
  495. CurrBuff : pchar;
  496. tel : byte;
  497. dbl : pdouble;
  498. begin
  499. with cursor as TPQCursor do
  500. begin
  501. for x := 0 to PQnfields(res)-1 do
  502. if PQfname(Res, x) = FieldDef.Name then break;
  503. if PQfname(Res, x) <> FieldDef.Name then
  504. DatabaseErrorFmt(SFieldNotFound,[FieldDef.Name],self);
  505. if pqgetisnull(res,0,x)=1 then
  506. result := false
  507. else
  508. begin
  509. i := PQfsize(res, x);
  510. CurrBuff := pqgetvalue(res,0,x);
  511. case FieldDef.DataType of
  512. ftInteger, ftSmallint, ftLargeInt,ftfloat :
  513. begin
  514. for tel := 1 to i do // postgres returns big-endian numbers
  515. pchar(Buffer)[tel-1] := CurrBuff[i-tel];
  516. end;
  517. ftString :
  518. begin
  519. li := pqgetlength(res,0,x);
  520. Move(CurrBuff^, Buffer^, li);
  521. pchar(Buffer + li)^ := #0;
  522. i := pqfmod(res,x)-3;
  523. end;
  524. ftdate :
  525. begin
  526. li := 0;
  527. for tel := 1 to i do // postgres returns big-endian numbers
  528. pchar(@li)[tel-1] := CurrBuff[i-tel];
  529. // double(buffer^) := x + 36526; This doesn't work, please tell me what is wrong with it?
  530. dbl := pointer(buffer);
  531. dbl^ := li + 36526;
  532. i := sizeof(double);
  533. end;
  534. ftDateTime, fttime :
  535. begin
  536. dbl := pointer(buffer);
  537. dbl^ := 0;
  538. for tel := 1 to i do // postgres returns big-endian numbers
  539. pchar(Buffer)[tel-1] := CurrBuff[i-tel];
  540. dbl^ := (dbl^+3.1558464E+009)/86400; // postgres counts seconds elapsed since 1-1-2000
  541. end;
  542. ftBCD:
  543. begin
  544. // not implemented
  545. end;
  546. ftBoolean:
  547. pchar(buffer)[0] := CurrBuff[0]
  548. end;
  549. result := true;
  550. end;
  551. end;
  552. end;
  553. procedure TPQConnection.UpdateIndexDefs(var IndexDefs : TIndexDefs;TableName : string);
  554. var qry : TSQLQuery;
  555. begin
  556. if not assigned(Transaction) then
  557. DatabaseError(SErrConnTransactionnSet);
  558. qry := tsqlquery.Create(nil);
  559. qry.transaction := Transaction;
  560. qry.database := Self;
  561. with qry do
  562. begin
  563. ReadOnly := True;
  564. sql.clear;
  565. sql.add('select '+
  566. 'ic.relname as indexname, '+
  567. 'tc.relname as tablename, '+
  568. 'ia.attname, '+
  569. 'i.indisprimary, '+
  570. 'i.indisunique '+
  571. 'from '+
  572. 'pg_attribute ta, '+
  573. 'pg_attribute ia, '+
  574. 'pg_class tc, '+
  575. 'pg_class ic, '+
  576. 'pg_index i '+
  577. 'where '+
  578. '(i.indrelid = tc.oid) and '+
  579. '(ta.attrelid = tc.oid) and '+
  580. '(ia.attrelid = i.indexrelid) and '+
  581. '(ic.oid = i.indexrelid) and '+
  582. '(ta.attnum = i.indkey[ia.attnum-1]) and '+
  583. '(upper(tc.relname)=''' + UpperCase(TableName) +''') '+
  584. 'order by '+
  585. 'ic.relname;');
  586. open;
  587. end;
  588. while not qry.eof do with IndexDefs.AddIndexDef do
  589. begin
  590. Name := trim(qry.fields[0].asstring);
  591. Fields := trim(qry.Fields[2].asstring);
  592. If qry.fields[3].asboolean then options := options + [ixPrimary];
  593. If qry.fields[4].asboolean then options := options + [ixUnique];
  594. qry.next;
  595. while (name = qry.fields[0].asstring) and (not qry.eof) do
  596. begin
  597. Fields := Fields + ';' + trim(qry.Fields[2].asstring);
  598. qry.next;
  599. end;
  600. end;
  601. qry.close;
  602. qry.free;
  603. end;
  604. end.