~ubuntu-branches/ubuntu/lucid/psqlodbc/lucid

« back to all changes in this revision

Viewing changes to bind.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-05-13 10:47:36 UTC
  • Revision ID: james.westby@ubuntu.com-20040513104736-a530gmn0p3knep89
Tags: upstream-07.03.0200
ImportĀ upstreamĀ versionĀ 07.03.0200

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------
 
2
 * Module:                      bind.c
 
3
 *
 
4
 * Description:         This module contains routines related to binding
 
5
 *                                      columns and parameters.
 
6
 *
 
7
 * Classes:                     BindInfoClass, ParameterInfoClass
 
8
 *
 
9
 * API functions:       SQLBindParameter, SQLBindCol, SQLDescribeParam, SQLNumParams,
 
10
 *                                      SQLParamOptions
 
11
 *
 
12
 * Comments:            See "notice.txt" for copyright and license information.
 
13
 *-------
 
14
 */
 
15
 
 
16
#include "bind.h"
 
17
 
 
18
#include "environ.h"
 
19
#include "statement.h"
 
20
#include "descriptor.h"
 
21
#include "qresult.h"
 
22
#include "pgtypes.h"
 
23
#include <stdlib.h>
 
24
#include <string.h>
 
25
 
 
26
#include "pgapifunc.h"
 
27
 
 
28
 
 
29
/*              Bind parameters on a statement handle */
 
30
RETCODE         SQL_API
 
31
PGAPI_BindParameter(
 
32
                                        HSTMT hstmt,
 
33
                                        UWORD ipar,
 
34
                                        SWORD fParamType,
 
35
                                        SWORD fCType,
 
36
                                        SWORD fSqlType,
 
37
                                        UDWORD cbColDef,
 
38
                                        SWORD ibScale,
 
39
                                        PTR rgbValue,
 
40
                                        SDWORD cbValueMax,
 
41
                                        SDWORD FAR * pcbValue)
 
42
{
 
43
        StatementClass *stmt = (StatementClass *) hstmt;
 
44
        CSTR func = "PGAPI_BindParameter";
 
45
        APDFields       *apdopts;
 
46
        IPDFields       *ipdopts;
 
47
 
 
48
        mylog("%s: entering...\n", func);
 
49
 
 
50
        if (!stmt)
 
51
        {
 
52
                SC_log_error(func, "", NULL);
 
53
                return SQL_INVALID_HANDLE;
 
54
        }
 
55
        SC_clear_error(stmt);
 
56
 
 
57
        apdopts = SC_get_APD(stmt);
 
58
        if (apdopts->allocated < ipar)
 
59
                extend_parameter_bindings(apdopts, ipar);
 
60
        ipdopts = SC_get_IPD(stmt);
 
61
        if (ipdopts->allocated < ipar)
 
62
                extend_iparameter_bindings(ipdopts, ipar);
 
63
 
 
64
        /* use zero based column numbers for the below part */
 
65
        ipar--;
 
66
 
 
67
        /* store the given info */
 
68
        apdopts->parameters[ipar].buflen = cbValueMax;
 
69
        apdopts->parameters[ipar].buffer = rgbValue;
 
70
        apdopts->parameters[ipar].used = pcbValue;
 
71
        apdopts->parameters[ipar].paramType = fParamType;
 
72
        apdopts->parameters[ipar].CType = fCType;
 
73
        ipdopts->parameters[ipar].SQLType = fSqlType;
 
74
        ipdopts->parameters[ipar].paramType = fParamType;
 
75
        ipdopts->parameters[ipar].column_size = cbColDef;
 
76
        ipdopts->parameters[ipar].decimal_digits = ibScale;
 
77
        ipdopts->parameters[ipar].precision = 0;
 
78
        ipdopts->parameters[ipar].scale = 0;
 
79
        ipdopts->parameters[ipar].PGType = sqltype_to_pgtype(stmt, fSqlType);
 
80
#if (ODBCVER >= 0x0300)
 
81
        switch (fCType)
 
82
        {
 
83
                case SQL_C_NUMERIC:
 
84
                        if (cbColDef > 0)
 
85
                                ipdopts->parameters[ipar].precision = (UInt2) cbColDef;
 
86
                        if (ibScale > 0)
 
87
                                ipdopts->parameters[ipar].scale = ibScale;
 
88
                        break;
 
89
                case SQL_C_TYPE_TIMESTAMP:
 
90
                        if (ibScale > 0)
 
91
                                ipdopts->parameters[ipar].precision = ibScale;
 
92
                        break;
 
93
        }
 
94
        apdopts->parameters[ipar].precision = ipdopts->parameters[ipar].precision;
 
95
        apdopts->parameters[ipar].scale = ipdopts->parameters[ipar].scale;
 
96
#endif /* ODBCVER */
 
97
 
 
98
        /*
 
99
         * If rebinding a parameter that had data-at-exec stuff in it, then
 
100
         * free that stuff
 
101
         */
 
102
        if (apdopts->parameters[ipar].EXEC_used)
 
103
        {
 
104
                free(apdopts->parameters[ipar].EXEC_used);
 
105
                apdopts->parameters[ipar].EXEC_used = NULL;
 
106
        }
 
107
 
 
108
        if (apdopts->parameters[ipar].EXEC_buffer)
 
109
        {
 
110
                free(apdopts->parameters[ipar].EXEC_buffer);
 
111
                apdopts->parameters[ipar].EXEC_buffer = NULL;
 
112
        }
 
113
 
 
114
        if (pcbValue && apdopts->param_offset_ptr)
 
115
                pcbValue += (*apdopts->param_offset_ptr >> 2);
 
116
        /* Data at exec macro only valid for C char/binary data */
 
117
        if (pcbValue && (*pcbValue == SQL_DATA_AT_EXEC ||
 
118
                                         *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET))
 
119
                apdopts->parameters[ipar].data_at_exec = TRUE;
 
120
        else
 
121
                apdopts->parameters[ipar].data_at_exec = FALSE;
 
122
 
 
123
        /* Clear premature result */
 
124
        if (stmt->status == STMT_PREMATURE)
 
125
                SC_recycle_statement(stmt);
 
126
 
 
127
        mylog("PGAPI_BindParamater: ipar=%d, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=%d, ibScale=%d, rgbValue=%d, *pcbValue = %d, data_at_exec = %d\n", ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, pcbValue ? *pcbValue : -777, apdopts->parameters[ipar].data_at_exec);
 
128
 
 
129
        return SQL_SUCCESS;
 
130
}
 
