1 : /*
2 : * Code to test ODBC implementation.
3 : * - David Fraser, Abelon Systems 2003.
4 : */
5 :
6 : /*
7 : * TODO
8 : * remove Northwind dependency
9 : */
10 :
11 : #include "common.h"
12 :
13 : static char software_version[] = "$Id: testodbc.c,v 1.9 2005/06/29 07:21:24 freddy77 Exp $";
14 : static void *no_unused_var_warn[] = { software_version, no_unused_var_warn };
15 :
16 : #ifdef DEBUG
17 : # define AB_FUNCT(x) do { printf x; printf("\n"); } while(0)
18 : # define AB_PRINT(x) do { printf x; printf("\n"); } while(0)
19 : #else
20 : # define AB_FUNCT(x)
21 : # define AB_PRINT(x)
22 : #endif
23 : #define AB_ERROR(x) do { printf("ERROR: "); printf x; printf("\n"); } while(0)
24 :
25 : #undef TRUE
26 : #undef FALSE
27 : enum
28 : { FALSE, TRUE };
29 : typedef int DbTestFn(void);
30 :
31 : static int RunTests(void);
32 :
33 : typedef struct
34 : {
35 : DbTestFn *testFn;
36 : const char *description;
37 : } DbTestEntry;
38 :
39 : /*
40 : * Output ODBC errors.
41 : */
42 : static void
43 : DispODBCErrs(SQLHENV envHandle, SQLHDBC connHandle, SQLHSTMT statementHandle)
44 0 : {
45 : SQLCHAR buffer[256];
46 : SQLCHAR sqlState[16];
47 :
48 : /* Statement errors */
49 0 : if (statementHandle) {
50 0 : while (SQLError(envHandle, connHandle, statementHandle, sqlState, 0, buffer, sizeof(buffer), 0) == SQL_SUCCESS) {
51 0 : AB_ERROR(("%s, SQLSTATE=%s", buffer, sqlState));
52 : }
53 : }
54 :
55 : /* Connection errors */
56 0 : while (SQLError(envHandle, connHandle, SQL_NULL_HSTMT, sqlState, 0, buffer, sizeof(buffer), 0) == SQL_SUCCESS) {
57 0 : AB_ERROR(("%s, SQLSTATE=%s", buffer, sqlState));
58 : }
59 :
60 : /* Environmental errors */
61 0 : while (SQLError(envHandle, SQL_NULL_HDBC, SQL_NULL_HSTMT, sqlState, 0, buffer, sizeof(buffer), 0) == SQL_SUCCESS) {
62 0 : AB_ERROR(("%s, SQLSTATE=%s", buffer, sqlState));
63 : }
64 0 : }
65 :
66 : /*
67 : * Output ODBC diagnostics. Only used for 'raw' ODBC tests.
68 : */
69 : static void
70 : DispODBCDiags(SQLHSTMT statementHandle)
71 0 : {
72 : SQLSMALLINT recNumber;
73 : SQLCHAR sqlState[10];
74 0 : SQLINTEGER nativeError = -99;
75 : SQLCHAR messageText[500];
76 0 : SQLSMALLINT bufferLength = 500;
77 0 : SQLSMALLINT textLength = -99;
78 : SQLRETURN status;
79 :
80 0 : recNumber = 1;
81 :
82 0 : AB_FUNCT(("DispODBCDiags (in)"));
83 :
84 : do {
85 0 : status = SQLGetDiagRec(SQL_HANDLE_STMT, statementHandle, recNumber,
86 : sqlState, &nativeError, messageText, bufferLength, &textLength);
87 0 : if (status != SQL_SUCCESS) {
88 : /* No data mean normal end of iteration. Anything else is error. */
89 0 : if (status != SQL_NO_DATA) {
90 0 : AB_ERROR(("SQLGetDiagRec status is %d", status));
91 : }
92 0 : break;
93 : }
94 0 : printf("DIAG #%d, sqlState=%s, nativeError=%d, message=%s\n", recNumber, sqlState, (int) nativeError, messageText);
95 0 : recNumber++;
96 0 : } while (status == SQL_SUCCESS);
97 :
98 0 : AB_FUNCT(("DispODBCDiags (out)"));
99 0 : }
100 :
101 : /*
102 : * Test that makes a parameterized ODBC query using SQLPrepare and SQLExecute
103 : */
104 : static int
105 : TestRawODBCPreparedQuery(void)
106 2 : {
107 : SQLRETURN status;
108 : SQLCHAR queryString[200];
109 2 : SQLLEN lenOrInd = 0;
110 2 : SQLSMALLINT supplierId = 4;
111 : int count;
112 :
113 2 : AB_FUNCT(("TestRawODBCPreparedQuery (in)"));
114 :
115 : /* INIT */
116 :
117 2 : Connect();
118 :
119 : /* MAKE QUERY */
120 :
121 2 : Command(Statement, "CREATE TABLE #Products ("
122 : "ProductID int NOT NULL ,"
123 : "ProductName varchar (40) ,"
124 : "SupplierID int NULL ,"
125 : "CategoryID int NULL ,"
126 : "QuantityPerUnit varchar (20) ,"
127 : "UnitPrice money NULL ,"
128 : "UnitsInStock smallint NULL ,"
129 : "UnitsOnOrder smallint NULL ,"
130 : "ReorderLevel smallint NULL ,"
131 : "Discontinued bit NOT NULL "
132 : ") "
133 : "INSERT INTO #Products(ProductID,ProductName,SupplierID,CategoryID,QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder,ReorderLevel,Discontinued) VALUES(9,'Mishi Kobe Niku',4,6,'18 - 500 g pkgs.',97.00,29,0,0,1) "
134 : "INSERT INTO #Products(ProductID,ProductName,SupplierID,CategoryID,QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder,ReorderLevel,Discontinued) VALUES(10,'Ikura',4,8,'12 - 200 ml jars',31.00,31,0,0,0) "
135 : "INSERT INTO #Products(ProductID,ProductName,SupplierID,CategoryID,QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder,ReorderLevel,Discontinued) VALUES(74,'Longlife Tofu',4,7,'5 kg pkg.',10.00,4,20,5,0) "
136 : "INSERT INTO #Products(ProductID,ProductName,SupplierID,CategoryID,QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder,ReorderLevel,Discontinued) VALUES(11,'Queso Cabrales',5,4,'1 kg pkg.',21.00,22,30,30,0) "
137 : "INSERT INTO #Products(ProductID,ProductName,SupplierID,CategoryID,QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder,ReorderLevel,Discontinued) VALUES(12,'Queso Manchego La Pastora',5,4,'10 - 500 g pkgs.',38.00,86,0,0,0)");
138 10 : while (SQLMoreResults(Statement) == SQL_SUCCESS);
139 :
140 2 : strcpy((char *) (queryString), "SELECT * FROM #Products WHERE SupplierID = ?");
141 :
142 2 : status = SQLBindParameter(Statement, 1, SQL_PARAM_INPUT, SQL_C_SSHORT, SQL_INTEGER, 0, 0, &supplierId, 0, &lenOrInd);
143 2 : if (status != SQL_SUCCESS) {
144 0 : AB_ERROR(("SQLBindParameter failed"));
145 0 : DispODBCErrs(Environment, Connection, Statement);
146 0 : DispODBCDiags(Statement);
147 0 : AB_FUNCT(("TestRawODBCPreparedQuery (out): error"));
148 0 : return FALSE;
149 : }
150 :
151 2 : status = SQLPrepare(Statement, queryString, SQL_NTS);
152 2 : if (status != SQL_SUCCESS) {
153 0 : AB_ERROR(("Prepare failed"));
154 0 : AB_FUNCT(("TestRawODBCPreparedQuery (out): error"));
155 0 : return FALSE;
156 : }
157 :
158 2 : status = SQLExecute(Statement);
159 2 : if (status != SQL_SUCCESS) {
160 0 : AB_ERROR(("Execute failed"));
161 0 : DispODBCErrs(Environment, Connection, Statement);
162 0 : DispODBCDiags(Statement);
163 0 : AB_FUNCT(("TestRawODBCPreparedQuery (out): error"));
164 0 : return FALSE;
165 : }
166 :
167 2 : count = 0;
168 :
169 10 : while (SQLFetch(Statement) == SQL_SUCCESS) {
170 6 : count++;
171 : }
172 2 : AB_PRINT(("Got %d rows", count));
173 :
174 2 : if (count != 3) {
175 : /*
176 : * OK - so 3 is a magic number - it's the number of rows matching
177 : * this query from the MS sample Northwind database and is a constant.
178 : */
179 0 : AB_ERROR(("Expected %d rows - but got %d rows", 3, count));
180 0 : AB_FUNCT(("TestRawODBCPreparedQuery (out): error"));
181 0 : return FALSE;
182 : }
183 :
184 : /* CLOSEDOWN */
185 :
186 2 : Disconnect();
187 :
188 2 : AB_FUNCT(("TestRawODBCPreparedQuery (out): ok"));
189 2 : return TRUE;
190 : }
191 :
192 : /*
193 : * Test that makes a parameterized ODBC query using SQLExecDirect.
194 : */
195 : static int
196 : TestRawODBCDirectQuery(void)
197 2 : {
198 : SQLRETURN status;
199 : SQLCHAR queryString[200];
200 2 : SQLLEN lenOrInd = 0;
201 2 : SQLSMALLINT supplierId = 1;
202 : int count;
203 :
204 2 : AB_FUNCT(("TestRawODBCDirectQuery (in)"));
205 :
206 : /* INIT */
207 :
208 2 : Connect();
209 :
210 : /* MAKE QUERY */
211 :
212 2 : Command(Statement, "CREATE TABLE #Products ("
213 : "ProductID int NOT NULL ,"
214 : "ProductName varchar (40) ,"
215 : "SupplierID int NULL ,"
216 : "CategoryID int NULL ,"
217 : "QuantityPerUnit varchar (20) ,"
218 : "UnitPrice money NULL ,"
219 : "UnitsInStock smallint NULL ,"
220 : "UnitsOnOrder smallint NULL ,"
221 : "ReorderLevel smallint NULL ,"
222 : "Discontinued bit NOT NULL "
223 : ") "
224 : "INSERT INTO #Products(ProductID,ProductName,SupplierID,CategoryID,QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder,ReorderLevel,Discontinued) VALUES(1,'Chai',1,1,'10 boxes x 20 bags',18.00,39,0,10,0) "
225 : "INSERT INTO #Products(ProductID,ProductName,SupplierID,CategoryID,QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder,ReorderLevel,Discontinued) VALUES(2,'Chang',1,1,'24 - 12 oz bottles',19.00,17,40,25,0) "
226 : "INSERT INTO #Products(ProductID,ProductName,SupplierID,CategoryID,QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder,ReorderLevel,Discontinued) VALUES(3,'Aniseed Syrup',1,2,'12 - 550 ml bottles',10.00,13,70,25,0) "
227 : "INSERT INTO #Products(ProductID,ProductName,SupplierID,CategoryID,QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder,ReorderLevel,Discontinued) VALUES(4,'Chef Anton''s Cajun Seasoning',2,2,'48 - 6 oz jars',22.00,53,0,0,0) "
228 : "INSERT INTO #Products(ProductID,ProductName,SupplierID,CategoryID,QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder,ReorderLevel,Discontinued) VALUES(5,'Chef Anton''s Gumbo Mix',2,2,'36 boxes',21.35,0,0,0,1) ");
229 10 : while (SQLMoreResults(Statement) == SQL_SUCCESS);
230 :
231 2 : strcpy((char *) (queryString), "SELECT * FROM #Products WHERE SupplierID = ?");
232 :
233 2 : status = SQLBindParameter(Statement, 1, SQL_PARAM_INPUT, SQL_C_SSHORT, SQL_INTEGER, 0, 0, &supplierId, 0, &lenOrInd);
234 2 : if (status != SQL_SUCCESS) {
235 0 : AB_ERROR(("SQLBindParameter failed"));
236 0 : DispODBCErrs(Environment, Connection, Statement);
237 0 : DispODBCDiags(Statement);
238 0 : AB_FUNCT(("TestRawODBCDirectQuery (out): error"));
239 0 : return FALSE;
240 : }
241 :
242 2 : status = SQLExecDirect(Statement, queryString, SQL_NTS);
243 2 : if (status != SQL_SUCCESS) {
244 0 : AB_ERROR(("Execute failed"));
245 0 : DispODBCErrs(Environment, Connection, Statement);
246 0 : DispODBCDiags(Statement);
247 0 : AB_FUNCT(("TestRawODBCDirectQuery (out): error"));
248 0 : return FALSE;
249 : }
250 :
251 2 : count = 0;
252 :
253 10 : while (SQLFetch(Statement) == SQL_SUCCESS) {
254 6 : count++;
255 : }
256 2 : AB_PRINT(("Got %d rows", count));
257 :
258 2 : if (count != 3) {
259 : /*
260 : * OK - so 3 is a magic number - it's the number of rows matching
261 : * this query from the MS sample Northwind database and is a constant.
262 : */
263 0 : AB_ERROR(("Expected %d rows - but got %d rows", 3, count));
264 0 : AB_FUNCT(("TestRawODBCDirectQuery (out): error"));
265 0 : return FALSE;
266 : }
267 :
268 : /* CLOSEDOWN */
269 :
270 2 : Disconnect();
271 :
272 2 : AB_FUNCT(("TestRawODBCDirectQuery (out): ok"));
273 2 : return TRUE;
274 : }
275 :
276 : /*
277 : * Test that show what works and what doesn't for the poorly
278 : * documented GUID.
279 : */
280 : static int
281 : TestRawODBCGuid(void)
282 2 : {
283 : SQLRETURN status;
284 :
285 : SQLCHAR queryString[300];
286 : SQLLEN lenOrInd;
287 : SQLSMALLINT age;
288 : SQLCHAR guid[40];
289 : SQLCHAR name[20];
290 :
291 : SQLGUID sqlguid;
292 2 : int count = 0;
293 :
294 2 : AB_FUNCT(("TestRawODBCGuid (in)"));
295 :
296 2 : Connect();
297 :
298 2 : if (!db_is_microsoft()) {
299 1 : Disconnect();
300 1 : return TRUE;
301 : }
302 :
303 1 : AB_PRINT(("Creating #pet table"));
304 :
305 1 : strcpy((char *) (queryString), "CREATE TABLE #pet (name VARCHAR(20), owner VARCHAR(20), "
306 : "species VARCHAR(20), sex CHAR(1), age INTEGER, " "guid UNIQUEIDENTIFIER DEFAULT NEWID() ); ");
307 1 : status = SQLExecDirect(Statement, queryString, SQL_NTS);
308 1 : if (status != SQL_SUCCESS && status != SQL_NO_DATA) {
309 0 : AB_ERROR(("Create table failed"));
310 0 : goto odbcfail;
311 : }
312 :
313 1 : CommandWithResult(Statement, "DROP PROC GetGUIDRows");
314 :
315 1 : AB_PRINT(("Creating stored proc GetGUIDRows"));
316 :
317 1 : strcpy((char *) (queryString), "CREATE PROCEDURE GetGUIDRows (@guidpar uniqueidentifier) AS \
318 : SELECT name, guid FROM #pet WHERE guid = @guidpar");
319 1 : status = SQLExecDirect(Statement, queryString, SQL_NTS);
320 1 : if (status != SQL_SUCCESS && status != SQL_NO_DATA) {
321 0 : AB_ERROR(("Create procedure failed"));
322 0 : goto odbcfail;
323 : }
324 :
325 1 : AB_PRINT(("Insert row 1"));
326 :
327 1 : strcpy((char *) (queryString), "INSERT INTO #pet( name, owner, species, sex, age ) \
328 : VALUES ( 'Fang', 'Mike', 'dog', 'm', 12 );");
329 1 : status = SQLExecDirect(Statement, queryString, SQL_NTS);
330 1 : if (status != SQL_SUCCESS) {
331 0 : AB_ERROR(("Insert row 1 failed"));
332 0 : goto odbcfail;
333 : }
334 :
335 1 : AB_PRINT(("Insert row 2"));
336 :
337 : /*
338 : * Ok - new row with explicit GUID, but parameterised age.
339 : */
340 1 : strcpy((char *) (queryString), "INSERT INTO #pet( name, owner, species, sex, age, guid ) \
341 : VALUES ( 'Splash', 'Dan', 'fish', 'm', ?, \
342 : '12345678-1234-1234-1234-123456789012' );");
343 :
344 1 : lenOrInd = 0;
345 1 : age = 3;
346 1 : if (SQLBindParameter(Statement, 1, SQL_PARAM_INPUT, SQL_C_SSHORT, SQL_INTEGER, 0, 0, &age, 0, &lenOrInd)
347 : != SQL_SUCCESS) {
348 0 : AB_ERROR(("SQLBindParameter failed"));
349 0 : goto odbcfail;
350 : }
351 :
352 1 : status = SQLExecDirect(Statement, queryString, SQL_NTS);
353 1 : if (status != SQL_SUCCESS) {
354 0 : AB_ERROR(("Insert row 2 failed"));
355 0 : goto odbcfail;
356 : }
357 1 : if (SQLFreeStmt(Statement, SQL_CLOSE) != SQL_SUCCESS) {
358 0 : AB_ERROR(("Free statement failed (5)"));
359 0 : goto odbcfail;
360 : }
361 :
362 1 : AB_PRINT(("Insert row 3"));
363 : /*
364 : * Ok - new row with parameterised GUID.
365 : */
366 1 : strcpy((char *) (queryString), "INSERT INTO #pet( name, owner, species, sex, age, guid ) \
367 : VALUES ( 'Woof', 'Tom', 'cat', 'f', 2, ? );");
368 :
369 1 : lenOrInd = SQL_NTS;
370 1 : strcpy((char *) (guid), "87654321-4321-4321-4321-123456789abc");
371 :
372 1 : if (SQLBindParameter(Statement, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_GUID, 0, 0, guid, 0, &lenOrInd)
373 : != SQL_SUCCESS) {
374 0 : AB_ERROR(("SQLBindParameter failed"));
375 0 : goto odbcfail;
376 : }
377 1 : status = SQLExecDirect(Statement, queryString, SQL_NTS);
378 1 : if (status != SQL_SUCCESS) {
379 0 : AB_ERROR(("Insert row 3 failed"));
380 0 : goto odbcfail;
381 : }
382 :
383 1 : AB_PRINT(("Insert row 4"));
384 : /*
385 : * Ok - new row with parameterised GUID.
386 : */
387 1 : strcpy((char *) (queryString), "INSERT INTO #pet( name, owner, species, sex, age, guid ) \
388 : VALUES ( 'Spike', 'Diane', 'pig', 'f', 4, ? );");
389 :
390 1 : lenOrInd = SQL_NTS;
391 1 : strcpy((char *) (guid), "1234abcd-abcd-abcd-abcd-123456789abc");
392 :
393 1 : if (SQLBindParameter(Statement, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 36, 0, guid, 0, &lenOrInd)
394 : != SQL_SUCCESS) {
395 0 : AB_ERROR(("SQLBindParameter failed"));
396 0 : goto odbcfail;
397 : }
398 1 : status = SQLExecDirect(Statement, queryString, SQL_NTS);
399 1 : if (status != SQL_SUCCESS) {
400 0 : AB_ERROR(("Insert row 4 failed"));
401 0 : goto odbcfail;
402 : }
403 :
404 1 : AB_PRINT(("Insert row 5"));
405 : /*
406 : * Ok - new row with parameterised GUID.
407 : */
408 1 : strcpy((char *) (queryString), "INSERT INTO #pet( name, owner, species, sex, age, guid ) \
409 : VALUES ( 'Fluffy', 'Sam', 'dragon', 'm', 16, ? );");
410 :
411 1 : sqlguid.Data1 = 0xaabbccdd;
412 1 : sqlguid.Data2 = 0xeeff;
413 1 : sqlguid.Data3 = 0x1122;
414 1 : sqlguid.Data4[0] = 0x11;
415 1 : sqlguid.Data4[1] = 0x22;
416 1 : sqlguid.Data4[2] = 0x33;
417 1 : sqlguid.Data4[3] = 0x44;
418 1 : sqlguid.Data4[4] = 0x55;
419 1 : sqlguid.Data4[5] = 0x66;
420 1 : sqlguid.Data4[6] = 0x77;
421 1 : sqlguid.Data4[7] = 0x88;
422 :
423 1 : lenOrInd = 16;
424 1 : strcpy((char *) (guid), "1234abcd-abcd-abcd-abcd-123456789abc");
425 :
426 1 : if (SQLBindParameter(Statement, 1, SQL_PARAM_INPUT, SQL_C_GUID, SQL_GUID, 16, 0, &sqlguid, 16, &lenOrInd)
427 : != SQL_SUCCESS) {
428 0 : AB_ERROR(("SQLBindParameter failed"));
429 0 : goto odbcfail;
430 : }
431 1 : status = SQLExecDirect(Statement, queryString, SQL_NTS);
432 1 : if (status != SQL_SUCCESS) {
433 0 : AB_ERROR(("Insert row 5 failed"));
434 0 : AB_ERROR(("Sadly this was expected in *nix ODBC. Carry on."));
435 : }
436 :
437 : /*
438 : * Now retrieve rows - especially GUID column values.
439 : */
440 1 : AB_PRINT(("retrieving name and guid"));
441 1 : strcpy((char *) (queryString), "SELECT name, guid FROM #pet");
442 1 : status = SQLExecDirect(Statement, queryString, SQL_NTS);
443 1 : if (status != SQL_SUCCESS) {
444 0 : AB_ERROR(("SELECT failed"));
445 0 : goto odbcfail;
446 : }
447 7 : while (SQLFetch(Statement) == SQL_SUCCESS) {
448 5 : count++;
449 5 : if (SQLGetData(Statement, 1, SQL_CHAR, name, 20, 0)
450 : != SQL_SUCCESS) {
451 0 : AB_ERROR(("Get row %d, name column failed", count));
452 0 : goto odbcfail;
453 : }
454 5 : if (SQLGetData(Statement, 2, SQL_CHAR, guid, 37, 0)
455 : != SQL_SUCCESS) {
456 0 : AB_ERROR(("Get row %d, guid column failed", count));
457 0 : goto odbcfail;
458 : }
459 :
460 5 : AB_PRINT(("name: %-10s guid: %s", name, guid));
461 : }
462 :
463 : /*
464 : * Realloc cursor handle - (Windows ODBC considers it an invalid cursor
465 : * state if we try SELECT again).
466 : */
467 1 : if (SQLFreeStmt(Statement, SQL_CLOSE) != SQL_SUCCESS) {
468 0 : AB_ERROR(("Free statement failed (5)"));
469 0 : goto odbcfail;
470 : }
471 1 : if (SQLAllocHandle(SQL_HANDLE_STMT, Connection, &Statement)
472 : != SQL_SUCCESS) {
473 0 : AB_ERROR(("SQLAllocStmt failed(1)"));
474 0 : goto odbcfail;
475 : }
476 :
477 :
478 : /*
479 : * Now retrieve rows - especially GUID column values.
480 : */
481 :
482 1 : AB_PRINT(("retrieving name and guid again"));
483 1 : strcpy((char *) (queryString), "SELECT name, guid FROM #pet");
484 1 : status = SQLExecDirect(Statement, queryString, SQL_NTS);
485 1 : if (status != SQL_SUCCESS) {
486 0 : AB_ERROR(("SELECT failed"));
487 0 : goto odbcfail;
488 : }
489 7 : while (SQLFetch(Statement) == SQL_SUCCESS) {
490 5 : count++;
491 5 : if (SQLGetData(Statement, 1, SQL_CHAR, name, 20, 0)
492 : != SQL_SUCCESS) {
493 0 : AB_ERROR(("Get row %d, name column failed", count));
494 0 : goto odbcfail;
495 : }
496 5 : if (SQLGetData(Statement, 2, SQL_GUID, &sqlguid, 16, 0)
497 : != SQL_SUCCESS) {
498 0 : AB_ERROR(("Get row %d, guid column failed", count));
499 0 : goto odbcfail;
500 : }
501 :
502 5 : AB_PRINT(("%-10s %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
503 : name,
504 : (int) (sqlguid.Data1), sqlguid.Data2,
505 : sqlguid.Data3, sqlguid.Data4[0], sqlguid.Data4[1],
506 : sqlguid.Data4[2], sqlguid.Data4[3], sqlguid.Data4[4],
507 : sqlguid.Data4[5], sqlguid.Data4[6], sqlguid.Data4[7]));
508 : }
509 :
510 : /*
511 : * Realloc cursor handle - (Windows ODBC considers it an invalid cursor
512 : * state if we try SELECT again).
513 : */
514 1 : if (SQLFreeStmt(Statement, SQL_CLOSE) != SQL_SUCCESS) {
515 0 : AB_ERROR(("Free statement failed (5)"));
516 0 : goto odbcfail;
517 : }
518 1 : if (SQLAllocHandle(SQL_HANDLE_STMT, Connection, &Statement)
519 : != SQL_SUCCESS) {
520 0 : AB_ERROR(("SQLAllocStmt failed(1)"));
521 0 : goto odbcfail;
522 : }
523 :
524 : /*
525 : * Now retrieve rows via stored procedure passing GUID as param.
526 : */
527 1 : AB_PRINT(("retrieving name and guid"));
528 :
529 1 : strcpy((char *) (queryString), "{call GetGUIDRows(?)}");
530 1 : lenOrInd = SQL_NTS;
531 1 : strcpy((char *) (guid), "87654321-4321-4321-4321-123456789abc");
532 :
533 1 : if (SQLBindParameter(Statement, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_GUID, 0, 0, guid, 0, &lenOrInd)
534 : != SQL_SUCCESS) {
535 0 : AB_ERROR(("SQLBindParameter failed"));
536 0 : goto odbcfail;
537 : }
538 1 : status = SQLExecDirect(Statement, queryString, SQL_NTS);
539 1 : if (status != SQL_SUCCESS) {
540 0 : AB_ERROR(("SELECT failed"));
541 0 : goto odbcfail;
542 : }
543 3 : while (SQLFetch(Statement) == SQL_SUCCESS) {
544 1 : count++;
545 1 : if (SQLGetData(Statement, 1, SQL_CHAR, name, 20, 0)
546 : != SQL_SUCCESS) {
547 0 : AB_ERROR(("Get row %d, name column failed", count));
548 0 : goto odbcfail;
549 : }
550 1 : if (SQLGetData(Statement, 2, SQL_CHAR, guid, 37, 0)
551 : != SQL_SUCCESS) {
552 0 : AB_ERROR(("Get row %d, guid column failed", count));
553 0 : goto odbcfail;
554 : }
555 :
556 1 : AB_PRINT(("%-10s %s", name, guid));
557 : }
558 :
559 : /*
560 : * Realloc cursor handle - (Windows ODBC considers it an invalid cursor
561 : * state after a previous SELECT has occurred).
562 : */
563 1 : if (SQLFreeStmt(Statement, SQL_CLOSE) != SQL_SUCCESS) {
564 0 : AB_ERROR(("Free statement failed (5)"));
565 0 : goto odbcfail;
566 : }
567 1 : if (SQLAllocHandle(SQL_HANDLE_STMT, Connection, &Statement)
568 : != SQL_SUCCESS) {
569 0 : AB_ERROR(("SQLAllocStmt failed(1)"));
570 0 : goto odbcfail;
571 : }
572 :
573 : /* cleanup */
574 1 : CommandWithResult(Statement, "DROP PROC GetGUIDRows");
575 :
576 : /* CLOSEDOWN */
577 :
578 1 : Disconnect();
579 :
580 1 : AB_FUNCT(("TestRawODBCGuid (out): ok"));
581 1 : return TRUE;
582 :
583 0 : odbcfail:
584 0 : DispODBCErrs(Environment, Connection, Statement);
585 0 : DispODBCDiags(Statement);
586 0 : AB_FUNCT(("TestRawODBCGuid (out): error"));
587 0 : return FALSE;
588 : }
589 :
590 : /**
591 : * Array of tests.
592 : */
593 : static DbTestEntry _dbTests[] = {
594 : /* 1 */ {TestRawODBCDirectQuery, "Raw ODBC direct query"},
595 : /* 2 */ {TestRawODBCPreparedQuery, "Raw ODBC prepared query"},
596 : /* 3 */ {TestRawODBCGuid, "Raw ODBC GUID"},
597 : /* end */ {0, 0}
598 : };
599 :
600 : static DbTestEntry *tests = _dbTests;
601 :
602 : /**
603 : * Code to iterate through all tests to run.
604 : *
605 : * \return
606 : * TRUE if all tests pass, FALSE if any tests fail.
607 : */
608 : static int
609 : RunTests(void)
610 2 : {
611 : unsigned int i;
612 2 : unsigned int passes = 0;
613 2 : unsigned int fails = 0;
614 :
615 2 : i = 0;
616 10 : while (tests[i].testFn) {
617 6 : printf("Running test %2d: %s... ", i + 1, tests[i].description);
618 6 : fflush(stdout);
619 6 : if (tests[i].testFn()) {
620 6 : printf("pass\n");
621 6 : passes++;
622 : } else {
623 0 : printf("fail\n");
624 0 : fails++;
625 : }
626 6 : i++;
627 : }
628 :
629 2 : if (fails == 0) {
630 2 : printf("\nAll %d tests passed.\n\n", passes);
631 : } else {
632 0 : printf("\nTest passes: %d, test fails: %d\n\n", passes, fails);
633 : }
634 :
635 : /* Return TRUE if there are no failures */
636 2 : return (!fails);
637 : }
638 :
639 : int
640 : main(int argc, char *argv[])
641 2 : {
642 2 : use_odbc_version3 = 1;
643 :
644 2 : if (RunTests()) {
645 2 : return 0; /* Success */
646 : } else {
647 0 : return 1; /* Error code */
648 : }
649 : }
|