~ubuntu-branches/ubuntu/gutsy/psqlodbc/gutsy

« back to all changes in this revision

Viewing changes to statement.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:                      statement.c
 
3
 *
 
4
 * Description:         This module contains functions related to creating
 
5
 *                                      and manipulating a statement.
 
6
 *
 
7
 * Classes:                     StatementClass (Functions prefix: "SC_")
 
8
 *
 
9
 * API functions:       SQLAllocStmt, SQLFreeStmt
 
10
 *
 
11
 * Comments:            See "notice.txt" for copyright and license information.
 
12
 *-------
 
13
 */
 
14
 
 
15
#include "statement.h"
 
16
 
 
17
#include "bind.h"
 
18
#include "connection.h"
 
19
#include "qresult.h"
 
20
#include "convert.h"
 
21
#include "environ.h"
 
22
 
 
23
#include <stdio.h>
 
24
#include <string.h>
 
25
#include <ctype.h>
 
26
 
 
27
#include "pgapifunc.h"
 
28
 
 
29
 
 
30
#define PRN_NULLCHECK
 
31
 
 
32
 
 
33
/*      Map sql commands to statement types */
 
34
static struct
 
35
{
 
36
        int                     type;
 
37
        char       *s;
 
38
}       Statement_Type[] =
 
39
 
 
40
{
 
41
        {
 
42
                STMT_TYPE_SELECT, "SELECT"
 
43
        },
 
44
        {
 
45
                STMT_TYPE_INSERT, "INSERT"
 
46
        },
 
47
        {
 
48
                STMT_TYPE_UPDATE, "UPDATE"
 
49
        },
 
50
        {
 
51
                STMT_TYPE_DELETE, "DELETE"
 
52
        },
 
53
        {
 
54
                STMT_TYPE_CREATE, "CREATE"
 
55
        },
 
56
        {
 
57
                STMT_TYPE_ALTER, "ALTER"
 
58
        },
 
59
        {
 
60
                STMT_TYPE_DROP, "DROP"
 
61
        },
 
62
        {
 
63
                STMT_TYPE_GRANT, "GRANT"
 
64
        },
 
65
        {
 
66
                STMT_TYPE_REVOKE, "REVOKE"
 
67
        },
 
68
        {
 
69
                STMT_TYPE_PROCCALL, "{"
 
70
        },
 
71
        {
 
72
                STMT_TYPE_LOCK, "LOCK"
 
73
        },
 
74
        {
 
75
                0, NULL
 
76
        }
 
77
};
 
78
 
 
79
 
 
80
RETCODE         SQL_API
 
81
PGAPI_AllocStmt(HDBC hdbc,
 
82
                                HSTMT FAR * phstmt)
 
83
{
 
84
        CSTR func = "PGAPI_AllocStmt";
 
85
        ConnectionClass *conn = (ConnectionClass *) hdbc;
 
86
        StatementClass *stmt;
 
87
 
 
88
        mylog("%s: entering...\n", func);
 
89
 
 
90
        if (!conn)
 
91
        {
 
92
                CC_log_error(func, "", NULL);
 
93
                return SQL_INVALID_HANDLE;
 
94
        }
 
95
 
 
96
        stmt = SC_Constructor();
 
97
 
 
98
        mylog("**** PGAPI_AllocStmt: hdbc = %u, stmt = %u\n", hdbc, stmt);
 
99
 
 
100
        if (!stmt)
 
101
        {
 
102
                CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "No more memory to allocate a further SQL-statement");
 
103
                *phstmt = SQL_NULL_HSTMT;
 
104
                CC_log_error(func, "", conn);
 
105
                return SQL_ERROR;
 
106
        }
 
107
 
 
108
        if (!CC_add_statement(conn, stmt))
 
109
        {
 
110
                CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "Maximum number of connections exceeded.");
 
111
                CC_log_error(func, "", conn);
 
112
                SC_Destructor(stmt);
 
113
                *phstmt = SQL_NULL_HSTMT;
 
114
                return SQL_ERROR;
 
115
        }
 
116
 
 
117
        *phstmt = (HSTMT) stmt;
 
118
 
 
119
        /* Copy default statement options based from Connection options */
 
120
        stmt->options = stmt->options_orig = conn->stmtOptions;
 
121
        stmt->ardopts = conn->ardOptions;
 
122
        stmt->ardopts.bookmark = (BindInfoClass *) malloc(sizeof(BindInfoClass));
 
123
        stmt->ardopts.bookmark->buffer = NULL;
 
124
        stmt->ardopts.bookmark->used = NULL;
 
125
 
 
126
        stmt->stmt_size_limit = CC_get_max_query_len(conn);
 
127
        /* Save the handle for later */
 
128
        stmt->phstmt = phstmt;
 
129
 
 
130
        return SQL_SUCCESS;
 
131
}
 
132
 
 
133
 
 
134
RETCODE         SQL_API
 
135
PGAPI_FreeStmt(HSTMT hstmt,
 
136
                           UWORD fOption)
 
137
{
 
138
        CSTR func = "PGAPI_FreeStmt";
 
139
        StatementClass *stmt = (StatementClass *) hstmt;
 
140
 
 
141
        mylog("%s: entering...hstmt=%u, fOption=%d\n", func, hstmt, fOption);
 
142
 
 
143
        if (!stmt)
 
144
        {
 
145
                SC_log_error(func, "", NULL);
 
146
                return SQL_INVALID_HANDLE;
 
147
        }
 
148
        SC_clear_error(stmt);
 
149
 
 
150
        if (fOption == SQL_DROP)
 
151
        {
 
152
                ConnectionClass *conn = stmt->hdbc;
 
153
 
 
154
                /* Remove the statement from the connection's statement list */
 
155
                if (conn)
 
156
                {
 
157
                        QResultClass    *res;
 
158
 
 
159
                        if (!CC_remove_statement(conn, stmt))
 
160
                        {
 
161
                                SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.");
 
162
                                SC_log_error(func, "", stmt);
 
163
                                return SQL_ERROR;               /* stmt may be executing a
 
164
                                                                                 * transaction */
 
165
                        }
 
166
 
 
167
                        /* Free any cursors and discard any result info */
 
168
                        if (res = SC_get_Result(stmt), res)
 
169
                        {
 
170
                                QR_Destructor(res);
 
171
                                SC_set_Result(stmt,  NULL);
 
172
                        }
 
173
                }
 
174
 
 
175
                /* Destroy the statement and free any results, cursors, etc. */
 
176
                SC_Destructor(stmt);
 
177
        }
 
178
        else if (fOption == SQL_UNBIND)
 
179
                SC_unbind_cols(stmt);
 
180
        else if (fOption == SQL_CLOSE)
 
181
        {
 
182
                /*
 
183
                 * this should discard all the results, but leave the statement
 
184
                 * itself in place (it can be executed again)
 
185
                 */
 
186
                stmt->transition_status = 0;
 
187
                if (!SC_recycle_statement(stmt))
 
188
                {
 
189
                        /* errormsg passed in above */
 
190
                        SC_log_error(func, "", stmt);
 
191
                        return SQL_ERROR;
 
192
                }
 
193
        }
 
194
        else if (fOption == SQL_RESET_PARAMS)
 
195
                SC_free_params(stmt, STMT_FREE_PARAMS_ALL);
 
196
        else
 
197
        {
 
198
                SC_set_error(stmt, STMT_OPTION_OUT_OF_RANGE_ERROR, "Invalid option passed to PGAPI_FreeStmt.");
 
199
                SC_log_error(func, "", stmt);
 
200
                return SQL_ERROR;
 
201
        }
 
202
 
 
203
        return SQL_SUCCESS;
 
204
}
 
