📄 qresult.c
字号:
} /* End the transaction if there are no cursors left on this conn */ if (CC_cursor_count(self->conn) == 0) { mylog("QResult: END transaction on conn=%u\n", self->conn); res = CC_send_query(self->conn, "END", NULL); CC_set_no_trans(self->conn); if (res == NULL) { self->status = PGRES_FATAL_ERROR; QR_set_message(self, "Error ending transaction."); return FALSE; } } } return TRUE;}// This function is called by fetch_tuples() AND SQLFetch()intQR_next_tuple(QResultClass *self){int id;QResultClass *res;SocketClass *sock;/* Speed up access */int fetch_count = self->fetch_count;int fcount = self->fcount;int fetch_size, offset= 0;int end_tuple = self->rowset_size + self->base;char corrected = FALSE;TupleField *the_tuples = self->backend_tuples;static char msgbuffer[MAX_MESSAGE_LEN+1];char cmdbuffer[MAX_MESSAGE_LEN+1]; // QR_set_command() dups this string so dont need staticchar fetch[128];QueryInfo qi; if (fetch_count < fcount) { /* return a row from cache */ mylog("next_tuple: fetch_count < fcount: returning tuple %d, fcount = %d\n", fetch_count, fcount); self->tupleField = the_tuples + (fetch_count * self->num_fields); /* next row */ self->fetch_count++; return TRUE; } else if (self->fcount < self->cache_size) { /* last row from cache */ // We are done because we didn't even get CACHE_SIZE tuples mylog("next_tuple: fcount < CACHE_SIZE: fcount = %d, fetch_count = %d\n", fcount, fetch_count); self->tupleField = NULL; self->status = PGRES_END_TUPLES; return -1; /* end of tuples */ } else { /* See if we need to fetch another group of rows. We may be being called from send_query(), and if so, don't send another fetch, just fall through and read the tuples. */ self->tupleField = NULL; if ( ! self->inTuples) { if ( ! globals.use_declarefetch) { mylog("next_tuple: ALL_ROWS: done, fcount = %d, fetch_count = %d\n", fcount, fetch_count); self->tupleField = NULL; self->status = PGRES_END_TUPLES; return -1; /* end of tuples */ } if (self->base == fcount) { /* not a correction */ /* Determine the optimum cache size. */ if (globals.fetch_max % self->rowset_size == 0) fetch_size = globals.fetch_max; else if (self->rowset_size < globals.fetch_max) fetch_size = (globals.fetch_max / self->rowset_size) * self->rowset_size; else fetch_size = self->rowset_size; self->cache_size = fetch_size; self->fetch_count = 1; } else { /* need to correct */ corrected = TRUE; fetch_size = end_tuple - fcount; self->cache_size += fetch_size; offset = self->fetch_count; self->fetch_count++; } self->backend_tuples = (TupleField *) realloc(self->backend_tuples, self->num_fields * sizeof(TupleField) * self->cache_size); if ( ! self->backend_tuples) { self->status = PGRES_FATAL_ERROR; QR_set_message(self, "Out of memory while reading tuples."); return FALSE; } sprintf(fetch, "fetch %d in %s", fetch_size, self->cursor); mylog("next_tuple: sending actual fetch (%d) query '%s'\n", fetch_size, fetch); // don't read ahead for the next tuple (self) ! qi.row_size = self->cache_size; qi.result_in = self; qi.cursor = NULL; res = CC_send_query(self->conn, fetch, &qi); if (res == NULL) { self->status = PGRES_FATAL_ERROR; QR_set_message(self, "Error fetching next group."); return FALSE; } self->inTuples = TRUE; } else { mylog("next_tuple: inTuples = true, falling through: fcount = %d, fetch_count = %d\n", self->fcount, self->fetch_count); /* This is a pre-fetch (fetching rows right after query but before any real SQLFetch() calls. This is done so the field attributes are available. */ self->fetch_count = 0; } } if ( ! corrected) { self->base = 0; self->fcount = 0; } sock = CC_get_socket(self->conn); self->tupleField = NULL; for ( ; ;) { id = SOCK_get_char(sock); switch (id) { case 'T': /* Tuples within tuples cannot be handled */ self->status = PGRES_BAD_RESPONSE; QR_set_message(self, "Tuples within tuples cannot be handled"); return FALSE; case 'B': /* Tuples in binary format */ case 'D': /* Tuples in ASCII format */ if ( ! globals.use_declarefetch && self->fcount > 0 && ! (self->fcount % TUPLE_MALLOC_INC)) { size_t old_size = self->fcount * self->num_fields * sizeof(TupleField); mylog("REALLOC: old_size = %d\n", old_size); self->backend_tuples = (TupleField *) realloc(self->backend_tuples, old_size + (self->num_fields * sizeof(TupleField) * TUPLE_MALLOC_INC)); if ( ! self->backend_tuples) { self->status = PGRES_FATAL_ERROR; QR_set_message(self, "Out of memory while reading tuples."); return FALSE; } } if ( ! QR_read_tuple(self, (char) (id == 0))) { self->status = PGRES_BAD_RESPONSE; QR_set_message(self, "Error reading the tuple"); return FALSE; } self->fcount++; break; // continue reading case 'C': /* End of tuple list */ SOCK_get_string(sock, cmdbuffer, MAX_MESSAGE_LEN); QR_set_command(self, cmdbuffer); mylog("end of tuple list -- setting inUse to false: this = %u\n", self); self->inTuples = FALSE; if (self->fcount > 0) { qlog(" [ fetched %d rows ]\n", self->fcount); mylog("_next_tuple: 'C' fetch_max && fcount = %d\n", self->fcount); /* set to first row */ self->tupleField = self->backend_tuples + (offset * self->num_fields); return TRUE; } else { // We are surely done here (we read 0 tuples) qlog(" [ fetched 0 rows ]\n"); mylog("_next_tuple: 'C': DONE (fcount == 0)\n"); return -1; /* end of tuples */ } case 'E': /* Error */ SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH); QR_set_message(self, msgbuffer); self->status = PGRES_FATAL_ERROR; if ( ! strncmp(msgbuffer, "FATAL", 5)) CC_set_no_trans(self->conn); qlog("ERROR from backend in next_tuple: '%s'\n", msgbuffer); return FALSE; case 'N': /* Notice */ SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH); QR_set_message(self, msgbuffer); self->status = PGRES_NONFATAL_ERROR; qlog("NOTICE from backend in next_tuple: '%s'\n", msgbuffer); continue; default: /* this should only happen if the backend dumped core */ mylog("QR_next_tuple: Unexpected result from backend: id = '%c' (%d)\n", id, id); qlog("QR_next_tuple: Unexpected result from backend: id = '%c' (%d)\n", id, id); QR_set_message(self, "Unexpected result from backend. It probably crashed"); self->status = PGRES_FATAL_ERROR; CC_set_no_trans(self->conn); return FALSE; } } return TRUE;}charQR_read_tuple(QResultClass *self, char binary){Int2 field_lf;TupleField *this_tuplefield;char bmp, bitmap[MAX_FIELDS]; /* Max. len of the bitmap */Int2 bitmaplen; /* len of the bitmap in bytes */Int2 bitmap_pos;Int2 bitcnt;Int4 len;char *buffer;int num_fields = self->num_fields; // speed up accessSocketClass *sock = CC_get_socket(self->conn);ColumnInfoClass *flds; /* set the current row to read the fields into */ this_tuplefield = self->backend_tuples + (self->fcount * num_fields); bitmaplen = (Int2) num_fields / BYTELEN; if ((num_fields % BYTELEN) > 0) bitmaplen++; /* At first the server sends a bitmap that indicates which database fields are null */ SOCK_get_n_char(sock, bitmap, bitmaplen); bitmap_pos = 0; bitcnt = 0; bmp = bitmap[bitmap_pos]; for(field_lf = 0; field_lf < num_fields; field_lf++) { /* Check if the current field is NULL */ if(!(bmp & 0200)) { /* YES, it is NULL ! */ this_tuplefield[field_lf].len = 0; this_tuplefield[field_lf].value = 0; } else { /* NO, the field is not null. so get at first the length of the field (four bytes) */ len = SOCK_get_int(sock, VARHDRSZ); if (!binary) len -= VARHDRSZ; buffer = (char *)malloc(len+1); SOCK_get_n_char(sock, buffer, len); buffer[len] = '\0'; mylog("qresult: len=%d, buffer='%s'\n", len, buffer); this_tuplefield[field_lf].len = len; this_tuplefield[field_lf].value = buffer; /* This can be used to set the longest length of the column for any row in the tuple cache. It would not be accurate for varchar and text fields to use this since a tuple cache is only 100 rows. Bpchar can be handled since the strlen of all rows is fixed, assuming there are not 100 nulls in a row! */ flds = self->fields; if (flds->display_size[field_lf] < len) flds->display_size[field_lf] = len; } /* Now adjust for the next bit to be scanned in the next loop. */ bitcnt++; if (BYTELEN == bitcnt) { bitmap_pos++; bmp = bitmap[bitmap_pos]; bitcnt = 0; } else bmp <<= 1; } self->currTuple++; return TRUE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -