advantage 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1735 @@
1
+ /*******************************************************************************
2
+ * Source File : DBCAPI.CPP
3
+ * Copyright : 2010 Sybase, an SAP company
4
+ * Description : This contains all entry points to implement the DBCAPI interface
5
+ * for many clients such as Python, PHP, Ruby, etc.
6
+ * Notes :
7
+ *
8
+ * The purpose of this module is to implement a thin layer between our ACE client
9
+ * and Sybase's DBCAPI clients. Bascially DBCAPI is a standard API shared between
10
+ * SQL Anywhere and Adaptive Server Enterprise for use with common thin clients.
11
+ * By implementing the same API in ACE we can consume those same thin clients
12
+ * and support many more development environments.
13
+ *******************************************************************************/
14
+
15
+ // This functionality is only used on the client side (in ACE)
16
+ #ifdef ACE
17
+
18
+ #include "adsinc.h"
19
+ #include <ctype.h>
20
+ #include "ace.h"
21
+ #include "acetypes.h"
22
+ #include "aceclass.h"
23
+ #include "adsutil.h"
24
+ #include "cconnect.h"
25
+
26
+ #define ACE_ADSVERSION // to get the ACE version string from adsver.h
27
+ #include "adsver.h"
28
+
29
+ #include "dbcapi.h"
30
+
31
+ #ifdef _DEBUG
32
+ #define DBCLogTrace(x)
33
+ //#define DBCLogTrace(x) printf( "%s\n", x )
34
+ #else
35
+ #define DBCLogTrace(x)
36
+ #endif
37
+
38
+ #define DBCAPI_SUCCESS 1 // General success
39
+ #define DBCAPI_FAILURE 0 // General failure
40
+ #define DBCAPI_NEGONE (UNSIGNED32) - 1 // Failure when returning a length
41
+
42
+ /*******************************************************************************
43
+ * Module : ConvertACEtoNativeType
44
+ * Created : 11-04-2010 Peter F
45
+ * Last Mod :
46
+ * Return Value : a_ads_native_type
47
+ * Desc : Convert an ACE type to a native DBCAPI type
48
+ * Notes :
49
+ *******************************************************************************/
50
+ a_ads_native_type ConvertACEtoNativeType(UNSIGNED16 usACEType)
51
+ {
52
+ switch (usACEType)
53
+ {
54
+ case ADS_LOGICAL:
55
+ return DT_BIT;
56
+ case ADS_NUMERIC:
57
+ return DT_DECIMAL;
58
+ case ADS_DATE:
59
+ return DT_DATE;
60
+ case ADS_STRING:
61
+ return DT_STRING;
62
+ case ADS_MEMO:
63
+ return DT_LONGVARCHAR;
64
+ case ADS_BINARY:
65
+ return DT_BINARY;
66
+ case ADS_IMAGE:
67
+ return DT_BINARY;
68
+ case ADS_VARCHAR:
69
+ return DT_VARCHAR;
70
+ case ADS_COMPACTDATE:
71
+ return DT_DATE;
72
+ case ADS_DOUBLE:
73
+ return DT_DOUBLE;
74
+ case ADS_INTEGER:
75
+ return DT_INT;
76
+ case ADS_SHORTINT:
77
+ return DT_SMALLINT;
78
+ case ADS_TIME:
79
+ return DT_TIME;
80
+ case ADS_TIMESTAMP:
81
+ return DT_TIMESTAMP;
82
+ case ADS_AUTOINC:
83
+ return DT_INT;
84
+ case ADS_RAW:
85
+ return DT_BINARY;
86
+ case ADS_CURDOUBLE:
87
+ return DT_DOUBLE;
88
+ case ADS_MONEY:
89
+ return DT_BIGINT;
90
+ case ADS_LONGLONG:
91
+ return DT_BIGINT;
92
+ case ADS_CISTRING:
93
+ return DT_STRING;
94
+ case ADS_ROWVERSION:
95
+ return DT_BIGINT;
96
+ case ADS_MODTIME:
97
+ return DT_TIMESTAMP;
98
+ case ADS_VARCHAR_FOX:
99
+ return DT_VARCHAR;
100
+ case ADS_VARBINARY_FOX:
101
+ return DT_BINARY;
102
+ case ADS_SYSTEM_FIELD:
103
+ return DT_NOTYPE;
104
+ case ADS_NCHAR:
105
+ return DT_NSTRING;
106
+ case ADS_NVARCHAR:
107
+ return DT_NSTRING;
108
+ case ADS_NMEMO:
109
+ return DT_LONGNVARCHAR;
110
+
111
+ default:
112
+ ASSERT(0);
113
+ return DT_NOTYPE;
114
+ }
115
+
116
+ } /* ConvertACEtoNativeType */
117
+
118
+ /*******************************************************************************
119
+ * Module : ConvertACEToIOType
120
+ * Created : 11-04-2010 Peter F
121
+ * Last Mod :
122
+ * Return Value : a_ads_data_type
123
+ * Desc : Convert an ACE type to a DBCAPI IO type
124
+ * Notes :
125
+ *******************************************************************************/
126
+ a_ads_data_type ConvertACEToIOType(UNSIGNED16 usACEType)
127
+ {
128
+ switch (usACEType)
129
+ {
130
+ case ADS_LOGICAL:
131
+ return A_UVAL8;
132
+ case ADS_NUMERIC:
133
+ return A_DECIMAL;
134
+ case ADS_DATE:
135
+ return A_DATE;
136
+ case ADS_STRING:
137
+ return A_STRING;
138
+ case ADS_MEMO:
139
+ return A_STRING;
140
+ case ADS_BINARY:
141
+ return A_BINARY;
142
+ case ADS_IMAGE:
143
+ return A_BINARY;
144
+ case ADS_VARCHAR:
145
+ return A_STRING;
146
+ case ADS_COMPACTDATE:
147
+ return A_DATE;
148
+ case ADS_DOUBLE:
149
+ return A_DOUBLE;
150
+ case ADS_INTEGER:
151
+ return A_VAL32;
152
+ case ADS_SHORTINT:
153
+ return A_VAL16;
154
+ case ADS_TIME:
155
+ return A_TIME;
156
+ case ADS_TIMESTAMP:
157
+ return A_TIMESTAMP;
158
+ case ADS_AUTOINC:
159
+ return A_UVAL32;
160
+ case ADS_RAW:
161
+ return A_BINARY;
162
+ case ADS_CURDOUBLE:
163
+ return A_DOUBLE;
164
+ case ADS_MONEY:
165
+ return A_VAL64;
166
+ case ADS_LONGLONG:
167
+ return A_VAL64;
168
+ case ADS_CISTRING:
169
+ return A_STRING;
170
+ case ADS_ROWVERSION:
171
+ return A_UVAL64;
172
+ case ADS_MODTIME:
173
+ return A_TIMESTAMP;
174
+ case ADS_VARCHAR_FOX:
175
+ return A_STRING;
176
+ case ADS_VARBINARY_FOX:
177
+ return A_BINARY;
178
+ case ADS_SYSTEM_FIELD:
179
+ return A_INVALID_TYPE;
180
+ case ADS_NCHAR:
181
+ return A_NCHAR;
182
+ case ADS_NVARCHAR:
183
+ return A_NCHAR;
184
+ case ADS_NMEMO:
185
+ return A_NCHAR;
186
+
187
+ default:
188
+ ASSERT(0);
189
+ return A_INVALID_TYPE;
190
+ }
191
+
192
+ } /* ConvertACEToIOType */
193
+
194
+ /*******************************************************************************
195
+ * Module : ads_affected_rows
196
+ * Created : 11-04-2010 Peter F
197
+ * Last Mod :
198
+ * Return Value : Number of rows affected
199
+ * Desc : Return the number of rows affected by a query
200
+ * Notes :
201
+ *******************************************************************************/
202
+ UNSIGNED32 ENTRYPOINT ads_affected_rows(ADSHANDLE hStatement)
203
+ {
204
+ UNSIGNED32 ulRows;
205
+ UNSIGNED32 ulRetCode;
206
+
207
+ DBCLogTrace("ads_affected_rows");
208
+
209
+ // Returns rows affected for statement handles
210
+ ulRetCode = AdsGetRecordCount(hStatement, ADS_IGNOREFILTERS, &ulRows);
211
+ if (ulRetCode == AE_SUCCESS)
212
+ return ulRows;
213
+ else
214
+ return DBCAPI_FAILURE;
215
+
216
+ } /* ads_affected_rows */
217
+
218
+ /*******************************************************************************
219
+ * Module : ads_bind_param
220
+ * Created : 11-04-2010 Peter F
221
+ * Last Mod :
222
+ * Return Value : SUCCESS or FAILURE
223
+ * Desc : Bind a user-supplied buffer as a parameter to the prepared statement.
224
+ * Notes :
225
+ *******************************************************************************/
226
+ UNSIGNED32 ENTRYPOINT ads_bind_param(ADSHANDLE hStatement, UNSIGNED32 ulIndex, a_ads_bind_param *param)
227
+ {
228
+ UNSIGNED32 ulRetCode;
229
+
230
+ DBCLogTrace("ads_bind_param");
231
+
232
+ if (param == NULL)
233
+ return DBCAPI_FAILURE;
234
+
235
+ if (param->value.buffer == NULL)
236
+ return DBCAPI_FAILURE;
237
+
238
+ if (param->value.length == NULL)
239
+ return DBCAPI_FAILURE;
240
+
241
+ // If the parameter value is NULL, set it to empty in ACE
242
+ if (param->value.is_null && *param->value.is_null)
243
+ {
244
+ if (AdsSetEmpty(hStatement, ADSFIELD(ulIndex + 1)) == AE_SUCCESS)
245
+ return DBCAPI_SUCCESS;
246
+ else
247
+ return DBCAPI_FAILURE;
248
+ }
249
+
250
+ switch (param->value.type)
251
+ {
252
+ case A_VAL32:
253
+ case A_UVAL32:
254
+ ulRetCode = AdsSetLong(hStatement, ADSFIELD(ulIndex + 1), *((SIGNED32 *)(param->value.buffer)));
255
+ break;
256
+
257
+ case A_STRING:
258
+ ulRetCode = AdsSetString(hStatement, ADSFIELD(ulIndex + 1), param->value.buffer, *(param->value.length));
259
+ break;
260
+
261
+ case A_BINARY:
262
+ ulRetCode = AdsSetBinary(hStatement, ADSFIELD(ulIndex + 1), ADS_BINARY, *(param->value.length),
263
+ 0, param->value.buffer, *(param->value.length));
264
+ break;
265
+
266
+ case A_DOUBLE:
267
+ ulRetCode = AdsSetDouble(hStatement, ADSFIELD(ulIndex + 1), *((double *)(param->value.buffer)));
268
+ break;
269
+
270
+ case A_VAL64:
271
+ case A_UVAL64:
272
+ ulRetCode = AdsSetLongLong(hStatement, ADSFIELD(ulIndex + 1), *((SIGNED64 *)(param->value.buffer)));
273
+ break;
274
+
275
+ case A_VAL16:
276
+ case A_UVAL16:
277
+ ulRetCode = AdsSetShort(hStatement, ADSFIELD(ulIndex + 1), *((SIGNED16 *)(param->value.buffer)));
278
+ break;
279
+
280
+ case A_VAL8:
281
+ case A_UVAL8:
282
+ ulRetCode = AdsSetLogical(hStatement, ADSFIELD(ulIndex + 1), *((SIGNED8 *)(param->value.buffer)));
283
+ break;
284
+
285
+ case A_NCHAR:
286
+ {
287
+ // Unicode buffer lengths are always in bytes, but AdsSetStringW needs it in chars (UTF-16)
288
+ UNSIGNED32 ulChars = (*(param->value.length) >> 1) - 2; // -2 for the BOM
289
+ ulRetCode = AdsSetStringW(hStatement, ADSFIELD(ulIndex + 1),
290
+ (WCHAR *)(param->value.buffer) + 1, // skip the BOM
291
+ ulChars);
292
+ }
293
+ break;
294
+
295
+ default:
296
+ ulRetCode = AdsSetLastError(AE_INVALID_DATA_TYPE, "Unsupported parameter data type.");
297
+ break;
298
+ }
299
+
300
+ if (ulRetCode == AE_SUCCESS)
301
+ return DBCAPI_SUCCESS;
302
+ else
303
+ return DBCAPI_FAILURE;
304
+
305
+ } /* ads_bind_param */
306
+
307
+ /*******************************************************************************
308
+ * Module : DBCAPICallback
309
+ * Created : 11-04-2010 Peter F
310
+ * Last Mod :
311
+ * Return Value : 1 to cancel the operation, 0 to keep it going
312
+ * Desc : Callback funtion to support query cancel
313
+ * Notes : This is a 64 bit FN and must be registered with AdsRegisterCallbackFunction101
314
+ *******************************************************************************/
315
+ UNSIGNED32 WINAPI DBCAPICallback(UNSIGNED16 usPercentDone, SIGNED64 qCallbackID)
316
+ {
317
+ UNSIGNED32 ulCancel = 0;
318
+
319
+ #ifdef x64
320
+ if (AdsSetProperty90((ADSHANDLE)qCallbackID, ADS_DBCAPI_CANCEL, (UNSIGNED64)&ulCancel) == AE_SUCCESS)
321
+ #else
322
+ if (AdsSetProperty((ADSHANDLE)qCallbackID, ADS_DBCAPI_CANCEL, (UNSIGNED32)&ulCancel) == AE_SUCCESS)
323
+ #endif
324
+ return ulCancel;
325
+
326
+ return 0;
327
+
328
+ } /* ShowPercentage */
329
+
330
+ /*******************************************************************************
331
+ * Module : ads_cancel
332
+ * Created : 11-04-2010 Peter F
333
+ * Last Mod :
334
+ * Return Value :
335
+ * Desc : Cancel a query
336
+ * Notes :
337
+ *******************************************************************************/
338
+ void ENTRYPOINT ads_cancel(a_ads_connection *poConnect)
339
+ {
340
+ UNSIGNED32 ulCancel = TRUE;
341
+
342
+ DBCLogTrace("ads_cancel");
343
+
344
+ // Set the cancel flag on the connection and the next time the callback
345
+ // function gets called with this connection, it will abort the query.
346
+ // Not using AdsSetProperty here since we already have the connection sync and
347
+ // calling an API would block.
348
+ if (poConnect && poConnect->hConnect && ValidConnectionHandle(poConnect->hConnect))
349
+ ((CCONNECTION *)poConnect->hConnect)->GetDBCAPICancel(&ulCancel);
350
+
351
+ } /* ads_cancel */
352
+
353
+ /*******************************************************************************
354
+ * Module : ads_clear_error
355
+ * Created : 11-04-2010 Peter F
356
+ * Last Mod :
357
+ * Return Value :
358
+ * Desc : Clear the current/last error
359
+ * Notes :
360
+ *******************************************************************************/
361
+ void ENTRYPOINT ads_clear_error(a_ads_connection *poConnect)
362
+ {
363
+ DBCLogTrace("ads_clear_error");
364
+ AdsClearLastError();
365
+
366
+ } /* ads_clear_error */
367
+
368
+ /*******************************************************************************
369
+ * Module : ads_client_version
370
+ * Created : 11-04-2010 Peter F
371
+ * Last Mod :
372
+ * Return Value :
373
+ * Desc : Return the client version
374
+ * Notes :
375
+ *******************************************************************************/
376
+ UNSIGNED32 ENTRYPOINT ads_client_version(UNSIGNED8 *pucBuffer, UNSIGNED32 ulLength)
377
+ {
378
+ DBCLogTrace("ads_client_version");
379
+ if (pucBuffer && ulLength)
380
+ {
381
+ AXSTRNCPY((SIGNED8 *)pucBuffer, pcIdAxsVer + 9, ulLength);
382
+ *(pucBuffer + ulLength - 1) = 0x00; // ensure NULL terminator
383
+ return DBCAPI_SUCCESS;
384
+ }
385
+
386
+ return DBCAPI_FAILURE;
387
+
388
+ } /* ads_client_version */
389
+
390
+ /*******************************************************************************
391
+ * Module : ads_commit
392
+ * Created : 11-04-2010 Peter F
393
+ * Last Mod :
394
+ * Return Value :
395
+ * Desc : Commit the current transaction
396
+ * Notes :
397
+ *******************************************************************************/
398
+ UNSIGNED32 ENTRYPOINT ads_commit(a_ads_connection *poConnect)
399
+ {
400
+ DBCLogTrace("ads_commit");
401
+
402
+ if (poConnect == NULL)
403
+ return DBCAPI_FAILURE;
404
+
405
+ if (AdsCommitTransaction(poConnect->hConnect) == AE_SUCCESS)
406
+ return DBCAPI_SUCCESS;
407
+ else
408
+ return DBCAPI_FAILURE;
409
+
410
+ } /* ads_commit */
411
+
412
+ /*******************************************************************************
413
+ * Module : ads_connect
414
+ * Created : 11-04-2010 Peter F
415
+ * Last Mod :
416
+ * Return Value :
417
+ * Desc : Connect to Advantage
418
+ * Notes :
419
+ *******************************************************************************/
420
+ UNSIGNED32 ENTRYPOINT ads_connect(a_ads_connection *poConnect, UNSIGNED8 *pucConnectString)
421
+ {
422
+ DBCLogTrace("ads_connect");
423
+
424
+ if (poConnect == NULL)
425
+ return DBCAPI_FAILURE;
426
+
427
+ if (AdsConnect101(pucConnectString, NULL, &(poConnect->hConnect)) == AE_SUCCESS)
428
+ return DBCAPI_SUCCESS;
429
+ else
430
+ return DBCAPI_FAILURE;
431
+
432
+ } /* ads_connect */
433
+
434
+ /*******************************************************************************
435
+ * Module : ads_describe_bind_param
436
+ * Created : 11-04-2010 Peter F
437
+ * Last Mod :
438
+ * Return Value :
439
+ * Desc : Describe a parameter
440
+ * Notes : Not fully functional...
441
+ *******************************************************************************/
442
+ UNSIGNED32 ENTRYPOINT ads_describe_bind_param(ADSHANDLE hStatement, UNSIGNED32 ulIndex, a_ads_bind_param *param)
443
+ {
444
+ DBCLogTrace("ads_describe_bind_param");
445
+
446
+ // Since ACE doesn't know anything about the type of parameters in a prepared
447
+ // statement, we can't tell the type of a parameter. All we know is that
448
+ // it must be an INPUT parameter since we don't support OUTPUT (or INPUT_OUTPUT) ones.
449
+ // If in the future ACE becomes aware of parameters (like our ODBC client), we can update
450
+ // this function to do what it is supposed to. The effect of this is that the caller must
451
+ // set the data type themselves.
452
+ if (hStatement == 0)
453
+ return DBCAPI_FAILURE;
454
+
455
+ if (param == NULL)
456
+ return DBCAPI_FAILURE;
457
+
458
+ // All parameters must be INPUT for ADS
459
+ param->direction = DD_INPUT;
460
+
461
+ return DBCAPI_SUCCESS;
462
+
463
+ } /* ads_describe_bind_param */
464
+
465
+ /*******************************************************************************
466
+ * Module : ads_disconnect
467
+ * Created : 11-04-2010 Peter F
468
+ * Last Mod :
469
+ * Return Value :
470
+ * Desc : Disconnect from Advantage
471
+ * Notes :
472
+ *******************************************************************************/
473
+ UNSIGNED32 ENTRYPOINT ads_disconnect(a_ads_connection *poConnect)
474
+ {
475
+ UNSIGNED32 ulRetCode;
476
+
477
+ DBCLogTrace("ads_disconnect");
478
+
479
+ if (poConnect == NULL)
480
+ return DBCAPI_FAILURE;
481
+
482
+ ulRetCode = AdsDisconnect(poConnect->hConnect);
483
+ poConnect->hConnect = 0;
484
+
485
+ if (ulRetCode == AE_SUCCESS)
486
+ return DBCAPI_SUCCESS;
487
+ else
488
+ return DBCAPI_FAILURE;
489
+
490
+ } /* ads_disconnect */
491
+
492
+ /*******************************************************************************
493
+ * Module : ads_error
494
+ * Created : 11-04-2010 Peter F
495
+ * Last Mod :
496
+ * Return Value :
497
+ * Desc : Get the last (current) error
498
+ * Notes :
499
+ *******************************************************************************/
500
+ UNSIGNED32 ENTRYPOINT ads_error(a_ads_connection *poConnect, UNSIGNED8 *pucError, UNSIGNED32 ulLength)
501
+ {
502
+ UNSIGNED32 ulError;
503
+ UNSIGNED16 usLen = (UNSIGNED16)ulLength;
504
+
505
+ DBCLogTrace("ads_error");
506
+
507
+ AdsGetLastError(&ulError, pucError, &usLen);
508
+ if (pucError && ulLength)
509
+ *(pucError + ulLength - 1) = 0x00;
510
+
511
+ return ulError;
512
+
513
+ } /* ads_error */
514
+
515
+ /*******************************************************************************
516
+ * Module : SetupCursorBuffer
517
+ * Created : 11-04-2010 Peter F
518
+ * Last Mod :
519
+ * Return Value :
520
+ * Desc : Allocate a record buffer structure to hold values as they are fetched
521
+ * Notes :
522
+ *******************************************************************************/
523
+ UNSIGNED32 SetupCursorBuffer(ADSHANDLE hCursor)
524
+ {
525
+ UNSIGNED32 ulAllocationSize;
526
+ UNSIGNED8 *pucFieldData;
527
+ DBCAPI_COLUMN *pstFieldStruct;
528
+ UNSIGNED16 usIndex;
529
+ UNSIGNED16 usFieldCount;
530
+ UNSIGNED16 usFieldType;
531
+ UNSIGNED32 ulFieldLength;
532
+ UNSIGNED32 ulRetCode;
533
+ UNSIGNED16 usLen;
534
+ UNSIGNED8 aucFieldName[ADS_MAX_FIELD_NAME + 1];
535
+
536
+ // If we're re-executing a query that was already open we might be reusing the
537
+ // ACE cursor object. In that case, we will already have the DBCAPI_COLUMN structures
538
+ // initialized.
539
+ #ifdef x64
540
+ ulRetCode = AdsSetProperty90(hCursor, ADS_GET_DBCAPI_BUFFER, (UNSIGNED64)&pstFieldStruct);
541
+ #else
542
+ ulRetCode = AdsSetProperty(hCursor, ADS_GET_DBCAPI_BUFFER, (UNSIGNED32)&pstFieldStruct);
543
+ #endif
544
+
545
+ if ((ulRetCode == AE_SUCCESS) && pstFieldStruct)
546
+ // That was easy!
547
+ return AE_SUCCESS;
548
+
549
+ ulRetCode = AdsGetNumFields(hCursor, &usFieldCount);
550
+ if (ulRetCode != AE_SUCCESS)
551
+ return ulRetCode;
552
+
553
+ ulAllocationSize = usFieldCount * sizeof(DBCAPI_COLUMN);
554
+
555
+ // Calculate how much extra memory we need for each column's data
556
+ for (usIndex = 0; usIndex < usFieldCount; usIndex++)
557
+ {
558
+ // Include some memory for the field name
559
+ usLen = sizeof(aucFieldName);
560
+ ulRetCode = AdsGetFieldName(hCursor, usIndex + 1, aucFieldName, &usLen);
561
+ if (ulRetCode != AE_SUCCESS)
562
+ return ulRetCode;
563
+
564
+ ulAllocationSize += usLen + 1;
565
+
566
+ ulRetCode = AdsGetFieldType(hCursor, ADSFIELD(usIndex + 1), &usFieldType);
567
+ if (ulRetCode != AE_SUCCESS)
568
+ return ulRetCode;
569
+
570
+ switch (usFieldType)
571
+ {
572
+ case ADS_MEMO:
573
+ case ADS_NMEMO:
574
+ case ADS_IMAGE:
575
+ case ADS_BINARY:
576
+ case ADS_VARCHAR:
577
+ // Blob fields use a dynamic buffer
578
+ break;
579
+
580
+ case ADS_TIME:
581
+ // Time gets converted to strings
582
+ ulAllocationSize += 39; // max length if values are wacky
583
+ break;
584
+
585
+ case ADS_DATE:
586
+ case ADS_COMPACTDATE:
587
+ // Dates get converted to strings
588
+ ulAllocationSize += ADS_MAX_DATEMASK;
589
+ break;
590
+
591
+ case ADS_TIMESTAMP:
592
+ case ADS_MODTIME:
593
+ // Timestamps get converted to strings
594
+ ulAllocationSize += 39 + ADS_MAX_DATEMASK;
595
+ break;
596
+
597
+ case ADS_NCHAR:
598
+ case ADS_NVARCHAR:
599
+ // Unicode char fields
600
+ ulRetCode = AdsGetFieldLength100(hCursor, ADSFIELD(usIndex + 1), ADS_BYTE_LENGTH, &ulFieldLength);
601
+ if (ulRetCode != AE_SUCCESS)
602
+ return ulRetCode;
603
+
604
+ ulAllocationSize += ulFieldLength + 2; // +2 for the double NULL
605
+ break;
606
+
607
+ case ADS_STRING:
608
+ case ADS_CISTRING:
609
+ case ADS_VARCHAR_FOX:
610
+ case ADS_NUMERIC:
611
+ // Strings need one extra byte for the NULL terminator
612
+ ulAllocationSize += 1;
613
+
614
+ default:
615
+ // Everything else needs the field length amount of bytes
616
+ ulRetCode = AdsGetFieldLength100(hCursor, ADSFIELD(usIndex + 1), ADS_BYTE_LENGTH, &ulFieldLength);
617
+ if (ulRetCode != AE_SUCCESS)
618
+ return ulRetCode;
619
+
620
+ ulAllocationSize += ulFieldLength;
621
+ break;
622
+ }
623
+ }
624
+
625
+ pstFieldStruct = (DBCAPI_COLUMN *)MAllocateMemory(ulAllocationSize);
626
+ if (pstFieldStruct == NULL)
627
+ return AdsSetLastError(AE_ALLOCATION_FAILED, NULL);
628
+
629
+ pucFieldData = (UNSIGNED8 *)pstFieldStruct + (usFieldCount * sizeof(DBCAPI_COLUMN));
630
+
631
+ for (usIndex = 0; usIndex < usFieldCount; usIndex++)
632
+ {
633
+ usLen = sizeof(aucFieldName);
634
+ ulRetCode = AdsGetFieldName(hCursor, usIndex + 1, pucFieldData, &usLen);
635
+ if (ulRetCode != AE_SUCCESS)
636
+ return ulRetCode;
637
+
638
+ pstFieldStruct[usIndex].pucColumnName = pucFieldData;
639
+ pucFieldData += usLen + 1;
640
+
641
+ ulRetCode = AdsGetFieldType(hCursor, ADSFIELD(usIndex + 1), &usFieldType);
642
+ if (ulRetCode != AE_SUCCESS)
643
+ return ulRetCode;
644
+
645
+ pstFieldStruct[usIndex].ulIsNull = 0;
646
+ switch (usFieldType)
647
+ {
648
+ case ADS_MEMO:
649
+ case ADS_NMEMO:
650
+ case ADS_IMAGE:
651
+ case ADS_BINARY:
652
+ case ADS_VARCHAR:
653
+ // Blob fields use dynamic memory
654
+ pstFieldStruct[usIndex].pucData = NULL;
655
+ pstFieldStruct[usIndex].ulBufferLength = 0;
656
+ break;
657
+
658
+ case ADS_TIME:
659
+ // Time gets converted to strings
660
+ pstFieldStruct[usIndex].pucData = pucFieldData;
661
+ pstFieldStruct[usIndex].ulBufferLength = 39;
662
+ pucFieldData += 39;
663
+ break;
664
+
665
+ case ADS_DATE:
666
+ case ADS_COMPACTDATE:
667
+ // Dates get converted to strings
668
+ pstFieldStruct[usIndex].pucData = pucFieldData;
669
+ pstFieldStruct[usIndex].ulBufferLength = ADS_MAX_DATEMASK;
670
+ pucFieldData += ADS_MAX_DATEMASK;
671
+ break;
672
+
673
+ case ADS_TIMESTAMP:
674
+ case ADS_MODTIME:
675
+ // Timestamps get converted to strings
676
+ pstFieldStruct[usIndex].pucData = pucFieldData;
677
+ pstFieldStruct[usIndex].ulBufferLength = 39 + ADS_MAX_DATEMASK;
678
+ pucFieldData += 39 + ADS_MAX_DATEMASK;
679
+ break;
680
+
681
+ case ADS_STRING:
682
+ case ADS_CISTRING:
683
+ case ADS_VARCHAR_FOX:
684
+ case ADS_NUMERIC:
685
+ ulRetCode = AdsGetFieldLength100(hCursor, ADSFIELD(usIndex + 1), ADS_BYTE_LENGTH, &ulFieldLength);
686
+ if (ulRetCode != AE_SUCCESS)
687
+ return ulRetCode;
688
+
689
+ pstFieldStruct[usIndex].pucData = pucFieldData;
690
+ pstFieldStruct[usIndex].ulBufferLength = ulFieldLength + 1;
691
+ pucFieldData += ulFieldLength + 1;
692
+ break;
693
+
694
+ case ADS_NCHAR:
695
+ case ADS_NVARCHAR:
696
+ ulRetCode = AdsGetFieldLength100(hCursor, ADSFIELD(usIndex + 1), ADS_BYTE_LENGTH, &ulFieldLength);
697
+ if (ulRetCode != AE_SUCCESS)
698
+ return ulRetCode;
699
+
700
+ pstFieldStruct[usIndex].pucData = pucFieldData;
701
+ pstFieldStruct[usIndex].ulBufferLength = ulFieldLength + 2;
702
+ pucFieldData += ulFieldLength + 1;
703
+ break;
704
+
705
+ default:
706
+ ulRetCode = AdsGetFieldLength100(hCursor, ADSFIELD(usIndex + 1), ADS_BYTE_LENGTH, &ulFieldLength);
707
+ if (ulRetCode != AE_SUCCESS)
708
+ return ulRetCode;
709
+
710
+ pstFieldStruct[usIndex].pucData = pucFieldData;
711
+ pstFieldStruct[usIndex].ulBufferLength = ulFieldLength;
712
+ pucFieldData += ulFieldLength;
713
+ break;
714
+ }
715
+ }
716
+
717
+ // Store the field structure pointer in the cursor object
718
+ return AdsSetProperty90(hCursor, ADS_SET_DBCAPI_BUFFER, (UNSIGNED64)pstFieldStruct);
719
+
720
+ } /* SetupCursorBuffer */
721
+
722
+ /*******************************************************************************
723
+ * Module : ads_execute
724
+ * Created : 11-04-2010 Peter F
725
+ * Last Mod :
726
+ * Return Value :
727
+ * Desc : Execute a prepared query
728
+ * Notes :
729
+ *******************************************************************************/
730
+ UNSIGNED32 ENTRYPOINT ads_execute(ADSHANDLE hStatement)
731
+ {
732
+ ADSHANDLE hCursor;
733
+ UNSIGNED32 ulRetCode;
734
+ ADSHANDLE hConnect;
735
+
736
+ DBCLogTrace("ads_execute");
737
+
738
+ ulRetCode = AdsGetConnectionHandle(hStatement, &hConnect);
739
+ if (ulRetCode != AE_SUCCESS)
740
+ return DBCAPI_FAILURE;
741
+
742
+ ulRetCode = AdsRegisterCallbackFunction101(DBCAPICallback, hConnect);
743
+ if (ulRetCode != AE_SUCCESS)
744
+ return DBCAPI_FAILURE;
745
+
746
+ ulRetCode = AdsExecuteSQL(hStatement, &hCursor);
747
+ if ((ulRetCode == AE_SUCCESS) && hCursor)
748
+ {
749
+ ulRetCode = SetupCursorBuffer(hCursor);
750
+ if (ulRetCode != AE_SUCCESS)
751
+ AdsCloseTable(hCursor);
752
+ }
753
+
754
+ if (ulRetCode == AE_SUCCESS)
755
+ return DBCAPI_SUCCESS;
756
+ else
757
+ return DBCAPI_FAILURE;
758
+
759
+ } /* ads_execute */
760
+
761
+ /*******************************************************************************
762
+ * Module : ads_execute_direct
763
+ * Created : 11-04-2010 Peter F
764
+ * Last Mod :
765
+ * Return Value :
766
+ * Desc : Execute a query
767
+ * Notes :
768
+ *******************************************************************************/
769
+ ADSHANDLE ENTRYPOINT ads_execute_direct(a_ads_connection *poConnect, UNSIGNED8 *pucSQL)
770
+ {
771
+ UNSIGNED32 ulRetCode;
772
+ ADSHANDLE hCursor;
773
+ ADSHANDLE hStatement;
774
+
775
+ DBCLogTrace("ads_execute_direct");
776
+
777
+ if (poConnect == NULL)
778
+ return DBCAPI_FAILURE;
779
+
780
+ ulRetCode = AdsCreateSQLStatement(poConnect->hConnect, &hStatement);
781
+ if (ulRetCode != AE_SUCCESS)
782
+ return DBCAPI_FAILURE;
783
+
784
+ ulRetCode = AdsRegisterCallbackFunction101(DBCAPICallback, poConnect->hConnect);
785
+ if (ulRetCode != AE_SUCCESS)
786
+ return DBCAPI_FAILURE;
787
+
788
+ ulRetCode = AdsExecuteSQLDirect(hStatement, pucSQL, &hCursor);
789
+ if (ulRetCode != AE_SUCCESS)
790
+ {
791
+ AdsSetProperty(poConnect->hConnect, ADS_PUSH_ERROR_STACK, 0);
792
+ AdsCloseSQLStatement(hStatement);
793
+ AdsSetProperty(poConnect->hConnect, ADS_POP_ERROR_STACK, 0);
794
+ return DBCAPI_FAILURE;
795
+ }
796
+ else if (hCursor)
797
+ {
798
+ ulRetCode = SetupCursorBuffer(hCursor);
799
+ if (ulRetCode != AE_SUCCESS)
800
+ {
801
+ AdsCloseTable(hCursor);
802
+ AdsCloseSQLStatement(hStatement);
803
+ return DBCAPI_FAILURE;
804
+ }
805
+ }
806
+
807
+ return hStatement;
808
+
809
+ } /* ads_execute_direct */
810
+
811
+ /*******************************************************************************
812
+ * Module : ads_execute_immediate
813
+ * Created : 11-04-2010 Peter F
814
+ * Last Mod :
815
+ * Return Value :
816
+ * Desc : Execute a query that has no results
817
+ * Notes :
818
+ *******************************************************************************/
819
+ UNSIGNED32 ENTRYPOINT ads_execute_immediate(a_ads_connection *poConnect, UNSIGNED8 *pucSQL)
820
+ {
821
+ ADSHANDLE hCursor = 0;
822
+ UNSIGNED32 ulRetCode;
823
+ ADSHANDLE hStatement;
824
+
825
+ DBCLogTrace("ads_execute_immediate");
826
+
827
+ if (poConnect == NULL)
828
+ return DBCAPI_FAILURE;
829
+
830
+ ulRetCode = AdsCreateSQLStatement(poConnect->hConnect, &hStatement);
831
+ if (ulRetCode != AE_SUCCESS)
832
+ return DBCAPI_FAILURE;
833
+
834
+ ulRetCode = AdsRegisterCallbackFunction101(DBCAPICallback, poConnect->hConnect);
835
+ if (ulRetCode != AE_SUCCESS)
836
+ return DBCAPI_FAILURE;
837
+
838
+ ulRetCode = AdsExecuteSQLDirect(hStatement, pucSQL, &hCursor);
839
+ if ((ulRetCode == AE_SUCCESS) && hCursor)
840
+ // There shouldn't be a result set with this API
841
+ AdsCloseTable(hCursor);
842
+
843
+ if (ulRetCode == AE_SUCCESS)
844
+ AdsCloseSQLStatement(hStatement);
845
+ else
846
+ {
847
+ AdsSetProperty(poConnect->hConnect, ADS_PUSH_ERROR_STACK, 0);
848
+ AdsCloseSQLStatement(hStatement);
849
+ AdsSetProperty(poConnect->hConnect, ADS_POP_ERROR_STACK, 0);
850
+ }
851
+
852
+ if (ulRetCode == AE_SUCCESS)
853
+ return DBCAPI_SUCCESS;
854
+ else
855
+ return DBCAPI_FAILURE;
856
+
857
+ } /* ads_execute_immediate */
858
+
859
+ /*******************************************************************************
860
+ * Module : ads_fetch_absolute
861
+ * Created : 11-04-2010 Peter F
862
+ * Last Mod :
863
+ * Return Value :
864
+ * Desc : Fetch a specific record in a cursor
865
+ * Notes :
866
+ *******************************************************************************/
867
+ UNSIGNED32 ENTRYPOINT ads_fetch_absolute(ADSHANDLE hStatement, UNSIGNED32 ulRowNum)
868
+ {
869
+ ADSHANDLE hCursor;
870
+
871
+ DBCLogTrace("ads_fetch_absolute");
872
+
873
+ if (AdsStmtGetCursorHandle(hStatement, &hCursor) != AE_SUCCESS)
874
+ return DBCAPI_FAILURE;
875
+
876
+ if (AdsGotoRecord(hCursor, ulRowNum) != AE_SUCCESS)
877
+ return DBCAPI_FAILURE;
878
+ else
879
+ return DBCAPI_SUCCESS;
880
+
881
+ } /* ads_fetch_absolute */
882
+
883
+ /*******************************************************************************
884
+ * Module : ads_fetch_next
885
+ * Created : 11-04-2010 Peter F
886
+ * Last Mod :
887
+ * Return Value :
888
+ * Desc : Fetch the next record, ie Skip to the next record
889
+ * Notes :
890
+ *******************************************************************************/
891
+ UNSIGNED32 ENTRYPOINT ads_fetch_next(ADSHANDLE hStatement)
892
+ {
893
+ ADSHANDLE hCursor;
894
+
895
+ DBCLogTrace("ads_fetch_next");
896
+
897
+ if (AdsStmtGetCursorHandle(hStatement, &hCursor) != AE_SUCCESS)
898
+ return FALSE;
899
+
900
+ if (hCursor)
901
+ {
902
+ UNSIGNED32 ulFirstFetch;
903
+ UNSIGNED32 ulRetCode;
904
+ UNSIGNED16 usIsDeleted;
905
+
906
+ // Peek into the cursor object and see if this is the first time we fetch a record
907
+ #ifdef x64
908
+ if (AdsSetProperty90(hCursor, ADS_IS_FIRST_FETCH, (UNSIGNED64)&ulFirstFetch) != AE_SUCCESS)
909
+ #else
910
+ if (AdsSetProperty(hCursor, ADS_IS_FIRST_FETCH, (UNSIGNED32)&ulFirstFetch) != AE_SUCCESS)
911
+ #endif
912
+ return FALSE;
913
+
914
+ // Since ACE automatically puts us at the first record, don't skip for the first fetch
915
+ if (ulFirstFetch == FALSE)
916
+ {
917
+ if (AdsSkip(hCursor, 1) != AE_SUCCESS)
918
+ return FALSE;
919
+ }
920
+
921
+ // If we are not positioned, this API will return AE_NO_CURRENT_RECORD
922
+ ulRetCode = AdsIsRecordDeleted(hCursor, &usIsDeleted);
923
+ if (ulRetCode != AE_SUCCESS)
924
+ {
925
+ if (ulRetCode == AE_NO_CURRENT_RECORD)
926
+ // Not really an error
927
+ AdsClearLastError();
928
+
929
+ return FALSE;
930
+ }
931
+
932
+ // Don't really care about usIsDeleted, as long as we are positioned
933
+ return TRUE;
934
+ }
935
+ else
936
+ return FALSE;
937
+
938
+ } /* ads_fetch_next */
939
+
940
+ /*******************************************************************************
941
+ * Module : ads_fini
942
+ * Created : 11-04-2010 Peter F
943
+ * Last Mod :
944
+ * Return Value :
945
+ * Desc : Perform any finalization tasks
946
+ * Notes :
947
+ *******************************************************************************/
948
+ UNSIGNED32 ENTRYPOINT ads_fini(void)
949
+ {
950
+ DBCLogTrace("ads_fini");
951
+
952
+ AdsDisconnect(0);
953
+
954
+ return DBCAPI_SUCCESS;
955
+
956
+ } /* ads_fini */
957
+
958
+ /*******************************************************************************
959
+ * Module : ads_free_connection
960
+ * Created : 11-04-2010 Peter F
961
+ * Last Mod :
962
+ * Return Value :
963
+ * Desc : Free an a_ads_connection object & disconnect if necessary
964
+ * Notes :
965
+ *******************************************************************************/
966
+ UNSIGNED32 ENTRYPOINT ads_free_connection(a_ads_connection *poConnect)
967
+ {
968
+ DBCLogTrace("ads_free_connection");
969
+
970
+ if (poConnect == NULL)
971
+ return DBCAPI_FAILURE;
972
+
973
+ if (poConnect->hConnect)
974
+ AdsDisconnect(poConnect->hConnect);
975
+
976
+ ReleaseMemory(poConnect);
977
+
978
+ return DBCAPI_SUCCESS;
979
+
980
+ } /* ads_free_connection */
981
+
982
+ /*******************************************************************************
983
+ * Module : ads_free_stmt
984
+ * Created : 11-04-2010 Peter F
985
+ * Last Mod :
986
+ * Return Value :
987
+ * Desc : Free a statement
988
+ * Notes : This will free any open cursors & the DBCAPI_COLUMN data within
989
+ *******************************************************************************/
990
+ UNSIGNED32 ENTRYPOINT ads_free_stmt(ADSHANDLE hStatement)
991
+ {
992
+ DBCLogTrace("ads_free_stmt");
993
+
994
+ if (hStatement == 0)
995
+ return DBCAPI_FAILURE;
996
+
997
+ if (AdsCloseSQLStatement(hStatement) != AE_SUCCESS)
998
+ return DBCAPI_FAILURE;
999
+
1000
+ return DBCAPI_SUCCESS;
1001
+
1002
+ } /* ads_free_stmt */
1003
+
1004
+ /*******************************************************************************
1005
+ * Module : ads_get_bind_param_info
1006
+ * Created : 11-04-2010 Peter F
1007
+ * Last Mod :
1008
+ * Return Value :
1009
+ * Desc : Retrieves information about the parameters that were bound using ads_bind_param
1010
+ * Notes : Currently not supported
1011
+ *******************************************************************************/
1012
+ UNSIGNED32 ENTRYPOINT ads_get_bind_param_info(ADSHANDLE hStatement, UNSIGNED32 ulIndex, a_ads_bind_param_info *info)
1013
+ {
1014
+ DBCLogTrace("ads_get_bind_param_info");
1015
+
1016
+ // UNRESOLVED PF: I think we could support this if the parameter has
1017
+ // already been set. The statement in ACE has the parameter name, number,
1018
+ // type, and length. Since we don't support binding variables to parameters
1019
+ // this function will be incomplete and perhaps not very useful anyway.
1020
+ return DBCAPI_FAILURE;
1021
+
1022
+ } /* ads_get_bind_param_info */
1023
+
1024
+ /*******************************************************************************
1025
+ * Module : DBCAPIGetData
1026
+ * Created : 11-04-2010 Peter F
1027
+ * Last Mod :
1028
+ * Return Value :
1029
+ * Desc : Utility FN to get column data
1030
+ * Notes :
1031
+ *******************************************************************************/
1032
+ UNSIGNED32 DBCAPIGetData(
1033
+ ADSHANDLE hCursor,
1034
+ a_ads_data_type usDataType,
1035
+ UNSIGNED32 ulIndex,
1036
+ UNSIGNED8 **ppucBuffer,
1037
+ UNSIGNED32 *pulLength,
1038
+ UNSIGNED32 *pulBufferLength,
1039
+ UNSIGNED16 *pusIsNull,
1040
+ UNSIGNED32 ulOffset)
1041
+ {
1042
+ UNSIGNED32 ulRetCode;
1043
+ UNSIGNED16 usFieldType;
1044
+
1045
+ ulRetCode = AdsIsNull(hCursor, ADSFIELD(ulIndex + 1), pusIsNull);
1046
+ if (ulRetCode != AE_SUCCESS)
1047
+ return ulRetCode;
1048
+
1049
+ switch (usDataType)
1050
+ {
1051
+ case A_VAL16:
1052
+ ulRetCode = AdsGetShort(hCursor, ADSFIELD(ulIndex + 1), (SIGNED16 *)*ppucBuffer);
1053
+ if (ulRetCode != AE_SUCCESS)
1054
+ return ulRetCode;
1055
+
1056
+ *pulLength = sizeof(SIGNED16);
1057
+ break;
1058
+
1059
+ case A_UVAL8:
1060
+ {
1061
+ UNSIGNED16 usShort;
1062
+ ulRetCode = AdsGetLogical(hCursor, ADSFIELD(ulIndex + 1), &usShort);
1063
+ if (ulRetCode != AE_SUCCESS)
1064
+ return ulRetCode;
1065
+
1066
+ **ppucBuffer = (UNSIGNED8)usShort;
1067
+ *pulLength = sizeof(UNSIGNED8);
1068
+ }
1069
+ break;
1070
+
1071
+ case A_VAL32:
1072
+ case A_UVAL32:
1073
+ ulRetCode = AdsGetLong(hCursor, ADSFIELD(ulIndex + 1), (SIGNED32 *)*ppucBuffer);
1074
+ if (ulRetCode != AE_SUCCESS)
1075
+ return ulRetCode;
1076
+
1077
+ *pulLength = sizeof(SIGNED32);
1078
+ break;
1079
+
1080
+ case A_DOUBLE:
1081
+ ulRetCode = AdsGetDouble(hCursor, ADSFIELD(ulIndex + 1), (double *)*ppucBuffer);
1082
+ if (ulRetCode != AE_SUCCESS)
1083
+ return ulRetCode;
1084
+
1085
+ *pulLength = sizeof(double);
1086
+ break;
1087
+
1088
+ case A_VAL64:
1089
+ case A_UVAL64:
1090
+ ulRetCode = AdsGetLongLong(hCursor, ADSFIELD(ulIndex + 1), (SIGNED64 *)*ppucBuffer);
1091
+ if (ulRetCode != AE_SUCCESS)
1092
+ return ulRetCode;
1093
+
1094
+ *pulLength = sizeof(SIGNED64);
1095
+ break;
1096
+
1097
+ default:
1098
+ // If no buffer length is provided, the user provided us the buffer so just call AdsGetField
1099
+ if (!pulBufferLength)
1100
+ {
1101
+ if (ulOffset)
1102
+ return AdsGetBinary(hCursor, ADSFIELD(ulIndex + 1), ulOffset, *ppucBuffer, pulLength);
1103
+ else
1104
+ return AdsGetField(hCursor, ADSFIELD(ulIndex + 1), *ppucBuffer, pulLength, ADS_NONE);
1105
+ }
1106
+
1107
+ ulRetCode = AdsGetFieldType(hCursor, ADSFIELD(ulIndex + 1), &usFieldType);
1108
+ if (ulRetCode != AE_SUCCESS)
1109
+ return ulRetCode;
1110
+
1111
+ switch (usFieldType)
1112
+ {
1113
+ case ADS_MEMO:
1114
+ case ADS_NMEMO:
1115
+ case ADS_IMAGE:
1116
+ case ADS_BINARY:
1117
+ case ADS_VARCHAR:
1118
+ // BLOB fields use a dynamic buffer to store the data
1119
+ if (*pusIsNull)
1120
+ *pulLength = 0;
1121
+ else
1122
+ {
1123
+ UNSIGNED32 ulBlobLength;
1124
+
1125
+ ulRetCode = AdsGetMemoLength(hCursor, ADSFIELD(ulIndex + 1), &ulBlobLength);
1126
+ if (ulRetCode != AE_SUCCESS)
1127
+ return ulRetCode;
1128
+
1129
+ // Memo (string) fields need an extra byte for the NULL
1130
+ if ((usFieldType == ADS_MEMO) || (usFieldType == ADS_VARCHAR))
1131
+ ulBlobLength++;
1132
+
1133
+ else if (usFieldType == ADS_NMEMO)
1134
+ ulBlobLength = (ulBlobLength + 1) * 2;
1135
+
1136
+ // Allocate a larger buffer if necessary
1137
+ if (*pulBufferLength < ulBlobLength)
1138
+ {
1139
+ if (*ppucBuffer)
1140
+ *ppucBuffer = (UNSIGNED8 *)ReallocateMemory(*ppucBuffer, ulBlobLength);
1141
+ else
1142
+ *ppucBuffer = (UNSIGNED8 *)MAllocateMemory(ulBlobLength);
1143
+
1144
+ if (*ppucBuffer == NULL)
1145
+ return AdsSetLastError(AE_ALLOCATION_FAILED, NULL);
1146
+
1147
+ *pulBufferLength = ulBlobLength;
1148
+ }
1149
+
1150
+ *pulLength = *pulBufferLength;
1151
+ if ((usFieldType == ADS_MEMO) || (usFieldType == ADS_VARCHAR))
1152
+ ulRetCode = AdsGetString(hCursor, ADSFIELD(ulIndex + 1), *ppucBuffer, pulLength, ADS_NONE);
1153
+
1154
+ else if (usFieldType == ADS_NMEMO)
1155
+ {
1156
+ // AdsGetStringW expects number of chars, not bytes
1157
+ *pulLength >>= 1;
1158
+ ulRetCode = AdsGetStringW(hCursor, ADSFIELD(ulIndex + 1), (WCHAR *)*ppucBuffer, pulLength, ADS_NONE);
1159
+ if (ulRetCode == AE_SUCCESS)
1160
+ *pulLength <<= 1;
1161
+ }
1162
+
1163
+ else
1164
+ ulRetCode = AdsGetBinary(hCursor, ADSFIELD(ulIndex + 1), 0, *ppucBuffer, pulLength);
1165
+
1166
+ if (ulRetCode != AE_SUCCESS)
1167
+ return ulRetCode;
1168
+ }
1169
+ break;
1170
+
1171
+ case ADS_NCHAR:
1172
+ case ADS_NVARCHAR:
1173
+ *pulLength = *pulBufferLength;
1174
+ *pulLength >>= 1;
1175
+ ulRetCode = AdsGetStringW(hCursor, ADSFIELD(ulIndex + 1), (WCHAR *)*ppucBuffer, pulLength, ADS_NONE);
1176
+ if (ulRetCode == AE_SUCCESS)
1177
+ *pulLength <<= 1;
1178
+ break;
1179
+
1180
+ default:
1181
+ // Non blob fields can just use AdsGetField
1182
+ *pulLength = *pulBufferLength;
1183
+ ulRetCode = AdsGetField(hCursor, ADSFIELD(ulIndex + 1), *ppucBuffer, pulLength, ADS_NONE);
1184
+ if (ulRetCode != AE_SUCCESS)
1185
+ return ulRetCode;
1186
+
1187
+ break;
1188
+
1189
+ } // switch ( ACE type )
1190
+
1191
+ break;
1192
+
1193
+ } // switch( DBCAPI type )
1194
+
1195
+ return ulRetCode;
1196
+
1197
+ } /* DBCAPIGetData */
1198
+
1199
+ /*******************************************************************************
1200
+ * Module : ads_get_column
1201
+ * Created : 11-04-2010 Peter F
1202
+ * Last Mod :
1203
+ * Return Value :
1204
+ * Desc : Get the value of a column
1205
+ * Notes :
1206
+ *******************************************************************************/
1207
+ UNSIGNED32 ENTRYPOINT ads_get_column(ADSHANDLE hStatement, UNSIGNED32 ulIndex, a_ads_data_value *buffer)
1208
+ {
1209
+ ADSHANDLE hCursor;
1210
+ UNSIGNED16 usIsNull;
1211
+ UNSIGNED32 ulRetCode;
1212
+ DBCAPI_COLUMN *pstColumnStruct;
1213
+ UNSIGNED16 usFieldType;
1214
+
1215
+ DBCLogTrace("ads_get_column");
1216
+
1217
+ if (buffer == NULL)
1218
+ return DBCAPI_FAILURE;
1219
+
1220
+ if (AdsStmtGetCursorHandle(hStatement, &hCursor) != AE_SUCCESS)
1221
+ return DBCAPI_FAILURE;
1222
+
1223
+ #ifdef x64
1224
+ ulRetCode = AdsSetProperty90(hCursor, ADS_GET_DBCAPI_BUFFER, (UNSIGNED64)&pstColumnStruct);
1225
+ #else
1226
+ ulRetCode = AdsSetProperty(hCursor, ADS_GET_DBCAPI_BUFFER, (UNSIGNED32)&pstColumnStruct);
1227
+ #endif
1228
+
1229
+ if ((ulRetCode != AE_SUCCESS) || !pstColumnStruct)
1230
+ return DBCAPI_FAILURE;
1231
+
1232
+ pstColumnStruct += ulIndex;
1233
+
1234
+ if (AdsGetFieldType(hCursor, ADSFIELD(ulIndex + 1), &usFieldType) != AE_SUCCESS)
1235
+ return DBCAPI_FAILURE;
1236
+
1237
+ buffer->type = ConvertACEToIOType(usFieldType);
1238
+ ulRetCode = DBCAPIGetData(hCursor, buffer->type, ulIndex,
1239
+ &(pstColumnStruct->pucData),
1240
+ &(pstColumnStruct->ulDataLength),
1241
+ &(pstColumnStruct->ulBufferLength),
1242
+ &usIsNull, 0);
1243
+ if (ulRetCode == AE_SUCCESS)
1244
+ {
1245
+ buffer->buffer = pstColumnStruct->pucData;
1246
+ buffer->length = &(pstColumnStruct->ulDataLength);
1247
+ buffer->is_null = &(pstColumnStruct->ulIsNull);
1248
+ buffer->buffer_size = pstColumnStruct->ulBufferLength;
1249
+ *(buffer->is_null) = usIsNull;
1250
+ return DBCAPI_SUCCESS;
1251
+ }
1252
+ else
1253
+ {
1254
+ *(buffer->length) = 0;
1255
+ buffer->buffer_size = 0;
1256
+ buffer->buffer = NULL;
1257
+ buffer->type = A_INVALID_TYPE;
1258
+ *(buffer->is_null) = 0;
1259
+ return DBCAPI_NEGONE;
1260
+ }
1261
+
1262
+ } /* ads_get_column */
1263
+
1264
+ /*******************************************************************************
1265
+ * Module : ads_get_column_info
1266
+ * Created : 11-04-2010 Peter F
1267
+ * Last Mod :
1268
+ * Return Value :
1269
+ * Desc : Get some info about a column
1270
+ * Notes :
1271
+ *******************************************************************************/
1272
+ UNSIGNED32 ENTRYPOINT ads_get_column_info(ADSHANDLE hStatement, UNSIGNED32 ulIndex, a_ads_column_info *buffer)
1273
+ {
1274
+ ADSHANDLE hCursor;
1275
+ UNSIGNED16 usFieldType;
1276
+ UNSIGNED32 ulFieldLength;
1277
+ UNSIGNED16 usFieldDecimals;
1278
+ UNSIGNED16 usIsNullable;
1279
+ DBCAPI_COLUMN *pstColumnStruct;
1280
+ UNSIGNED32 ulRetCode;
1281
+
1282
+ DBCLogTrace("ads_get_column_info");
1283
+
1284
+ if (buffer == NULL)
1285
+ return DBCAPI_FAILURE;
1286
+
1287
+ if (AdsStmtGetCursorHandle(hStatement, &hCursor) != AE_SUCCESS)
1288
+ return DBCAPI_FAILURE;
1289
+
1290
+ if (AdsGetFieldType(hCursor, ADSFIELD(ulIndex + 1), &usFieldType) != AE_SUCCESS)
1291
+ return DBCAPI_FAILURE;
1292
+
1293
+ if (AdsGetFieldLength100(hCursor, ADSFIELD(ulIndex + 1), ADS_BYTE_LENGTH, &ulFieldLength) != AE_SUCCESS)
1294
+ return DBCAPI_FAILURE;
1295
+
1296
+ if (AdsGetFieldDecimals(hCursor, ADSFIELD(ulIndex + 1), &usFieldDecimals) != AE_SUCCESS)
1297
+ return DBCAPI_FAILURE;
1298
+
1299
+ if (AdsIsNullable(hCursor, ADSFIELD(ulIndex + 1), &usIsNullable) != AE_SUCCESS)
1300
+ return DBCAPI_FAILURE;
1301
+
1302
+ #ifdef x64
1303
+ ulRetCode = AdsSetProperty90(hCursor, ADS_GET_DBCAPI_BUFFER, (UNSIGNED64)&pstColumnStruct);
1304
+ #else
1305
+ ulRetCode = AdsSetProperty(hCursor, ADS_GET_DBCAPI_BUFFER, (UNSIGNED32)&pstColumnStruct);
1306
+ #endif
1307
+
1308
+ if ((ulRetCode != AE_SUCCESS) || !pstColumnStruct)
1309
+ return DBCAPI_FAILURE;
1310
+
1311
+ pstColumnStruct += ulIndex;
1312
+
1313
+ buffer->name = pstColumnStruct->pucColumnName;
1314
+ buffer->max_size = ulFieldLength;
1315
+ buffer->precision = (UNSIGNED16)ulFieldLength;
1316
+ buffer->scale = usFieldDecimals;
1317
+ buffer->nullable = usIsNullable;
1318
+ buffer->type = ConvertACEToIOType(usFieldType);
1319
+ buffer->native_type = ConvertACEtoNativeType(usFieldType);
1320
+
1321
+ return DBCAPI_SUCCESS;
1322
+
1323
+ } /* ads_get_column_info */
1324
+
1325
+ /*******************************************************************************
1326
+ * Module : ads_get_data
1327
+ * Created : 11-04-2010 Peter F
1328
+ * Last Mod :
1329
+ * Return Value :
1330
+ * Desc : Get data from a column
1331
+ * Notes :
1332
+ *******************************************************************************/
1333
+ UNSIGNED32 ENTRYPOINT ads_get_data(ADSHANDLE hStatement, UNSIGNED32 ulIndex, UNSIGNED32 ulOffset, void *buffer, UNSIGNED32 ulLength)
1334
+ {
1335
+ UNSIGNED32 ulRetCode;
1336
+ UNSIGNED16 usIsNull;
1337
+ UNSIGNED16 usFieldType;
1338
+ ADSHANDLE hCursor;
1339
+
1340
+ DBCLogTrace("ads_get_data");
1341
+
1342
+ if (buffer == NULL)
1343
+ return DBCAPI_NEGONE;
1344
+
1345
+ if (hStatement == 0)
1346
+ return DBCAPI_NEGONE;
1347
+
1348
+ ulRetCode = AdsStmtGetCursorHandle(hStatement, &hCursor);
1349
+ if (ulRetCode != AE_SUCCESS)
1350
+ return DBCAPI_NEGONE;
1351
+
1352
+ ulRetCode = AdsGetFieldType(hCursor, ADSFIELD(ulIndex + 1), &usFieldType);
1353
+ if (ulRetCode != AE_SUCCESS)
1354
+ return DBCAPI_NEGONE;
1355
+
1356
+ ulRetCode = DBCAPIGetData(hCursor, ConvertACEToIOType(usFieldType),
1357
+ ulIndex, (UNSIGNED8 **)&buffer,
1358
+ &ulLength, NULL, &usIsNull, ulOffset);
1359
+ if (ulRetCode != AE_SUCCESS)
1360
+ return DBCAPI_NEGONE;
1361
+
1362
+ return ulLength;
1363
+
1364
+ } /* ads_get_data */
1365
+
1366
+ /*******************************************************************************
1367
+ * Module : ads_get_data_info
1368
+ * Created : 11-04-2010 Peter F
1369
+ * Last Mod :
1370
+ * Return Value :
1371
+ * Desc : Get some info about a column's value
1372
+ * Notes :
1373
+ *******************************************************************************/
1374
+ UNSIGNED32 ENTRYPOINT ads_get_data_info(ADSHANDLE hStatement, UNSIGNED32 ulIndex, a_ads_data_info *buffer)
1375
+ {
1376
+ UNSIGNED32 ulRetCode;
1377
+ UNSIGNED16 usType;
1378
+ UNSIGNED16 usIsNull;
1379
+ UNSIGNED32 ulDataLength;
1380
+ ADSHANDLE hCursor;
1381
+
1382
+ DBCLogTrace("ads_get_data_info");
1383
+
1384
+ if (buffer == NULL)
1385
+ return DBCAPI_FAILURE;
1386
+
1387
+ if (AdsStmtGetCursorHandle(hStatement, &hCursor) != AE_SUCCESS)
1388
+ return DBCAPI_FAILURE;
1389
+
1390
+ if (hCursor == 0)
1391
+ return DBCAPI_FAILURE;
1392
+
1393
+ ulRetCode = AdsGetFieldType(hCursor, ADSFIELD(ulIndex + 1), &usType);
1394
+ if (ulRetCode != AE_SUCCESS)
1395
+ return DBCAPI_FAILURE;
1396
+
1397
+ ulRetCode = AdsIsNull(hCursor, ADSFIELD(ulIndex + 1), &usIsNull);
1398
+ if (ulRetCode != AE_SUCCESS)
1399
+ return DBCAPI_FAILURE;
1400
+
1401
+ if ((usType == ADS_MEMO) ||
1402
+ (usType == ADS_NMEMO) ||
1403
+ (usType == ADS_VARCHAR) ||
1404
+ (usType == ADS_BINARY) ||
1405
+ (usType == ADS_IMAGE))
1406
+ ulRetCode = AdsGetMemoLength(hCursor, ADSFIELD(ulIndex + 1), &ulDataLength);
1407
+ else
1408
+ ulRetCode = AdsGetFieldLength100(hCursor, ADSFIELD(ulIndex + 1), ADS_BYTE_LENGTH, &ulDataLength);
1409
+
1410
+ if (ulRetCode != AE_SUCCESS)
1411
+ return DBCAPI_FAILURE;
1412
+
1413
+ buffer->type = ConvertACEToIOType(usType);
1414
+ buffer->is_null = usIsNull;
1415
+ buffer->data_size = ulDataLength;
1416
+
1417
+ return DBCAPI_SUCCESS;
1418
+
1419
+ } /* ads_get_data_info */
1420
+
1421
+ /*******************************************************************************
1422
+ * Module : ads_get_next_result
1423
+ * Created : 11-04-2010 Peter F
1424
+ * Last Mod :
1425
+ * Return Value :
1426
+ * Desc : Get the next result set from the statement
1427
+ * Notes : Unsupported with ADS
1428
+ *******************************************************************************/
1429
+ UNSIGNED32 ENTRYPOINT ads_get_next_result(ADSHANDLE hStatement)
1430
+ {
1431
+ DBCLogTrace("ads_get_next_result");
1432
+
1433
+ // ADS doesn't support multiple result sets on a single statement
1434
+ return DBCAPI_FAILURE;
1435
+
1436
+ } /* ads_get_next_result */
1437
+
1438
+ /*******************************************************************************
1439
+ * Module : ads_init
1440
+ * Created : 11-04-2010 Peter F
1441
+ * Last Mod :
1442
+ * Return Value :
1443
+ * Desc : Initialize the DBCAPI client
1444
+ * Notes :
1445
+ *******************************************************************************/
1446
+ UNSIGNED32 ENTRYPOINT ads_init(UNSIGNED8 *app_name, UNSIGNED32 api_version, UNSIGNED32 *version_available)
1447
+ {
1448
+ DBCLogTrace("ads_init");
1449
+
1450
+ // We support the more basic version of DBCAPI, version 1
1451
+ *version_available = 1;
1452
+
1453
+ return DBCAPI_SUCCESS;
1454
+
1455
+ } /* ads_init */
1456
+
1457
+ /*******************************************************************************
1458
+ * Module : ads_make_connection
1459
+ * Created : 11-04-2010 Peter F
1460
+ * Last Mod :
1461
+ * Return Value :
1462
+ * Desc : "make" a connection from a DBLIB SQLCA object
1463
+ * Notes :
1464
+ *******************************************************************************/
1465
+ a_ads_connection_ptr ENTRYPOINT ads_make_connection(void *arg)
1466
+ {
1467
+ DBCLogTrace("ads_make_connection");
1468
+
1469
+ // Create a connection object based on a supplied DBLIB SQLCA pointer
1470
+ // UNRESOLVED how to interpret a DBLIB SQLCA object?
1471
+ return NULL;
1472
+
1473
+ } /* ads_make_connection */
1474
+
1475
+ /*******************************************************************************
1476
+ * Module : ads_new_connection
1477
+ * Created : 11-04-2010 Peter F
1478
+ * Last Mod :
1479
+ * Return Value :
1480
+ * Desc : Allocate a new a_ads_connection object
1481
+ * Notes : Doesn't connect, just creates a new object
1482
+ *******************************************************************************/
1483
+ a_ads_connection_ptr ENTRYPOINT ads_new_connection(void)
1484
+ {
1485
+ a_ads_connection *poConnect;
1486
+
1487
+ DBCLogTrace("ads_new_connection");
1488
+
1489
+ // Return a DBCAPI connection object, later we'll get a real connection via ads_connect
1490
+ poConnect = (a_ads_connection *)MAllocateMemory(sizeof(a_ads_connection));
1491
+ if (poConnect)
1492
+ memset(poConnect, 0, sizeof(a_ads_connection));
1493
+
1494
+ return poConnect;
1495
+
1496
+ } /* ads_new_connection */
1497
+
1498
+ /*******************************************************************************
1499
+ * Module : ads_num_cols
1500
+ * Created : 11-04-2010 Peter F
1501
+ * Last Mod :
1502
+ * Return Value :
1503
+ * Desc : Return the number of columns in the cursor
1504
+ * Notes :
1505
+ *******************************************************************************/
1506
+ UNSIGNED32 ENTRYPOINT ads_num_cols(ADSHANDLE hStatement)
1507
+ {
1508
+ ADSHANDLE hCursor;
1509
+ UNSIGNED16 usFieldCount;
1510
+
1511
+ DBCLogTrace("ads_num_cols");
1512
+
1513
+ if (hStatement == 0)
1514
+ return DBCAPI_FAILURE;
1515
+
1516
+ if (AdsStmtGetCursorHandle(hStatement, &hCursor) != AE_SUCCESS)
1517
+ return DBCAPI_FAILURE;
1518
+
1519
+ if (hCursor == 0)
1520
+ return DBCAPI_FAILURE;
1521
+
1522
+ if (AdsGetNumFields(hCursor, &usFieldCount) != AE_SUCCESS)
1523
+ return DBCAPI_FAILURE;
1524
+ else
1525
+ return usFieldCount;
1526
+
1527
+ } /* ads_num_cols */
1528
+
1529
+ /*******************************************************************************
1530
+ * Module : ads_num_params
1531
+ * Created : 11-04-2010 Peter F
1532
+ * Last Mod :
1533
+ * Return Value :
1534
+ * Desc : Return the number of parameters in the statement
1535
+ * Notes :
1536
+ *******************************************************************************/
1537
+ UNSIGNED32 ENTRYPOINT ads_num_params(ADSHANDLE hStatement)
1538
+ {
1539
+ UNSIGNED16 usNumParams;
1540
+
1541
+ DBCLogTrace("ads_num_params");
1542
+
1543
+ if (hStatement == 0)
1544
+ return DBCAPI_FAILURE;
1545
+
1546
+ if (AdsStmtGetNumParams(hStatement, &usNumParams) != AE_SUCCESS)
1547
+ return DBCAPI_FAILURE;
1548
+ else
1549
+ return usNumParams;
1550
+
1551
+ } /* ads_num_params */
1552
+
1553
+ /*******************************************************************************
1554
+ * Module : ads_num_rows
1555
+ * Created : 11-04-2010 Peter F
1556
+ * Last Mod :
1557
+ * Return Value :
1558
+ * Desc : Return the number of rows in the cursor
1559
+ * Notes :
1560
+ *******************************************************************************/
1561
+ UNSIGNED32 ENTRYPOINT ads_num_rows(ADSHANDLE hStatement)
1562
+ {
1563
+ UNSIGNED32 ulRecordCount;
1564
+ ADSHANDLE hCursor;
1565
+
1566
+ DBCLogTrace("ads_num_rows");
1567
+
1568
+ if (AdsStmtGetCursorHandle(hStatement, &hCursor) != AE_SUCCESS)
1569
+ return DBCAPI_FAILURE;
1570
+
1571
+ if (AdsGetRecordCount(hCursor, ADS_RESPECTFILTERS, &ulRecordCount) != AE_SUCCESS)
1572
+ return DBCAPI_FAILURE;
1573
+ else
1574
+ return ulRecordCount;
1575
+
1576
+ } /* ads_num_rows */
1577
+
1578
+ /*******************************************************************************
1579
+ * Module : ads_prepare
1580
+ * Created : 11-04-2010 Peter F
1581
+ * Last Mod :
1582
+ * Return Value :
1583
+ * Desc : Prepare a query for execution
1584
+ * Notes :
1585
+ *******************************************************************************/
1586
+ ADSHANDLE ENTRYPOINT ads_prepare(a_ads_connection *poConnect, UNSIGNED8 *pucSQL, UNSIGNED8 ucIsUnicode)
1587
+ {
1588
+ ADSHANDLE hStmt;
1589
+ UNSIGNED32 ulRetCode;
1590
+
1591
+ DBCLogTrace("ads_prepare");
1592
+
1593
+ if (poConnect == NULL)
1594
+ return DBCAPI_FAILURE;
1595
+
1596
+ ulRetCode = AdsCreateSQLStatement(poConnect->hConnect, &hStmt);
1597
+ if (ulRetCode != AE_SUCCESS)
1598
+ return DBCAPI_FAILURE;
1599
+
1600
+ if (ucIsUnicode)
1601
+ ulRetCode = AdsPrepareSQLW(hStmt, (WCHAR *)pucSQL);
1602
+ else
1603
+ ulRetCode = AdsPrepareSQL(hStmt, pucSQL);
1604
+ if (ulRetCode != AE_SUCCESS)
1605
+ {
1606
+ AdsSetProperty(poConnect->hConnect, ADS_PUSH_ERROR_STACK, 0);
1607
+ AdsCloseSQLStatement(hStmt);
1608
+ AdsSetProperty(poConnect->hConnect, ADS_POP_ERROR_STACK, 0);
1609
+ return DBCAPI_FAILURE;
1610
+ }
1611
+
1612
+ return hStmt;
1613
+
1614
+ } /* ads_prepare */
1615
+
1616
+ /*******************************************************************************
1617
+ * Module : ads_reset
1618
+ * Created : 11-04-2010 Peter F
1619
+ * Last Mod :
1620
+ * Return Value :
1621
+ * Desc : Resets a statement to its prepared state condition.
1622
+ * Notes :
1623
+ *******************************************************************************/
1624
+ UNSIGNED32 ENTRYPOINT ads_reset(ADSHANDLE hStatement)
1625
+ {
1626
+ ADSHANDLE hCursor;
1627
+
1628
+ DBCLogTrace("ads_reset");
1629
+
1630
+ // Preparing the same query twice is a no-op in ACE.
1631
+ // All we need to do here is close any open cursor on the STMT.
1632
+ if (hStatement == 0)
1633
+ return DBCAPI_FAILURE;
1634
+
1635
+ if (AdsStmtGetCursorHandle(hStatement, &hCursor) != AE_SUCCESS)
1636
+ return DBCAPI_FAILURE;
1637
+
1638
+ if (hCursor)
1639
+ AdsCloseTable(hCursor);
1640
+
1641
+ return DBCAPI_SUCCESS;
1642
+
1643
+ } /* ads_reset */
1644
+
1645
+ /*******************************************************************************
1646
+ * Module : ads_rollback
1647
+ * Created : 11-04-2010 Peter F
1648
+ * Last Mod :
1649
+ * Return Value :
1650
+ * Desc : Rollback an active transaction
1651
+ * Notes :
1652
+ *******************************************************************************/
1653
+ UNSIGNED32 ENTRYPOINT ads_rollback(a_ads_connection *poConnect)
1654
+ {
1655
+ DBCLogTrace("ads_rollback");
1656
+
1657
+ if (poConnect == NULL)
1658
+ return DBCAPI_FAILURE;
1659
+
1660
+ if (AdsRollbackTransaction(poConnect->hConnect) == AE_SUCCESS)
1661
+ return DBCAPI_SUCCESS;
1662
+ else
1663
+ return DBCAPI_FAILURE;
1664
+
1665
+ } /* ads_rollback */
1666
+
1667
+ /*******************************************************************************
1668
+ * Module : ads_send_param_data
1669
+ * Created : 11-04-2010 Peter F
1670
+ * Last Mod :
1671
+ * Return Value :
1672
+ * Desc : Sends data as part of a bound parameter.
1673
+ * Notes : This method can be used to send a large amount of data for a bound parameter in chunks.
1674
+ *******************************************************************************/
1675
+ UNSIGNED32 ENTRYPOINT ads_send_param_data(ADSHANDLE hStatement, UNSIGNED32 ulIndex, UNSIGNED8 *pucBuffer, UNSIGNED32 ulLength)
1676
+ {
1677
+ DBCLogTrace("ads_send_param_data");
1678
+
1679
+ if (hStatement == 0)
1680
+ return DBCAPI_FAILURE;
1681
+
1682
+ if (AdsSetBinary(hStatement, ADSFIELD(ulIndex + 1), ADS_BINARY, ulLength, 0, pucBuffer, ulLength) == AE_SUCCESS)
1683
+ return DBCAPI_SUCCESS;
1684
+ else
1685
+ return DBCAPI_FAILURE;
1686
+
1687
+ } /* ads_send_param_data */
1688
+
1689
+ /*******************************************************************************
1690
+ * Module : ads_sqlstate
1691
+ * Created : 11-04-2010 Peter F
1692
+ * Last Mod :
1693
+ * Return Value :
1694
+ * Desc : Return the 'sql state' of the last error
1695
+ * Notes :
1696
+ *******************************************************************************/
1697
+ UNSIGNED32 ENTRYPOINT ads_sqlstate(a_ads_connection *poConnect, UNSIGNED8 *pucBuffer, UNSIGNED32 ulLength)
1698
+ {
1699
+ UNSIGNED32 ulRetCode;
1700
+ UNSIGNED32 ulError;
1701
+ UNSIGNED8 aucError[ADS_MAX_ERROR_LEN + 1];
1702
+ UNSIGNED16 usLen;
1703
+
1704
+ DBCLogTrace("ads_sqlstate");
1705
+
1706
+ usLen = sizeof(aucError);
1707
+ ulRetCode = AdsGetLastError(&ulError, aucError, &usLen);
1708
+ if (ulRetCode != AE_SUCCESS)
1709
+ return DBCAPI_FAILURE;
1710
+
1711
+ if (ulError == AE_SUCCESS)
1712
+ strncpy((SIGNED8 *)pucBuffer, "00000", ulLength);
1713
+ else
1714
+ {
1715
+ UNSIGNED8 *pcState;
1716
+ #define StateMarker "State = "
1717
+
1718
+ pcState = (UNSIGNED8 *)strstr((SIGNED8 *)aucError, StateMarker);
1719
+ if (pcState == NULL)
1720
+ strncpy((SIGNED8 *)pucBuffer, "00000", ulLength);
1721
+ else
1722
+ {
1723
+ pcState += strlen(StateMarker);
1724
+
1725
+ /* The state code is a 5 digit alphanumeric. NULL termintate it */
1726
+ *(pcState + 5) = 0;
1727
+ strncpy((SIGNED8 *)pucBuffer, (SIGNED8 *)pcState, ulLength);
1728
+ }
1729
+ }
1730
+
1731
+ return DBCAPI_SUCCESS;
1732
+
1733
+ } /* ads_sqlstate */
1734
+
1735
+ #endif // ACE