131
 
 
132
 
 
133
/*      Associate a user-supplied buffer with a database column. */
 
134
RETCODE         SQL_API
 
135
PGAPI_BindCol(
 
136
                          HSTMT hstmt,
 
137
                          UWORD icol,
 
138
                          SWORD fCType,
 
139
                          PTR rgbValue,
 
140
                          SDWORD cbValueMax,
 
141
                          SDWORD FAR * pcbValue)
 
142
{
 
143
        StatementClass *stmt = (StatementClass *) hstmt;
 
144
        CSTR func = "PGAPI_BindCol";
 
145
        ARDFields       *opts;
 
146
 
 
147
        mylog("%s: entering...\n", func);
 
148
 
 
149
        mylog("**** PGAPI_BindCol: stmt = %u, icol = %d\n", stmt, icol);
 
150
        mylog("**** : fCType=%d rgb=%x valusMax=%d pcb=%x\n", fCType, rgbValue, cbValueMax, pcbValue);
 
151
 
 
152
        if (!stmt)
 
153
        {
 
154
                SC_log_error(func, "", NULL);
 
155
                return SQL_INVALID_HANDLE;
 
156
        }
 
157
 
 
158
 
 
159
 
 
160
        opts = SC_get_ARD(stmt);
 
161
        if (stmt->status == STMT_EXECUTING)
 
162
        {
 
163
                SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't bind columns while statement is still executing.");
 
164
                SC_log_error(func, "", stmt);
 
165
                return SQL_ERROR;
 
166
        }
 
167
 
 
168
        SC_clear_error(stmt);
 
169
        /* If the bookmark column is being bound, then just save it */
 
170
        if (icol == 0)
 
171
        {
 
172
                if (rgbValue == NULL)
 
173
                {
 
174
                        opts->bookmark->buffer = NULL;
 
175
                        opts->bookmark->used = NULL;
 
176
                }
 
177
                else
 
178
                {
 
179
                        /* Make sure it is the bookmark data type */
 
180
                        switch (fCType)
 
181
                        {
 
182
                                case SQL_C_BOOKMARK:
 
183
#if (ODBCVER >= 0x0300)
 
184
                                case SQL_C_VARBOOKMARK:
 
185
#endif /* ODBCVER */
 
186
                                        break;
 
187
                                default:
 
188
                                        SC_set_error(stmt, STMT_PROGRAM_TYPE_OUT_OF_RANGE, "Bind column 0 is not of type SQL_C_BOOKMARK");
 
189
inolog("Bind column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
 
190
                                        SC_log_error(func, "", stmt);
 
191
                                        return SQL_ERROR;
 
192
                        }
 
193
 
 
194
                        opts->bookmark->buffer = rgbValue;
 
195
                        opts->bookmark->used = pcbValue;
 
196
                        opts->bookmark->buflen = cbValueMax;
 
197
                        opts->bookmark->returntype = fCType;
 
198
                }
 
199
                return SQL_SUCCESS;
 
200
        }
 
201
 
 
202
        /*
 
203
         * Allocate enough bindings if not already done. Most likely,
 
204
         * execution of a statement would have setup the necessary bindings.
 
205
         * But some apps call BindCol before any statement is executed.
 
206
         */
 
207
        if (icol > opts->allocated)
 
208
                extend_column_bindings(opts, icol);
 
209
 
 
210
        /* check to see if the bindings were allocated */
 
211
        if (!opts->bindings)
 
212
        {
 
213
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Could not allocate memory for bindings.");
 
214
                SC_log_error(func, "", stmt);
 
215
                return SQL_ERROR;
 
216
        }
 
217
 
 
218
        /* use zero based col numbers from here out */
 
219
        icol--;
 
220
 
 
221
        /* Reset for SQLGetData */
 
222
        opts->bindings[icol].data_left = -1;
 
223
 
 
224
        if (rgbValue == NULL)
 
225
        {
 
226
                /* we have to unbind the column */
 
227
                opts->bindings[icol].buflen = 0;
 
228
                opts->bindings[icol].buffer = NULL;
 
229
                opts->bindings[icol].used = NULL;
 
230
                opts->bindings[icol].returntype = SQL_C_CHAR;
 
231
                if (opts->bindings[icol].ttlbuf)
 
232
                        free(opts->bindings[icol].ttlbuf);
 
233
                opts->bindings[icol].ttlbuf = NULL;
 
234
                opts->bindings[icol].ttlbuflen = 0;
 
235
                opts->bindings[icol].ttlbufused = 0;
 
236
                opts->bindings[icol].precision = 0;
 
237
                opts->bindings[icol].scale = 0;
 
238
        }
 
239
        else
 
240
        {
 
241
                /* ok, bind that column */
 
242
                opts->bindings[icol].buflen = cbValueMax;
 
243
                opts->bindings[icol].buffer = rgbValue;
 
244
                opts->bindings[icol].used = pcbValue;
 
245
                opts->bindings[icol].returntype = fCType;
 
246
#if (ODBCVER >= 0x0300)
 
247
                if (SQL_C_NUMERIC == fCType)
 
248
                        opts->bindings[icol].precision = 32;
 
249
                else
 
250
#endif /* ODBCVER */
 
251
                        opts->bindings[icol].precision = 0;
 
252
                opts->bindings[icol].scale = 0;
 
253
 
 
254
                mylog("       bound buffer[%d] = %u\n", icol, opts->bindings[icol].buffer);
 
255
        }
 
256
 
 
257
        return SQL_SUCCESS;
 
258
}
 
259
 
 
260
 
 
261
/*
 
262
 *      Returns the description of a parameter marker.
 
263
 *      This function is listed as not being supported by SQLGetFunctions() because it is
 
264
 *      used to describe "parameter markers" (not bound parameters), in which case,
 
265
 *      the dbms should return info on the markers.  Since Postgres doesn't support that,
 
266
 *      it is best to say this function is not supported and let the application assume a
 
267
 *      data type (most likely varchar).
 
268
 */
 
269
RETCODE         SQL_API
 
270
PGAPI_DescribeParam(
 
271
                                        HSTMT hstmt,
 
272
                                        UWORD ipar,
 
273
                                        SWORD FAR * pfSqlType,
 
274
                                        UDWORD FAR * pcbColDef,
 
275
                                        SWORD FAR * pibScale,
 
276
                                        SWORD FAR * pfNullable)
 
277
{
 
278
        StatementClass *stmt = (StatementClass *) hstmt;
 
279
        CSTR func = "PGAPI_DescribeParam";
 
280
        APDFields       *apdopts;
 
281
        IPDFields       *ipdopts;
 
282
 
 
283
        mylog("%s: entering...\n", func);
 
284
 
 
285
        if (!stmt)
 
286
        {
 
287
                SC_log_error(func, "", NULL);
 
288
                return SQL_INVALID_HANDLE;
 
289
        }
 
290
        SC_clear_error(stmt);
 
291
 
 
292
        apdopts = SC_get_APD(stmt);
 
293
        if ((ipar < 1) || (ipar > apdopts->allocated))
 
294
        {
 
295
                SC_set_error(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR, "Invalid parameter number for PGAPI_DescribeParam.");
 
296
                SC_log_error(func, "", stmt);
 
297
                return SQL_ERROR;
 
298
        }
 
299
        ipdopts = SC_get_IPD(stmt);
 
300
 
 
301
        ipar--;
 
302
 
 
303
        /*
 
304
         * This implementation is not very good, since it is supposed to
 
305
         * describe
 
306
         */
 
307
        /* parameter markers, not bound parameters.  */
 
308
        if (pfSqlType)
 
309
                *pfSqlType = ipdopts->parameters[ipar].SQLType;
 
310
 
 
311
        if (pcbColDef)
 
312
                *pcbColDef = ipdopts->parameters[ipar].column_size;
 
313
 
 
314
        if (pibScale)
 
315
                *pibScale = ipdopts->parameters[ipar].decimal_digits;
 
316
 
 
317
        if (pfNullable)
 
318
                *pfNullable = pgtype_nullable(stmt, apdopts->parameters[ipar].paramType);
 
319
 
 
320
        return SQL_SUCCESS;
 
321
}
 
322
 
 
323
 
 
324
/*      Sets multiple values (arrays) for the set of parameter markers. */
 
325
RETCODE         SQL_API
 
326
PGAPI_ParamOptions(
 
327
                                   HSTMT hstmt,
 
328
                                   UDWORD crow,
 
329
                                   UDWORD FAR * pirow)
 
330
{
 
331
        CSTR func = "PGAPI_ParamOptions";
 
332
        StatementClass *stmt = (StatementClass *) hstmt;
 
333
        APDFields       *apdopts;
 
334
 
 
335
        mylog("%s: entering... %d %x\n", func, crow, pirow);
 
336
 
 
337
        apdopts = SC_get_APD(stmt);
 
338
        apdopts->paramset_size = crow;
 
339
        SC_get_IPD(stmt)->param_processed_ptr = (UInt4 *) pirow;
 
340
        return SQL_SUCCESS;
 
341
}
 
342
 
 
343
 
 
344
/*
 
345
 *      This function should really talk to the dbms to determine the number of
 
346
 *      "parameter markers" (not bound parameters) in the statement.  But, since
 
347
 *      Postgres doesn't support that, the driver should just count the number of markers
 
348
 *      and return that.  The reason the driver just can't say this function is unsupported
 
349
 *      like it does for SQLDescribeParam is that some applications don't care and try
 
350
 *      to call it anyway.
 
351
 *      If the statement does not have parameters, it should just return 0.
 
352
 */
 
353
RETCODE         SQL_API
 
354
PGAPI_NumParams(
 
355
                                HSTMT hstmt,
 
356
                                SWORD FAR * pcpar)
 
357
{
 
358
        StatementClass *stmt = (StatementClass *) hstmt;
 
359
        char            in_quote = FALSE;
 
360
        unsigned int i;
 
361
        CSTR func = "PGAPI_NumParams";
 
362
 
 
363
        mylog("%s: entering...\n", func);
 
364
 
 
365
        if (!stmt)
 
366
        {
 
367
                SC_log_error(func, "", NULL);
 
368
                return SQL_INVALID_HANDLE;
 
369
        }
 
370
 
 
371
        if (pcpar)
 
372
                *pcpar = 0;
 
373
        else
 
374
        {
 
375
                SC_log_error(func, "pcpar was null", stmt);
 
376
                return SQL_ERROR;
 
377
        }
 
378
 
 
379
 
 
380
        if (!stmt->statement)
 
381
        {
 
382
                /* no statement has been allocated */
 
383
                SC_set_error(stmt, STMT_SEQUENCE_ERROR, "PGAPI_NumParams called with no statement ready.");
 
384
                SC_log_error(func, "", stmt);
 
385
                return SQL_ERROR;
 
386
        }
 
387
        else
 
388
        {
 
389
                for (i = 0; i < strlen(stmt->statement); i++)
 
390
                {
 
391
                        if (stmt->statement[i] == '?' && !in_quote)
 
392
                                (*pcpar)++;
 
393
                        else
 
394
                        {
 
395
                                if (stmt->statement[i] == '\'')
 
396
                                        in_quote = (in_quote ? FALSE : TRUE);
 
397
                        }
 
398
                }
 
399
                return SQL_SUCCESS;
 
400
        }
 
401
}
 
402
 
 
403
 
 
404
/*
 
405
 *       Bindings Implementation
 
406
 */
 
407
BindInfoClass *
 
408
create_empty_bindings(int num_columns)
 
409
{
 
410
        BindInfoClass *new_bindings;
 
411
        int                     i;
 
412
 
 
413
        new_bindings = (BindInfoClass *) malloc(num_columns * sizeof(BindInfoClass));
 
414
        if (!new_bindings)
 
415
                return 0;
 
416
 
 
417
        for (i = 0; i < num_columns; i++)
 
418
        {
 
419
                new_bindings[i].buflen = 0;
 
420
                new_bindings[i].buffer = NULL;
 
421
                new_bindings[i].used = NULL;
 
422
                new_bindings[i].data_left = -1;
 
423
                new_bindings[i].ttlbuf = NULL;
 
424
                new_bindings[i].ttlbuflen = 0;
 
425
                new_bindings[i].ttlbufused = 0;
 
426
        }
 
427
 
 
428
        return new_bindings;
 
429
}
 
430
 
 
431
void
 
432
extend_parameter_bindings(APDFields *self, int num_params)
 
433
{
 
434
        CSTR func = "extend_parameter_bindings";
 
435
        ParameterInfoClass *new_bindings;
 
436
 
 
437
        mylog("%s: entering ... self=%u, parameters_allocated=%d, num_params=%d\n", func, self, self->allocated, num_params);
 
438
 
 
439
        /*
 
440
         * if we have too few, allocate room for more, and copy the old
 
441
         * entries into the new structure
 
442
         */
 
443
        if (self->allocated < num_params)
 
444
        {
 
445
                new_bindings = (ParameterInfoClass *) realloc(self->parameters, sizeof(ParameterInfoClass) * num_params);
 
446
                if (!new_bindings)
 
447
                {
 
448
                        mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_params, self->allocated);
 
449
 
 
450
                        self->parameters = NULL;
 
451
                        self->allocated = 0;
 
452
                        return;
 
453
                }
 
454
                memset(&new_bindings[self->allocated], 0,
 
455
                        sizeof(ParameterInfoClass) * (num_params - self->allocated));
 
456
 
 
457
                self->parameters = new_bindings;
 
458
                self->allocated = num_params;
 
459
        }
 
460
 
 
461
        mylog("exit extend_parameter_bindings\n");
 
462
}
 
