pqconnection.pp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  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. ObtainSQLStatementType(cursor,buf);
  334. with (cursor as TPQCursor) do
  335. begin
  336. FPrepared := False;
  337. nr := inttostr(FCursorcount);
  338. inc(FCursorCount);
  339. // Prior to v8 there is no support for cursors and parameters.
  340. // So that's not supported.
  341. if FStatementType = stselect then
  342. statement := 'DECLARE slctst' + name + nr +' BINARY CURSOR FOR ' + buf
  343. else if FStatementType in [stInsert,stUpdate,stDelete] then
  344. begin
  345. tr := aTransaction.Handle;
  346. // Only available for pq 8.0, so don't use it...
  347. // Res := pqprepare(tr,'prepst'+name+nr,pchar(buf),params.Count,pchar(''));
  348. s := 'prepare prepst'+nr+' ';
  349. if Assigned(AParams) and (AParams.count > 0) then
  350. begin
  351. s := s + '(';
  352. for i := 0 to AParams.count-1 do
  353. begin
  354. s := s + TypeStrings[AParams[i].DataType] + ',';
  355. buf := stringreplace(buf,':'+AParams[i].Name,'$'+inttostr(i+1),[rfReplaceAll,rfIgnoreCase]);
  356. end;
  357. s[length(s)] := ')';
  358. end;
  359. s := s + ' as ' + buf;
  360. res := pqexec(tr,pchar(s));
  361. if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
  362. begin
  363. pqclear(res);
  364. DatabaseError(SErrPrepareFailed + ' (PostgreSQL: ' + PQerrorMessage(tr) + ')',self)
  365. end;
  366. FPrepared := True;
  367. end
  368. else
  369. statement := buf;
  370. end;
  371. end;
  372. procedure TPQConnection.CloseStatement(cursor : TSQLCursor);
  373. begin
  374. with cursor as TPQCursor do
  375. if (PQresultStatus(res) <> PGRES_FATAL_ERROR) then //Don't try to do anything if the transaction has already encountered an error.
  376. begin
  377. if FStatementType = stselect then
  378. begin
  379. Res := pqexec(tr,pchar('CLOSE slctst' + name + nr));
  380. if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
  381. begin
  382. pqclear(res);
  383. DatabaseError(SErrClearSelection + ' (PostgreSQL: ' + PQerrorMessage(tr) + ')',self)
  384. end
  385. end;
  386. pqclear(baseres);
  387. pqclear(res);
  388. end;
  389. end;
  390. procedure TPQConnection.UnPrepareStatement(cursor : TSQLCursor);
  391. begin
  392. with (cursor as TPQCursor) do if FPrepared then
  393. begin
  394. res := pqexec(tr,pchar('deallocate prepst'+nr));
  395. if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
  396. begin
  397. pqclear(res);
  398. DatabaseError(SErrPrepareFailed + ' (PostgreSQL: ' + PQerrorMessage(tr) + ')',self)
  399. end;
  400. pqclear(res);
  401. FPrepared := False;
  402. end;
  403. end;
  404. procedure TPQConnection.FreeFldBuffers(cursor : TSQLCursor);
  405. begin
  406. // Do nothing
  407. end;
  408. procedure TPQConnection.Execute(cursor: TSQLCursor;atransaction:tSQLtransaction;AParams : TParams);
  409. var ar : array of pchar;
  410. i : integer;
  411. s : string;
  412. begin
  413. with cursor as TPQCursor do
  414. begin
  415. if FStatementType in [stInsert,stUpdate,stDelete] then
  416. begin
  417. if Assigned(AParams) and (AParams.count > 0) then
  418. begin
  419. setlength(ar,Aparams.count);
  420. for i := 0 to AParams.count -1 do
  421. ar[i] := pchar(AParams[i].asstring);
  422. res := PQexecPrepared(tr,pchar('prepst'+nr),Aparams.count,@Ar[0],nil,nil,0)
  423. end
  424. else
  425. res := PQexecPrepared(tr,pchar('prepst'+nr),0,nil,nil,nil,0);
  426. if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
  427. begin
  428. pqclear(res);
  429. DatabaseError(SErrExecuteFailed + ' (PostgreSQL: ' + PQerrorMessage(tr) + ')',self);
  430. end;
  431. end
  432. else
  433. begin
  434. tr := aTransaction.Handle;
  435. s := statement;
  436. //Should be altered, just like in TSQLQuery.ApplyRecUpdate
  437. if assigned(AParams) then for i := 0 to AParams.count-1 do
  438. s := stringreplace(s,':'+AParams[i].Name,AParams[i].asstring,[rfReplaceAll,rfIgnoreCase]);
  439. res := pqexec(tr,pchar(s));
  440. if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
  441. begin
  442. pqclear(res);
  443. DatabaseError(SErrExecuteFailed + ' (PostgreSQL: ' + PQerrorMessage(tr) + ')',self);
  444. end;
  445. end;
  446. end;
  447. end;
  448. procedure TPQConnection.AddFieldDefs(cursor: TSQLCursor; FieldDefs : TfieldDefs);
  449. var
  450. i : integer;
  451. size : integer;
  452. st : string;
  453. fieldtype : tfieldtype;
  454. begin
  455. with cursor as TPQCursor do
  456. begin
  457. // BaseRes := pqexecParams(tr,'FETCH 0 IN selectst' + pchar(name) ,0,nil,nil,nil,nil,1);
  458. st := pchar('FETCH 0 IN slctst' + name+nr);
  459. BaseRes := pqexec(tr,pchar(st));
  460. if (PQresultStatus(BaseRes) <> PGRES_TUPLES_OK) then
  461. begin
  462. pqclear(BaseRes);
  463. DatabaseError(SErrFieldDefsFailed + ' (PostgreSQL: ' + PQerrorMessage(tr) + ')',self)
  464. end;
  465. nFields := PQnfields(BaseRes);
  466. for i := 0 to nFields-1 do
  467. begin
  468. size := PQfsize(BaseRes, i);
  469. fieldtype := TranslateFldType(PQftype(BaseRes, i));
  470. if (fieldtype = ftstring) and (size = -1) then
  471. size := pqfmod(baseres,i)-3;
  472. if fieldtype = ftdate then
  473. size := sizeof(double);
  474. TFieldDef.Create(FieldDefs, PQfname(BaseRes, i), fieldtype,size, False, (i + 1));
  475. end;
  476. end;
  477. end;
  478. function TPQConnection.GetHandle: pointer;
  479. begin
  480. Result := FSQLDatabaseHandle;
  481. end;
  482. function TPQConnection.Fetch(cursor : TSQLCursor) : boolean;
  483. var st : string;
  484. begin
  485. with cursor as TPQCursor do
  486. begin
  487. st := pchar('FETCH NEXT IN slctst' + name+nr);
  488. Res := pqexec(tr,pchar(st));
  489. if (PQresultStatus(res) <> PGRES_TUPLES_OK) then
  490. begin
  491. pqclear(Res);
  492. DatabaseError(SErrfetchFailed + ' (PostgreSQL: ' + PQerrorMessage(tr) + ')',self)
  493. end;
  494. Result := (PQntuples(res)<>0);
  495. end;
  496. end;
  497. function TPQConnection.LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer) : boolean;
  498. var
  499. x,i : integer;
  500. li : Longint;
  501. CurrBuff : pchar;
  502. tel : byte;
  503. dbl : pdouble;
  504. begin
  505. with cursor as TPQCursor do
  506. begin
  507. for x := 0 to PQnfields(res)-1 do
  508. if PQfname(Res, x) = FieldDef.Name then break;
  509. if PQfname(Res, x) <> FieldDef.Name then
  510. DatabaseErrorFmt(SFieldNotFound,[FieldDef.Name],self);
  511. if pqgetisnull(res,0,x)=1 then
  512. result := false
  513. else
  514. begin
  515. i := PQfsize(res, x);
  516. CurrBuff := pqgetvalue(res,0,x);
  517. case FieldDef.DataType of
  518. ftInteger, ftSmallint, ftLargeInt,ftfloat :
  519. begin
  520. for tel := 1 to i do // postgres returns big-endian numbers
  521. pchar(Buffer)[tel-1] := CurrBuff[i-tel];
  522. end;
  523. ftString :
  524. begin
  525. li := pqgetlength(res,0,x);
  526. Move(CurrBuff^, Buffer^, li);
  527. pchar(Buffer + li)^ := #0;
  528. i := pqfmod(res,x)-3;
  529. end;
  530. ftdate :
  531. begin
  532. li := 0;
  533. for tel := 1 to i do // postgres returns big-endian numbers
  534. pchar(@li)[tel-1] := CurrBuff[i-tel];
  535. // double(buffer^) := x + 36526; This doesn't work, please tell me what is wrong with it?
  536. dbl := pointer(buffer);
  537. dbl^ := li + 36526;
  538. i := sizeof(double);
  539. end;
  540. ftDateTime, fttime :
  541. begin
  542. dbl := pointer(buffer);
  543. dbl^ := 0;
  544. for tel := 1 to i do // postgres returns big-endian numbers
  545. pchar(Buffer)[tel-1] := CurrBuff[i-tel];
  546. dbl^ := (dbl^+3.1558464E+009)/86400; // postgres counts seconds elapsed since 1-1-2000
  547. end;
  548. ftBCD:
  549. begin
  550. // not implemented
  551. end;
  552. ftBoolean:
  553. pchar(buffer)[0] := CurrBuff[0]
  554. end;
  555. result := true;
  556. end;
  557. end;
  558. end;
  559. procedure TPQConnection.UpdateIndexDefs(var IndexDefs : TIndexDefs;TableName : string);
  560. var qry : TSQLQuery;
  561. begin
  562. if not assigned(Transaction) then
  563. DatabaseError(SErrConnTransactionnSet);
  564. qry := tsqlquery.Create(nil);
  565. qry.transaction := Transaction;
  566. qry.database := Self;
  567. with qry do
  568. begin
  569. ReadOnly := True;
  570. sql.clear;
  571. sql.add('select '+
  572. 'ic.relname as indexname, '+
  573. 'tc.relname as tablename, '+
  574. 'ia.attname, '+
  575. 'i.indisprimary, '+
  576. 'i.indisunique '+
  577. 'from '+
  578. 'pg_attribute ta, '+
  579. 'pg_attribute ia, '+
  580. 'pg_class tc, '+
  581. 'pg_class ic, '+
  582. 'pg_index i '+
  583. 'where '+
  584. '(i.indrelid = tc.oid) and '+
  585. '(ta.attrelid = tc.oid) and '+
  586. '(ia.attrelid = i.indexrelid) and '+
  587. '(ic.oid = i.indexrelid) and '+
  588. '(ta.attnum = i.indkey[ia.attnum-1]) and '+
  589. '(upper(tc.relname)=''' + UpperCase(TableName) +''') '+
  590. 'order by '+
  591. 'ic.relname;');
  592. open;
  593. end;
  594. while not qry.eof do with IndexDefs.AddIndexDef do
  595. begin
  596. Name := trim(qry.fields[0].asstring);
  597. Fields := trim(qry.Fields[2].asstring);
  598. If qry.fields[3].asboolean then options := options + [ixPrimary];
  599. If qry.fields[4].asboolean then options := options + [ixUnique];
  600. qry.next;
  601. while (name = qry.fields[0].asstring) and (not qry.eof) do
  602. begin
  603. Fields := Fields + ';' + trim(qry.Fields[2].asstring);
  604. qry.next;
  605. end;
  606. end;
  607. qry.close;
  608. qry.free;
  609. end;
  610. end.