205
 
 
206
 
 
207
/*
 
208
 * StatementClass implementation
 
209
 */
 
210
void
 
211
InitializeStatementOptions(StatementOptions *opt)
 
212
{
 
213
        memset(opt, 0, sizeof(StatementOptions));
 
214
        opt->maxRows = 0;               /* driver returns all rows */
 
215
        opt->maxLength = 0;             /* driver returns all data for char/binary */
 
216
        opt->keyset_size = 0;           /* fully keyset driven is the default */
 
217
        opt->scroll_concurrency = SQL_CONCUR_READ_ONLY;
 
218
        opt->cursor_type = SQL_CURSOR_FORWARD_ONLY;
 
219
        opt->retrieve_data = SQL_RD_ON;
 
220
        opt->use_bookmarks = SQL_UB_OFF;
 
221
#if (ODBCVER >= 0x0300)
 
222
        opt->metadata_id = SQL_FALSE;
 
223
#endif /* ODBCVER */
 
224
}
 
225
 
 
226
 
 
227
/*
 
228
 * ARDFields initialize
 
229
 */
 
230
void
 
231
InitializeARDFields(ARDFields *opt)
 
232
{
 
233
        memset(opt, 0, sizeof(ARDFields));
 
234
#if (ODBCVER >= 0x0300)
 
235
        opt->size_of_rowset = 1;
 
236
#endif /* ODBCVER */
 
237
        opt->bind_size = 0;             /* default is to bind by column */
 
238
        opt->size_of_rowset_odbc2 = 1;
 
239
}
 
240
/*
 
241
 * APDFields initialize
 
242
 */
 
243
void
 
244
InitializeAPDFields(APDFields *opt)
 
245
{
 
246
        memset(opt, 0, sizeof(APDFields));
 
247
        opt->paramset_size = 1;
 
248
        opt->param_bind_type = 0;       /* default is to bind by column */
 
249
}
 
250
 
 
251
 
 
252
StatementClass *
 
253
SC_Constructor(void)
 
254
{
 
255
        StatementClass *rv;
 
256
 
 
257
        rv = (StatementClass *) malloc(sizeof(StatementClass));
 
258
        if (rv)
 
259
        {
 
260
                rv->hdbc = NULL;                /* no connection associated yet */
 
261
                rv->phstmt = NULL;
 
262
                rv->result = NULL;
 
263
                rv->curres = NULL;
 
264
                rv->manual_result = FALSE;
 
265
                rv->prepare = FALSE;
 
266
                rv->prepared = FALSE;
 
267
                rv->status = STMT_ALLOCATED;
 
268
                rv->internal = FALSE;
 
269
                rv->transition_status = 0;
 
270
 
 
271
                rv->__error_message = NULL;
 
272
                rv->__error_number = 0;
 
273
                rv->errormsg_created = FALSE;
 
274
 
 
275
                rv->statement = NULL;
 
276
                rv->stmt_with_params = NULL;
 
277
                rv->load_statement = NULL;
 
278
                rv->execute_statement = NULL;
 
279
                rv->stmt_size_limit = -1;
 
280
                rv->statement_type = STMT_TYPE_UNKNOWN;
 
281
 
 
282
                rv->currTuple = -1;
 
283
                rv->rowset_start = -1;
 
284
                rv->current_col = -1;
 
285
                rv->bind_row = 0;
 
286
                rv->last_fetch_count = rv->last_fetch_count_include_ommitted = 0;
 
287
                rv->save_rowset_size = -1;
 
288
 
 
289
                rv->data_at_exec = -1;
 
290
                rv->current_exec_param = -1;
 
291
                rv->exec_start_row = -1;
 
292
                rv->exec_end_row = -1;
 
293
                rv->exec_current_row = -1;
 
294
                rv->put_data = FALSE;
 
295
 
 
296
                rv->lobj_fd = -1;
 
297
                rv->cursor_name[0] = '\0';
 
298
 
 
299
                /* Parse Stuff */
 
300
                rv->ti = NULL;
 
301
                rv->ntab = 0;
 
302
                rv->parse_status = STMT_PARSE_NONE;
 
303
 
 
304
                /* Clear Statement Options -- defaults will be set in AllocStmt */
 
305
                memset(&rv->options, 0, sizeof(StatementOptions));
 
306
                memset(&rv->ardopts, 0, sizeof(ARDFields));
 
307
                memset(&rv->apdopts, 0, sizeof(APDFields));
 
308
                memset(&rv->irdopts, 0, sizeof(IRDFields));
 
309
                memset(&rv->ipdopts, 0, sizeof(IPDFields));
 
310
 
 
311
                rv->pre_executing = FALSE;
 
312
                rv->inaccurate_result = FALSE;
 
313
                rv->miscinfo = 0;
 
314
                rv->updatable = FALSE;
 
315
                rv->error_recsize = -1;
 
316
                rv->diag_row_count = 0;
 
317
                rv->stmt_time = 0;
 
318
                INIT_STMT_CS(rv);
 
319
        }
 
320
        return rv;
 
321
}
 
322
 
 
323
 
 
324
void ARDFields_free(ARDFields * self)
 
325
{
 
326
        if (self->bookmark)
 
327
        {
 
328
                free(self->bookmark);
 
329
                self->bookmark = NULL;
 
330
        }
 
331
        /*
 
332
         * the memory pointed to by the bindings is not deallocated by the
 
333
         * driver but by the application that uses that driver, so we don't
 
334
         * have to care
 
335
         */
 
336
        ARD_unbind_cols(self, TRUE);
 
337
}
 
338
 
 
339
void APDFields_free(APDFields * self)
 
340
{
 
341
        /* param bindings */
 
342
        APD_free_params(self, STMT_FREE_PARAMS_ALL);
 
343
}
 
344
 
 
345
void IRDFields_free(IRDFields * self)
 
346
{
 
347
        /* Free the parsed field information */
 
348
        if (self->fi)
 
349
        {
 
350
                int                     i;
 
351
 
 
352
                for (i = 0; i < (int) self->nfields; i++)
 
353
                {
 
354
                        if (self->fi[i])
 
355
                        {
 
356
                                if (self->fi[i]->schema)
 
357
                                        free(self->fi[i]->schema);
 
358
                                free(self->fi[i]);
 
359
                        }
 
360
                }
 
361
                free(self->fi);
 
362
                self->fi = NULL;
 
363
        }
 
364
}
 
