testsqldb.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. unit TestSQLDB;
  2. {
  3. Unit tests which are specific to the sqlDB components like TSQLQuery, TSQLConnection.
  4. }
  5. {$mode objfpc}{$H+}
  6. interface
  7. uses
  8. Classes, sqldb, SysUtils, fpcunit, testregistry,
  9. sqldbtoolsunit,toolsunit, db;
  10. type
  11. { TSQLDBTestCase }
  12. TSQLDBTestCase = class(TTestCase)
  13. private
  14. function GetDBC: TSQLDBConnector;
  15. protected
  16. procedure SetUp; override;
  17. procedure TearDown; override;
  18. Property SQLDBConnector : TSQLDBConnector Read GetDBC;
  19. end;
  20. { TTestTSQLQuery }
  21. TTestTSQLQuery = class(TSQLDBTestCase)
  22. private
  23. FMyQ: TSQLQuery;
  24. procedure DoAfterPost(DataSet: TDataSet);
  25. Procedure Allow;
  26. Procedure DoApplyUpdates;
  27. Procedure SetQueryOPtions;
  28. Procedure TrySetPacketRecords;
  29. Protected
  30. Procedure setup; override;
  31. published
  32. procedure TestMasterDetail;
  33. procedure TestUpdateServerIndexDefs;
  34. Procedure TestDisconnected;
  35. Procedure TestDisconnectedPacketRecords;
  36. Procedure TestCheckSettingsOnlyWhenInactive;
  37. Procedure TestAutoApplyUpdatesPost;
  38. Procedure TestAutoApplyUpdatesDelete;
  39. Procedure TestCheckRowsAffected;
  40. Procedure TestAutoCOmmit;
  41. end;
  42. { TTestTSQLConnection }
  43. TTestTSQLConnection = class(TSQLDBTestCase)
  44. private
  45. procedure SetImplicit;
  46. procedure TestImplicitTransaction;
  47. procedure TestImplicitTransaction2;
  48. procedure TestImplicitTransactionNotAssignable;
  49. procedure TestImplicitTransactionOK;
  50. procedure TryOpen;
  51. published
  52. procedure TestUseImplicitTransaction;
  53. procedure TestUseExplicitTransaction;
  54. procedure TestExplicitConnect;
  55. end;
  56. { TTestTSQLScript }
  57. TTestTSQLScript = class(TSQLDBTestCase)
  58. published
  59. procedure TestExecuteScript;
  60. procedure TestScriptColon; //bug 25334
  61. procedure TestUseCommit; //E.g. Firebird cannot use COMMIT RETAIN if mixing DDL and DML in a script
  62. end;
  63. implementation
  64. { TTestTSQLQuery }
  65. procedure TTestTSQLQuery.DoAfterPost(DataSet: TDataSet);
  66. begin
  67. AssertTrue('Have modifications in after post',FMyq.UpdateStatus=usModified)
  68. end;
  69. Procedure TTestTSQLQuery.Allow;
  70. begin
  71. end;
  72. procedure TTestTSQLQuery.TestMasterDetail;
  73. var MasterQuery, DetailQuery: TSQLQuery;
  74. MasterSource: TDataSource;
  75. begin
  76. with SQLDBConnector do
  77. try
  78. MasterQuery := GetNDataset(10) as TSQLQuery;
  79. MasterSource := TDatasource.Create(nil);
  80. MasterSource.DataSet := MasterQuery;
  81. DetailQuery := Query;
  82. DetailQuery.SQL.Text := 'select NAME from FPDEV where ID=:ID';
  83. DetailQuery.DataSource := MasterSource;
  84. MasterQuery.Open;
  85. DetailQuery.Open;
  86. CheckEquals('TestName1', DetailQuery.Fields[0].AsString);
  87. MasterQuery.MoveBy(3);
  88. CheckEquals('TestName4', DetailQuery.Fields[0].AsString);
  89. finally
  90. MasterSource.Free;
  91. end;
  92. end;
  93. procedure TTestTSQLQuery.TestUpdateServerIndexDefs;
  94. var Q: TSQLQuery;
  95. name1, name2, name3: string;
  96. begin
  97. // Test retrieval of information about indexes on unquoted and quoted table names
  98. // (tests also case-sensitivity for DB's that support case-sensitivity of quoted identifiers)
  99. // For ODBC Firebird/Interbase we must define primary key as named constraint and
  100. // in ODBC driver must be set: "quoted identifiers" and "sensitive identifier"
  101. // See also: TTestFieldTypes.TestUpdateIndexDefs
  102. with SQLDBConnector do
  103. begin
  104. // SQLite ignores case-sensitivity of quoted table names
  105. // MS SQL Server case-sensitivity of identifiers depends on the case-sensitivity of default collation of the database
  106. // MySQL case-sensitivity depends on case-sensitivity of server's file system
  107. if SQLServerType in [ssMSSQL,ssSQLite{$IFDEF WINDOWS},ssMySQL{$ENDIF}] then
  108. name1 := Connection.FieldNameQuoteChars[0]+'fpdev 2'+Connection.FieldNameQuoteChars[1]
  109. else
  110. name1 := 'FPDEV2';
  111. ExecuteDirect('create table '+name1+' (id integer not null, constraint PK_FPDEV21 primary key(id))');
  112. // same but quoted table name
  113. name2 := Connection.FieldNameQuoteChars[0]+'FPdev2'+Connection.FieldNameQuoteChars[1];
  114. ExecuteDirect('create table '+name2+' (ID2 integer not null, constraint PK_FPDEV22 primary key(ID2))');
  115. // embedded quote in table name
  116. if SQLServerType in [ssMySQL] then
  117. name3 := '`FPdev``2`'
  118. else
  119. name3 := Connection.FieldNameQuoteChars[0]+'FPdev""2'+Connection.FieldNameQuoteChars[1];
  120. ExecuteDirect('create table '+name3+' (Id3 integer not null, constraint PK_FPDEV23 primary key(Id3))');
  121. CommitDDL;
  122. end;
  123. try
  124. Q := SQLDBConnector.Query;
  125. Q.SQL.Text:='select * from '+name1;
  126. Q.Prepare;
  127. Q.ServerIndexDefs.Update;
  128. CheckEquals(1, Q.ServerIndexDefs.Count);
  129. Q.SQL.Text:='select * from '+name2;
  130. Q.Prepare;
  131. Q.ServerIndexDefs.Update;
  132. CheckEquals(1, Q.ServerIndexDefs.Count, '2.1');
  133. CheckTrue(CompareText('ID2', Q.ServerIndexDefs[0].Fields)=0, '2.2'+Q.ServerIndexDefs[0].Fields);
  134. CheckTrue(Q.ServerIndexDefs[0].Options=[ixPrimary,ixUnique], '2.3');
  135. Q.SQL.Text:='select * from '+name3;
  136. Q.Prepare;
  137. Q.ServerIndexDefs.Update;
  138. CheckEquals(1, Q.ServerIndexDefs.Count, '3.1');
  139. CheckTrue(CompareText('ID3', Q.ServerIndexDefs[0].Fields)=0, '3.2');
  140. CheckTrue(Q.ServerIndexDefs[0].Options=[ixPrimary,ixUnique], '3.3');
  141. finally
  142. Q.UnPrepare;
  143. with SQLDBConnector do
  144. begin
  145. ExecuteDirect('DROP TABLE '+name1);
  146. ExecuteDirect('DROP TABLE '+name2);
  147. ExecuteDirect('DROP TABLE '+name3);
  148. CommitDDL;
  149. end;
  150. end;
  151. end;
  152. Procedure TTestTSQLQuery.TestDisconnected;
  153. var Q: TSQLQuery;
  154. I, J : Integer;
  155. begin
  156. // Test that for a disconnected SQL query, calling commit does not close the dataset.
  157. // Test also that an edit still works.
  158. with SQLDBConnector do
  159. begin
  160. TryDropIfExist('testdiscon');
  161. ExecuteDirect('create table testdiscon (id integer not null, a varchar(10), constraint pk_testdiscon primary key(id))');
  162. Transaction.COmmit;
  163. for I:=1 to 20 do
  164. ExecuteDirect(Format('INSERT INTO testdiscon values (%d,''%.6d'')',[i,i]));
  165. Transaction.COmmit;
  166. Q := SQLDBConnector.Query;
  167. Q.SQL.Text:='select * from testdiscon';
  168. Q.QueryOptions:=[sqoDisconnected];
  169. AssertEquals('PacketRecords forced to -1',-1,Q.PacketRecords);
  170. Q.Open;
  171. AssertEquals('Got all records',20,Q.RecordCount);
  172. Q.SQLTransaction.Commit;
  173. AssertTrue('Still open after transaction',Q.Active);
  174. // Now check editing
  175. Q.Locate('id',20,[]);
  176. Q.Edit;
  177. Q.FieldByName('a').AsString:='abc';
  178. Q.Post;
  179. AssertTrue('Have updates pending',Q.UpdateStatus=usModified);
  180. Q.ApplyUpdates;
  181. AssertTrue('Have no more updates pending',Q.UpdateStatus=usUnmodified);
  182. Q.Close;
  183. Q.SQL.Text:='select * from testdiscon where (id=20) and (a=''abc'')';
  184. Q.Open;
  185. AssertTrue('Have modified data record in database',not (Q.EOF AND Q.BOF));
  186. end;
  187. end;
  188. Procedure TTestTSQLQuery.TrySetPacketRecords;
  189. begin
  190. FMyQ.PacketRecords:=10;
  191. end;
  192. Procedure TTestTSQLQuery.setup;
  193. begin
  194. inherited setup;
  195. SQLDBConnector.Connection.Options:=[];
  196. end;
  197. Procedure TTestTSQLQuery.TestDisconnectedPacketRecords;
  198. begin
  199. with SQLDBConnector do
  200. begin
  201. FMyQ := SQLDBConnector.Query;
  202. FMyQ.QueryOptions:=[sqoDisconnected];
  203. AssertException('Cannot set packetrecords when sqoDisconnected is active',EDatabaseError,@TrySetPacketRecords);
  204. end;
  205. end;
  206. Procedure TTestTSQLQuery.SetQueryOPtions;
  207. begin
  208. FMyQ.QueryOptions:=[sqoDisconnected];
  209. end;
  210. Procedure TTestTSQLQuery.TestCheckSettingsOnlyWhenInactive;
  211. begin
  212. // Check that we can only set QueryOptions when the query is inactive.
  213. with SQLDBConnector do
  214. begin
  215. TryDropIfExist('testdiscon');
  216. ExecuteDirect('create table testdiscon (id integer not null, a varchar(10), constraint pk_testdiscon primary key(id))');
  217. Transaction.COmmit;
  218. ExecuteDirect(Format('INSERT INTO testdiscon values (%d,''%.6d'')',[1,1]));
  219. Transaction.COmmit;
  220. FMyQ := SQLDBConnector.Query;
  221. FMyQ.SQL.Text:='select * from testdiscon';
  222. FMyQ := SQLDBConnector.Query;
  223. FMyQ.OPen;
  224. AssertException('Cannot set packetrecords when sqoDisconnected is active',EDatabaseError,@SetQueryOptions);
  225. end;
  226. end;
  227. Procedure TTestTSQLQuery.TestAutoApplyUpdatesPost;
  228. var Q: TSQLQuery;
  229. I, J : Integer;
  230. begin
  231. // Test that if sqoAutoApplyUpdates is in QueryOptions, then POST automatically does an ApplyUpdates
  232. // Test also that POST afterpost event is backwards compatible.
  233. with SQLDBConnector do
  234. begin
  235. TryDropIfExist('testdiscon');
  236. ExecuteDirect('create table testdiscon (id integer not null, a varchar(10), constraint pk_testdiscon primary key(id))');
  237. Transaction.COmmit;
  238. for I:=1 to 2 do
  239. ExecuteDirect(Format('INSERT INTO testdiscon values (%d,''%.6d'')',[i,i]));
  240. Transaction.COmmit;
  241. Q := SQLDBConnector.Query;
  242. FMyQ:=Q; // so th event handler can reach it.
  243. Q.SQL.Text:='select * from testdiscon';
  244. Q.QueryOptions:=[ sqoAutoApplyUpdates];
  245. // We must test that in AfterPost, the modification is still there, for backwards compatibilty
  246. Q.AfterPost:=@DoAfterPost;
  247. Q.Open;
  248. AssertEquals('Got all records',2,Q.RecordCount);
  249. // Now check editing
  250. Q.Locate('id',2,[]);
  251. Q.Edit;
  252. Q.FieldByName('a').AsString:='abc';
  253. Q.Post;
  254. AssertTrue('Have no more updates pending',Q.UpdateStatus=usUnmodified);
  255. Q.Close;
  256. Q.SQL.Text:='select * from testdiscon where (id=2) and (a=''abc'')';
  257. Q.Open;
  258. AssertTrue('Have modified data record in database',not (Q.EOF AND Q.BOF));
  259. end;
  260. end;
  261. Procedure TTestTSQLQuery.TestAutoApplyUpdatesDelete;
  262. var Q: TSQLQuery;
  263. I, J : Integer;
  264. begin
  265. // Test that if sqoAutoApplyUpdates is in QueryOptions, then Delete automatically does an ApplyUpdates
  266. with SQLDBConnector do
  267. begin
  268. TryDropIfExist('testdiscon');
  269. ExecuteDirect('create table testdiscon (id integer not null, a varchar(10), constraint pk_testdiscon primary key(id))');
  270. Transaction.COmmit;
  271. for I:=1 to 2 do
  272. ExecuteDirect(Format('INSERT INTO testdiscon values (%d,''%.6d'')',[i,i]));
  273. Transaction.COmmit;
  274. Q := SQLDBConnector.Query;
  275. FMyQ:=Q; // so th event handler can reach it.
  276. Q.SQL.Text:='select * from testdiscon';
  277. Q.QueryOptions:=[ sqoAutoApplyUpdates];
  278. // We must test that in AfterPost, the modification is still there, for backwards compatibilty
  279. Q.AfterPost:=@DoAfterPost;
  280. Q.Open;
  281. AssertEquals('Got all records',2,Q.RecordCount);
  282. // Now check editing
  283. Q.Locate('id',2,[]);
  284. Q.Delete;
  285. AssertTrue('Have no more updates pending',Q.UpdateStatus=usUnmodified);
  286. Q.Close;
  287. Q.SQL.Text:='select * from testdiscon where (id=2)';
  288. Q.Open;
  289. AssertTrue('Data record is deleted in database', (Q.EOF AND Q.BOF));
  290. end;
  291. end;
  292. Procedure TTestTSQLQuery.DoApplyUpdates;
  293. begin
  294. FMyQ.ApplyUpdates();
  295. end;
  296. Procedure TTestTSQLQuery.TestCheckRowsAffected;
  297. var Q: TSQLQuery;
  298. I, J : Integer;
  299. begin
  300. // Test that if sqoAutoApplyUpdates is in QueryOptions, then Delete automatically does an ApplyUpdates
  301. with SQLDBConnector do
  302. begin
  303. TryDropIfExist('testdiscon');
  304. ExecuteDirect('create table testdiscon (id integer not null, a varchar(10), constraint pk_testdiscon primary key(id))');
  305. Transaction.COmmit;
  306. for I:=1 to 2 do
  307. ExecuteDirect(Format('INSERT INTO testdiscon values (%d,''%.6d'')',[i,i]));
  308. Transaction.COmmit;
  309. SQLDBConnector.Connection.Options:=[coCheckRowsAffected];
  310. Q := SQLDBConnector.Query;
  311. Q.SQL.Text:='select * from testdiscon';
  312. Q.DeleteSQL.Text:='delete from testdiscon';
  313. Q.Open;
  314. AssertEquals('Got all records',2,Q.RecordCount);
  315. // Now check editing
  316. Q.Delete;
  317. FMyQ:=Q;
  318. AssertException('Rowsaffected > 1 raises exception',EUpdateError,@DoApplyUpdates);
  319. end;
  320. end;
  321. Procedure TTestTSQLQuery.TestAutoCOmmit;
  322. var
  323. Q: TSQLQuery;
  324. T : TSQLTransaction;
  325. I, J : Integer;
  326. begin
  327. with SQLDBConnector do
  328. begin
  329. TryDropIfExist('testdiscon');
  330. ExecuteDirect('create table testdiscon (id integer not null, a varchar(10), constraint pk_testdiscon primary key(id))');
  331. if Transaction.Active then
  332. Transaction.Commit;
  333. end;
  334. Q:=SQLDBConnector.Query;
  335. Q.QueryOptions:=[sqoAutoCommit];
  336. for I:=1 to 2 do
  337. begin
  338. Q.SQL.Text:=Format('INSERT INTO testdiscon values (%d,''%.6d'');',[i,i]);
  339. Q.Prepare;
  340. Q.ExecSQL;
  341. // We do not commit anything explicitly.
  342. end;
  343. Q:=Nil;
  344. T:=Nil;
  345. try
  346. T:=TSQLTransaction.Create(Nil);
  347. Q:=TSQLQuery.Create(Nil);
  348. Q.Transaction:=T;
  349. Q.Database:=SQLDBConnector.Connection;
  350. T.Database:=SQLDBConnector.Connection;
  351. Q.SQL.text:='SELECT COUNT(*) from testdiscon';
  352. Q.Open;
  353. AssertEquals('Records have been committed to database',2,Q.Fields[0].AsInteger);
  354. finally
  355. Q.Free;
  356. T.Free;
  357. end;
  358. end;
  359. { TTestTSQLConnection }
  360. procedure TTestTSQLConnection.TestImplicitTransaction;
  361. Var
  362. T : TSQLTransaction;
  363. begin
  364. T:=TSQLTransaction.Create(Nil);
  365. try
  366. T.Options:=[toUseImplicit];
  367. T.DataBase:=SQLDBConnector.Connection;
  368. finally
  369. T.Free;
  370. end;
  371. end;
  372. procedure TTestTSQLConnection.TestImplicitTransaction2;
  373. Var
  374. T : TSQLTransaction;
  375. begin
  376. T:=TSQLTransaction.Create(Nil);
  377. try
  378. T.Options:=[toUseImplicit];
  379. SQLDBConnector.Connection.Transaction:=T;
  380. finally
  381. T.Free;
  382. end;
  383. end;
  384. procedure TTestTSQLConnection.SetImplicit;
  385. begin
  386. SQLDBConnector.Transaction.Options:=[toUseImplicit];
  387. end;
  388. procedure TTestTSQLConnection.TestImplicitTransactionNotAssignable;
  389. begin
  390. AssertException('Cannot set toUseImplicit option if database does not allow it',EDatabaseError,@SetImplicit);
  391. AssertException('Cannot assign database to transaction with toUseImplicit, if database does not allow it',EDatabaseError,@TestImplicitTransaction);
  392. AssertException('Cannot assign transaction with toUseImplicit to database, if database does not allow it',EDatabaseError,@TestImplicitTransaction2);
  393. end;
  394. procedure TTestTSQLConnection.TestImplicitTransactionOK;
  395. var
  396. Q : TSQLQuery;
  397. T : TSQLTransaction;
  398. I, J : Integer;
  399. begin
  400. with SQLDBConnector do
  401. begin
  402. TryDropIfExist('testdiscon');
  403. ExecuteDirect('create table testdiscon (id integer not null, a varchar(10), constraint pk_testdiscon primary key(id))');
  404. if Transaction.Active then
  405. Transaction.Commit;
  406. end;
  407. SetImplicit;
  408. Q:=SQLDBConnector.Query;
  409. for I:=1 to 2 do
  410. begin
  411. Q.SQL.Text:=Format('INSERT INTO testdiscon values (%d,''%.6d'');',[i,i]);
  412. Q.Prepare;
  413. Q.ExecSQL;
  414. // We do not commit anything explicitly.
  415. end;
  416. Q:=Nil;
  417. T:=Nil;
  418. try
  419. T:=TSQLTransaction.Create(Nil);
  420. Q:=TSQLQuery.Create(Nil);
  421. Q.Transaction:=T;
  422. Q.Database:=SQLDBConnector.Connection;
  423. T.Database:=SQLDBConnector.Connection;
  424. Q.SQL.text:='SELECT COUNT(*) from testdiscon';
  425. Q.Open;
  426. AssertEquals('Records have been committed to database',2,Q.Fields[0].AsInteger);
  427. finally
  428. Q.Free;
  429. T.Free;
  430. end;
  431. end;
  432. procedure TTestTSQLConnection.TestUseImplicitTransaction;
  433. begin
  434. if (sqImplicitTransaction in SQLDBConnector.Connection.ConnOptions) then
  435. TestImplicitTransactionOK
  436. else
  437. TestImplicitTransactionNotAssignable;
  438. end;
  439. procedure TTestTSQLConnection.TryOpen;
  440. begin
  441. SQLDBConnector.Query.Open;
  442. end;
  443. procedure TTestTSQLConnection.TestUseExplicitTransaction;
  444. begin
  445. SQLDBConnector.Transaction.Active:=False;
  446. SQLDBConnector.Transaction.Options:=[toExplicitStart];
  447. SQLDBConnector.Query.SQL.Text:='select * from FPDEV';
  448. AssertException('toExplicitStart raises exception on implicit start',EDatabaseError,@TryOpen)
  449. end;
  450. procedure TTestTSQLConnection.TestExplicitConnect;
  451. begin
  452. SQLDBConnector.Transaction.Active:=False;
  453. SQLDBConnector.Connection.Options:=[coExplicitConnect];
  454. SQLDBConnector.Connection.Connected:=False;
  455. SQLDBConnector.Query.SQL.Text:='select * from FPDEV';
  456. AssertException('toExplicitStart raises exception on implicit start',EDatabaseError,@TryOpen)
  457. end;
  458. { TTestTSQLScript }
  459. procedure TTestTSQLScript.TestExecuteScript;
  460. var Ascript : TSQLScript;
  461. begin
  462. Ascript := TSQLScript.Create(nil);
  463. try
  464. with Ascript do
  465. begin
  466. DataBase := SQLDBConnector.Connection;
  467. Transaction := SQLDBConnector.Transaction;
  468. Script.Clear;
  469. Script.Append('create table FPDEV_A (id int);');
  470. Script.Append('create table FPDEV_B (id int);');
  471. ExecuteScript;
  472. // Firebird/Interbase need a commit after a DDL statement. Not necessary for the other connections
  473. SQLDBConnector.CommitDDL;
  474. end;
  475. finally
  476. AScript.Free;
  477. SQLDBConnector.ExecuteDirect('drop table FPDEV_A');
  478. SQLDBConnector.ExecuteDirect('drop table FPDEV_B');
  479. // Firebird/Interbase need a commit after a DDL statement. Not necessary for the other connections
  480. SQLDBConnector.CommitDDL;
  481. end;
  482. end;
  483. procedure TTestTSQLScript.TestScriptColon;
  484. // Bug 25334: TSQLScript incorrectly treats : in scripts as sqldb query parameter markers
  485. // Firebird-only test; can be extended for other dbs that use : in SQL
  486. var
  487. Ascript : TSQLScript;
  488. begin
  489. if not(SQLConnType in [interbase]) then Ignore(STestNotApplicable);
  490. Ascript := TSQLScript.Create(nil);
  491. try
  492. with Ascript do
  493. begin
  494. DataBase := SQLDBConnector.Connection;
  495. Transaction := SQLDBConnector.Transaction;
  496. Script.Clear;
  497. UseSetTerm := true;
  498. // Example procedure that selects table names
  499. Script.Append(
  500. 'SET TERM ^ ; '+LineEnding+
  501. 'CREATE PROCEDURE FPDEV_TESTCOLON '+LineEnding+
  502. 'RETURNS (tblname VARCHAR(31)) '+LineEnding+
  503. 'AS '+LineEnding+
  504. 'begin '+LineEnding+
  505. '/* Show tables. Note statement uses colon */ '+LineEnding+
  506. 'FOR '+LineEnding+
  507. ' SELECT RDB$RELATION_NAME '+LineEnding+
  508. ' FROM RDB$RELATIONS '+LineEnding+
  509. ' ORDER BY RDB$RELATION_NAME '+LineEnding+
  510. ' INTO :tblname '+LineEnding+
  511. 'DO '+LineEnding+
  512. ' SUSPEND; '+LineEnding+
  513. 'end^ '+LineEnding+
  514. 'SET TERM ; ^'
  515. );
  516. ExecuteScript;
  517. // Firebird/Interbase need a commit after a DDL statement. Not necessary for the other connections
  518. SQLDBConnector.CommitDDL;
  519. end;
  520. finally
  521. AScript.Free;
  522. SQLDBConnector.ExecuteDirect('DROP PROCEDURE FPDEV_TESTCOLON');
  523. // Firebird/Interbase need a commit after a DDL statement. Not necessary for the other connections
  524. SQLDBConnector.CommitDDL;
  525. end;
  526. end;
  527. procedure TTestTSQLScript.TestUseCommit;
  528. // E.g. Firebird needs explicit COMMIT sometimes, e.g. if mixing DDL and DML
  529. // statements in a script.
  530. // Probably same as bug 17829 Error executing SQL script
  531. const
  532. TestValue='Some text';
  533. var
  534. Ascript : TSQLScript;
  535. CheckQuery : TSQLQuery;
  536. begin
  537. Ascript := TSQLScript.Create(nil);
  538. try
  539. with Ascript do
  540. begin
  541. DataBase := SQLDBConnector.Connection;
  542. Transaction := SQLDBConnector.Transaction;
  543. Script.Clear;
  544. UseCommit:=true;
  545. // Example procedure that selects table names
  546. Script.Append('CREATE TABLE fpdev_scriptusecommit (logmessage VARCHAR(255));');
  547. Script.Append('COMMIT;'); //needed for table to show up
  548. Script.Append('INSERT INTO fpdev_scriptusecommit (logmessage) VALUES('''+TestValue+''');');
  549. Script.Append('COMMIT;');
  550. ExecuteScript;
  551. // This line should not run, as the commit above should have taken care of it:
  552. //SQLDBConnector.CommitDDL;
  553. // Test whether second line of script executed, just to be sure
  554. CheckQuery:=SQLDBConnector.Query;
  555. CheckQuery.SQL.Text:='SELECT logmessage FROM fpdev_scriptusecommit ';
  556. CheckQuery.Open;
  557. CheckEquals(TestValue, CheckQuery.Fields[0].AsString, 'Insert script line should have inserted '+TestValue);
  558. CheckQuery.Close;
  559. end;
  560. finally
  561. AScript.Free;
  562. SQLDBConnector.ExecuteDirect('DROP TABLE fpdev_scriptusecommit');
  563. SQLDBConnector.Transaction.Commit;
  564. end;
  565. end;
  566. { TSQLDBTestCase }
  567. function TSQLDBTestCase.GetDBC: TSQLDBConnector;
  568. begin
  569. Result:=DBConnector as TSQLDBConnector;
  570. end;
  571. procedure TSQLDBTestCase.SetUp;
  572. begin
  573. inherited SetUp;
  574. InitialiseDBConnector;
  575. DBConnector.StartTest(TestName);
  576. end;
  577. procedure TSQLDBTestCase.TearDown;
  578. begin
  579. DBConnector.StopTest(TestName);
  580. if assigned(DBConnector) then
  581. with SQLDBConnector do
  582. if Assigned(Transaction) and not (toUseImplicit in Transaction.Options) then
  583. Transaction.Rollback;
  584. FreeDBConnector;
  585. inherited TearDown;
  586. end;
  587. initialization
  588. if uppercase(dbconnectorname)='SQL' then
  589. begin
  590. RegisterTest(TTestTSQLQuery);
  591. RegisterTest(TTestTSQLConnection);
  592. RegisterTest(TTestTSQLScript);
  593. end;
  594. end.