advantage 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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