463
 
 
464
void
 
465
extend_iparameter_bindings(IPDFields *self, int num_params)
 
466
{
 
467
        CSTR func = "extend_iparameter_bindings";
 
468
        ParameterImplClass *new_bindings;
 
469
 
 
470
        mylog("%s: entering ... self=%u, parameters_allocated=%d, num_params=%d\n", func, self, self->allocated, num_params);
 
471
 
 
472
        /*
 
473
         * if we have too few, allocate room for more, and copy the old
 
474
         * entries into the new structure
 
475
         */
 
476
        if (self->allocated < num_params)
 
477
        {
 
478
                new_bindings = (ParameterImplClass *) realloc(self->parameters, sizeof(ParameterImplClass) * num_params);
 
479
                if (!new_bindings)
 
480
                {
 
481
                        mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_params, self->allocated);
 
482
 
 
483
                        self->parameters = NULL;
 
484
                        self->allocated = 0;
 
485
                        return;
 
486
                }
 
487
                memset(&new_bindings[self->allocated], 0,
 
488
                        sizeof(ParameterImplClass) * (num_params - self->allocated));
 
489
 
 
490
                self->parameters = new_bindings;
 
491
                self->allocated = num_params;
 
492
        }
 
493
 
 
494
        mylog("exit extend_iparameter_bindings\n");
 
