testsqldb.pas 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094
  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 GetSQLDBConnector: TSQLDBConnector;
  15. protected
  16. procedure SetUp; override;
  17. procedure TearDown; override;
  18. Property SQLDBConnector : TSQLDBConnector Read GetSQLDBConnector;
  19. end;
  20. { TTestTSQLQuery }
  21. TTestTSQLQuery = class(TSQLDBTestCase)
  22. private
  23. FMyQ: TSQLQuery;
  24. FPrepareCount:Integer;
  25. procedure DoAfterPost(DataSet: TDataSet);
  26. Procedure DoApplyUpdates;
  27. procedure DoCount(Sender: TSQLConnection; EventType: TDBEventType; const Msg: String);
  28. Procedure TrySetQueryOptions;
  29. Procedure TrySetPacketRecords;
  30. Protected
  31. Procedure Setup; override;
  32. published
  33. procedure TestMasterDetail;
  34. procedure TestUpdateServerIndexDefs;
  35. Procedure TestKeepOpenOnCommit;
  36. Procedure TestKeepOpenOnCommitPacketRecords;
  37. Procedure TestCheckSettingsOnlyWhenInactive;
  38. Procedure TestAutoApplyUpdatesPost;
  39. Procedure TestAutoApplyUpdatesDelete;
  40. Procedure TestCheckRowsAffected;
  41. Procedure TestAutoCommit;
  42. Procedure TestGeneratedRefreshSQL;
  43. Procedure TestGeneratedRefreshSQL1Field;
  44. Procedure TestGeneratedRefreshSQLNoKey;
  45. Procedure TestRefreshSQL;
  46. Procedure TestRefreshSQLMultipleRecords;
  47. Procedure TestRefreshSQLNoRecords;
  48. Procedure TestFetchAutoInc;
  49. procedure TestSequence;
  50. procedure TestReturningInsert;
  51. procedure TestReturningUpdate;
  52. procedure TestMacros;
  53. Procedure TestPrepareCount;
  54. end;
  55. { TTestTSQLConnection }
  56. TTestTSQLConnection = class(TSQLDBTestCase)
  57. private
  58. procedure SetImplicit;
  59. procedure TestImplicitTransaction;
  60. procedure TestImplicitTransaction2;
  61. procedure TestImplicitTransactionNotAssignable;
  62. procedure TestImplicitTransactionOK;
  63. procedure TryOpen;
  64. published
  65. procedure TestUseImplicitTransaction;
  66. procedure TestUseExplicitTransaction;
  67. procedure TestExplicitConnect;
  68. procedure TestGetStatementInfo;
  69. end;
  70. { TTestTSQLScript }
  71. TTestTSQLScript = class(TSQLDBTestCase)
  72. published
  73. procedure TestExecuteScript;
  74. procedure TestScriptColon; //bug 25334
  75. procedure TestUseCommit; //E.g. Firebird cannot use COMMIT RETAIN if mixing DDL and DML in a script
  76. end;
  77. implementation
  78. { TTestTSQLQuery }
  79. procedure TTestTSQLQuery.Setup;
  80. begin
  81. inherited Setup;
  82. FPrepareCount:=0;
  83. SQLDBConnector.Connection.Options:=[];
  84. end;
  85. procedure TTestTSQLQuery.TestMasterDetail;
  86. var MasterQuery, DetailQuery: TSQLQuery;
  87. MasterSource: TDataSource;
  88. begin
  89. with SQLDBConnector do
  90. try
  91. MasterQuery := GetNDataset(10) as TSQLQuery;
  92. MasterSource := TDatasource.Create(nil);
  93. MasterSource.DataSet := MasterQuery;
  94. DetailQuery := Query;
  95. DetailQuery.SQL.Text := 'select NAME from FPDEV where ID=:ID';
  96. DetailQuery.DataSource := MasterSource;
  97. MasterQuery.Open;
  98. DetailQuery.Open;
  99. CheckEquals('TestName1', DetailQuery.Fields[0].AsString);
  100. MasterQuery.MoveBy(3);
  101. CheckEquals('TestName4', DetailQuery.Fields[0].AsString);
  102. MasterQuery.Close;
  103. CheckTrue(DetailQuery.Active, 'Detail dataset should remain intact, when master dataset is closed');
  104. finally
  105. MasterSource.Free;
  106. end;
  107. end;
  108. procedure TTestTSQLQuery.TestUpdateServerIndexDefs;
  109. var Q: TSQLQuery;
  110. name1, name2, name3: string;
  111. begin
  112. // Test retrieval of information about indexes on unquoted and quoted table names
  113. // (tests also case-sensitivity for DB's that support case-sensitivity of quoted identifiers)
  114. // For ODBC Firebird/Interbase we must define primary key as named constraint and
  115. // in ODBC driver must be set: "quoted identifiers" and "sensitive identifier"
  116. // See also: TTestFieldTypes.TestUpdateIndexDefs
  117. with SQLDBConnector do
  118. begin
  119. // SQLite ignores case-sensitivity of quoted table names
  120. // MS SQL Server case-sensitivity of identifiers depends on the case-sensitivity of default collation of the database
  121. // MySQL case-sensitivity depends on case-sensitivity of server's file system
  122. if SQLServerType in [ssMSSQL,ssSQLite{$IFDEF WINDOWS},ssMySQL{$ENDIF}] then
  123. name1 := Connection.FieldNameQuoteChars[0]+'fpdev 2'+Connection.FieldNameQuoteChars[1]
  124. else
  125. name1 := 'FPDEV2';
  126. ExecuteDirect('create table '+name1+' (id integer not null, constraint PK_FPDEV21 primary key(id))');
  127. // same but quoted table name
  128. name2 := Connection.FieldNameQuoteChars[0]+'FPdev2'+Connection.FieldNameQuoteChars[1];
  129. ExecuteDirect('create table '+name2+' (ID2 integer not null, constraint PK_FPDEV22 primary key(ID2))');
  130. // embedded quote in table name
  131. if SQLServerType in [ssMySQL] then
  132. name3 := '`FPdev``2`'
  133. else
  134. name3 := Connection.FieldNameQuoteChars[0]+'FPdev""2'+Connection.FieldNameQuoteChars[1];
  135. ExecuteDirect('create table '+name3+' (Id3 integer not null, constraint PK_FPDEV23 primary key(Id3))');
  136. CommitDDL;
  137. end;
  138. try
  139. Q := SQLDBConnector.Query;
  140. Q.SQL.Text:='select * from '+name1;
  141. Q.Prepare;
  142. Q.ServerIndexDefs.Update;
  143. CheckEquals(1, Q.ServerIndexDefs.Count);
  144. Q.SQL.Text:='select * from '+name2;
  145. Q.Prepare;
  146. Q.ServerIndexDefs.Update;
  147. CheckEquals(1, Q.ServerIndexDefs.Count, '2.1');
  148. CheckTrue(CompareText('ID2', Q.ServerIndexDefs[0].Fields)=0, '2.2'+Q.ServerIndexDefs[0].Fields);
  149. CheckTrue(Q.ServerIndexDefs[0].Options=[ixPrimary,ixUnique], '2.3');
  150. Q.SQL.Text:='select * from '+name3;
  151. Q.Prepare;
  152. Q.ServerIndexDefs.Update;
  153. CheckEquals(1, Q.ServerIndexDefs.Count, '3.1');
  154. CheckTrue(CompareText('ID3', Q.ServerIndexDefs[0].Fields)=0, '3.2');
  155. CheckTrue(Q.ServerIndexDefs[0].Options=[ixPrimary,ixUnique], '3.3');
  156. finally
  157. Q.UnPrepare;
  158. with SQLDBConnector do
  159. begin
  160. ExecuteDirect('DROP TABLE '+name1);
  161. ExecuteDirect('DROP TABLE '+name2);
  162. ExecuteDirect('DROP TABLE '+name3);
  163. CommitDDL;
  164. end;
  165. end;
  166. end;
  167. procedure TTestTSQLQuery.TestKeepOpenOnCommit;
  168. var Q: TSQLQuery;
  169. I: Integer;
  170. begin
  171. // Test that for a SQL query with Options=sqoKeepOpenOnCommit, calling commit does not close the dataset.
  172. // Test also that an edit still works.
  173. with SQLDBConnector do
  174. begin
  175. ExecuteDirect('create table FPDEV2 (id integer not null, a varchar(10), constraint PK_FPDEV2 primary key(id))');
  176. Transaction.Commit;
  177. for I:=1 to 20 do
  178. ExecuteDirect(Format('INSERT INTO FPDEV2 values (%d,''%.6d'')',[i,i]));
  179. Transaction.Commit;
  180. Q := SQLDBConnector.Query;
  181. Q.SQL.Text:='select * from FPDEV2';
  182. Q.Options:=[sqoKeepOpenOnCommit,sqoRefreshUsingSelect];
  183. AssertEquals('PacketRecords forced to -1',-1,Q.PacketRecords);
  184. Q.Open;
  185. AssertEquals('Got all records',20,Q.RecordCount);
  186. Q.SQLTransaction.Commit;
  187. AssertTrue('Still open after transaction',Q.Active);
  188. // Now check editing
  189. Q.Locate('id',20,[]);
  190. Q.Edit;
  191. Q.FieldByName('a').AsString:='abc';
  192. Q.Post;
  193. AssertTrue('Have updates pending',Q.UpdateStatus=usModified);
  194. Q.ApplyUpdates;
  195. AssertTrue('Have no more updates pending',Q.UpdateStatus=usUnmodified);
  196. Q.Close;
  197. Q.SQL.Text:='select * from FPDEV2 where (id=20) and (a=''abc'')';
  198. Q.Open;
  199. AssertTrue('Have modified data record in database', not (Q.EOF AND Q.BOF));
  200. end;
  201. end;
  202. procedure TTestTSQLQuery.TrySetPacketRecords;
  203. begin
  204. FMyQ.PacketRecords:=10;
  205. end;
  206. procedure TTestTSQLQuery.TestKeepOpenOnCommitPacketRecords;
  207. begin
  208. with SQLDBConnector do
  209. begin
  210. FMyQ := SQLDBConnector.Query;
  211. FMyQ.Options:=[sqoKeepOpenOnCommit];
  212. AssertException('Cannot set PacketRecords when sqoKeepOpenOnCommit is active',EDatabaseError,@TrySetPacketRecords);
  213. end;
  214. end;
  215. procedure TTestTSQLQuery.TrySetQueryOptions;
  216. begin
  217. FMyQ.Options:=[sqoKeepOpenOnCommit];
  218. end;
  219. procedure TTestTSQLQuery.TestCheckSettingsOnlyWhenInactive;
  220. begin
  221. // Check that we can only set QueryOptions when the query is inactive.
  222. with SQLDBConnector do
  223. begin
  224. ExecuteDirect('create table FPDEV2 (id integer not null, a varchar(10), constraint PK_FPDEV2 primary key(id))');
  225. Transaction.Commit;
  226. ExecuteDirect(Format('INSERT INTO FPDEV2 values (%d,''%.6d'')',[1,1]));
  227. Transaction.Commit;
  228. FMyQ := SQLDBConnector.Query;
  229. FMyQ.SQL.Text:='select * from FPDEV2';
  230. FMyQ := SQLDBConnector.Query;
  231. FMyQ.Open;
  232. AssertException('Cannot set Options when query is active',EDatabaseError,@TrySetQueryOptions);
  233. end;
  234. end;
  235. procedure TTestTSQLQuery.DoAfterPost(DataSet: TDataSet);
  236. begin
  237. AssertTrue('Have modifications in after post',FMyq.UpdateStatus=usModified)
  238. end;
  239. procedure TTestTSQLQuery.TestAutoApplyUpdatesPost;
  240. var Q: TSQLQuery;
  241. I: Integer;
  242. begin
  243. // Test that if sqoAutoApplyUpdates is in QueryOptions, then POST automatically does an ApplyUpdates
  244. // Test also that POST afterpost event is backwards compatible.
  245. with SQLDBConnector do
  246. begin
  247. ExecuteDirect('create table FPDEV2 (id integer not null, a varchar(10), constraint PK_FPDEV2 primary key(id))');
  248. Transaction.COmmit;
  249. for I:=1 to 2 do
  250. ExecuteDirect(Format('INSERT INTO FPDEV2 values (%d,''%.6d'')',[i,i]));
  251. Transaction.COmmit;
  252. Q := SQLDBConnector.Query;
  253. FMyQ:=Q; // so th event handler can reach it.
  254. Q.SQL.Text:='select * from FPDEV2';
  255. Q.Options:=[sqoAutoApplyUpdates];
  256. // We must test that in AfterPost, the modification is still there, for backwards compatibilty
  257. Q.AfterPost:=@DoAfterPost;
  258. Q.Open;
  259. AssertEquals('Got all records',2,Q.RecordCount);
  260. // Now check editing
  261. Q.Locate('id',2,[]);
  262. Q.Edit;
  263. Q.FieldByName('a').AsString:='abc';
  264. Q.Post;
  265. AssertTrue('Have no more updates pending',Q.UpdateStatus=usUnmodified);
  266. Q.Close;
  267. Q.SQL.Text:='select * from FPDEV2 where (id=2) and (a=''abc'')';
  268. Q.Open;
  269. AssertTrue('Have modified data record in database',not (Q.EOF AND Q.BOF));
  270. end;
  271. end;
  272. procedure TTestTSQLQuery.TestAutoApplyUpdatesDelete;
  273. var Q: TSQLQuery;
  274. I: Integer;
  275. begin
  276. // Test that if sqoAutoApplyUpdates is in QueryOptions, then Delete automatically does an ApplyUpdates
  277. with SQLDBConnector do
  278. begin
  279. ExecuteDirect('create table FPDEV2 (id integer not null, a varchar(10), constraint PK_FPDEV2 primary key(id))');
  280. Transaction.COmmit;
  281. for I:=1 to 2 do
  282. ExecuteDirect(Format('INSERT INTO FPDEV2 values (%d,''%.6d'')',[i,i]));
  283. Transaction.COmmit;
  284. Q := SQLDBConnector.Query;
  285. FMyQ:=Q; // so th event handler can reach it.
  286. Q.SQL.Text:='select * from FPDEV2';
  287. Q.Options:=[sqoAutoApplyUpdates];
  288. // We must test that in AfterPost, the modification is still there, for backwards compatibilty
  289. Q.AfterPost:=@DoAfterPost;
  290. Q.Open;
  291. AssertEquals('Got all records',2,Q.RecordCount);
  292. // Now check editing
  293. Q.Locate('id',2,[]);
  294. Q.Delete;
  295. AssertTrue('Have no more updates pending',Q.UpdateStatus=usUnmodified);
  296. Q.Close;
  297. Q.SQL.Text:='select * from FPDEV2 where (id=2)';
  298. Q.Open;
  299. AssertTrue('Data record is deleted in database', (Q.EOF AND Q.BOF));
  300. end;
  301. end;
  302. procedure TTestTSQLQuery.DoApplyUpdates;
  303. begin
  304. FMyQ.ApplyUpdates();
  305. end;
  306. procedure TTestTSQLQuery.DoCount(Sender: TSQLConnection; EventType: TDBEventType; const Msg: String);
  307. begin
  308. If (EventType=detPrepare) then
  309. Inc(FPrepareCount);
  310. end;
  311. procedure TTestTSQLQuery.TestCheckRowsAffected;
  312. var Q: TSQLQuery;
  313. I: Integer;
  314. begin
  315. // Test that if sqoAutoApplyUpdates is in QueryOptions, then Delete automatically does an ApplyUpdates
  316. with SQLDBConnector do
  317. begin
  318. ExecuteDirect('create table FPDEV2 (id integer not null, a varchar(10), constraint PK_FPDEV2 primary key(id))');
  319. Transaction.COmmit;
  320. for I:=1 to 2 do
  321. ExecuteDirect(Format('INSERT INTO FPDEV2 values (%d,''%.6d'')',[i,i]));
  322. Transaction.COmmit;
  323. SQLDBConnector.Connection.Options:=[scoApplyUpdatesChecksRowsAffected];
  324. Q := SQLDBConnector.Query;
  325. Q.SQL.Text:='select * from FPDEV2';
  326. Q.DeleteSQL.Text:='delete from FPDEV2';
  327. Q.Open;
  328. AssertEquals('Got all records',2,Q.RecordCount);
  329. // Now check editing
  330. Q.Delete;
  331. FMyQ:=Q;
  332. AssertException('RowsAffected > 1 raises exception',EUpdateError,@DoApplyUpdates);
  333. end;
  334. end;
  335. procedure TTestTSQLQuery.TestAutoCommit;
  336. var
  337. I : Integer;
  338. begin
  339. with SQLDBConnector do
  340. begin
  341. ExecuteDirect('create table FPDEV2 (id integer not null, a varchar(10), constraint PK_FPDEV2 primary key(id))');
  342. if Transaction.Active then
  343. Transaction.Commit;
  344. Query.Options:=[sqoAutoCommit];
  345. for I:=1 to 2 do
  346. begin
  347. Query.SQL.Text:=Format('INSERT INTO FPDEV2 values (%d,''%.6d'');',[i,i]);
  348. Query.Prepare;
  349. Query.ExecSQL;
  350. // We do not commit anything explicitly.
  351. end;
  352. AssertFalse('Transaction is still active after expected auto commit', Transaction.Active);
  353. Connection.Close;
  354. Connection.Open;
  355. Query.SQL.Text:='SELECT COUNT(*) from FPDEV2';
  356. Query.Open;
  357. AssertEquals('Records haven''t been committed to database', 2, Query.Fields[0].AsInteger);
  358. end;
  359. end;
  360. procedure TTestTSQLQuery.TestGeneratedRefreshSQL;
  361. var
  362. Q: TSQLQuery;
  363. begin
  364. with SQLDBConnector do
  365. begin
  366. ExecuteDirect('create table FPDEV2 (id integer not null, a varchar(10) default ''abcde'', b varchar(5) default ''fgh'', constraint PK_FPDEV2 primary key(id))');
  367. if Transaction.Active then
  368. Transaction.Commit;
  369. end;
  370. Q:=SQLDBConnector.Query;
  371. Q.SQL.Text:='select * from FPDEV2';
  372. Q.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
  373. Q.Options:=Q.Options+[sqoRefreshUsingSelect];
  374. Q.Open;
  375. With Q.FieldByName('id') do
  376. ProviderFlags:=ProviderFlags+[pfInKey];
  377. With Q.FieldByName('a') do
  378. ProviderFlags:=ProviderFlags+[pfRefreshOnInsert,pfRefreshOnUpdate];
  379. With Q.FieldByName('b') do
  380. ProviderFlags:=ProviderFlags+[pfRefreshOnInsert,pfRefreshOnUpdate];
  381. Q.Insert;
  382. Q.FieldByName('id').AsInteger:=1;
  383. Q.Post;
  384. AssertTrue('Field value has not been fetched after post',Q.FieldByName('a').IsNull);
  385. Q.ApplyUpdates(0);
  386. AssertEquals('Still on correct field',1,Q.FieldByName('id').AsInteger);
  387. AssertEquals('Field value has been fetched from the database ','abcde',Q.FieldByName('a').AsString);
  388. AssertEquals('Field value has been fetched from the database ','fgh',Q.FieldByName('b').AsString);
  389. end;
  390. procedure TTestTSQLQuery.TestGeneratedRefreshSQL1Field;
  391. var
  392. Q: TSQLQuery;
  393. begin
  394. with SQLDBConnector do
  395. begin
  396. ExecuteDirect('create table FPDEV2 (id integer not null, a varchar(10) default ''abcde'', b varchar(5) default ''fgh'', constraint PK_FPDEV2 primary key(id))');
  397. if Transaction.Active then
  398. Transaction.Commit;
  399. end;
  400. Q:=SQLDBConnector.Query;
  401. Q.SQL.Text:='select * from FPDEV2';
  402. Q.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
  403. Q.Options:=Q.Options+[sqoRefreshUsingSelect];
  404. Q.Open;
  405. With Q.FieldByName('id') do
  406. ProviderFlags:=ProviderFlags+[pfInKey];
  407. With Q.FieldByName('a') do
  408. ProviderFlags:=ProviderFlags+[pfRefreshOnInsert,pfRefreshOnUpdate];
  409. Q.Insert;
  410. Q.FieldByName('id').AsInteger:=1;
  411. Q.Post;
  412. AssertTrue('Field value has not been fetched after post',Q.FieldByName('a').IsNull);
  413. Q.ApplyUpdates(0);
  414. AssertEquals('Still on correct field',1,Q.FieldByName('id').AsInteger);
  415. AssertEquals('Field value a has been fetched from the database ','abcde',Q.FieldByName('a').AsString);
  416. AssertEquals('Field value b has NOT been fetched from the database ','',Q.FieldByName('b').AsString);
  417. end;
  418. procedure TTestTSQLQuery.TestGeneratedRefreshSQLNoKey;
  419. begin
  420. with SQLDBConnector do
  421. begin
  422. ExecuteDirect('create table FPDEV2 (id integer not null, a varchar(10) default ''abcde'', b varchar(5) default ''fgh'', constraint PK_FPDEV2 primary key(id))');
  423. if Transaction.Active then
  424. Transaction.Commit;
  425. end;
  426. FMyQ:=SQLDBConnector.Query;
  427. FMyQ.SQL.Text:='select * from FPDEV2';
  428. FMyQ.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
  429. FMyQ.Options:=FMyQ.Options+[sqoRefreshUsingSelect];
  430. FMyQ.Open;
  431. With FMyQ.FieldByName('id') do
  432. ProviderFlags:=ProviderFlags-[pfInKey];
  433. With FMyQ.FieldByName('a') do
  434. ProviderFlags:=ProviderFlags+[pfRefreshOnInsert,pfRefreshOnUpdate];
  435. FMyQ.Insert;
  436. FMyQ.FieldByName('id').AsInteger:=1;
  437. FMyQ.Post;
  438. AssertException('Cannot refresh without primary key',EUpdateError,@DoApplyUpdates);
  439. end;
  440. procedure TTestTSQLQuery.TestRefreshSQL;
  441. var
  442. Q: TSQLQuery;
  443. begin
  444. with SQLDBConnector do
  445. begin
  446. ExecuteDirect('create table FPDEV2 (id integer not null primary key, a varchar(5) default ''abcde'', b integer default 1)');
  447. if Transaction.Active then
  448. Transaction.Commit;
  449. end;
  450. Q:=SQLDBConnector.Query;
  451. Q.SQL.Text:='select * from FPDEV2';
  452. Q.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
  453. Q.RefreshSQL.Text:='SELECT a,b FROM FPDEV2 WHERE (id=:id)';
  454. Q.Open;
  455. Q.Insert; // #1 record
  456. Q.FieldByName('id').AsInteger:=1;
  457. Q.Post;
  458. Q.Append; // #2 record
  459. Q.FieldByName('id').AsInteger:=2;
  460. Q.Post;
  461. AssertTrue('Field value has not been fetched after Post', Q.FieldByName('a').IsNull);
  462. Q.ApplyUpdates(0);
  463. // #2 record:
  464. AssertEquals('Still on correct field', 2, Q.FieldByName('id').AsInteger);
  465. AssertEquals('Field value has been fetched from the database', 'abcde', Q.FieldByName('a').AsString);
  466. AssertEquals('Field value has been fetched from the database', 1, Q.FieldByName('b').AsInteger);
  467. Q.Prior;
  468. // #1 record:
  469. AssertEquals('Still on correct field', 1, Q.FieldByName('id').AsInteger);
  470. AssertEquals('Field value has been fetched from the database', 'abcde', Q.FieldByName('a').AsString);
  471. AssertEquals('Field value has been fetched from the database', 1, Q.FieldByName('b').AsInteger);
  472. end;
  473. procedure TTestTSQLQuery.TestRefreshSQLMultipleRecords;
  474. begin
  475. with SQLDBConnector do
  476. begin
  477. ExecuteDirect('create table FPDEV2 (id integer not null, a varchar(10) default ''abcde'', b varchar(5) default ''fgh'', constraint PK_FPDEV2 primary key(id))');
  478. if Transaction.Active then
  479. Transaction.Commit;
  480. ExecuteDirect('insert into FPDEV2 (id) values (123)');
  481. if Transaction.Active then
  482. Transaction.Commit;
  483. end;
  484. FMyQ:=SQLDBConnector.Query;
  485. FMyQ.SQL.Text:='select * from FPDEV2';
  486. FMyQ.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
  487. FMyQ.RefreshSQL.Text:='select * from FPDEV2';
  488. FMyQ.Open;
  489. With FMyQ.FieldByName('id') do
  490. ProviderFlags:=ProviderFlags+[pfInKey];
  491. With FMyQ.FieldByName('a') do
  492. ProviderFlags:=ProviderFlags+[pfRefreshOnInsert,pfRefreshOnUpdate];
  493. FMyQ.Insert;
  494. FMyQ.FieldByName('id').AsInteger:=1;
  495. FMyQ.Post;
  496. AssertException('Multiple records returned by RefreshSQL gives an error',EUpdateError,@DoApplyUpdates);
  497. end;
  498. procedure TTestTSQLQuery.TestRefreshSQLNoRecords;
  499. begin
  500. with SQLDBConnector do
  501. begin
  502. ExecuteDirect('create table FPDEV2 (id integer not null, a varchar(10) default ''abcde'', b varchar(5) default ''fgh'', constraint PK_FPDEV2 primary key(id))');
  503. if Transaction.Active then
  504. Transaction.Commit;
  505. ExecuteDirect('insert into FPDEV2 (id) values (123)');
  506. if Transaction.Active then
  507. Transaction.Commit;
  508. end;
  509. FMyQ:=SQLDBConnector.Query;
  510. FMyQ.SQL.Text:='select * from FPDEV2';
  511. FMyQ.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
  512. FMyQ.RefreshSQL.Text:='select * from FPDEV2 where 1=2';
  513. FMyQ.Open;
  514. With FMyQ.FieldByName('id') do
  515. ProviderFlags:=ProviderFlags+[pfInKey];
  516. With FMyQ.FieldByName('a') do
  517. ProviderFlags:=ProviderFlags+[pfRefreshOnInsert,pfRefreshOnUpdate];
  518. FMyQ.Insert;
  519. FMyQ.FieldByName('id').AsInteger:=1;
  520. FMyQ.Post;
  521. AssertException('No records returned by RefreshSQL gives an error',EUpdateError,@DoApplyUpdates);
  522. end;
  523. procedure TTestTSQLQuery.TestFetchAutoInc;
  524. var datatype: string;
  525. id: largeint;
  526. begin
  527. with SQLDBConnector do
  528. begin
  529. case SQLServerType of
  530. ssMySQL:
  531. datatype := 'integer auto_increment';
  532. ssMSSQL, ssSybase:
  533. datatype := 'integer identity';
  534. ssSQLite:
  535. datatype := 'integer';
  536. else
  537. Ignore(STestNotApplicable);
  538. end;
  539. ExecuteDirect('create table FPDEV2 (id '+datatype+' primary key, f varchar(5))');
  540. CommitDDL;
  541. end;
  542. with SQLDBConnector.Query do
  543. begin
  544. SQL.Text:='select * from FPDEV2';
  545. Open;
  546. Insert;
  547. FieldByName('f').AsString:='a';
  548. Post; // #1 record
  549. Append;
  550. FieldByName('f').AsString:='b';
  551. Post; // #2 record
  552. AssertTrue('ID field is not null after Post', FieldByName('id').IsNull);
  553. First; // #1 record
  554. ApplyUpdates(0);
  555. AssertTrue('ID field is still null after ApplyUpdates', Not FieldByName('id').IsNull);
  556. // Should be 1 after the table was created, but this is not guaranteed... So we just test positive values.
  557. id := FieldByName('id').AsLargeInt;
  558. AssertTrue('ID field has not positive value', id>0);
  559. Next; // #2 record
  560. AssertTrue('Next ID value is not greater than previous', FieldByName('id').AsLargeInt>id);
  561. end;
  562. end;
  563. procedure TTestTSQLQuery.TestSequence;
  564. var SequenceNames : TStringList;
  565. begin
  566. case SQLServerType of
  567. ssFirebird:
  568. SQLDBConnector.ExecuteDirect('create sequence FPDEV_SEQ1');
  569. ssMSSQL, ssOracle, ssPostgreSQL:
  570. SQLDBConnector.ExecuteDirect('create sequence FPDEV_SEQ1 MINVALUE 1');
  571. else
  572. Ignore(STestNotApplicable);
  573. end;
  574. SQLDBConnector.ExecuteDirect('create table FPDEV2 (id integer)');
  575. SQLDBConnector.CommitDDL;
  576. with SQLDBConnector.Query do
  577. begin
  578. SQL.Text := 'select * from FPDEV2';
  579. Sequence.FieldName:='id';
  580. Sequence.SequenceName:='FPDEV_SEQ1';
  581. Open;
  582. // default is get next value on new record
  583. Append;
  584. AssertEquals(1, FieldByName('id').AsInteger);
  585. Sequence.ApplyEvent:=saeOnPost;
  586. Append;
  587. AssertTrue('Field ID must be null after Append', FieldByName('id').IsNull);
  588. Post;
  589. AssertEquals(2, FieldByName('id').AsInteger);
  590. end;
  591. // test GetSequenceNames
  592. SequenceNames := TStringList.Create;
  593. try
  594. SQLDBConnector.Connection.GetSequenceNames(SequenceNames);
  595. AssertTrue(SequenceNames.IndexOf('FPDEV_SEQ1') >= 0);
  596. finally
  597. SequenceNames.Free;
  598. end;
  599. SQLDBConnector.ExecuteDirect('drop sequence FPDEV_SEQ1');
  600. SQLDBConnector.CommitDDL;
  601. end;
  602. procedure TTestTSQLQuery.TestReturningInsert;
  603. begin
  604. with SQLDBConnector do
  605. begin
  606. if not (sqSupportReturning in Connection.ConnOptions) then
  607. Ignore(STestNotApplicable);
  608. ExecuteDirect('create table FPDEV2 (id integer not null, a varchar(10) default ''abcde'', b varchar(5) default ''fgh'', constraint PK_FPDEV2 primary key(id))');
  609. if Transaction.Active then
  610. Transaction.Commit;
  611. ExecuteDirect('insert into FPDEV2 (id) values (123)');
  612. if Transaction.Active then
  613. Transaction.Commit;
  614. end;
  615. FMyQ:=SQLDBConnector.Query;
  616. FMyQ.SQL.Text:='select * from FPDEV2';
  617. // FMyQ.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
  618. FMyQ.Open;
  619. With FMyQ.FieldByName('id') do
  620. ProviderFlags:=ProviderFlags+[pfInKey];
  621. With FMyQ.FieldByName('a') do
  622. ProviderFlags:=ProviderFlags+[pfRefreshOnInsert];
  623. With FMyQ.FieldByName('b') do
  624. ProviderFlags:=[];
  625. FMyQ.Insert;
  626. FMyQ.FieldByName('id').AsInteger:=1;
  627. FMyQ.Post;
  628. FMyQ.ApplyUpdates;
  629. AssertEquals('a updated','abcde',FMyQ.FieldByName('a').AsString);
  630. AssertEquals('b not updated','',FMyQ.FieldByName('b').AsString);
  631. end;
  632. procedure TTestTSQLQuery.TestReturningUpdate;
  633. begin
  634. with SQLDBConnector do
  635. begin
  636. if not (sqSupportReturning in Connection.ConnOptions) then
  637. Ignore(STestNotApplicable);
  638. ExecuteDirect('create table FPDEV2 (id integer not null, a varchar(10) default ''abcde'', b varchar(5) default ''fgh'', constraint PK_FPDEV2 primary key(id))');
  639. CommitDDL;
  640. ExecuteDirect('insert into FPDEV2 (id) values (1)');
  641. ExecuteDirect('insert into FPDEV2 (id) values (2)');
  642. end;
  643. FMyQ:=SQLDBConnector.Query;
  644. FMyQ.SQL.Text:='select * from FPDEV2';
  645. FMyQ.Open;
  646. With FMyQ.FieldByName('id') do
  647. ProviderFlags:=ProviderFlags+[pfInKey];
  648. With FMyQ.FieldByName('b') do
  649. ProviderFlags:=[pfRefreshOnUpdate]; // Do not update, just fetch new value
  650. SQLDBConnector.ExecuteDirect('update FPDEV2 set b=''b1'' where id=1');
  651. SQLDBConnector.ExecuteDirect('update FPDEV2 set b=''b2'' where id=2');
  652. FMyQ.Edit;
  653. FMyQ.FieldByName('a').AsString:='a1';
  654. FMyQ.Post; // #1 record
  655. FMyQ.Next;
  656. FMyQ.Edit;
  657. FMyQ.FieldByName('a').AsString:='a2';
  658. FMyQ.Post; // #2 record
  659. FMyQ.ApplyUpdates;
  660. FMyQ.First;
  661. AssertEquals('#1.a updated', 'a1', FMyQ.FieldByName('a').AsString);
  662. AssertEquals('#1.b updated', 'b1', FMyQ.FieldByName('b').AsString);
  663. FMyQ.Next;
  664. AssertEquals('#2.a updated', 'a2', FMyQ.FieldByName('a').AsString);
  665. AssertEquals('#2.b updated', 'b2', FMyQ.FieldByName('b').AsString);
  666. end;
  667. procedure TTestTSQLQuery.TestMacros;
  668. begin
  669. with SQLDBConnector do
  670. begin
  671. ExecuteDirect('create table FPDEV2 (id integer not null, constraint PK_FPDEV2 primary key(id))');
  672. CommitDDL;
  673. ExecuteDirect('insert into FPDEV2 (id) values (1)');
  674. ExecuteDirect('insert into FPDEV2 (id) values (2)');
  675. end;
  676. With SQLDBConnector.Query do
  677. begin
  678. SQL.Text:='Select ID from FPDEV2 '+
  679. '%WHERE_CL' +sLineBreak+
  680. '%ORDER_CL' +sLineBreak;
  681. MacroCheck:=true;
  682. MacroByName('WHERE_CL').AsString:='where 1=1';
  683. MacroByName('ORDER_CL').AsString:='order by 1';
  684. Open;
  685. AssertEquals('Correct SQL executed, macros substituted: ',1,Fields[0].AsInteger);
  686. Close;
  687. MacroByName('ORDER_CL').AsString := 'Order by 1 DESC';
  688. Open;
  689. AssertEquals('Correct SQL executed, macro value changed: ',2,Fields[0].AsInteger);
  690. end;
  691. end;
  692. procedure TTestTSQLQuery.TestPrepareCount;
  693. begin
  694. with SQLDBConnector do
  695. begin
  696. ExecuteDirect('create table FPDEV2 (id integer not null, constraint PK_FPDEV2 primary key(id))');
  697. CommitDDL;
  698. ExecuteDirect('insert into FPDEV2 (id) values (1)');
  699. ExecuteDirect('insert into FPDEV2 (id) values (2)');
  700. Connection.OnLog:=@DoCount;
  701. Connection.LogEvents:=[detPrepare];
  702. end;
  703. try
  704. With SQLDBConnector.Query do
  705. begin
  706. Unidirectional:=True; // Disable server index defs etc
  707. UsePrimaryKeyAsKey:=False; // Idem
  708. SQL.Text:='Select ID from FPDEV2 where (ID=:ID)';
  709. ParamByname('ID').AsInteger:=1;
  710. Prepare;
  711. Open;
  712. AssertEquals('Correct record count param 1',1,RecordCount);
  713. AssertEquals('Correct SQL executed, correct paramete: ',1,Fields[0].AsInteger);
  714. Close;
  715. ParamByname('ID').AsInteger:=2;
  716. Open;
  717. AssertEquals('Correct record count param 2',1,RecordCount);
  718. AssertEquals('Correct SQL executed, macro value changed: ',2,Fields[0].AsInteger);
  719. end;
  720. AssertEquals('Prepare called only once ',1,FPrepareCount);
  721. finally
  722. SQLDBConnector.Connection.OnLog:=Nil;
  723. end;
  724. end;
  725. { TTestTSQLConnection }
  726. procedure TTestTSQLConnection.TestImplicitTransaction;
  727. Var
  728. T : TSQLTransaction;
  729. begin
  730. T:=TSQLTransaction.Create(Nil);
  731. try
  732. T.Options:=[stoUseImplicit];
  733. T.DataBase:=SQLDBConnector.Connection;
  734. finally
  735. T.Free;
  736. end;
  737. end;
  738. procedure TTestTSQLConnection.TestImplicitTransaction2;
  739. Var
  740. T : TSQLTransaction;
  741. begin
  742. T:=TSQLTransaction.Create(Nil);
  743. try
  744. T.Options:=[stoUseImplicit];
  745. SQLDBConnector.Connection.Transaction:=T;
  746. finally
  747. T.Free;
  748. end;
  749. end;
  750. procedure TTestTSQLConnection.SetImplicit;
  751. begin
  752. SQLDBConnector.Transaction.Options:=[stoUseImplicit];
  753. end;
  754. procedure TTestTSQLConnection.TestImplicitTransactionNotAssignable;
  755. begin
  756. AssertException('Cannot set toUseImplicit option if database does not allow it',EDatabaseError,@SetImplicit);
  757. AssertException('Cannot assign database to transaction with toUseImplicit, if database does not allow it',EDatabaseError,@TestImplicitTransaction);
  758. AssertException('Cannot assign transaction with toUseImplicit to database, if database does not allow it',EDatabaseError,@TestImplicitTransaction2);
  759. end;
  760. procedure TTestTSQLConnection.TestImplicitTransactionOK;
  761. var
  762. Q : TSQLQuery;
  763. T : TSQLTransaction;
  764. I : Integer;
  765. begin
  766. with SQLDBConnector do
  767. begin
  768. ExecuteDirect('create table FPDEV2 (id integer not null, a varchar(10), constraint PK_FPDEV2 primary key(id))');
  769. if Transaction.Active then
  770. Transaction.Commit;
  771. end;
  772. SetImplicit;
  773. Q:=SQLDBConnector.Query;
  774. for I:=1 to 2 do
  775. begin
  776. Q.SQL.Text:=Format('INSERT INTO FPDEV2 values (%d,''%.6d'');',[i,i]);
  777. Q.Prepare;
  778. Q.ExecSQL;
  779. // We do not commit anything explicitly.
  780. end;
  781. Q:=Nil;
  782. T:=Nil;
  783. try
  784. T:=TSQLTransaction.Create(Nil);
  785. Q:=TSQLQuery.Create(Nil);
  786. Q.Transaction:=T;
  787. Q.Database:=SQLDBConnector.Connection;
  788. T.Database:=SQLDBConnector.Connection;
  789. Q.SQL.text:='SELECT COUNT(*) from FPDEV2';
  790. Q.Open;
  791. AssertEquals('Records have been committed to database',2,Q.Fields[0].AsInteger);
  792. finally
  793. Q.Free;
  794. T.Free;
  795. end;
  796. end;
  797. procedure TTestTSQLConnection.TestUseImplicitTransaction;
  798. begin
  799. if (sqImplicitTransaction in SQLDBConnector.Connection.ConnOptions) then
  800. TestImplicitTransactionOK
  801. else
  802. TestImplicitTransactionNotAssignable;
  803. end;
  804. procedure TTestTSQLConnection.TryOpen;
  805. begin
  806. SQLDBConnector.Query.Open;
  807. end;
  808. procedure TTestTSQLConnection.TestUseExplicitTransaction;
  809. begin
  810. SQLDBConnector.Transaction.Active:=False;
  811. SQLDBConnector.Transaction.Options:=[stoExplicitStart];
  812. SQLDBConnector.Query.SQL.Text:='select * from FPDEV';
  813. AssertException('toExplicitStart raises exception on implicit start',EDatabaseError,@TryOpen)
  814. end;
  815. procedure TTestTSQLConnection.TestExplicitConnect;
  816. begin
  817. SQLDBConnector.Transaction.Active:=False;
  818. SQLDBConnector.Connection.Options:=[scoExplicitConnect];
  819. SQLDBConnector.Connection.Connected:=False;
  820. SQLDBConnector.Query.SQL.Text:='select * from FPDEV';
  821. AssertException('toExplicitStart raises exception on implicit start',EDatabaseError,@TryOpen)
  822. end;
  823. procedure TTestTSQLConnection.TestGetStatementInfo;
  824. var StmtInfo: TSQLStatementInfo;
  825. begin
  826. // single table
  827. StmtInfo := SQLDBConnector.Connection.GetStatementInfo('SELECT * FROM tab1');
  828. AssertEquals('StatementType', ord(stSELECT), ord(StmtInfo.StatementType));
  829. AssertEquals('TableName', 'tab1', StmtInfo.TableName);
  830. AssertEquals('Updateable', True, StmtInfo.Updateable);
  831. StmtInfo := SQLDBConnector.Connection.GetStatementInfo('SELECT * FROM tab2 WHERE col1=1');
  832. AssertEquals('TableName', 'tab2', StmtInfo.TableName);
  833. AssertEquals('Updateable', True, StmtInfo.Updateable);
  834. // single table with schema
  835. StmtInfo := SQLDBConnector.Connection.GetStatementInfo('SELECT * FROM dbo.tab2 WHERE col1=1');
  836. AssertEquals('TableName', 'dbo.tab2', StmtInfo.TableName);
  837. AssertEquals('Updateable', True, StmtInfo.Updateable);
  838. // single table with quoted schema
  839. StmtInfo := SQLDBConnector.Connection.GetStatementInfo('SELECT * FROM "dbo".tab2 WHERE col1=1');
  840. AssertEquals('TableName', '"dbo".tab2', StmtInfo.TableName);
  841. AssertEquals('Updateable', True, StmtInfo.Updateable);
  842. StmtInfo := SQLDBConnector.Connection.GetStatementInfo('SELECT * FROM "dbo"."tab2" WHERE col1=1');
  843. AssertEquals('TableName', '"dbo"."tab2"', StmtInfo.TableName);
  844. AssertEquals('Updateable', True, StmtInfo.Updateable);
  845. // multiple tables
  846. StmtInfo := SQLDBConnector.Connection.GetStatementInfo('SELECT * FROM tab3,tab4 WHERE col1=1');
  847. AssertEquals('TableName', '', StmtInfo.TableName);
  848. AssertEquals('Updateable', False, StmtInfo.Updateable);
  849. // function
  850. StmtInfo := SQLDBConnector.Connection.GetStatementInfo('SELECT * FROM dbo.fn1(1)');
  851. AssertEquals('TableName', '', StmtInfo.TableName);
  852. AssertEquals('Updateable', False, StmtInfo.Updateable);
  853. end;
  854. { TTestTSQLScript }
  855. procedure TTestTSQLScript.TestExecuteScript;
  856. var Ascript : TSQLScript;
  857. begin
  858. Ascript := TSQLScript.Create(nil);
  859. try
  860. with Ascript do
  861. begin
  862. DataBase := SQLDBConnector.Connection;
  863. Transaction := SQLDBConnector.Transaction;
  864. Script.Clear;
  865. Script.Append('create table FPDEV_A (id int);');
  866. Script.Append('create table FPDEV_B (id int);');
  867. ExecuteScript;
  868. // Firebird/Interbase need a commit after a DDL statement. Not necessary for the other connections
  869. SQLDBConnector.CommitDDL;
  870. end;
  871. finally
  872. AScript.Free;
  873. SQLDBConnector.ExecuteDirect('drop table FPDEV_A');
  874. SQLDBConnector.ExecuteDirect('drop table FPDEV_B');
  875. // Firebird/Interbase need a commit after a DDL statement. Not necessary for the other connections
  876. SQLDBConnector.CommitDDL;
  877. end;
  878. end;
  879. procedure TTestTSQLScript.TestScriptColon;
  880. // Bug 25334: TSQLScript incorrectly treats : in scripts as sqldb query parameter markers
  881. // Firebird-only test; can be extended for other dbs that use : in SQL
  882. var
  883. Ascript : TSQLScript;
  884. begin
  885. if not(SQLConnType in [interbase]) then Ignore(STestNotApplicable);
  886. Ascript := TSQLScript.Create(nil);
  887. try
  888. with Ascript do
  889. begin
  890. DataBase := SQLDBConnector.Connection;
  891. Transaction := SQLDBConnector.Transaction;
  892. Script.Clear;
  893. UseSetTerm := true;
  894. // Example procedure that selects table names
  895. Script.Append(
  896. 'SET TERM ^ ; '+LineEnding+
  897. 'CREATE PROCEDURE FPDEV_TESTCOLON '+LineEnding+
  898. 'RETURNS (tblname VARCHAR(31)) '+LineEnding+
  899. 'AS '+LineEnding+
  900. 'begin '+LineEnding+
  901. '/* Show tables. Note statement uses colon */ '+LineEnding+
  902. 'FOR '+LineEnding+
  903. ' SELECT RDB$RELATION_NAME '+LineEnding+
  904. ' FROM RDB$RELATIONS '+LineEnding+
  905. ' ORDER BY RDB$RELATION_NAME '+LineEnding+
  906. ' INTO :tblname '+LineEnding+
  907. 'DO '+LineEnding+
  908. ' SUSPEND; '+LineEnding+
  909. 'end^ '+LineEnding+
  910. 'SET TERM ; ^'
  911. );
  912. ExecuteScript;
  913. // Firebird/Interbase need a commit after a DDL statement. Not necessary for the other connections
  914. SQLDBConnector.CommitDDL;
  915. end;
  916. finally
  917. AScript.Free;
  918. SQLDBConnector.ExecuteDirect('DROP PROCEDURE FPDEV_TESTCOLON');
  919. // Firebird/Interbase need a commit after a DDL statement. Not necessary for the other connections
  920. SQLDBConnector.CommitDDL;
  921. end;
  922. end;
  923. procedure TTestTSQLScript.TestUseCommit;
  924. // E.g. Firebird needs explicit COMMIT sometimes, e.g. if mixing DDL and DML
  925. // statements in a script.
  926. // Probably same as bug 17829 Error executing SQL script
  927. const
  928. TestValue='Some text';
  929. var
  930. Ascript : TSQLScript;
  931. CheckQuery : TSQLQuery;
  932. begin
  933. Ascript := TSQLScript.Create(nil);
  934. try
  935. with Ascript do
  936. begin
  937. DataBase := SQLDBConnector.Connection;
  938. Transaction := SQLDBConnector.Transaction;
  939. Script.Clear;
  940. UseCommit:=true;
  941. // Example procedure that selects table names
  942. Script.Append('CREATE TABLE fpdev_scriptusecommit (logmessage VARCHAR(255));');
  943. Script.Append('COMMIT;'); //needed for table to show up
  944. Script.Append('INSERT INTO fpdev_scriptusecommit (logmessage) VALUES('''+TestValue+''');');
  945. Script.Append('COMMIT;');
  946. ExecuteScript;
  947. // This line should not run, as the commit above should have taken care of it:
  948. //SQLDBConnector.CommitDDL;
  949. // Test whether second line of script executed, just to be sure
  950. CheckQuery:=SQLDBConnector.Query;
  951. CheckQuery.SQL.Text:='SELECT logmessage FROM fpdev_scriptusecommit ';
  952. CheckQuery.Open;
  953. CheckEquals(TestValue, CheckQuery.Fields[0].AsString, 'Insert script line should have inserted '+TestValue);
  954. CheckQuery.Close;
  955. end;
  956. finally
  957. AScript.Free;
  958. SQLDBConnector.ExecuteDirect('DROP TABLE fpdev_scriptusecommit');
  959. SQLDBConnector.Transaction.Commit;
  960. end;
  961. end;
  962. { TSQLDBTestCase }
  963. function TSQLDBTestCase.GetSQLDBConnector: TSQLDBConnector;
  964. begin
  965. Result := DBConnector as TSQLDBConnector;
  966. end;
  967. procedure TSQLDBTestCase.SetUp;
  968. begin
  969. inherited SetUp;
  970. InitialiseDBConnector;
  971. DBConnector.StartTest(TestName);
  972. end;
  973. procedure TSQLDBTestCase.TearDown;
  974. begin
  975. DBConnector.StopTest(TestName);
  976. if assigned(DBConnector) then
  977. with SQLDBConnector do
  978. if Assigned(Transaction) and Transaction.Active and not (stoUseImplicit in Transaction.Options) then
  979. Transaction.Rollback;
  980. FreeDBConnector;
  981. inherited TearDown;
  982. end;
  983. initialization
  984. if uppercase(dbconnectorname)='SQL' then
  985. begin
  986. RegisterTest(TTestTSQLQuery);
  987. RegisterTest(TTestTSQLConnection);
  988. RegisterTest(TTestTSQLScript);
  989. end;
  990. end.