1 #if !defined(ODBCXX_QT)
2
3 #include <odbc++/drivermanager.h>
4 #include <odbc++/connection.h>
5 #include <odbc++/resultset.h>
6 #include <odbc++/resultsetmetadata.h>
7 #include <odbc++/callablestatement.h>
8 #include <odbc++/databasemetadata.h>
9
10 #include <sstream>
11 #include <iostream>
12 #include <memory>
13
14 using namespace std;
15 using namespace odbc;
16
17 // note: this must be even
18 const int TABLE_ROWS=500;
19
20 #define PREFIX ODBCXX_STRING_CONST("odbcxx_")
21
22 const ODBCXX_STRING tableName(PREFIX ODBCXX_STRING_CONST("test"));
23 const ODBCXX_STRING procName(PREFIX ODBCXX_STRING_CONST("ptest"));
24 const ODBCXX_STRING funcName(PREFIX ODBCXX_STRING_CONST("ftest"));
25
26 int assertionsFailed=0;
27
28 #define ASSERT(x) \
29 do { \
30 if(!(x)) { \
31 ODBCXX_CERR << ODBCXX_STRING_CONST("Assertion \"") << #x \
32 << ODBCXX_STRING_CONST("\" failed") << endl; \
33 assertionsFailed++; \
34 } \
35 } while(false)
36
dumpWarnings(Statement * stmt)37 static void dumpWarnings(Statement* stmt)
38 {
39 std::auto_ptr<WarningList> warnings
40 =std::auto_ptr<WarningList>(stmt->getWarnings());
41 for(WarningList::iterator i=warnings->begin();
42 i!=warnings->end(); i++) {
43 ODBCXX_COUT << ODBCXX_STRING_CONST("Warning: ")
44 << (*i)->getMessage() << endl;
45 }
46 }
47
dropStuff(Connection * con)48 static void dropStuff(Connection* con)
49 {
50 std::auto_ptr<Statement> stmt=std::auto_ptr<Statement>(con->createStatement());
51 try {
52 stmt->executeUpdate(ODBCXX_STRING_CONST("drop table ")+tableName);
53 ODBCXX_COUT << ODBCXX_STRING_CONST("Dropped table ") << tableName << endl;
54 dumpWarnings(stmt.get());
55 } catch(SQLException& e) {}
56
57 try {
58 stmt->executeUpdate(ODBCXX_STRING_CONST("drop procedure ")+procName);
59 ODBCXX_COUT << ODBCXX_STRING_CONST("Dropped procedure ") << procName << endl;
60 dumpWarnings(stmt.get());
61 } catch(SQLException& e) {}
62
63 try {
64 stmt->executeUpdate(ODBCXX_STRING_CONST("drop function ")+funcName);
65 ODBCXX_COUT << ODBCXX_STRING_CONST("Dropped function ") << funcName << endl;
66 dumpWarnings(stmt.get());
67 } catch(SQLException& e) {}
68 }
69
createStuff(Connection * con)70 static void createStuff(Connection* con)
71 {
72 std::auto_ptr<Statement> stmt=std::auto_ptr<Statement>(con->createStatement());
73
74 // create the table
75 stmt->executeUpdate(ODBCXX_STRING_CONST("create table ")+tableName+
76 ODBCXX_STRING_CONST(" (id number(4) not null primary key, ")
77 ODBCXX_STRING_CONST("name varchar2(22) not null, ")
78 ODBCXX_STRING_CONST("ts date)"));
79
80 dumpWarnings(stmt.get());
81 ODBCXX_COUT << ODBCXX_STRING_CONST("Created table ") << tableName << endl;
82
83 // create the procedure
84 stmt->executeUpdate
85 (ODBCXX_STRING_CONST("create procedure ")+procName+
86 ODBCXX_STRING_CONST(" (a in integer, b out integer, s in out varchar2) as ")
87 ODBCXX_STRING_CONST("begin ")
88 ODBCXX_STRING_CONST(" b:=a*2; ")
89 ODBCXX_STRING_CONST(" s:= s || ': ' || a || '*2=' || b; ")
90 ODBCXX_STRING_CONST("end;"));
91
92 dumpWarnings(stmt.get());
93 ODBCXX_COUT << ODBCXX_STRING_CONST("Created procedure ") << procName << endl;
94
95 // create the function
96 stmt->executeUpdate
97 (ODBCXX_STRING_CONST("create function ")+funcName+
98 ODBCXX_STRING_CONST(" (a in number, s in out varchar2) ")
99 ODBCXX_STRING_CONST("return number as ")
100 ODBCXX_STRING_CONST("b number; ")
101 ODBCXX_STRING_CONST("begin ")
102 ODBCXX_STRING_CONST(" b:=a*2; ")
103 ODBCXX_STRING_CONST(" s:= s || ': ' || a || '*2=' || b; ")
104 ODBCXX_STRING_CONST(" return b; ")
105 ODBCXX_STRING_CONST("end;"));
106
107 dumpWarnings(stmt.get());
108 ODBCXX_COUT << ODBCXX_STRING_CONST("Created function ") << funcName << endl;
109 }
110
testProc(Connection * con)111 static void testProc(Connection* con)
112 {
113 std::auto_ptr<CallableStatement> stmt=std::auto_ptr<CallableStatement>(con->prepareCall
114 (ODBCXX_STRING_CONST("{call ")+procName+ODBCXX_STRING_CONST("(?,?,?)}")));
115 stmt->setInt(1,22);
116 stmt->registerOutParameter(2,Types::INTEGER);
117 stmt->setString(3, ODBCXX_STRING_CONST("Okay"));
118 stmt->executeUpdate();
119
120 ASSERT(stmt->getInt(2)==44);
121 ASSERT(stmt->getString(3)==ODBCXX_STRING_CONST("Okay: 22*2=44"));
122 }
123
testFunc(Connection * con)124 static void testFunc(Connection* con)
125 {
126 std::auto_ptr<CallableStatement> stmt=std::auto_ptr<CallableStatement>(con->prepareCall
127 (ODBCXX_STRING_CONST("{?=call ")+procName+ODBCXX_STRING_CONST("(?,?)}")));
128
129 stmt->registerOutParameter(1,Types::INTEGER);
130 stmt->setInt(2,22);
131 stmt->setString(3,ODBCXX_STRING_CONST("Okay"));
132 stmt->executeUpdate();
133
134 ASSERT(stmt->getInt(1)==44);
135 ASSERT(stmt->getString(3)==ODBCXX_STRING_CONST("Okay: 22*2=44"));
136 }
137
138
testTable(Connection * con)139 static void testTable(Connection* con)
140 {
141 int i=0;
142 int driverVersion=con->getMetaData()->getDriverMajorVersion();
143
144 if(driverVersion<3) {
145 // insert the first row using a prepared statement
146 // ODBC 2 drivers can't do inserts before a fetch is done.
147 // some can't do inserts if the result set is not on a
148 // real row.
149 std::auto_ptr<PreparedStatement> pstmt
150 =std::auto_ptr<PreparedStatement>(con->prepareStatement
151 (ODBCXX_STRING_CONST("insert into ")+tableName+
152 ODBCXX_STRING_CONST(" (id,name,ts) values(?,?,?)")));
153 pstmt->setInt(1,i);
154 pstmt->setString(2,ODBCXX_STRING_CONST("This is row number 0"));
155 {
156 Timestamp ts;
157 pstmt->setTimestamp(3,ts);
158 }
159 pstmt->executeUpdate();
160 ODBCXX_COUT << ODBCXX_STRING_CONST("Inserted row 0") << endl;
161 i++;
162 }
163
164 // populate our table using a ResultSet
165 std::auto_ptr<Statement> stmt=std::auto_ptr<Statement>(con->createStatement
166 (ResultSet::TYPE_SCROLL_SENSITIVE, ResultSet::CONCUR_UPDATABLE));
167
168 // set fetch size to something useful
169 stmt->setFetchSize(10);
170
171 std::auto_ptr<ResultSet> rs=std::auto_ptr<ResultSet>
172 (stmt->executeQuery(ODBCXX_STRING_CONST("select id,name,ts from ")+tableName));
173
174 if(driverVersion<3) {
175 // position ourselves on a real row
176 ASSERT(rs->next());
177 }
178
179 rs->moveToInsertRow();
180
181 while(i<TABLE_ROWS) {
182 basic_ostringstream<ODBCXX_CHAR_TYPE> ns;
183 ns << ODBCXX_STRING_CONST("This is row number ") << i;
184 ODBCXX_STRING name(ns.str());
185 rs->updateInt(1,i);
186 rs->updateString(2,name);
187 rs->updateTimestamp(3,Timestamp());
188 rs->insertRow();
189 ODBCXX_COUT << ODBCXX_STRING_CONST("Inserted row ") << i << endl;
190 i++;
191 }
192 rs->moveToCurrentRow();
193
194 con->commit();
195
196 rs=std::auto_ptr<ResultSet>(stmt->executeQuery
197 (ODBCXX_STRING_CONST("select id,name from ")+tableName));
198
199 i=0;
200 while(rs->next()) {
201 ODBCXX_COUT << ODBCXX_STRING_CONST("Checking row ") << i << endl;
202 basic_ostringstream<ODBCXX_CHAR_TYPE> ns;
203 ns << ODBCXX_STRING_CONST("This is row number ") << i;
204 ODBCXX_STRING name(ns.str());
205 ASSERT(rs->getString(ODBCXX_STRING_CONST("name"))==name);
206
207 ASSERT(rs->getInt(ODBCXX_STRING_CONST("id"))==i);
208 i++;
209 }
210
211 ODBCXX_COUT << ODBCXX_STRING_CONST("Check done") << endl;
212
213 rs=std::auto_ptr<ResultSet>(stmt->executeQuery
214 (ODBCXX_STRING_CONST("select id,name,ts from ")+tableName));
215 i=0;
216 while(rs->next()) {
217 if((i%2)==1) {
218 basic_ostringstream<ODBCXX_CHAR_TYPE> ns;
219 ns << ODBCXX_STRING_CONST("This IS row number ") << i;
220 ODBCXX_STRING name(ns.str());
221
222 rs->updateString(ODBCXX_STRING_CONST("name"),name);
223 Timestamp ts;
224 rs->updateTimestamp(ODBCXX_STRING_CONST("ts"),ts);
225 rs->updateRow();
226 ODBCXX_COUT << ODBCXX_STRING_CONST("Updated row ") << i << endl;
227 } else {
228 rs->deleteRow();
229 ODBCXX_COUT << ODBCXX_STRING_CONST("Deleted row ") << i << endl;
230 }
231 i++;
232 }
233
234 rs=std::auto_ptr<ResultSet>(stmt->executeQuery
235 (ODBCXX_STRING_CONST("select id,name,ts from ")+tableName));
236 i=1;
237 while(rs->next()) {
238 basic_ostringstream<ODBCXX_CHAR_TYPE> ns;
239 ns << ODBCXX_STRING_CONST("This IS row number ") << i;
240 ODBCXX_STRING name(ns.str());
241
242 ASSERT(rs->getString(ODBCXX_STRING_CONST("name"))==name);
243 ASSERT(rs->getInt(1)==i);
244
245 i+=2;
246 }
247
248 ASSERT(i==TABLE_ROWS+1);
249
250 con->commit();
251 }
252
253
main(int argc,char ** argv)254 int main(int argc, char** argv)
255 {
256 if(argc!=2 && argc!=4) {
257 cerr << "Usage: " << argv[0] << " connect-string" << endl
258 << "or " << argv[0] << " dsn username password" << endl;
259 return 0;
260 }
261 try {
262 std::vector<ODBCXX_STRING> vargv(argc-1);
263 const size_t MAX_CHARS = 256;
264 for(int i=1;i<argc;++i)
265 {
266 ODBCXX_STRING& arg=vargv[i-1];
267 #if defined(ODBCXX_UNICODE)
268 wchar_t buffer[MAX_CHARS];
269 size_t len=mbstowcs(buffer,argv[i],MAX_CHARS);
270 if(0<len&&MAX_CHARS>len)
271 {
272 arg=buffer;
273 }
274 #else
275 arg=argv[i];
276 #endif
277 }
278 std::auto_ptr<Connection> con;
279 if(argc==2) {
280 ODBCXX_COUT << ODBCXX_STRING_CONST("Connecting to ") << vargv[0]
281 << ODBCXX_STRING_CONST("...") << flush;
282 con=std::auto_ptr<Connection>(DriverManager::getConnection(vargv[0]));
283 } else {
284 ODBCXX_COUT << ODBCXX_STRING_CONST("Connecting to dsn=") << vargv[0]
285 << ODBCXX_STRING_CONST(", uid=") << vargv[1]
286 << ODBCXX_STRING_CONST(", pwd=") << vargv[2]
287 << ODBCXX_STRING_CONST("...") << flush;
288 con=std::auto_ptr<Connection>(DriverManager::getConnection(vargv[0],vargv[1],vargv[2]));
289 }
290 ODBCXX_COUT << ODBCXX_STRING_CONST(" done.") << endl;
291
292 int numTests=3;
293 int failedTests=0;
294
295 con->setAutoCommit(false);
296 dropStuff(con.get());
297 createStuff(con.get());
298 try {
299 testProc(con.get());
300 } catch(SQLException& e) {
301 ODBCXX_COUT << ODBCXX_STRING_CONST("Procedure test FAILED: ")
302 << e.getMessage() << endl;
303 failedTests++;
304 }
305
306 try {
307 testFunc(con.get());
308 } catch(SQLException& e) {
309 ODBCXX_COUT << ODBCXX_STRING_CONST("Function test FAILED: ")
310 << e.getMessage() << endl;
311 failedTests++;
312 }
313
314 try {
315 testTable(con.get());
316 } catch(SQLException& e) {
317 ODBCXX_COUT << ODBCXX_STRING_CONST("Table test FAILED: ")
318 << e.getMessage() << endl;
319 failedTests++;
320 }
321
322 dropStuff(con.get());
323
324 if(failedTests>0) {
325 ODBCXX_COUT << failedTests << ODBCXX_STRING_CONST(" of ") << numTests
326 << ODBCXX_STRING_CONST(" tests failed.") << endl;
327 }
328 } catch(exception& e) {
329 cout << "Whoops: " << e.what() << endl;
330 return 1;
331 }
332
333 if(assertionsFailed>0) {
334 ODBCXX_COUT << assertionsFailed << ODBCXX_STRING_CONST(" assertions failed.") << endl;
335 return 2;
336 }
337 return 0;
338 }
339
340 #else
main()341 int main() { return 0; }
342 #endif
343