365
 
 
366
void IPDFields_free(IPDFields * self)
 
367
{
 
368
        /* param bindings */
 
369
        IPD_free_params(self, STMT_FREE_PARAMS_ALL);
 
370
}
 
371
 
 
372
char
 
373
SC_Destructor(StatementClass *self)
 
374
{
 
375
        QResultClass    *res = SC_get_Result(self);
 
376
 
 
377
        if (!self)      return FALSE;
 
378
        mylog("SC_Destructor: self=%u, self->result=%u, self->hdbc=%u\n", self, res, self->hdbc);
 
379
        SC_clear_error(self);
 
380
        if (STMT_EXECUTING == self->status)
 
381
        {
 
382
                SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.");
 
383
                return FALSE;
 
384
        }
 
385
 
 
386
        if (res)
 
387
        {
 
388
                if (!self->hdbc)
 
389
                        res->conn = NULL;       /* prevent any dbase activity */
 
390
 
 
391
                QR_Destructor(res);
 
392
        }
 
393
 
 
394
        SC_initialize_stmts(self, TRUE);
 
395
 
 
396
        /* Free the parsed table information */
 
397
        if (self->ti)
 
398
        {
 
399
                int     i;
 
400
 
 
401
                for (i = 0; i < self->ntab; i++)
 
402
                        if (self->ti[i])
 
403
                                free(self->ti[i]);
 
404
 
 
405
                free(self->ti);
 
406
                self->ti = NULL;
 
407
        }
 
408
 
 
409
        /* Free the parsed field information */
 
410
        ARDFields_free(&(self->ardopts));
 
411
        APDFields_free(&(self->apdopts));
 
412
        IRDFields_free(&(self->irdopts));
 
413
        IPDFields_free(&(self->ipdopts));
 
414
        
 
415
        if (self->__error_message)
 
416
                free(self->__error_message);
 
417
        DELETE_STMT_CS(self);
 
418
        free(self);
 
419
 
 
420
        mylog("SC_Destructor: EXIT\n");
 
421
 
 
422
        return TRUE;
 
423
}
 
424
 
 
425
 
 
426
/*
 
427
 *      Free parameters and free the memory from the
 
428
 *      data-at-execution parameters that was allocated in SQLPutData.
 
429
 */
 
430
void
 
431
SC_free_params(StatementClass *self, char option)
 
432
{
 
433
        APD_free_params(SC_get_APD(self), option);
 
434
        IPD_free_params(SC_get_IPD(self), option);
 
435
        self->data_at_exec = -1;
 
436
        self->current_exec_param = -1;
 
437
        self->put_data = FALSE;
 
438
        if (option == STMT_FREE_PARAMS_ALL)
 
439
        {
 
440
                self->exec_start_row = -1;
 
441
                self->exec_end_row = -1;
 
442
                self->exec_current_row = -1;
 
443
        }
 
444
}
 
445
 
 
446
 
 
447
int
 
448
statement_type(const char *statement)
 
449
{
 
450
        int                     i;
 
451
 
 
452
        /* ignore leading whitespace in query string */
 
453
        while (*statement && (isspace((unsigned char) *statement) || *statement == '('))
 
454
                statement++;
 
455
 
 
456
        for (i = 0; Statement_Type[i].s; i++)
 
457
                if (!strnicmp(statement, Statement_Type[i].s, strlen(Statement_Type[i].s)))
 
458
                        return Statement_Type[i].type;
 
459
 
 
460
        return STMT_TYPE_OTHER;
 
461
}
 
462
 
 
463
void
 
464
SC_set_prepared(StatementClass *stmt, BOOL prepared)
 
465
{
 
466
        if (prepared == stmt->prepared)
 
467
                return;
 
468
        if (!prepared)
 
469
        {
 
470
                ConnectionClass *conn = SC_get_conn(stmt);
 
471
                if (CONN_CONNECTED == conn->status)
 
472
                {
 
473
                        QResultClass    *res;
 
474
                        char dealloc_stmt[128];
 
475
 
 
476
                        sprintf(dealloc_stmt, "DEALLOCATE _PLAN%0x", stmt);
 
477
                        res = CC_send_query(conn, dealloc_stmt, NULL, 0);
 
478
                        if (res)
 
479
                                QR_Destructor(res); 
 
480
                }
 
481
        }
 
482
        stmt->prepared = prepared;
 
483
}
 
484
 
 
485
/*
 
486
 *      Initialize stmt_with_params, load_statement and execute_statement
 
487
 *              member pointer deallocating corresponding prepared plan.
 
488
 *      Also initialize statement member pointer if specified.
 
489
 */
 
490
RETCODE
 
491
SC_initialize_stmts(StatementClass *self, BOOL initializeOriginal)
 
492
{
 
493
        if (initializeOriginal)
 
494
        {
 
495
                if (self->statement)
 
496
                {
 
497
                        free(self->statement);
 
498
                        self->statement = NULL;
 
499
                }
 
500
                if (self->execute_statement)
 
501
                {
 
502
                        free(self->execute_statement);
 
503
                        self->execute_statement = NULL;
 
504
                }
 
505
                SC_set_prepared(self,FALSE);
 
506
        }
 
507
        if (self->stmt_with_params)
 
508
        {
 
509
                free(self->stmt_with_params);
 
510
                self->stmt_with_params = NULL;
 
511
        }
 
512
        if (self->load_statement)
 
513
        {
 
514
                free(self->load_statement);
 
515
                self->load_statement = NULL;
 
516
        }
 
517
 
 
518
        return 0;
 
519
}
 
520
 
 
521
/*
 
522
 *      Called from SQLPrepare if STMT_PREMATURE, or
 
523
 *      from SQLExecute if STMT_FINISHED, or
 
524
 *      from SQLFreeStmt(SQL_CLOSE)
 
525
 */
 
526
char
 
527
SC_recycle_statement(StatementClass *self)
 
