pqconnection.pp 19 KB

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