495
}
 
496
 
 
497
void
 
498
reset_a_parameter_binding(APDFields *self, int ipar)
 
499
{
 
500
        CSTR func = "reset_a_parameter_binding";
 
501
 
 
502
        mylog("%s: entering ... self=%u, parameters_allocated=%d, ipar=%d\n", func, self, self->allocated, ipar);
 
503
 
 
504
        if (ipar < 1 || ipar > self->allocated)
 
505
                return;
 
506
 
 
507
        ipar--;
 
508
        self->parameters[ipar].buflen = 0;
 
509
        self->parameters[ipar].buffer = 0;
 
510
        self->parameters[ipar].used = 0;
 
511
        self->parameters[ipar].paramType = 0;
 
512
        self->parameters[ipar].CType = 0;
 
513
        self->parameters[ipar].data_at_exec = FALSE;
 
514
        if (self->parameters[ipar].EXEC_used)
 
515
        {
 
516
                free(self->parameters[ipar].EXEC_used);
 
517
                self->parameters[ipar].EXEC_used = NULL;
 
518
        }
 
519
 
 
520
        if (self->parameters[ipar].EXEC_buffer)
 
521
        {
 
522
                free(self->parameters[ipar].EXEC_buffer);
 
523
                self->parameters[ipar].EXEC_buffer = NULL;
 
524
        }
 
525
        self->parameters[ipar].lobj_oid = 0;
 
526
        self->parameters[ipar].precision = 0;
 
527
        self->parameters[ipar].scale = 0;
 
528
}
 
