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

« back to all changes in this revision

Viewing changes to qresult.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:                      qresult.c
 
3
 *
 
4
 * Description:         This module contains functions related to
 
5
 *                                      managing result information (i.e, fetching rows
 
6
 *                                      from the backend, managing the tuple cache, etc.)
 
7
 *                                      and retrieving it.      Depending on the situation, a
 
8
 *                                      QResultClass will hold either data from the backend
 
9
 *                                      or a manually built result (see "qresult.h" to
 
10
 *                                      see which functions/macros are for manual or backend
 
11
 *                                      results.  For manually built results, the
 
12
 *                                      QResultClass simply points to TupleList and
 
13
 *                                      ColumnInfo structures, which actually hold the data.
 
14
 *
 
15
 * Classes:                     QResultClass (Functions prefix: "QR_")
 
16
 *
 
17
 * API functions:       none
 
18
 *
 
19
 * Comments:            See "notice.txt" for copyright and license information.
 
20
 *---------
 
21
 */
 
22
 
 
23
#include "qresult.h"
 
24
 
 
25
#include "misc.h"
 
26
#include <stdio.h>
 
27
#include <string.h>
 
28
 
 
29
#ifndef TRUE
 
30
#define TRUE    (BOOL)1
 
31
#endif
 
32
#ifndef FALSE
 
33
#define FALSE   (BOOL)0
 
34
#endif
 
35
 
 
36
 
 
37
/*
 
38
 *      Used for building a Manual Result only
 
39
 *      All info functions call this function to create the manual result set.
 
40
 */
 
41
void
 
42
QR_set_num_fields(QResultClass *self, int new_num_fields)
 
43
{
 
44
        if (!self)      return;
 
45
        mylog("in QR_set_num_fields\n");
 
46
 
 
47
        CI_set_num_fields(self->fields, new_num_fields);
 
48
        if (self->manual_tuples)
 
49
                TL_Destructor(self->manual_tuples);
 
50
 
 
51
        self->manual_tuples = TL_Constructor(new_num_fields);
 
52
 
 
53
        mylog("exit QR_set_num_fields\n");
 
54
}
 
55
 
 
56
 
 
57
void
 
58
QR_set_position(QResultClass *self, int pos)
 
59
{
 
60
        self->tupleField = self->backend_tuples + ((self->base + pos) * self->num_fields);
 
61
}
 
62
 
 
63
 
 
64
void
 
65
QR_set_cache_size(QResultClass *self, int cache_size)
 
66
{
 
67
        self->cache_size = cache_size;
 
68
}
 
69
 
 
70
 
 
71
void
 
72
QR_set_rowset_size(QResultClass *self, int rowset_size)
 
73
{
 
74
        self->rowset_size = rowset_size;
 
75
}
 
76
 
 
77
 
 
78
void
 
79
QR_inc_base(QResultClass *self, int base_inc)
 
80
{
 
81
        self->base += base_inc;
 
82
}
 
83
 
 
84
 
 
85
/*
 
86
 * CLASS QResult
 
87
 */
 
88
QResultClass *
 
89
QR_Constructor()
 
90
{
 
91
        QResultClass *rv;
 
92
 
 
93
        mylog("in QR_Constructor\n");
 
94
        rv = (QResultClass *) malloc(sizeof(QResultClass));
 
95
 
 
96
        if (rv != NULL)
 
97
        {
 
98
                rv->status = PGRES_EMPTY_QUERY;
 
99
 
 
100
                /* construct the column info */
 
101
                if (!(rv->fields = CI_Constructor()))
 
102
                {
 
103
                        free(rv);
 
104
                        return NULL;
 
105
                }
 
106
                rv->manual_tuples = NULL;
 
107
                rv->backend_tuples = NULL;
 
108
                rv->message = NULL;
 
109
                rv->command = NULL;
 
110
                rv->notice = NULL;
 
111
                rv->conn = NULL;
 
112
                rv->next = NULL;
 
113
                rv->inTuples = FALSE;
 
114
                rv->count_backend_allocated = 0;
 
115
                rv->count_keyset_allocated = 0;
 
116
                rv->num_total_rows = 0;
 
117
                rv->num_backend_rows = 0;
 
118
                rv->fetch_count = 0;
 
119
                rv->base = 0;
 
120
                rv->recent_processed_row_count = -1;
 
121
                rv->currTuple = -1;
 
122
                rv->num_fields = 0;
 
123
                rv->tupleField = NULL;
 
124
                rv->cursor = NULL;
 
125
                rv->aborted = FALSE;
 
126
 
 
127
                rv->cache_size = 0;
 
128
                rv->rowset_size = 1;
 
129
                rv->haskeyset = 0;
 
130
                rv->keyset = NULL;
 
131
                rv->rb_alloc = 0;
 
132
                rv->rb_count = 0;
 
133
                rv->rollback = NULL;
 
134
                rv->dl_alloc = 0;
 
135
                rv->dl_count = 0;
 
136
                rv->deleted = NULL;
 
137
        }
 
138
 
 
139
        mylog("exit QR_Constructor\n");
 
140
        return rv;
 
141
}
 
142
 
 
143
 
 
144
void
 
145
QR_Destructor(QResultClass *self)
 
146
{
 
147
        if (!self)      return;
 
148
        mylog("QResult: in DESTRUCTOR\n");
 
149
 
 
150
        /* manual result set tuples */
 
151
        if (self->manual_tuples)
 
152
        {
 
153
                TL_Destructor(self->manual_tuples);
 
154
                self->manual_tuples = NULL;
 
155
        }
 
156
 
 
157
        /*
 
158
         * If conn is defined, then we may have used "backend_tuples", so in
 
159
         * case we need to, free it up.  Also, close the cursor.
 
160
         */
 
161
        if (self->conn && self->conn->sock && CC_is_in_trans(self->conn))
 
162
                QR_close(self);                 /* close the cursor if there is one */
 
163
 
 
164
        QR_free_memory(self);           /* safe to call anyway */
 
165
 
 
166
        /* Should have been freed in the close() but just in case... */
 
167
        if (self->cursor)
 
168
        {
 
169
                free(self->cursor);
 
170
                self->cursor = NULL;
 
171
        }
 
172
 
 
173
        /* Free up column info */
 
174
        if (self->fields)
 
175
        {
 
176
                CI_Destructor(self->fields);
 
177
                self->fields = NULL;
 
178
        }
 
179
 
 
180
        /* Free command info (this is from strdup()) */
 
181
        if (self->command)
 
182
        {
 
183
                free(self->command);
 
184
                self->command = NULL;
 
185
        }
 
186
 
 
187
        /* Free message info (this is from strdup()) */
 
188
        if (self->message)
 
189
        {
 
190
                free(self->message);
 
191
                self->message = NULL;
 
192
        }
 
193
 
 
194
        /* Free notice info (this is from strdup()) */
 
195
        if (self->notice)
 
196
        {
 
197
                free(self->notice);
 
198
                self->notice = NULL;
 
199
        }
 
200
        /* Destruct the result object in the chain */
 
201
        if (self->next)
 
202
        {
 
203
                QR_Destructor(self->next);
 
204
                self->next = NULL;
 
205
        }
 
206
 
 
207
        free(self);
 
208
 
 
209
        mylog("QResult: exit DESTRUCTOR\n");
 
210
}
 
211
 
 
212
 
 
213
void
 
214
QR_set_command(QResultClass *self, const char *msg)
 
215
{
 
216
        if (self->command)
 
217
                free(self->command);
 
218
 
 
219
        self->command = msg ? strdup(msg) : NULL;
 
220
}
 
221
 
 
222
 
 
223
void
 
224
QR_set_message(QResultClass *self, const char *msg)
 
225
{
 
226
        if (self->message)
 
227
                free(self->message);
 
228
 
 
229
        self->message = msg ? strdup(msg) : NULL;
 
230
}
 
231
 
 
232
 
 
233
void
 
234
QR_set_notice(QResultClass *self, const char *msg)
 
235
{
 
236
        if (self->notice)
 
237
                free(self->notice);
 
238
 
 
239
        self->notice = msg ? strdup(msg) : NULL;
 
240
}
 
241
 
 
242
 
 
243
void
 
244
QR_free_memory(QResultClass *self)
 
245
{
 
246
        register int lf,
 
247
                                row;
 
248
        register TupleField *tuple = self->backend_tuples;
 
249
        int                     num_backend_rows = self->num_backend_rows;
 
250
        int                     num_fields = self->num_fields;
 
251
 
 
252
        mylog("QResult: free memory in, fcount=%d\n", num_backend_rows);
 
253
 
 
254
        if (self->backend_tuples)
 
255
        {
 
256
                for (row = 0; row < num_backend_rows; row++)
 
257
                {
 
258
                        mylog("row = %d, num_fields = %d\n", row, num_fields);
 
259
                        for (lf = 0; lf < num_fields; lf++)
 
260
                        {
 
261
                                if (tuple[lf].value != NULL)
 
262
                                {
 
263
                                        mylog("free [lf=%d] %u\n", lf, tuple[lf].value);
 
264
                                        free(tuple[lf].value);
 
265
                                }
 
266
                        }
 
267
                        tuple += num_fields;    /* next row */
 
268
                }
 
269
 
 
270
                free(self->backend_tuples);
 
271
                self->count_backend_allocated = 0;
 
272
                self->backend_tuples = NULL;
 
273
        }
 
274
        if (self->keyset)
 
275
        {
 
276
                free(self->keyset);
 
277
                self->keyset = NULL;
 
278
                self->count_keyset_allocated = 0;
 
279
        }
 
280
        if (self->rollback)
 
281
        {
 
282
                free(self->rollback);
 
283
                self->rb_alloc = 0;
 
284
                self->rb_count = 0;
 
285
                self->rollback = NULL;
 
286
        }
 
287
        if (self->deleted)
 
288
        {
 
289
                free(self->deleted);
 
290
                self->dl_alloc = 0;
 
291
                self->dl_count = 0;
 
292
                self->deleted = NULL;
 
293
        }
 
294
 
 
295
        self->num_total_rows = 0;
 
296
        self->num_backend_rows = 0;
 
297
 
 
298
        mylog("QResult: free memory out\n");
 
299
}
 
300
 
 
301
 
 
302
/*      This function is called by send_query() */
 
303
char
 
304
QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
 
305
{
 
306
        int                     tuple_size;
 
307
 
 
308
        /*
 
309
         * If called from send_query the first time (conn != NULL), then set
 
310
         * the inTuples state, and read the tuples.  If conn is NULL, it
 
311
         * implies that we are being called from next_tuple(), like to get
 
312
         * more rows so don't call next_tuple again!
 
313
         */
 
314
        if (conn != NULL)
 
315
        {
 
316
                ConnInfo   *ci = &(conn->connInfo);
 
317
                BOOL            fetch_cursor = (ci->drivers.use_declarefetch && cursor && cursor[0]);
 
318
 
 
319
                self->conn = conn;
 
320
 
 
321
                mylog("QR_fetch_tuples: cursor = '%s', self->cursor=%u\n", (cursor == NULL) ? "" : cursor, self->cursor);
 
322
 
 
323
                if (self->cursor)
 
324
                        free(self->cursor);
 
325
                self->cursor = NULL;
 
326
 
 
327
                if (fetch_cursor)
 
328
                {
 
329
                        if (!cursor || cursor[0] == '\0')
 
330
                        {
 
331
                                self->status = PGRES_INTERNAL_ERROR;
 
332
                                QR_set_message(self, "Internal Error -- no cursor for fetch");
 
333
                                return FALSE;
 
334
                        }
 
335
                        self->cursor = strdup(cursor);
 
336
                }
 
337
 
 
338
                /*
 
339
                 * Read the field attributes.
 
340
                 *
 
341
                 * $$$$ Should do some error control HERE! $$$$
 
342
                 */
 
343
                if (CI_read_fields(self->fields, self->conn))
 
344
                {
 
345
                        self->status = PGRES_FIELDS_OK;
 
346
                        self->num_fields = CI_get_num_fields(self->fields);
 
347
                        if (self->haskeyset)
 
348
                                self->num_fields -= 2;
 
349
                }
 
350
                else
 
351
                {
 
352
                        self->status = PGRES_BAD_RESPONSE;
 
353
                        QR_set_message(self, "Error reading field information");
 
354
                        return FALSE;
 
355
                }
 
356
 
 
357
                mylog("QR_fetch_tuples: past CI_read_fields: num_fields = %d\n", self->num_fields);
 
358
 
 
359
                if (fetch_cursor)
 
360
                {
 
361
                        if (self->cache_size <= 0)
 
362
                                self->cache_size = ci->drivers.fetch_max;
 
363
                        tuple_size = self->cache_size;
 
364
                }
 
365
                else
 
366
                        tuple_size = TUPLE_MALLOC_INC;
 
367
 
 
368
                /* allocate memory for the tuple cache */
 
369
                mylog("MALLOC: tuple_size = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
 
370
                self->count_backend_allocated = self->count_keyset_allocated = 0;
 
371
                if (self->num_fields > 0)
 
372
                {
 
373
                        self->backend_tuples = (TupleField *) malloc(self->num_fields * sizeof(TupleField) * tuple_size);
 
374
                        if (!self->backend_tuples)
 
375
                        {
 
376
                                self->status = PGRES_FATAL_ERROR;
 
377
                                QR_set_message(self, "Could not get memory for tuple cache.");
 
378
                                return FALSE;
 
379
                        }
 
380
                        self->count_backend_allocated = tuple_size;
 
381
                }
 
382
                if (self->haskeyset)
 
383
                {
 
384
                        if (self->keyset = (KeySet *) calloc(sizeof(KeySet), tuple_size), !self->keyset)
 
385
                        {
 
386
                                self->status = PGRES_FATAL_ERROR;
 
387
                                QR_set_message(self, "Could not get memory for tuple cache.");
 
388
                                return FALSE;
 
389
                        }
 
390
                        self->count_keyset_allocated = tuple_size;
 
391
                }
 
392
 
 
393
                self->inTuples = TRUE;
 
394
 
 
395
                /* Force a read to occur in next_tuple */
 
396
                self->num_total_rows = 0;
 
397
                self->num_backend_rows = tuple_size + 1;
 
398
                self->fetch_count = tuple_size + 1;
 
399
                self->base = 0;
 
400
 
 
401
                return QR_next_tuple(self);
 
402
        }
 
403
        else
 
404
        {
 
405
                /*
 
406
                 * Always have to read the field attributes. But we dont have to
 
407
                 * reallocate memory for them!
 
408
                 */
 
409
 
 
410
                if (!CI_read_fields(NULL, self->conn))
 
411
                {
 
412
                        self->status = PGRES_BAD_RESPONSE;
 
413
                        QR_set_message(self, "Error reading field information");
 
414
                        return FALSE;
 
415
                }
 
416
                return TRUE;
 
417
        }
 
418
}
 
419
 
 
420
 
 
421
/*
 
422
 *      Close the cursor and end the transaction (if no cursors left)
 
423
 *      We only close cursor/end the transaction if a cursor was used.
 
424
 */
 
425
int
 
426
QR_close(QResultClass *self)
 
427
{
 
428
        QResultClass *res;
 
429
 
 
430
        if (self->conn && self->cursor && self->conn->connInfo.drivers.use_declarefetch)
 
431
        {
 
432
                char            buf[64];
 
433
 
 
434
                sprintf(buf, "close %s", self->cursor);
 
435
                mylog("QResult: closing cursor: '%s'\n", buf);
 
436
 
 
437
                res = CC_send_query(self->conn, buf, NULL, CLEAR_RESULT_ON_ABORT);
 
438
 
 
439
                self->inTuples = FALSE;
 
440
                self->currTuple = -1;
 
441
 
 
442
                free(self->cursor);
 
443
                self->cursor = NULL;
 
444
 
 
445
                if (res == NULL)
 
446
                {
 
447
                        self->status = PGRES_FATAL_ERROR;
 
448
                        QR_set_message(self, "Error closing cursor.");
 
449
                        return FALSE;
 
450
                }
 
451
                QR_Destructor(res);
 
452
 
 
453
                /* End the transaction if there are no cursors left on this conn */
 
454
                if (CC_is_in_autocommit(self->conn) && CC_cursor_count(self->conn) == 0)
 
455
                {
 
456
                        mylog("QResult: END transaction on conn=%u\n", self->conn);
 
457
 
 
458
                        if (!CC_commit(self->conn))
 
459
                        {
 
460
                                self->status = PGRES_FATAL_ERROR;
 
461
                                QR_set_message(self, "Error ending transaction.");
 
462
                                return FALSE;
 
463
                        }
 
464
                }
 
465
        }
 
466
 
 
467
        return TRUE;
 
468
}
 
469
 
 
470
 
 
471
/*      This function is called by fetch_tuples() AND SQLFetch() */
 
472
int
 
473
QR_next_tuple(QResultClass *self)
 
474
{
 
475
        int                     id;
 
476
        QResultClass *res;
 
477
        SocketClass *sock;
 
478
 
 
479
        /* Speed up access */
 
480
        int                     fetch_count = self->fetch_count;
 
481
        int                     num_backend_rows = self->num_backend_rows;
 
482
        int                     fetch_size,
 
483
                                offset = 0;
 
484
        int                     end_tuple = self->rowset_size + self->base;
 
485
        char            corrected = FALSE;
 
486
        TupleField *the_tuples = self->backend_tuples;
 
487
 
 
488
        /* ERROR_MSG_LENGTH is sufficient */
 
489
        char msgbuffer[ERROR_MSG_LENGTH + 1];
 
490
 
 
491
        /* QR_set_command() dups this string so doesn't need static */
 
492
        char            cmdbuffer[ERROR_MSG_LENGTH + 1];
 
493
        char            fetch[128];
 
494
        QueryInfo       qi;
 
495
        ConnInfo   *ci = NULL;
 
496
        BOOL            msg_truncated;
 
497
        UDWORD          abort_opt;
 
498
 
 
499
        if (fetch_count < num_backend_rows)
 
500
        {
 
501
                /* return a row from cache */
 
502
                mylog("next_tuple: fetch_count < fcount: returning tuple %d, fcount = %d\n", fetch_count, num_backend_rows);
 
503
                self->tupleField = the_tuples + (fetch_count * self->num_fields);               /* next row */
 
504
                self->fetch_count++;
 
505
                return TRUE;
 
506
        }
 
507
        else if (self->num_backend_rows < self->cache_size)
 
508
        {
 
509
                /* last row from cache */
 
510
                /* We are done because we didn't even get CACHE_SIZE tuples */
 
511
                mylog("next_tuple: fcount < CACHE_SIZE: fcount = %d, fetch_count = %d\n", num_backend_rows, fetch_count);
 
512
                self->tupleField = NULL;
 
513
                self->status = PGRES_END_TUPLES;
 
514
                /* end of tuples */
 
515
                return -1;
 
516
        }
 
517
        else
 
518
        {
 
519
                /*
 
520
                 * See if we need to fetch another group of rows. We may be being
 
521
                 * called from send_query(), and if so, don't send another fetch,
 
522
                 * just fall through and read the tuples.
 
523
                 */
 
524
                self->tupleField = NULL;
 
525
 
 
526
                if (!self->inTuples)
 
527
                {
 
528
                        ci = &(self->conn->connInfo);
 
529
                        if (!self->cursor || !ci->drivers.use_declarefetch)
 
530
                        {
 
531
                                mylog("next_tuple: ALL_ROWS: done, fcount = %d, fetch_count = %d\n", self->num_total_rows, fetch_count);
 
532
                                self->tupleField = NULL;
 
533
                                self->status = PGRES_END_TUPLES;
 
534
                                return -1;              /* end of tuples */
 
535
                        }
 
536
 
 
537
                        if (self->base == num_backend_rows)
 
538
                        {
 
539
                                int     row, lf;
 
540
                                TupleField *tuple = self->backend_tuples;
 
541
 
 
542
                                /* not a correction */
 
543
                                /* Determine the optimum cache size.  */
 
544
                                if (ci->drivers.fetch_max % self->rowset_size == 0)
 
545
                                        fetch_size = ci->drivers.fetch_max;
 
546
                                else if (self->rowset_size < ci->drivers.fetch_max)
 
547
                                        fetch_size = (ci->drivers.fetch_max / self->rowset_size) * self->rowset_size;
 
548
                                else
 
549
                                        fetch_size = self->rowset_size;
 
550
 
 
551
                                self->cache_size = fetch_size;
 
552
                                /* clear obsolete tuples */
 
553
inolog("clear obsolete %d tuples\n", num_backend_rows);
 
554
                                for (row = 0; row < num_backend_rows; row++)
 
555
                                {
 
556
                                        for (lf = 0; lf < self->num_fields; lf++)
 
557
                                        {
 
558
                                                if (tuple[lf].value != NULL)
 
559
                                                {
 
560
                                                        free(tuple[lf].value);
 
561
                                                        tuple[lf].value = NULL;
 
562
                                                }
 
563
                                        }
 
564
                                        tuple += self->num_fields;
 
565
                                }
 
566
                                self->fetch_count = 1;
 
567
                        }
 
568
                        else
 
569
                        {
 
570
                                /* need to correct */
 
571
                                corrected = TRUE;
 
572
 
 
573
                                fetch_size = end_tuple - num_backend_rows;
 
574
 
 
575
                                self->cache_size += fetch_size;
 
576
 
 
577
                                offset = self->fetch_count;
 
578
                                self->fetch_count++;
 
579
                        }
 
580
 
 
581
                        if (!self->backend_tuples || self->cache_size > self->count_backend_allocated)
 
582
                        {
 
583
                                self->count_backend_allocated = 0;
 
584
                                if (self->num_fields > 0)
 
585
                                {
 
586
                                        self->backend_tuples = (TupleField *) realloc(self->backend_tuples,
 
587
                                                self->num_fields * sizeof(TupleField) * self->cache_size);
 
588
                                        if (!self->backend_tuples)
 
589
                                        {
 
590
                                                self->status = PGRES_FATAL_ERROR;
 
591
                                                QR_set_message(self, "Out of memory while reading tuples.");
 
592
                                                return FALSE;
 
593
                                        }
 
594
                                        self->count_backend_allocated = self->cache_size;
 
595
                                }
 
596
                        }
 
597
                        if (self->haskeyset && (!self->keyset || self->cache_size > self->count_keyset_allocated))
 
598
                        {
 
599
                                self->count_keyset_allocated = 0;
 
600
                                self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * self->cache_size); 
 
601
                                self->count_keyset_allocated = self->cache_size;
 
602
                        }
 
603
                        sprintf(fetch, "fetch %d in %s", fetch_size, self->cursor);
 
604
 
 
605
                        mylog("next_tuple: sending actual fetch (%d) query '%s'\n", fetch_size, fetch);
 
606
 
 
607
                        /* don't read ahead for the next tuple (self) ! */
 
608
                        qi.row_size = self->cache_size;
 
609
                        qi.result_in = self;
 
610
                        qi.cursor = NULL;
 
611
                        res = CC_send_query(self->conn, fetch, &qi, CLEAR_RESULT_ON_ABORT);
 
612
                        if (res == NULL)
 
613
                        {
 
614
                                self->status = PGRES_FATAL_ERROR;
 
615
                                QR_set_message(self, "Error fetching next group.");
 
616
                                return FALSE;
 
617
                        }
 
618
                        self->inTuples = TRUE;
 
619
                }
 
620
                else
 
621
                {
 
622
                        mylog("next_tuple: inTuples = true, falling through: fcount = %d, fetch_count = %d\n", self->num_backend_rows, self->fetch_count);
 
623
 
 
624
                        /*
 
625
                         * This is a pre-fetch (fetching rows right after query but
 
626
                         * before any real SQLFetch() calls.  This is done so the
 
627
                         * field attributes are available.
 
628
                         */
 
629
                        self->fetch_count = 0;
 
630
                }
 
631
        }
 
632
 
 
633
        if (!corrected)
 
634
        {
 
635
                self->base = 0;
 
636
                self->num_backend_rows = 0;
 
637
        }
 
638
 
 
639
        sock = CC_get_socket(self->conn);
 
640
        self->tupleField = NULL;
 
641
        ci = &(self->conn->connInfo);
 
642
 
 
643
        for (;;)
 
644
        {
 
645
                id = SOCK_get_char(sock);
 
646
 
 
647
                switch (id)
 
648
                {
 
649
 
 
650
                        case 'P':
 
651
                                mylog("Portal name within tuples ?? just ignore\n");
 
652
                                SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
 
653
                                break;
 
654
                        case 'T':
 
655
                                mylog("Tuples within tuples ?? OK try to handle them\n");
 
656
                                self->inTuples = FALSE;
 
657
                                if (self->num_total_rows > 0)
 
658
                                {
 
659
                                        mylog("fetched %d rows\n", self->num_total_rows);
 
660
                                        /* set to first row */
 
661
                                        self->tupleField = self->backend_tuples + (offset * self->num_fields);
 
662
                                }
 
663
                                else
 
664
                                {
 
665
                                        mylog("    [ fetched 0 rows ]\n");
 
666
                                }
 
667
                                /* add new Result class */
 
668
                                self->next = QR_Constructor();
 
669
                                if (!self->next)
 
670
                                {
 
671
                                        CC_set_error(self->conn, CONNECTION_COULD_NOT_RECEIVE, "Could not create result info in send_query.");
 
672
                                        CC_on_abort(self->conn, NO_TRANS | CONN_DEAD);
 
673
                                        return FALSE;
 
674
                                }
 
675
                                QR_set_cache_size(self->next, self->cache_size);
 
676
                                self = self->next;
 
677
                                if (!QR_fetch_tuples(self, self->conn, NULL))
 
678
                                {
 
679
                                        CC_set_error(self->conn, CONNECTION_COULD_NOT_RECEIVE, QR_get_message(self));
 
680
                                        return FALSE;
 
681
                                }
 
682
 
 
683
                                return TRUE;
 
684
                        case 'B':                       /* Tuples in binary format */
 
685
                        case 'D':                       /* Tuples in ASCII format  */
 
686
 
 
687
                                if (!self->cursor || !ci->drivers.use_declarefetch)
 
688
                                { 
 
689
                                        if (self->num_fields > 0 &&
 
690
                                            self->num_total_rows >= self->count_backend_allocated)
 
691
                                        {
 
692
                                                int     tuple_size = self->count_backend_allocated;
 
693
 
 
694
                                                mylog("REALLOC: old_count = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
 
695
                                                tuple_size *= 2;
 
696
                                                self->backend_tuples = (TupleField *) realloc(self->backend_tuples,
 
697
                                                        tuple_size * self->num_fields * sizeof(TupleField));
 
698
                                                if (!self->backend_tuples)
 
699
                                                {
 
700
                                                        self->status = PGRES_FATAL_ERROR;
 
701
                                                        QR_set_message(self, "Out of memory while reading tuples.");
 
702
                                                        return FALSE;
 
703
                                                }
 
704
                                                self->count_backend_allocated = tuple_size;
 
705
                                        }
 
706
                                        if (self->haskeyset &&
 
707
                                            self->num_total_rows >= self->count_keyset_allocated)
 
708
                                        {
 
709
                                                int     tuple_size = self->count_keyset_allocated;
 
710
                                                tuple_size *= 2;
 
711
                                                self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * tuple_size);
 
712
                                                self->count_keyset_allocated = tuple_size;
 
713
                                        }
 
714
                                }
 
715
 
 
716
                                if (!QR_read_tuple(self, (char) (id == 0)))
 
717
                                {
 
718
                                        self->status = PGRES_BAD_RESPONSE;
 
719
                                        QR_set_message(self, "Error reading the tuple");
 
720
                                        return FALSE;
 
721
                                }
 
722
                                self->num_total_rows++;
 
723
                                if (self->num_fields > 0)
 
724
                                        self->num_backend_rows++;
 
725
                                break;                  /* continue reading */
 
726
 
 
727
                        case 'C':                       /* End of tuple list */
 
728
                                SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
 
729
                                QR_set_command(self, cmdbuffer);
 
730
 
 
731
                                mylog("end of tuple list -- setting inUse to false: this = %u\n", self);
 
732
 
 
733
                                self->inTuples = FALSE;
 
734
                                qlog("    [ fetched %d rows ]\n", self->num_total_rows);
 
735
                                mylog("_next_tuple: 'C' fetch_total = %d & this_fetch = %d\n", self->num_total_rows, self->num_backend_rows);
 
736
                                if (self->num_backend_rows > 0)
 
737
                                {
 
738
                                        /* set to first row */
 
739
                                        self->tupleField = self->backend_tuples + (offset * self->num_fields);
 
740
                                        return TRUE;
 
741
                                }
 
742
                                else
 
743
                                {
 
744
                                        /* We are surely done here (we read 0 tuples) */
 
745
                                        mylog("_next_tuple: 'C': DONE (fcount == 0)\n");
 
746
                                        return -1;      /* end of tuples */
 
747
                                }
 
748
 
 
749
                        case 'E':                       /* Error */
 
750
                                msg_truncated = SOCK_get_string(sock, msgbuffer,
 
751
 ERROR_MSG_LENGTH);
 
752
 
 
753
                                /* Remove a newline */
 
754
                                if (msgbuffer[0] != '\0' && msgbuffer[strlen(msgbuffer) - 1] == '\n')
 
755
                                        msgbuffer[strlen(msgbuffer) - 1] = '\0';
 
756
 
 
757
                                abort_opt = 0;
 
758
                                if (!strncmp(msgbuffer, "FATAL", 5))
 
759
                                        abort_opt = NO_TRANS | CONN_DEAD;
 
760
                                CC_on_abort(self->conn, abort_opt);
 
761
                                QR_set_status(self, PGRES_FATAL_ERROR);
 
762
                                QR_set_message(self, msgbuffer);
 
763
                                QR_set_aborted(self, TRUE);
 
764
 
 
765
                                mylog("ERROR from backend in next_tuple: '%s'\n", msgbuffer);
 
766
                                qlog("ERROR from backend in next_tuple: '%s'\n", msgbuffer);
 
767
                                while (msg_truncated)
 
768
                                        msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
 
769
 
 
770
                                return FALSE;
 
771
 
 
772
                        case 'N':                       /* Notice */
 
773
                                msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
 
774
                                QR_set_notice(self, cmdbuffer);
 
775
                                if (QR_command_successful(self))
 
776
                                        QR_set_status(self, PGRES_NONFATAL_ERROR);
 
777
                                qlog("NOTICE from backend in next_tuple: '%s'\n", msgbuffer);
 
778
                                while (msg_truncated)
 
779
                                        msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
 
780
                                continue;
 
781
 
 
782
                        default:                        /* this should only happen if the backend
 
783
                                                                 * dumped core */
 
784
                                mylog("QR_next_tuple: Unexpected result from backend: id = '%c' (%d)\n", id, id);
 
785
                                qlog("QR_next_tuple: Unexpected result from backend: id = '%c' (%d)\n", id, id);
 
786
                                QR_set_message(self, "Unexpected result from backend. It probably crashed");
 
787
                                self->status = PGRES_FATAL_ERROR;
 
788
                                CC_on_abort(self->conn, NO_TRANS | CONN_DEAD);
 
789
                                return FALSE;
 
790
                }
 
791
        }
 
792
        return TRUE;
 
793
}
 
794
 
 
795
 
 
796
char
 
797
QR_read_tuple(QResultClass *self, char binary)
 
798
{
 
799
        Int2            field_lf;
 
800
        TupleField *this_tuplefield;
 
801
        KeySet  *this_keyset = NULL;
 
802
        char            bmp,
 
803
                                bitmap[MAX_FIELDS];             /* Max. len of the bitmap */
 
804
        Int2            bitmaplen;              /* len of the bitmap in bytes */
 
805
        Int2            bitmap_pos;
 
806
        Int2            bitcnt;
 
807
        Int4            len;
 
808
        char       *buffer;
 
809
        int             ci_num_fields = QR_NumResultCols(self); /* speed up access */
 
810
        int             num_fields = self->num_fields;  /* speed up access */
 
811
        SocketClass *sock = CC_get_socket(self->conn);
 
812
        ColumnInfoClass *flds;
 
813
        int             effective_cols;
 
814
        char            tidoidbuf[32];
 
815
 
 
816
        /* set the current row to read the fields into */
 
817
        effective_cols = QR_NumPublicResultCols(self);
 
818
        this_tuplefield = self->backend_tuples + (self->num_backend_rows * num_fields);
 
819
        if (self->haskeyset)
 
820
        {
 
821
                this_keyset = self->keyset + self->num_total_rows;
 
822
                this_keyset->status = 0;
 
823
        }
 
824
 
 
825
        bitmaplen = (Int2) ci_num_fields / BYTELEN;
 
826
        if ((ci_num_fields % BYTELEN) > 0)
 
827
                bitmaplen++;
 
828
 
 
829
        /*
 
830
         * At first the server sends a bitmap that indicates which database
 
831
         * fields are null
 
832
         */
 
833
        SOCK_get_n_char(sock, bitmap, bitmaplen);
 
834
 
 
835
        bitmap_pos = 0;
 
836
        bitcnt = 0;
 
837
        bmp = bitmap[bitmap_pos];
 
838
        flds = self->fields;
 
839
 
 
840
        for (field_lf = 0; field_lf < ci_num_fields; field_lf++)
 
841
        {
 
842
                /* Check if the current field is NULL */
 
843
                if (!(bmp & 0200))
 
844
                {
 
845
                        /* YES, it is NULL ! */
 
846
                        this_tuplefield[field_lf].len = 0;
 
847
                        this_tuplefield[field_lf].value = 0;
 
848
                }
 
849
                else
 
850
                {
 
851
                        /*
 
852
                         * NO, the field is not null. so get at first the length of
 
853
                         * the field (four bytes)
 
854
                         */
 
855
                        len = SOCK_get_int(sock, VARHDRSZ);
 
856
                        if (!binary)
 
857
                                len -= VARHDRSZ;
 
858
 
 
859
                        if (field_lf >= effective_cols)
 
860
                                buffer = tidoidbuf;
 
861
                        else
 
862
                                buffer = (char *) malloc(len + 1);
 
863
                        SOCK_get_n_char(sock, buffer, len);
 
864
                        buffer[len] = '\0';
 
865
 
 
866
                        mylog("qresult: len=%d, buffer='%s'\n", len, buffer);
 
867
 
 
868
                        if (field_lf >= effective_cols)
 
869
                        {
 
870
                                if (field_lf == effective_cols)
 
871
                                        sscanf(buffer, "(%lu,%hu)",
 
872
                                                &this_keyset->blocknum, &this_keyset->offset);
 
873
                                else
 
874
                                        this_keyset->oid = strtoul(buffer, NULL, 10);
 
875
                        }
 
876
                        else
 
877
                        {
 
878
                                this_tuplefield[field_lf].len = len;
 
879
                                this_tuplefield[field_lf].value = buffer;
 
880
 
 
881
                        /*
 
882
                         * This can be used to set the longest length of the column
 
883
                         * for any row in the tuple cache.      It would not be accurate
 
884
                         * for varchar and text fields to use this since a tuple cache
 
885
                         * is only 100 rows. Bpchar can be handled since the strlen of
 
886
                         * all rows is fixed, assuming there are not 100 nulls in a
 
887
                         * row!
 
888
                         */
 
889
 
 
890
                                if (flds && flds->display_size && flds->display_size[field_lf] < len)
 
891
                                        flds->display_size[field_lf] = len;
 
892
                        }
 
893
                }
 
894
 
 
895
                /*
 
896
                 * Now adjust for the next bit to be scanned in the next loop.
 
897
                 */
 
898
                bitcnt++;
 
899
                if (BYTELEN == bitcnt)
 
900
                {
 
901
                        bitmap_pos++;
 
902
                        bmp = bitmap[bitmap_pos];
 
903
                        bitcnt = 0;
 
904
                }
 
905
                else
 
906
                        bmp <<= 1;
 
907
        }
 
908
        self->currTuple++;
 
909
        return TRUE;
 
910
}