528
{
 
529
        ConnectionClass *conn;
 
530
        QResultClass    *res;
 
531
 
 
532
        mylog("recycle statement: self= %u\n", self);
 
533
 
 
534
        SC_clear_error(self);
 
535
        /* This would not happen */
 
536
        if (self->status == STMT_EXECUTING)
 
537
        {
 
538
                SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.");
 
539
                return FALSE;
 
540
        }
 
541
 
 
542
        switch (self->status)
 
543
        {
 
544
                case STMT_ALLOCATED:
 
545
                        /* this statement does not need to be recycled */
 
546
                        return TRUE;
 
547
 
 
548
                case STMT_READY:
 
549
                        break;
 
550
 
 
551
                case STMT_PREMATURE:
 
552
 
 
553
                        /*
 
554
                         * Premature execution of the statement might have caused the
 
555
                         * start of a transaction. If so, we have to rollback that
 
556
                         * transaction.
 
557
                         */
 
558
                        conn = SC_get_conn(self);
 
559
                        if (!CC_is_in_autocommit(conn) && CC_is_in_trans(conn))
 
560
                        {
 
561
                                if (SC_is_pre_executable(self) && !conn->connInfo.disallow_premature)
 
562
                                        CC_abort(conn);
 
563
                        }
 
564
                        break;
 
565
 
 
566
                case STMT_FINISHED:
 
567
                        break;
 
568
 
 
569
                default:
 
570
                        SC_set_error(self, STMT_INTERNAL_ERROR, "An internal error occured while recycling statements");
 
571
                        return FALSE;
 
572
        }
 
573
 
 
574
        /* Free the parsed table information */
 
575
        if (self->ti)
 
576
        {
 
577
                int     i;
 
578
 
 
579
                for (i = 0; i < self->ntab; i++)
 
580
                        if (self->ti[i])
 
581
                                free(self->ti[i]);
 
582
                self->ti = NULL;
 
583
                self->ntab = 0;
 
584
        }
 
585
        /* Free the parsed field information */
 
586
        IRDFields_free(SC_get_IRD(self));
 
587
 
 
588
        self->parse_status = STMT_PARSE_NONE;
 
589
        self->updatable = FALSE;
 
590
 
 
591
        /* Free any cursors */
 
592
        if (res = SC_get_Result(self), res)
 
593
        {
 
594
                QR_Destructor(res);
 
595
                SC_set_Result(self, NULL);
 
596
        }
 
597
        self->inaccurate_result = FALSE;
 
598
 
 
599
        /*
 
600
         * Reset only parameters that have anything to do with results
 
601
         */
 
602
        self->status = STMT_READY;
 
603
        self->manual_result = FALSE;    /* very important */
 
604
 
 
605
        self->currTuple = -1;
 
606
        self->rowset_start = -1;
 
607
        self->current_col = -1;
 
608
        self->bind_row = 0;
 
609
        self->last_fetch_count = self->last_fetch_count_include_ommitted = 0;
 
610
 
 
611
        self->__error_message = NULL;
 
612
        self->__error_number = 0;
 
613
        self->errormsg_created = FALSE;
 
614
 
 
615
        self->lobj_fd = -1;
 
616
 
 
617
        /*
 
618
         * Free any data at exec params before the statement is executed
 
619
         * again.  If not, then there will be a memory leak when the next
 
620
         * SQLParamData/SQLPutData is called.
 
621
         */
 
622
        SC_free_params(self, STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY);
 
623
        SC_initialize_stmts(self, FALSE);
 
624
        /*
 
625
         *      reset the current attr setting to the original one.
 
626
         */
 
627
        self->options.scroll_concurrency = self->options_orig.scroll_concurrency;
 
628
        self->options.cursor_type = self->options_orig.cursor_type;
 
629
        self->options.keyset_size = self->options_orig.keyset_size;
 
630
        self->options.maxLength = self->options_orig.maxLength;
 
631
        self->options.maxRows = self->options_orig.maxRows;
 
632
 
 
633
        return TRUE;
 
634
}
 
635
 
 
636
 
 
637
/* Pre-execute a statement (SQLPrepare/SQLDescribeCol) */
 
638
void
 
639
SC_pre_execute(StatementClass *self)
 
640
{
 
641
        mylog("SC_pre_execute: status = %d\n", self->status);
 
642
 
 
643
        if (self->status == STMT_READY)
 
644
        {
 
645
                mylog("              preprocess: status = READY\n");
 
646
 
 
647
                self->miscinfo = 0;
 
648
                if (self->statement_type == STMT_TYPE_SELECT)
 
649
                {
 
650
                        char            old_pre_executing = self->pre_executing;
 
651
 
 
652
                        self->pre_executing = TRUE;
 
653
                        self->inaccurate_result = FALSE;
 
654
 
 
655
                        PGAPI_Execute(self);
 
656
 
 
657
                        self->pre_executing = old_pre_executing;
 
658
 
 
659
                        if (self->status == STMT_FINISHED)
 
660
                        {
 
661
                                mylog("              preprocess: after status = FINISHED, so set PREMATURE\n");
 
662
                                self->status = STMT_PREMATURE;
 
663
                        }
 
664
                }
 
665
                if (!SC_is_pre_executable(self))
 
666
                {
 
667
                        SC_set_Result(self, QR_Constructor());
 
668
                        QR_set_status(SC_get_Result(self), PGRES_TUPLES_OK);
 
669
                        self->inaccurate_result = TRUE;
 
670
                        self->status = STMT_PREMATURE;
 
671
                }
 
672
        }
 
673
}
 
674
 
 
675
 
 
676
/* This is only called from SQLFreeStmt(SQL_UNBIND) */
 
677
char
 
678
SC_unbind_cols(StatementClass *self)
 
679
{
 
680
        ARDFields       *opts = SC_get_ARD(self);
 
681
 
 
682
        ARD_unbind_cols(opts, FALSE);
 
683
        opts->bookmark->buffer = NULL;
 
684
        opts->bookmark->used = NULL;
 
685
 
 
686
        return 1;
 
687
}
 
688
 
 
689
 
 
690
void
 
691
SC_clear_error(StatementClass *self)
 
692
{
 
693
        self->__error_number = 0;
 
694
        if (self->__error_message)
 
695
                free(self->__error_message);
 
696
        self->__error_message = NULL;
 
697
        self->errormsg_created = FALSE;
 
698
        self->errorpos = 0;
 
699
        self->error_recsize = -1;
 
700
        self->diag_row_count = 0;
 
701
}
 
702
 
 
703
 
 
704
/*
 
705
 *      This function creates an error msg which is the concatenation
 
706
 *      of the result, statement, connection, and socket messages.
 
707
 */
 
708
char *
 
709
SC_create_errormsg(const StatementClass *self)
 
710
{
 
711
        QResultClass *res = SC_get_Curres(self);
 
712
        ConnectionClass *conn = self->hdbc;
 
713
        int                     pos;
 
714
        BOOL                    detailmsg = FALSE;
 
715
        char                     msg[4096];
 
716
 
 
717
        msg[0] = '\0';
 
718
 
 
719
        if (res && res->message)
 
720
        {
 
721
                strncpy(msg, res->message, sizeof(msg));
 
722
                detailmsg = TRUE;
 
723
        }
 
724
        else if (SC_get_errormsg(self))
 
725
                strncpy(msg, SC_get_errormsg(self), sizeof(msg));
 
726
 
 
727
        if (!msg[0] && res && QR_get_notice(res))
 
728
        {
 
729
                char *notice = QR_get_notice(res);
 
730
                int len = strlen(notice);
 
731
                if (len < sizeof(msg))
 
732
                {
 
733
                        memcpy(msg, notice, len);
 
734
                        msg[len] = '\0';
 
735
                }
 
736
                else
 
737
                        return strdup(notice);
 
738
        }
 
739
        if (conn)
 
740
        {
 
741
                SocketClass *sock = conn->sock;
 
742
 
 
743
                if (!detailmsg && CC_get_errormsg(conn) && (CC_get_errormsg(conn))[0] != '\0')
 
744
                {
 
745
                        pos = strlen(msg);
 
746
                        sprintf(&msg[pos], ";\n%s", CC_get_errormsg(conn));
 
747
                }
 
748
 
 
749
                if (sock && sock->errormsg && sock->errormsg[0] != '\0')
 
750
                {
 
751
                        pos = strlen(msg);
 
752
                        sprintf(&msg[pos], ";\n%s", sock->errormsg);
 
753
                }
 
754
        }
 
755
        return msg[0] ? strdup(msg) : NULL;
 
756
}
 
