testsqldb.pas 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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, SysUtils, fpcunit, testregistry,
  9. db;
  10. type
  11. { TSQLDBTestCase }
  12. TSQLDBTestCase = class(TTestCase)
  13. protected
  14. procedure SetUp; override;
  15. procedure TearDown; override;
  16. end;
  17. { TTestTSQLQuery }
  18. TTestTSQLQuery = class(TSQLDBTestCase)
  19. private
  20. published
  21. procedure TestMasterDetail;
  22. procedure TestUpdateServerIndexDefs;
  23. end;
  24. { TTestTSQLConnection }
  25. TTestTSQLConnection = class(TSQLDBTestCase)
  26. private
  27. published
  28. procedure ReplaceMe;
  29. end;
  30. { TTestTSQLScript }
  31. TTestTSQLScript = class(TSQLDBTestCase)
  32. published
  33. procedure TestExecuteScript;
  34. procedure TestScriptColon; //bug 25334
  35. procedure TestUseCommit; //E.g. Firebird cannot use COMMIT RETAIN if mixing DDL and DML in a script
  36. end;
  37. implementation
  38. uses sqldbtoolsunit, toolsunit, sqldb;
  39. { TTestTSQLQuery }
  40. procedure TTestTSQLQuery.TestMasterDetail;
  41. var MasterQuery, DetailQuery: TSQLQuery;
  42. MasterSource: TDataSource;
  43. begin
  44. with TSQLDBConnector(DBConnector) do
  45. try
  46. MasterQuery := GetNDataset(10) as TSQLQuery;
  47. MasterSource := TDatasource.Create(nil);
  48. MasterSource.DataSet := MasterQuery;
  49. DetailQuery := Query;
  50. DetailQuery.SQL.Text := 'select NAME from FPDEV where ID=:ID';
  51. DetailQuery.DataSource := MasterSource;
  52. MasterQuery.Open;
  53. DetailQuery.Open;
  54. CheckEquals('TestName1', DetailQuery.Fields[0].AsString);
  55. MasterQuery.MoveBy(3);
  56. CheckEquals('TestName4', DetailQuery.Fields[0].AsString);
  57. finally
  58. MasterSource.Free;
  59. end;
  60. end;
  61. procedure TTestTSQLQuery.TestUpdateServerIndexDefs;
  62. var Q: TSQLQuery;
  63. name1, name2, name3: string;
  64. begin
  65. // Test retrieval of information about indexes on unquoted and quoted table names
  66. // (tests also case-sensitivity for DB's that support case-sensitivity of quoted identifiers)
  67. // For ODBC Firebird/Interbase we must define primary key as named constraint and
  68. // in ODBC driver must be set: "quoted identifiers" and "sensitive identifier"
  69. // See also: TTestFieldTypes.TestUpdateIndexDefs
  70. with TSQLDBConnector(DBConnector) do
  71. begin
  72. // SQLite ignores case-sensitivity of quoted table names
  73. // MS SQL Server case-sensitivity of identifiers depends on the case-sensitivity of default collation of the database
  74. // MySQL case-sensitivity depends on case-sensitivity of server's file system
  75. if SQLServerType in [ssMSSQL,ssSQLite{$IFDEF WINDOWS},ssMySQL{$ENDIF}] then
  76. name1 := Connection.FieldNameQuoteChars[0]+'fpdev 2'+Connection.FieldNameQuoteChars[1]
  77. else
  78. name1 := 'FPDEV2';
  79. ExecuteDirect('create table '+name1+' (id integer not null, constraint PK_FPDEV21 primary key(id))');
  80. // same but quoted table name
  81. name2 := Connection.FieldNameQuoteChars[0]+'FPdev2'+Connection.FieldNameQuoteChars[1];
  82. ExecuteDirect('create table '+name2+' (ID2 integer not null, constraint PK_FPDEV22 primary key(ID2))');
  83. // embedded quote in table name
  84. if SQLServerType in [ssMySQL] then
  85. name3 := '`FPdev``2`'
  86. else
  87. name3 := Connection.FieldNameQuoteChars[0]+'FPdev""2'+Connection.FieldNameQuoteChars[1];
  88. ExecuteDirect('create table '+name3+' (Id3 integer not null, constraint PK_FPDEV23 primary key(Id3))');
  89. CommitDDL;
  90. end;
  91. try
  92. Q := TSQLDBConnector(DBConnector).Query;
  93. Q.SQL.Text:='select * from '+name1;
  94. Q.Prepare;
  95. Q.ServerIndexDefs.Update;
  96. CheckEquals(1, Q.ServerIndexDefs.Count);
  97. Q.SQL.Text:='select * from '+name2;
  98. Q.Prepare;
  99. Q.ServerIndexDefs.Update;
  100. CheckEquals(1, Q.ServerIndexDefs.Count, '2.1');
  101. CheckTrue(CompareText('ID2', Q.ServerIndexDefs[0].Fields)=0, '2.2'+Q.ServerIndexDefs[0].Fields);
  102. CheckTrue(Q.ServerIndexDefs[0].Options=[ixPrimary,ixUnique], '2.3');
  103. Q.SQL.Text:='select * from '+name3;
  104. Q.Prepare;
  105. Q.ServerIndexDefs.Update;
  106. CheckEquals(1, Q.ServerIndexDefs.Count, '3.1');
  107. CheckTrue(CompareText('ID3', Q.ServerIndexDefs[0].Fields)=0, '3.2');
  108. CheckTrue(Q.ServerIndexDefs[0].Options=[ixPrimary,ixUnique], '3.3');
  109. finally
  110. Q.UnPrepare;
  111. with TSQLDBConnector(DBConnector) do
  112. begin
  113. ExecuteDirect('DROP TABLE '+name1);
  114. ExecuteDirect('DROP TABLE '+name2);
  115. ExecuteDirect('DROP TABLE '+name3);
  116. CommitDDL;
  117. end;
  118. end;
  119. end;
  120. { TTestTSQLConnection }
  121. procedure TTestTSQLConnection.ReplaceMe;
  122. begin
  123. // replace this procedure with any test for TSQLConnection
  124. end;
  125. { TTestTSQLScript }
  126. procedure TTestTSQLScript.TestExecuteScript;
  127. var Ascript : TSQLScript;
  128. begin
  129. Ascript := TSQLScript.Create(nil);
  130. try
  131. with Ascript do
  132. begin
  133. DataBase := TSQLDBConnector(DBConnector).Connection;
  134. Transaction := TSQLDBConnector(DBConnector).Transaction;
  135. Script.Clear;
  136. Script.Append('create table FPDEV_A (id int);');
  137. Script.Append('create table FPDEV_B (id int);');
  138. ExecuteScript;
  139. // Firebird/Interbase need a commit after a DDL statement. Not necessary for the other connections
  140. TSQLDBConnector(DBConnector).CommitDDL;
  141. end;
  142. finally
  143. AScript.Free;
  144. TSQLDBConnector(DBConnector).ExecuteDirect('drop table FPDEV_A');
  145. TSQLDBConnector(DBConnector).ExecuteDirect('drop table FPDEV_B');
  146. // Firebird/Interbase need a commit after a DDL statement. Not necessary for the other connections
  147. TSQLDBConnector(DBConnector).CommitDDL;
  148. end;
  149. end;
  150. procedure TTestTSQLScript.TestScriptColon;
  151. // Bug 25334: TSQLScript incorrectly treats : in scripts as sqldb query parameter markers
  152. // Firebird-only test; can be extended for other dbs that use : in SQL
  153. var
  154. Ascript : TSQLScript;
  155. begin
  156. if not(SQLConnType in [interbase]) then Ignore(STestNotApplicable);
  157. Ascript := TSQLScript.Create(nil);
  158. try
  159. with Ascript do
  160. begin
  161. DataBase := TSQLDBConnector(DBConnector).Connection;
  162. Transaction := TSQLDBConnector(DBConnector).Transaction;
  163. Script.Clear;
  164. UseSetTerm := true;
  165. // Example procedure that selects table names
  166. Script.Append(
  167. 'SET TERM ^ ; '+LineEnding+
  168. 'CREATE PROCEDURE FPDEV_TESTCOLON '+LineEnding+
  169. 'RETURNS (tblname VARCHAR(31)) '+LineEnding+
  170. 'AS '+LineEnding+
  171. 'begin '+LineEnding+
  172. '/* Show tables. Note statement uses colon */ '+LineEnding+
  173. 'FOR '+LineEnding+
  174. ' SELECT RDB$RELATION_NAME '+LineEnding+
  175. ' FROM RDB$RELATIONS '+LineEnding+
  176. ' ORDER BY RDB$RELATION_NAME '+LineEnding+
  177. ' INTO :tblname '+LineEnding+
  178. 'DO '+LineEnding+
  179. ' SUSPEND; '+LineEnding+
  180. 'end^ '+LineEnding+
  181. 'SET TERM ; ^'
  182. );
  183. ExecuteScript;
  184. // Firebird/Interbase need a commit after a DDL statement. Not necessary for the other connections
  185. TSQLDBConnector(DBConnector).CommitDDL;
  186. end;
  187. finally
  188. AScript.Free;
  189. TSQLDBConnector(DBConnector).ExecuteDirect('DROP PROCEDURE FPDEV_TESTCOLON');
  190. // Firebird/Interbase need a commit after a DDL statement. Not necessary for the other connections
  191. TSQLDBConnector(DBConnector).CommitDDL;
  192. end;
  193. end;
  194. procedure TTestTSQLScript.TestUseCommit;
  195. // E.g. Firebird needs explicit COMMIT sometimes, e.g. if mixing DDL and DML
  196. // statements in a script.
  197. // Probably same as bug 17829 Error executing SQL script
  198. const
  199. TestValue='Some text';
  200. var
  201. Ascript : TSQLScript;
  202. CheckQuery : TSQLQuery;
  203. begin
  204. Ascript := TSQLScript.Create(nil);
  205. try
  206. with Ascript do
  207. begin
  208. DataBase := TSQLDBConnector(DBConnector).Connection;
  209. Transaction := TSQLDBConnector(DBConnector).Transaction;
  210. Script.Clear;
  211. UseCommit:=true;
  212. // Example procedure that selects table names
  213. Script.Append('CREATE TABLE fpdev_scriptusecommit (logmessage VARCHAR(255));');
  214. Script.Append('COMMIT;'); //needed for table to show up
  215. Script.Append('INSERT INTO fpdev_scriptusecommit (logmessage) VALUES('''+TestValue+''');');
  216. Script.Append('COMMIT;');
  217. ExecuteScript;
  218. // This line should not run, as the commit above should have taken care of it:
  219. //TSQLDBConnector(DBConnector).CommitDDL;
  220. // Test whether second line of script executed, just to be sure
  221. CheckQuery:=TSQLDBConnector(DBConnector).Query;
  222. CheckQuery.SQL.Text:='SELECT logmessage FROM fpdev_scriptusecommit ';
  223. CheckQuery.Open;
  224. CheckEquals(TestValue, CheckQuery.Fields[0].AsString, 'Insert script line should have inserted '+TestValue);
  225. CheckQuery.Close;
  226. end;
  227. finally
  228. AScript.Free;
  229. TSQLDBConnector(DBConnector).ExecuteDirect('DROP TABLE fpdev_scriptusecommit');
  230. TSQLDBConnector(DBConnector).Transaction.Commit;
  231. end;
  232. end;
  233. { TSQLDBTestCase }
  234. procedure TSQLDBTestCase.SetUp;
  235. begin
  236. inherited SetUp;
  237. InitialiseDBConnector;
  238. DBConnector.StartTest(TestName);
  239. end;
  240. procedure TSQLDBTestCase.TearDown;
  241. begin
  242. DBConnector.StopTest(TestName);
  243. if assigned(DBConnector) then
  244. with TSQLDBConnector(DBConnector) do
  245. Transaction.Rollback;
  246. FreeDBConnector;
  247. inherited TearDown;
  248. end;
  249. initialization
  250. if uppercase(dbconnectorname)='SQL' then
  251. begin
  252. RegisterTest(TTestTSQLQuery);
  253. RegisterTest(TTestTSQLConnection);
  254. RegisterTest(TTestTSQLScript);
  255. end;
  256. end.