529
 
 
530
void
 
531
reset_a_iparameter_binding(IPDFields *self, int ipar)
 
532
{
 
533
        CSTR func = "reset_a_iparameter_binding";
 
534
 
 
535
        mylog("%s: entering ... self=%u, parameters_allocated=%d, ipar=%d\n", func, self, self->allocated, ipar);
 
536
 
 
537
        if (ipar < 1 || ipar > self->allocated)
 
538
                return;
 
539
 
 
540
        ipar--;
 
541
        self->parameters[ipar].paramType = 0;
 
542
        self->parameters[ipar].SQLType = 0;
 
543
        self->parameters[ipar].column_size = 0;
 
544
        self->parameters[ipar].decimal_digits = 0;
 
545
        self->parameters[ipar].precision = 0;
 
546
        self->parameters[ipar].scale = 0;
 
547
}
 
548
 
 
549
/*
 
550
 *      Free parameters and free the memory.
 
551
 */
 
552
void
 
553
APD_free_params(APDFields *apdopts, char option)
 
554
{
 
555
        int                     i;
 
556
 
 
557
        mylog("APD_free_params:  ENTER, self=%d\n", apdopts);
 
558
 
 
559
        if (!apdopts->parameters)
 
560
                return;
 
561
 
 
562
        for (i = 0; i < apdopts->allocated; i++)
 
563
        {
 
564
                if (apdopts->parameters[i].data_at_exec)
 
565
                {
 
566
                        if (apdopts->parameters[i].EXEC_used)
 
567
                        {
 
568
                                free(apdopts->parameters[i].EXEC_used);
 
569
                                apdopts->parameters[i].EXEC_used = NULL;
 
570
                        }
 
571
                        if (apdopts->parameters[i].EXEC_buffer)
 
572
                        {
 
573
                                free(apdopts->parameters[i].EXEC_buffer);
 
574
                                apdopts->parameters[i].EXEC_buffer = NULL;
 
575
                        }
 
576
                }
 
577
        }
 
578
 
 
579
        if (option == STMT_FREE_PARAMS_ALL)
 
580
        {
 
581
                if (apdopts->parameters)
 
582
                        free(apdopts->parameters);
 
583
                apdopts->parameters = NULL;
 
584
                apdopts->allocated = 0;
 
585
        }
 
586
 
 
587
        mylog("APD_free_params:  EXIT\n");
 
588
}
 