757
 
 
758
 
 
759
void
 
760
SC_set_error(StatementClass *self, int number, const char *message)
 
761
{
 
762
        if (self->__error_message)
 
763
                free(self->__error_message);
 
764
        self->__error_number = number;
 
765
        self->__error_message = message ? strdup(message) : NULL;
 
766
}
 
767
 
 
768
 
 
769
void
 
770
SC_set_errormsg(StatementClass *self, const char *message)
 
771
{
 
772
        if (self->__error_message)
 
773
                free(self->__error_message);
 
774
        self->__error_message = message ? strdup(message) : NULL;
 
775
}
 
776
 
 
777
 
 
778
void
 
779
SC_error_copy(StatementClass *self, const StatementClass *from)
 
780
{
 
781
        if (self->__error_message)
 
782
                free(self->__error_message);
 
783
        self->__error_number = from->__error_number;
 
784
        self->__error_message = from->__error_message ? strdup(from->__error_message) : NULL;
 
785
}
 
786
 
 
787
 
 
788
void
 
789
SC_full_error_copy(StatementClass *self, const StatementClass *from)
 
790
{
 
791
        if (self->__error_message)
 
792
                free(self->__error_message);
 
793
        self->__error_number = from->__error_number;
 
794
        self->__error_message = SC_create_errormsg(from);
 
795
        self->errormsg_created = TRUE;
 
796
}
 
797
 
 
798
char
 
799
SC_get_error(StatementClass *self, int *number, char **message)
 
800
{
 
801
        char    rv, *msgcrt;
 
802
 
 
803
        /* Create a very informative errormsg if it hasn't been done yet. */
 
804
        if (!self->errormsg_created)
 
805
        {
 
806
                msgcrt = SC_create_errormsg(self);
 
807
                if (self->__error_message)
 
808
                        free(self->__error_message);
 
809
                self->__error_message = msgcrt; 
 
810
                self->errormsg_created = TRUE;
 
811
                self->errorpos = 0;
 
812
                self->error_recsize = -1;
 
813
        }
 
814
 
 
815
        if (SC_get_errornumber(self))
 
816
        {
 
817
                *number = SC_get_errornumber(self);
 
818
                *message = self->__error_message;
 
819
        }
 
820
 
 
821
        rv = (SC_get_errornumber(self) != 0);
 
822
 
 
823
        return rv;
 
824
}
 
825
 
 
826
 
 
827
time_t
 
828
SC_get_time(StatementClass *stmt)
 
829
{
 
830
        if (!stmt)
 
831
                return time(NULL);
 
832
        if (!stmt->stmt_time)
 
833
                stmt->stmt_time = time(NULL);
 
834
        return stmt->stmt_time;
 
835
}
 
836
/*
 
837
 *      Currently, the driver offers very simple bookmark support -- it is
 
838
 *      just the current row number.  But it could be more sophisticated
 
839
 *      someday, such as mapping a key to a 32 bit value
 
840
 */
 
841
unsigned long
 
842
SC_get_bookmark(StatementClass *self)
 
843
{
 
844
        return (self->currTuple + 1);
 
845
}
 
846
 
 
847
 
 
848
RETCODE
 
849
SC_fetch(StatementClass *self)
 
