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.
15
* Classes: QResultClass (Functions prefix: "QR_")
19
* Comments: See "notice.txt" for copyright and license information.
38
* Used for building a Manual Result only
39
* All info functions call this function to create the manual result set.
42
QR_set_num_fields(QResultClass *self, int new_num_fields)
45
mylog("in QR_set_num_fields\n");
47
CI_set_num_fields(self->fields, new_num_fields);
48
if (self->manual_tuples)
49
TL_Destructor(self->manual_tuples);
51
self->manual_tuples = TL_Constructor(new_num_fields);
53
mylog("exit QR_set_num_fields\n");
58
QR_set_position(QResultClass *self, int pos)
60
self->tupleField = self->backend_tuples + ((self->base + pos) * self->num_fields);
65
QR_set_cache_size(QResultClass *self, int cache_size)
67
self->cache_size = cache_size;
72
QR_set_rowset_size(QResultClass *self, int rowset_size)
74
self->rowset_size = rowset_size;
79
QR_inc_base(QResultClass *self, int base_inc)
81
self->base += base_inc;
93
mylog("in QR_Constructor\n");
94
rv = (QResultClass *) malloc(sizeof(QResultClass));
98
rv->status = PGRES_EMPTY_QUERY;
100
/* construct the column info */
101
if (!(rv->fields = CI_Constructor()))
106
rv->manual_tuples = NULL;
107
rv->backend_tuples = 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;
120
rv->recent_processed_row_count = -1;
123
rv->tupleField = NULL;
139
mylog("exit QR_Constructor\n");
145
QR_Destructor(QResultClass *self)
148
mylog("QResult: in DESTRUCTOR\n");
150
/* manual result set tuples */
151
if (self->manual_tuples)
153
TL_Destructor(self->manual_tuples);
154
self->manual_tuples = NULL;
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.
161
if (self->conn && self->conn->sock && CC_is_in_trans(self->conn))
162
QR_close(self); /* close the cursor if there is one */
164
QR_free_memory(self); /* safe to call anyway */
166
/* Should have been freed in the close() but just in case... */
173
/* Free up column info */
176
CI_Destructor(self->fields);
180
/* Free command info (this is from strdup()) */
184
self->command = NULL;
187
/* Free message info (this is from strdup()) */
191
self->message = NULL;
194
/* Free notice info (this is from strdup()) */
200
/* Destruct the result object in the chain */
203
QR_Destructor(self->next);
209
mylog("QResult: exit DESTRUCTOR\n");
214
QR_set_command(QResultClass *self, const char *msg)
219
self->command = msg ? strdup(msg) : NULL;
224
QR_set_message(QResultClass *self, const char *msg)
229
self->message = msg ? strdup(msg) : NULL;
234
QR_set_notice(QResultClass *self, const char *msg)
239
self->notice = msg ? strdup(msg) : NULL;
244
QR_free_memory(QResultClass *self)
248
register TupleField *tuple = self->backend_tuples;
249
int num_backend_rows = self->num_backend_rows;
250
int num_fields = self->num_fields;
252
mylog("QResult: free memory in, fcount=%d\n", num_backend_rows);
254
if (self->backend_tuples)
256
for (row = 0; row < num_backend_rows; row++)
258
mylog("row = %d, num_fields = %d\n", row, num_fields);
259
for (lf = 0; lf < num_fields; lf++)
261
if (tuple[lf].value != NULL)
263
mylog("free [lf=%d] %u\n", lf, tuple[lf].value);
264
free(tuple[lf].value);
267
tuple += num_fields; /* next row */
270
free(self->backend_tuples);
271
self->count_backend_allocated = 0;
272
self->backend_tuples = NULL;
278
self->count_keyset_allocated = 0;
282
free(self->rollback);
285
self->rollback = NULL;
292
self->deleted = NULL;
295
self->num_total_rows = 0;
296
self->num_backend_rows = 0;
298
mylog("QResult: free memory out\n");
302
/* This function is called by send_query() */
304
QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
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!
316
ConnInfo *ci = &(conn->connInfo);
317
BOOL fetch_cursor = (ci->drivers.use_declarefetch && cursor && cursor[0]);
321
mylog("QR_fetch_tuples: cursor = '%s', self->cursor=%u\n", (cursor == NULL) ? "" : cursor, self->cursor);
329
if (!cursor || cursor[0] == '\0')
331
self->status = PGRES_INTERNAL_ERROR;
332
QR_set_message(self, "Internal Error -- no cursor for fetch");
335
self->cursor = strdup(cursor);
339
* Read the field attributes.
341
* $$$$ Should do some error control HERE! $$$$
343
if (CI_read_fields(self->fields, self->conn))
345
self->status = PGRES_FIELDS_OK;
346
self->num_fields = CI_get_num_fields(self->fields);
348
self->num_fields -= 2;
352
self->status = PGRES_BAD_RESPONSE;
353
QR_set_message(self, "Error reading field information");
357
mylog("QR_fetch_tuples: past CI_read_fields: num_fields = %d\n", self->num_fields);
361
if (self->cache_size <= 0)
362
self->cache_size = ci->drivers.fetch_max;
363
tuple_size = self->cache_size;
366
tuple_size = TUPLE_MALLOC_INC;
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)
373
self->backend_tuples = (TupleField *) malloc(self->num_fields * sizeof(TupleField) * tuple_size);
374
if (!self->backend_tuples)
376
self->status = PGRES_FATAL_ERROR;
377
QR_set_message(self, "Could not get memory for tuple cache.");
380
self->count_backend_allocated = tuple_size;
384
if (self->keyset = (KeySet *) calloc(sizeof(KeySet), tuple_size), !self->keyset)
386
self->status = PGRES_FATAL_ERROR;
387
QR_set_message(self, "Could not get memory for tuple cache.");
390
self->count_keyset_allocated = tuple_size;
393
self->inTuples = TRUE;
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;
401
return QR_next_tuple(self);
406
* Always have to read the field attributes. But we dont have to
407
* reallocate memory for them!
410
if (!CI_read_fields(NULL, self->conn))
412
self->status = PGRES_BAD_RESPONSE;
413
QR_set_message(self, "Error reading field information");
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.
426
QR_close(QResultClass *self)
430
if (self->conn && self->cursor && self->conn->connInfo.drivers.use_declarefetch)
434
sprintf(buf, "close %s", self->cursor);
435
mylog("QResult: closing cursor: '%s'\n", buf);
437
res = CC_send_query(self->conn, buf, NULL, CLEAR_RESULT_ON_ABORT);
439
self->inTuples = FALSE;
440
self->currTuple = -1;
447
self->status = PGRES_FATAL_ERROR;
448
QR_set_message(self, "Error closing cursor.");
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)
456
mylog("QResult: END transaction on conn=%u\n", self->conn);
458
if (!CC_commit(self->conn))
460
self->status = PGRES_FATAL_ERROR;
461
QR_set_message(self, "Error ending transaction.");
471
/* This function is called by fetch_tuples() AND SQLFetch() */
473
QR_next_tuple(QResultClass *self)
479
/* Speed up access */
480
int fetch_count = self->fetch_count;
481
int num_backend_rows = self->num_backend_rows;
484
int end_tuple = self->rowset_size + self->base;
485
char corrected = FALSE;
486
TupleField *the_tuples = self->backend_tuples;
488
/* ERROR_MSG_LENGTH is sufficient */
489
char msgbuffer[ERROR_MSG_LENGTH + 1];
491
/* QR_set_command() dups this string so doesn't need static */
492
char cmdbuffer[ERROR_MSG_LENGTH + 1];
499
if (fetch_count < num_backend_rows)
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 */
507
else if (self->num_backend_rows < self->cache_size)
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;
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.
524
self->tupleField = NULL;
528
ci = &(self->conn->connInfo);
529
if (!self->cursor || !ci->drivers.use_declarefetch)
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 */
537
if (self->base == num_backend_rows)
540
TupleField *tuple = self->backend_tuples;
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;
549
fetch_size = self->rowset_size;
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++)
556
for (lf = 0; lf < self->num_fields; lf++)
558
if (tuple[lf].value != NULL)
560
free(tuple[lf].value);
561
tuple[lf].value = NULL;
564
tuple += self->num_fields;
566
self->fetch_count = 1;
570
/* need to correct */
573
fetch_size = end_tuple - num_backend_rows;
575
self->cache_size += fetch_size;
577
offset = self->fetch_count;
581
if (!self->backend_tuples || self->cache_size > self->count_backend_allocated)
583
self->count_backend_allocated = 0;
584
if (self->num_fields > 0)
586
self->backend_tuples = (TupleField *) realloc(self->backend_tuples,
587
self->num_fields * sizeof(TupleField) * self->cache_size);
588
if (!self->backend_tuples)
590
self->status = PGRES_FATAL_ERROR;
591
QR_set_message(self, "Out of memory while reading tuples.");
594
self->count_backend_allocated = self->cache_size;
597
if (self->haskeyset && (!self->keyset || self->cache_size > self->count_keyset_allocated))
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;
603
sprintf(fetch, "fetch %d in %s", fetch_size, self->cursor);
605
mylog("next_tuple: sending actual fetch (%d) query '%s'\n", fetch_size, fetch);
607
/* don't read ahead for the next tuple (self) ! */
608
qi.row_size = self->cache_size;
611
res = CC_send_query(self->conn, fetch, &qi, CLEAR_RESULT_ON_ABORT);
614
self->status = PGRES_FATAL_ERROR;
615
QR_set_message(self, "Error fetching next group.");
618
self->inTuples = TRUE;
622
mylog("next_tuple: inTuples = true, falling through: fcount = %d, fetch_count = %d\n", self->num_backend_rows, self->fetch_count);
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.
629
self->fetch_count = 0;
636
self->num_backend_rows = 0;
639
sock = CC_get_socket(self->conn);
640
self->tupleField = NULL;
641
ci = &(self->conn->connInfo);
645
id = SOCK_get_char(sock);
651
mylog("Portal name within tuples ?? just ignore\n");
652
SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
655
mylog("Tuples within tuples ?? OK try to handle them\n");
656
self->inTuples = FALSE;
657
if (self->num_total_rows > 0)
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);
665
mylog(" [ fetched 0 rows ]\n");
667
/* add new Result class */
668
self->next = QR_Constructor();
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);
675
QR_set_cache_size(self->next, self->cache_size);
677
if (!QR_fetch_tuples(self, self->conn, NULL))
679
CC_set_error(self->conn, CONNECTION_COULD_NOT_RECEIVE, QR_get_message(self));
684
case 'B': /* Tuples in binary format */
685
case 'D': /* Tuples in ASCII format */
687
if (!self->cursor || !ci->drivers.use_declarefetch)
689
if (self->num_fields > 0 &&
690
self->num_total_rows >= self->count_backend_allocated)
692
int tuple_size = self->count_backend_allocated;
694
mylog("REALLOC: old_count = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
696
self->backend_tuples = (TupleField *) realloc(self->backend_tuples,
697
tuple_size * self->num_fields * sizeof(TupleField));
698
if (!self->backend_tuples)
700
self->status = PGRES_FATAL_ERROR;
701
QR_set_message(self, "Out of memory while reading tuples.");
704
self->count_backend_allocated = tuple_size;
706
if (self->haskeyset &&
707
self->num_total_rows >= self->count_keyset_allocated)
709
int tuple_size = self->count_keyset_allocated;
711
self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * tuple_size);
712
self->count_keyset_allocated = tuple_size;
716
if (!QR_read_tuple(self, (char) (id == 0)))
718
self->status = PGRES_BAD_RESPONSE;
719
QR_set_message(self, "Error reading the tuple");
722
self->num_total_rows++;
723
if (self->num_fields > 0)
724
self->num_backend_rows++;
725
break; /* continue reading */
727
case 'C': /* End of tuple list */
728
SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
729
QR_set_command(self, cmdbuffer);
731
mylog("end of tuple list -- setting inUse to false: this = %u\n", self);
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)
738
/* set to first row */
739
self->tupleField = self->backend_tuples + (offset * self->num_fields);
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 */
749
case 'E': /* Error */
750
msg_truncated = SOCK_get_string(sock, msgbuffer,
753
/* Remove a newline */
754
if (msgbuffer[0] != '\0' && msgbuffer[strlen(msgbuffer) - 1] == '\n')
755
msgbuffer[strlen(msgbuffer) - 1] = '\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);
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);
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);
782
default: /* this should only happen if the backend
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);
797
QR_read_tuple(QResultClass *self, char binary)
800
TupleField *this_tuplefield;
801
KeySet *this_keyset = NULL;
803
bitmap[MAX_FIELDS]; /* Max. len of the bitmap */
804
Int2 bitmaplen; /* len of the bitmap in bytes */
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;
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);
821
this_keyset = self->keyset + self->num_total_rows;
822
this_keyset->status = 0;
825
bitmaplen = (Int2) ci_num_fields / BYTELEN;
826
if ((ci_num_fields % BYTELEN) > 0)
830
* At first the server sends a bitmap that indicates which database
833
SOCK_get_n_char(sock, bitmap, bitmaplen);
837
bmp = bitmap[bitmap_pos];
840
for (field_lf = 0; field_lf < ci_num_fields; field_lf++)
842
/* Check if the current field is NULL */
845
/* YES, it is NULL ! */
846
this_tuplefield[field_lf].len = 0;
847
this_tuplefield[field_lf].value = 0;
852
* NO, the field is not null. so get at first the length of
853
* the field (four bytes)
855
len = SOCK_get_int(sock, VARHDRSZ);
859
if (field_lf >= effective_cols)
862
buffer = (char *) malloc(len + 1);
863
SOCK_get_n_char(sock, buffer, len);
866
mylog("qresult: len=%d, buffer='%s'\n", len, buffer);
868
if (field_lf >= effective_cols)
870
if (field_lf == effective_cols)
871
sscanf(buffer, "(%lu,%hu)",
872
&this_keyset->blocknum, &this_keyset->offset);
874
this_keyset->oid = strtoul(buffer, NULL, 10);
878
this_tuplefield[field_lf].len = len;
879
this_tuplefield[field_lf].value = buffer;
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
890
if (flds && flds->display_size && flds->display_size[field_lf] < len)
891
flds->display_size[field_lf] = len;
896
* Now adjust for the next bit to be scanned in the next loop.
899
if (BYTELEN == bitcnt)
902
bmp = bitmap[bitmap_pos];