589
 
 
590
/*
 
591
 *      Free parameters and free the memory.
 
592
 */
 
593
void
 
594
IPD_free_params(IPDFields *ipdopts, char option)
 
595
{
 
596
        mylog("IPD_free_params:  ENTER, self=%d\n", ipdopts);
 
597
 
 
598
        if (ipdopts->parameters &&
 
599
                option == STMT_FREE_PARAMS_ALL)
 
600
        {
 
601
                if (ipdopts->parameters)
 
602
                        free(ipdopts->parameters);
 
603
                ipdopts->parameters = NULL;
 
604
                ipdopts->allocated = 0;
 
605
        }
 
606
 
 
607
        mylog("IPD_free_params:  EXIT\n");
 
608
}
 
609
 
 
610
void
 
611
extend_column_bindings(ARDFields *self, int num_columns)
 
612
{
 
613
        CSTR func = "extend_column_bindings";
 
614
        BindInfoClass *new_bindings;
 
615
        int                     i;
 
616
 
 
617
        mylog("%s: entering ... self=%u, bindings_allocated=%d, num_columns=%d\n", func, self, self->allocated, num_columns);
 
618
 
 
619
        /*
 
620
         * if we have too few, allocate room for more, and copy the old
 
621
         * entries into the new structure
 
622
         */
 
623
        if (self->allocated < num_columns)
 
624
        {
 
625
                new_bindings = create_empty_bindings(num_columns);
 
626
                if (!new_bindings)
 
627
                {
 
628
                        mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_columns, self->allocated);
 
629
 
 
630
                        if (self->bindings)
 
631
                        {
 
632
                                free(self->bindings);
 
633
                                self->bindings = NULL;
 
634
                        }
 
635
                        self->allocated = 0;
 
636
                        return;
 
637
                }
 
638
 
 
639
                if (self->bindings)
 
640
                {
 
641
                        for (i = 0; i < self->allocated; i++)
 
642
                                new_bindings[i] = self->bindings[i];
 
643
 
 
644
                        free(self->bindings);
 
645
                }
 
646
 
 
647
                self->bindings = new_bindings;
 
648
                self->allocated = num_columns;
 
649
        }
 