850
{
 
851
        CSTR func = "SC_fetch";
 
852
        QResultClass *res = SC_get_Curres(self);
 
853
        ARDFields       *opts;
 
854
        int                     retval,
 
855
                                result;
 
856
 
 
857
        Int2            num_cols,
 
858
                                lf;
 
859
        Oid                     type;
 
860
        char       *value;
 
861
        ColumnInfoClass *coli;
 
862
 
 
863
        /* TupleField *tupleField; */
 
864
        ConnInfo   *ci = &(SC_get_conn(self)->connInfo);
 
865
 
 
866
        self->last_fetch_count = self->last_fetch_count_include_ommitted = 0;
 
867
        coli = QR_get_fields(res);      /* the column info */
 
868
 
 
869
        mylog("manual_result = %d, use_declarefetch = %d\n", self->manual_result, ci->drivers.use_declarefetch);
 
870
 
 
871
        if (self->manual_result || !SC_is_fetchcursor(self))
 
872
        {
 
873
                if (self->currTuple >= QR_get_num_total_tuples(res) - 1 ||
 
874
                        (self->options.maxRows > 0 && self->currTuple == self->options.maxRows - 1))
 
875
                {
 
876
                        /*
 
877
                         * if at the end of the tuples, return "no data found" and set
 
878
                         * the cursor past the end of the result set
 
879
                         */
 
880
                        self->currTuple = QR_get_num_total_tuples(res);
 
881
                        return SQL_NO_DATA_FOUND;
 
882
                }
 
883
 
 
884
                mylog("**** SC_fetch: manual_result\n");
 
885
                (self->currTuple)++;
 
886
        }
 
887
        else
 
888
        {
 
889
                /* read from the cache or the physical next tuple */
 
890
                retval = QR_next_tuple(res);
 
891
                if (retval < 0)
 
892
                {
 
893
                        mylog("**** SC_fetch: end_tuples\n");
 
894
                        return SQL_NO_DATA_FOUND;
 
895
                }
 
896
                else if (retval > 0)
 
897
                        (self->currTuple)++;    /* all is well */
 
898
                else
 
899
                {
 
900
                        mylog("SC_fetch: error\n");
 
901
                        SC_set_error(self, STMT_EXEC_ERROR, "Error fetching next row");
 
902
                        SC_log_error(func, "", self);
 
903
                        return SQL_ERROR;
 
904
                }
 
905
        }
 
906
#ifdef  DRIVER_CURSOR_IMPLEMENT
 
907
        if (res->haskeyset)
 
908
        {
 
909
                UWORD   pstatus = res->keyset[self->currTuple].status;
 
910
                if (0 != (pstatus & (CURS_SELF_DELETING | CURS_SELF_DELETED)))
 
911
                        return SQL_SUCCESS_WITH_INFO;
 
912
                if (SQL_ROW_DELETED != (pstatus & KEYSET_INFO_PUBLIC) &&
 
913
                    0 != (pstatus & CURS_OTHER_DELETED))
 
914
                        return SQL_SUCCESS_WITH_INFO;
 
915
        }
 
916
#endif   /* DRIVER_CURSOR_IMPLEMENT */
 
917
 
 
918
        num_cols = QR_NumPublicResultCols(res);
 
919
 
 
920
        result = SQL_SUCCESS;
 
921
        self->last_fetch_count++;
 
922
        self->last_fetch_count_include_ommitted++;
 
923
 
 
924
        opts = SC_get_ARD(self);
 
925
        /*
 
926
         * If the bookmark column was bound then return a bookmark. Since this
 
927
         * is used with SQLExtendedFetch, and the rowset size may be greater
 
928
         * than 1, and an application can use row or column wise binding, use
 
929
         * the code in copy_and_convert_field() to handle that.
 
930
         */
 
931
        if (opts->bookmark->buffer)
 
932
        {
 
933
                char            buf[32];
 
934
                UInt4   offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
 
935
 
 
936
                sprintf(buf, "%ld", SC_get_bookmark(self));
 
937
                result = copy_and_convert_field(self, 0, buf,
 
938
                         SQL_C_ULONG, opts->bookmark->buffer + offset, 0,
 
939
                        opts->bookmark->used ? opts->bookmark->used + (offset >> 2) : NULL);
 
940
        }
 
941
 
 
942
        if (self->options.retrieve_data == SQL_RD_OFF)          /* data isn't required */
 
943
                return SQL_SUCCESS;
 
944
        for (lf = 0; lf < num_cols; lf++)
 
945
        {
 
946
                mylog("fetch: cols=%d, lf=%d, opts = %u, opts->bindings = %u, buffer[] = %u\n", num_cols, lf, opts, opts->bindings, opts->bindings[lf].buffer);
 
947
 
 
948
                /* reset for SQLGetData */
 
949
                opts->bindings[lf].data_left = -1;
 
950
 
 
951
                if (opts->bindings[lf].buffer != NULL)
 
952
                {
 
953
                        /* this column has a binding */
 
954
 
 
955
                        /* type = QR_get_field_type(res, lf); */
 
956
                        type = CI_get_oid(coli, lf);            /* speed things up */
 
957
 
 
958
                        mylog("type = %d\n", type);
 
959
 
 
960
                        if (self->manual_result)
 
961
                        {
 
962
                                value = QR_get_value_manual(res, self->currTuple, lf);
 
963
                                mylog("manual_result\n");
 
964
                        }
 
965
                        else if (SC_is_fetchcursor(self))
 
966
                                value = QR_get_value_backend(res, lf);
 
967
                        else
 
968
                        {
 
969
                                int     curt = GIdx2ResultIdx(self->currTuple, self, res);
 
970
                                value = QR_get_value_backend_row(res, curt, lf);
 
971
                        }
 
972
 
 
973
                        mylog("value = '%s'\n", (value == NULL) ? "<NULL>" : value);
 
974
 
 
975
                        retval = copy_and_convert_field_bindinfo(self, type, value, lf);
 
976
 
 
977
                        mylog("copy_and_convert: retval = %d\n", retval);
 
978
 
 
979
                        switch (retval)
 
980
                        {
 
981
                                case COPY_OK:
 
982
                                        break;          /* OK, do next bound column */
 
983
 
 
984
                                case COPY_UNSUPPORTED_TYPE:
 
985
                                        SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR, "Received an unsupported type from Postgres.");
 
986
                                        SC_log_error(func, "", self);
 
987
                                        result = SQL_ERROR;
 
988
                                        break;
 
989
 
 
990
                                case COPY_UNSUPPORTED_CONVERSION:
 
991
                                        SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR, "Couldn't handle the necessary data type conversion.");
 
992
                                        SC_log_error(func, "", self);
 
993
                                        result = SQL_ERROR;
 
994
                                        break;
 
995
 
 
996
                                case COPY_RESULT_TRUNCATED:
 
997
                                        SC_set_error(self, STMT_TRUNCATED, "Fetched item was truncated.");
 
998
                                        qlog("The %dth item was truncated\n", lf + 1);
 
999
                                        qlog("The buffer size = %d", opts->bindings[lf].buflen);
 
1000
                                        qlog(" and the value is '%s'\n", value);
 
1001
                                        result = SQL_SUCCESS_WITH_INFO;
 
1002
                                        break;
 
1003
 
 
1004
                                        /* error msg already filled in */
 
1005
                                case COPY_GENERAL_ERROR:
 
1006
                                        SC_log_error(func, "", self);
 
1007
                                        result = SQL_ERROR;
 
1008
                                        break;
 
1009
 
 
1010
                                        /* This would not be meaningful in SQLFetch. */
 
1011
                                case COPY_NO_DATA_FOUND:
 
1012
                                        break;
 
1013
 
 
1014
                                default:
 
1015
                                        SC_set_error(self, STMT_INTERNAL_ERROR, "Unrecognized return value from copy_and_convert_field.");
 
1016
                                        SC_log_error(func, "", self);
 
1017
                                        result = SQL_ERROR;
 
1018
                                        break;
 
1019
                        }
 
1020
                }
 
1021
        }
 
1022
 
 
1023
        return result;
 
1024
}
 
1025
 
 
1026
 
 
1027
RETCODE
 
1028
SC_execute(StatementClass *self)
 
1029
{
 
1030
        CSTR func = "SC_execute";
 
1031
        ConnectionClass *conn;
 
1032
        APDFields       *apdopts;
 
1033
        char            was_ok, was_nonfatal, was_rows_affected = 1;
 
1034
        /* was_rows_affected is set to 0 iff an UPDATE or DELETE affects 
 
1035
         * no rows. In this instance the driver should return
 
1036
         * SQL_NO_DATA_FOUND instead of SQL_SUCCESS.
 
1037
         */
 
1038
 
 
1039
        QResultClass    *res = NULL;
 
1040
        Int2            oldstatus,
 
1041
                                numcols;
 
1042
        QueryInfo       qi;
 
1043
        ConnInfo   *ci;
 
1044
        UDWORD          qflag = 0;
 
1045
        BOOL            auto_begin = FALSE, is_in_trans;
 
1046
 
 
1047
 
 
1048
        conn = SC_get_conn(self);
 
1049
        ci = &(conn->connInfo);
 
1050
 
 
1051
        /* Begin a transaction if one is not already in progress */
 
1052
 
 
1053
        /*
 
1054
         * Basically we don't have to begin a transaction in autocommit mode
 
1055
         * because Postgres backend runs in autocomit mode. We issue "BEGIN"
 
1056
         * in the following cases. 1) we use declare/fetch and the statement
 
1057
         * is SELECT (because declare/fetch must be called in a transaction).
 
1058
         * 2) we are in autocommit off state and the statement isn't of type
 
1059
         * OTHER.
 
1060
         */
 
1061
        ENTER_CONN_CS(conn);
 
1062
        if (CONN_EXECUTING == conn->status)
 
1063
        {
 
1064
                LEAVE_CONN_CS(conn);
 
1065
                SC_set_error(self, STMT_SEQUENCE_ERROR, "Connection is already in use.");
 
1066
                SC_log_error(func, "", self);
 
1067
                mylog("%s: problem with connection\n", func);
 
1068
                return SQL_ERROR;
 
1069
        }
 
1070
        is_in_trans = CC_is_in_trans(conn);
 
1071
        if (!self->internal && !is_in_trans &&
 
1072
                (SC_is_fetchcursor(self) ||
 
1073
                 (!CC_is_in_autocommit(conn) && self->statement_type != STMT_TYPE_OTHER)))
 
1074
        {
 
1075
                mylog("   about to begin a transaction on statement = %u\n", self);
 
1076
                auto_begin = TRUE;
 
1077
                if (PG_VERSION_GE(conn, 7.1))
 
1078
                        qflag |= GO_INTO_TRANSACTION;
 
1079
                else if (!CC_begin(conn))
 
1080
                {
 
1081
                        LEAVE_CONN_CS(conn);
 
1082
                        SC_set_error(self, STMT_EXEC_ERROR, "Could not begin a transaction");
 
1083
                        SC_log_error(func, "", self);
 
1084
                        return SQL_ERROR;
 
1085
                }
 
1086
        }
 
1087
 
 
1088
        oldstatus = conn->status;
 
1089
        conn->status = CONN_EXECUTING;
 
1090
        self->status = STMT_EXECUTING;
 
1091
 
 
1092
        /* If it's a SELECT statement, use a cursor. */
 
1093
 
 
1094
        /*
 
1095
         * Note that the declare cursor has already been prepended to the
 
1096
         * statement
 
1097
         */
 
1098
        /* in copy_statement... */
 
1099
        if (self->statement_type == STMT_TYPE_SELECT)
 
1100
        {
 
1101
                char            fetch[128];
 
1102
                qflag |= (SQL_CONCUR_READ_ONLY != self->options.scroll_concurrency ? CREATE_KEYSET : 0); 
 
1103
 
 
1104
                mylog("       Sending SELECT statement on stmt=%u, cursor_name='%s'\n", self, self->cursor_name);
 
1105
 
 
1106
                /* send the declare/select */
 
1107
                res = CC_send_query(conn, self->stmt_with_params, NULL, qflag);
 
1108
                if (SC_is_fetchcursor(self) && res != NULL &&
 
1109
                        QR_command_maybe_successful(res))
 
1110
                {
 
1111
                        QR_Destructor(res);
 
1112
                        qflag &= (~ GO_INTO_TRANSACTION);
 
1113
 
 
1114
                        /*
 
1115
                         * That worked, so now send the fetch to start getting data
 
1116
                         * back
 
1117
                         */
 
1118
                        qi.result_in = NULL;
 
1119
                        qi.cursor = self->cursor_name;
 
1120
                        qi.row_size = ci->drivers.fetch_max;
 
1121
 
 
1122
                        /*
 
1123
                         * Most likely the rowset size will not be set by the
 
1124
                         * application until after the statement is executed, so might
 
1125
                         * as well use the cache size. The qr_next_tuple() function
 
1126
                         * will correct for any discrepancies in sizes and adjust the
 
1127
                         * cache accordingly.
 
1128
                         */
 
1129
                        sprintf(fetch, "fetch %d in %s", qi.row_size, self->cursor_name);
 
1130
 
 
1131
                        res = CC_send_query(conn, fetch, &qi, qflag);
 
1132
                }
 
1133
                mylog("     done sending the query:\n");
 
1134
        }
 
1135
        else
 
1136
        {
 
1137
                /* not a SELECT statement so don't use a cursor */
 
1138
                mylog("      it's NOT a select statement: stmt=%u\n", self);
 
1139
                res = CC_send_query(conn, self->stmt_with_params, NULL, qflag);
 
1140
 
 
1141
                /*
 
1142
                 * We shouldn't send COMMIT. Postgres backend does the autocommit
 
1143
                 * if neccessary. (Zoltan, 04/26/2000)
 
1144
                 */
 
1145
 
 
1146
                /*
 
1147
                 * Above seems wrong. Even in case of autocommit, started
 
1148
                 * transactions must be committed. (Hiroshi, 02/11/2001)
 
1149
                 */
 
1150
                if (CC_is_in_trans(conn))
 
1151
                {
 
1152
                        if (!is_in_trans)
 
1153
                                CC_set_in_manual_trans(conn);
 
1154
                        if (!self->internal && CC_is_in_autocommit(conn) && !CC_is_in_manual_trans(conn))
 
1155
                                CC_commit(conn);
 
1156
                }
 
1157
        }
 
1158
 
 
1159
        if (CONN_DOWN != conn->status)
 
1160
                conn->status = oldstatus;
 
1161
        self->status = STMT_FINISHED;
 
1162
        LEAVE_CONN_CS(conn);
 
1163
 
 
1164
        /* Check the status of the result */
 
1165
        if (res)
 
1166
        {
 
1167
                was_ok = QR_command_successful(res);
 
1168
                was_nonfatal = QR_command_nonfatal(res);
 
1169
                if (res->command &&
 
1170
                        (strncmp(res->command, "UPDATE", 6) == 0 ||
 
1171
                        strncmp(res->command, "DELETE", 6) == 0) &&
 
1172
                        strtoul(res->command + 7, NULL, 0) == 0)
 
1173
                {
 
1174
                        was_rows_affected = 0;
 
1175
                }
 
1176
 
 
1177
                if (was_ok)
 
1178
                        SC_set_errornumber(self, STMT_OK);
 
1179
                else
 
1180
                        SC_set_errornumber(self, was_nonfatal ? STMT_INFO_ONLY : STMT_ERROR_TAKEN_FROM_BACKEND);
 
1181
 
 
1182
                /* set cursor before the first tuple in the list */
 
1183
                self->currTuple = -1;
 
1184
                self->current_col = -1;
 
1185
                self->rowset_start = -1;
 
1186
 
 
1187
                /* issue "ABORT" when query aborted */
 
1188
                if (QR_get_aborted(res))
 
1189
                {
 
1190
                        if (!self->internal)
 
1191
                                CC_abort(conn);
 
1192
                }
 
1193
                else
 
1194
                {
 
1195
                        QResultClass    *tres;
 
1196
 
 
1197
                        /* see if the query did return any result columns */
 
1198
                        for (tres = res, numcols = 0; !numcols && tres; tres = tres->next)
 
1199
                        {
 
1200
                                numcols = QR_NumResultCols(tres);
 
1201
                        }
 
1202
                        /* now allocate the array to hold the binding info */
 
1203
                        if (numcols > 0)
 
1204
                        {
 
1205
                                ARDFields       *opts = SC_get_ARD(self);
 
1206
                                extend_column_bindings(opts, numcols);
 
1207
                                if (opts->bindings == NULL)
 
1208
                                {
 
1209
                                        QR_Destructor(res);
 
1210
                                        SC_set_error(self, STMT_NO_MEMORY_ERROR,"Could not get enough free memory to store the binding information");
 
1211
                                        SC_log_error(func, "", self);
 
1212
                                        return SQL_ERROR;
 
1213
                                }
 
1214
                        }
 
1215
                }
 
1216
        }
 
1217
        else
 
1218
        {
 
1219
                /* Bad Error -- The error message will be in the Connection */
 
1220
                if (!conn->sock)
 
1221
                        SC_set_error(self, STMT_BAD_ERROR, CC_get_errormsg(conn));
 
1222
                else if (self->statement_type == STMT_TYPE_CREATE)
 
1223
                {
 
1224
                        SC_set_error(self, STMT_CREATE_TABLE_ERROR, "Error creating the table");
 
1225
 
 
1226
                        /*
 
1227
                         * This would allow the table to already exists, thus
 
1228
                         * appending rows to it.  BUT, if the table didn't have the
 
1229
                         * same attributes, it would fail. return
 
1230
                         * SQL_SUCCESS_WITH_INFO;
 
1231
                         */
 
1232
                }
 
1233
                else
 
1234
                {
 
1235
                        SC_set_error(self, STMT_EXEC_ERROR, CC_get_errormsg(conn));
 
1236
                }
 
1237
 
 
1238
                if (!self->internal)
 
1239
                        CC_abort(conn);
 
1240
        }
 
1241
        if (!SC_get_Result(self))
 
1242
                SC_set_Result(self, res);
 
1243
        else
 
1244
        {
 
1245
                QResultClass    *last;
 
1246
                for (last = SC_get_Result(self); last->next; last = last->next)
 
1247
                        ;
 
1248
                last->next = res;
 
1249
        }
 
1250
 
 
1251
        apdopts = SC_get_APD(self);
 
1252
        if (self->statement_type == STMT_TYPE_PROCCALL &&
 
1253
                (SC_get_errornumber(self) == STMT_OK ||
 
1254
                 SC_get_errornumber(self) == STMT_INFO_ONLY) &&
 
1255
                apdopts->parameters &&
 
1256
                apdopts->parameters[0].buffer &&
 
1257
                apdopts->parameters[0].paramType == SQL_PARAM_OUTPUT)
 
1258
        {                                                       /* get the return value of the procedure
 
1259
                                                                 * call */
 
1260
                RETCODE         ret;
 
1261
                HSTMT           hstmt = (HSTMT) self;
 
1262
 
 
1263
                ret = SC_fetch(hstmt);
 
1264
                if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
 
1265
                {
 
1266
                        ret = PGAPI_GetData(hstmt, 1, apdopts->parameters[0].CType, apdopts->parameters[0].buffer, apdopts->parameters[0].buflen, apdopts->parameters[0].used);
 
1267
                        if (ret != SQL_SUCCESS)
 
1268
                        {
 
1269
                                SC_set_error(self, STMT_EXEC_ERROR, "GetData to Procedure return failed.");
 
1270
                        }
 
1271
                }
 
1272
                else
 
1273
                {
 
1274
                        SC_set_error(self, STMT_EXEC_ERROR, "SC_fetch to get a Procedure return failed.");
 
1275
                }
 
1276
        }
 
1277
        if (SC_get_errornumber(self) == STMT_OK)
 
1278
                if (was_rows_affected)
 
1279
                        return SQL_SUCCESS;
 
1280
                else
 
1281
                        return SQL_NO_DATA_FOUND;
 
1282
        else if (SC_get_errornumber(self) == STMT_INFO_ONLY)
 
1283
                return SQL_SUCCESS_WITH_INFO;
 
1284
        else
 
1285
        {
 
1286
                if (!SC_get_errormsg(self) || !SC_get_errormsg(self)[0])
 
1287
                        SC_set_errormsg(self, "Error while executing the query");
 
1288
                SC_log_error(func, "", self);
 
1289
                return SQL_ERROR;
 
1290
        }
 
1291
}
 