650
 
 
651
        /*
 
652
         * There is no reason to zero out extra bindings if there are more
 
653
         * than needed.  If an app has allocated extra bindings, let it worry
 
654
         * about it by unbinding those columns.
 
655
         */
 
656
 
 
657
        /* SQLBindCol(1..) ... SQLBindCol(10...)   # got 10 bindings */
 
658
        /* SQLExecDirect(...)  # returns 5 cols */
 
659
        /* SQLExecDirect(...)  # returns 10 cols  (now OK) */
 
660
 
 
661
        mylog("exit extend_column_bindings\n");
 
662
}
 
663
 
 
664
void
 
665
reset_a_column_binding(ARDFields *self, int icol)
 
666
{
 
667
        CSTR func = "reset_a_column_binding";
 
668
 
 
669
        mylog("%s: entering ... self=%u, bindings_allocated=%d, icol=%d\n", func, self, self->allocated, icol);
 
670
 
 
671
        if (icol > self->allocated)
 
672
                return;
 
673
 
 
674
        /* use zero based col numbers from here out */
 
675
        if (0 == icol)
 
676
        {
 
677
                self->bookmark->buffer = NULL;
 
678
                self->bookmark->used = NULL;
 
679
        }
 
680
        else
 
681
        {
 
682
                icol--;
 
683
 
 
684
                /* we have to unbind the column */
 
685
                self->bindings[icol].buflen = 0;
 
686
                self->bindings[icol].buffer = NULL;
 
687
                self->bindings[icol].used = NULL;
 
688
                self->bindings[icol].data_left = -1;
 
689
                self->bindings[icol].returntype = SQL_C_CHAR;
 
690
                if (self->bindings[icol].ttlbuf)
 
691
                        free(self->bindings[icol].ttlbuf);
 
692
                self->bindings[icol].ttlbuf = NULL;
 
693
                self->bindings[icol].ttlbuflen = 0;
 
694
                self->bindings[icol].ttlbufused = 0;
 
695
        }
 
696
}
 
697
 
 
698
void    ARD_unbind_cols(ARDFields *self, BOOL freeall)
 
699
{
 
700
        Int2    lf;
 
701
 
 
702
        for (lf = 1; lf <= self->allocated; lf++)
 
703
                reset_a_column_binding(self, lf);
 
704
        if (freeall)
 
705
        {
 
706
                if (self->bindings)
 
707
                        free(self->bindings);
 
708
                self->bindings = NULL;
 
709
                self->allocated = 0;
 
710
        }
 
711