1292
 
 
1293
 
 
1294
void
 
1295
SC_log_error(const char *func, const char *desc, const StatementClass *self)
 
1296
{
 
1297
#ifdef PRN_NULLCHECK
 
1298
#define nullcheck(a) (a ? a : "(NULL)")
 
1299
#endif
 
1300
        if (self)
 
1301
        {
 
1302
                QResultClass *res = SC_get_Result(self);
 
1303
                const ARDFields *opts = SC_get_ARD(self);
 
1304
                const APDFields *apdopts = SC_get_APD(self);
 
1305
                int     rowsetSize;
 
1306
 
 
1307
#if (ODBCVER >= 0x0300)
 
1308
                rowsetSize = (7 == self->transition_status ? opts->size_of_rowset_odbc2 : opts->size_of_rowset);
 
1309
#else
 
1310
                rowsetSize = opts->size_of_rowset_odbc2;
 
1311
#endif /* ODBCVER */
 
1312
                qlog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__error_message));
 
1313
                mylog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__error_message));
 
1314
                qlog("                 ------------------------------------------------------------\n");
 
1315
                qlog("                 hdbc=%u, stmt=%u, result=%u\n", self->hdbc, self, res);
 
1316
                qlog("                 manual_result=%d, prepare=%d, internal=%d\n", self->manual_result, self->prepare, self->internal);
 
1317
                qlog("                 bindings=%u, bindings_allocated=%d\n", opts->bindings, opts->allocated);
 
1318
                qlog("                 parameters=%u, parameters_allocated=%d\n", apdopts->parameters, apdopts->allocated);
 
1319
                qlog("                 statement_type=%d, statement='%s'\n", self->statement_type, nullcheck(self->statement));
 
1320
                qlog("                 stmt_with_params='%s'\n", nullcheck(self->stmt_with_params));
 
1321
                qlog("                 data_at_exec=%d, current_exec_param=%d, put_data=%d\n", self->data_at_exec, self->current_exec_param, self->put_data);
 
1322
                qlog("                 currTuple=%d, current_col=%d, lobj_fd=%d\n", self->currTuple, self->current_col, self->lobj_fd);
 
1323
                qlog("                 maxRows=%d, rowset_size=%d, keyset_size=%d, cursor_type=%d, scroll_concurrency=%d\n", self->options.maxRows, rowsetSize, self->options.keyset_size, self->options.cursor_type, self->options.scroll_concurrency);
 
1324
                qlog("                 cursor_name='%s'\n", nullcheck(self->cursor_name));
 
1325
 
 
1326
                qlog("                 ----------------QResult Info -------------------------------\n");
 
1327
 
 
1328
                if (res)
 
1329
                {
 
1330
                        qlog("                 fields=%u, manual_tuples=%u, backend_tuples=%u, tupleField=%d, conn=%u\n", res->fields, res->manual_tuples, res->backend_tuples, res->tupleField, res->conn);
 
1331
                        qlog("                 fetch_count=%d, num_total_rows=%d, num_fields=%d, cursor='%s'\n", res->fetch_count, res->num_total_rows, res->num_fields, nullcheck(res->cursor));
 
1332
                        qlog("                 message='%s', command='%s', notice='%s'\n", nullcheck(res->message), nullcheck(res->command), nullcheck(res->notice));
 
1333
                        qlog("                 status=%d, inTuples=%d\n", res->status, res->inTuples);
 
1334
                }
 
1335
 
 
1336
                /* Log the connection error if there is one */
 
1337
                CC_log_error(func, desc, self->hdbc);
 
1338
        }
 
1339
        else
 
1340
        {
 
1341
                qlog("INVALID STATEMENT HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
 
1342
                mylog("INVALID STATEMENT HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
 
1343
        }
 
1344
#undef PRN_NULLCHECK
 
1345
}