qresult.c 16.3 KB
Newer Older
1
/* Module:			qresult.c
2
 *
3 4 5 6 7 8 9 10
 * Description:		This module contains functions related to
 *					managing result information (i.e, fetching rows from the backend,
 *					managing the tuple cache, etc.) and retrieving it.
 *					Depending on the situation, a QResultClass will hold either data
 *					from the backend or a manually built result (see "qresult.h" to
 *					see which functions/macros are for manual or backend results.
 *					For manually built results, the QResultClass simply points to
 *					TupleList and ColumnInfo structures, which actually hold the data.
11
 *
12
 * Classes:			QResultClass (Functions prefix: "QR_")
13
 *
14
 * API functions:	none
15
 *
16
 * Comments:		See "notice.txt" for copyright and license information.
17 18
 *
 */
19 20 21 22

#include "qresult.h"
#include "misc.h"
#include <stdio.h>
Byron Nikolaidis's avatar
Byron Nikolaidis committed
23 24 25 26 27 28 29 30
#include <string.h>

#ifndef TRUE
#define TRUE	(BOOL)1
#endif
#ifndef FALSE
#define FALSE	(BOOL)0
#endif
31 32 33

extern GLOBAL_VALUES globals;

34
/*	Used for building a Manual Result only */
35
/*	All info functions call this function to create the manual result set. */
36
void
Bruce Momjian's avatar
Bruce Momjian committed
37
QR_set_num_fields(QResultClass *self, int new_num_fields)
38 39 40
{
	mylog("in QR_set_num_fields\n");

41 42 43
	CI_set_num_fields(self->fields, new_num_fields);
	if (self->manual_tuples)
		TL_Destructor(self->manual_tuples);
44

45
	self->manual_tuples = TL_Constructor(new_num_fields);
46 47 48 49

	mylog("exit QR_set_num_fields\n");
}

50
void
Bruce Momjian's avatar
Bruce Momjian committed
51
QR_set_position(QResultClass *self, int pos)
52 53 54 55 56
{
	self->tupleField = self->backend_tuples + ((self->base + pos) * self->num_fields);
}

void
Bruce Momjian's avatar
Bruce Momjian committed
57
QR_set_cache_size(QResultClass *self, int cache_size)
58 59 60 61
{
	self->cache_size = cache_size;
}

62
void
Bruce Momjian's avatar
Bruce Momjian committed
63
QR_set_rowset_size(QResultClass *self, int rowset_size)
64 65 66 67 68
{
	self->rowset_size = rowset_size;
}

void
Bruce Momjian's avatar
Bruce Momjian committed
69
QR_inc_base(QResultClass *self, int base_inc)
70 71 72 73
{
	self->base += base_inc;
}

74
/************************************/
75
/* CLASS QResult					*/
76 77 78
/************************************/

QResultClass *
79
QR_Constructor(void)
80
{
81
	QResultClass *rv;
82 83 84 85

	mylog("in QR_Constructor\n");
	rv = (QResultClass *) malloc(sizeof(QResultClass));

86 87
	if (rv != NULL)
	{
88 89 90
		rv->status = PGRES_EMPTY_QUERY;

		/* construct the column info */
91 92
		if (!(rv->fields = CI_Constructor()))
		{
93 94 95
			free(rv);
			return NULL;
		}
96 97
		rv->manual_tuples = NULL;
		rv->backend_tuples = NULL;
98 99 100 101 102 103 104
		rv->message = NULL;
		rv->command = NULL;
		rv->notice = NULL;
		rv->conn = NULL;
		rv->inTuples = FALSE;
		rv->fcount = 0;
		rv->fetch_count = 0;
105 106
		rv->base = 0;
		rv->currTuple = -1;
107 108 109
		rv->num_fields = 0;
		rv->tupleField = NULL;
		rv->cursor = NULL;
110 111 112

		rv->cache_size = globals.fetch_max;
		rv->rowset_size = 1;
113 114 115 116 117 118 119
	}

	mylog("exit QR_Constructor\n");
	return rv;
}

void
Bruce Momjian's avatar
Bruce Momjian committed
120
QR_Destructor(QResultClass *self)
121 122 123 124
{
	mylog("QResult: in DESTRUCTOR\n");

	/* manual result set tuples */
125
	if (self->manual_tuples)
126 127
		TL_Destructor(self->manual_tuples);

128 129
	/* If conn is defined, then we may have used "backend_tuples", */
	/* so in case we need to, free it up.  Also, close the cursor. */
130
	if (self->conn && self->conn->sock && CC_is_in_trans(self->conn))
131
		QR_close(self);			/* close the cursor if there is one */
132

133
	QR_free_memory(self);		/* safe to call anyway */
134

135
	/* Should have been freed in the close() but just in case... */
136 137 138
	if (self->cursor)
		free(self->cursor);

139
	/* Free up column info */
140 141 142
	if (self->fields)
		CI_Destructor(self->fields);

143
	/* Free command info (this is from strdup()) */
144 145 146
	if (self->command)
		free(self->command);

147
	/* Free notice info (this is from strdup()) */
148 149 150 151 152 153 154 155 156
	if (self->notice)
		free(self->notice);

	free(self);

	mylog("QResult: exit DESTRUCTOR\n");
}

void
Bruce Momjian's avatar
Bruce Momjian committed
157
QR_set_command(QResultClass *self, char *msg)
158 159 160 161 162 163 164
{
	if (self->command)
		free(self->command);

	self->command = msg ? strdup(msg) : NULL;
}

165
void
Bruce Momjian's avatar
Bruce Momjian committed
166
QR_set_notice(QResultClass *self, char *msg)
167 168 169 170 171 172 173
{
	if (self->notice)
		free(self->notice);

	self->notice = msg ? strdup(msg) : NULL;
}

174
void
Bruce Momjian's avatar
Bruce Momjian committed
175
QR_free_memory(QResultClass *self)
176
{
177 178 179 180 181
	register int lf,
				row;
	register TupleField *tuple = self->backend_tuples;
	int			fcount = self->fcount;
	int			num_fields = self->num_fields;
182 183 184

	mylog("QResult: free memory in, fcount=%d\n", fcount);

185 186 187 188
	if (self->backend_tuples)
	{
		for (row = 0; row < fcount; row++)
		{
189
			mylog("row = %d, num_fields = %d\n", row, num_fields);
190 191 192 193
			for (lf = 0; lf < num_fields; lf++)
			{
				if (tuple[lf].value != NULL)
				{
194 195 196 197
					mylog("free [lf=%d] %u\n", lf, tuple[lf].value);
					free(tuple[lf].value);
				}
			}
198
			tuple += num_fields;/* next row */
199 200 201 202 203 204 205 206 207 208 209
		}

		free(self->backend_tuples);
		self->backend_tuples = NULL;
	}

	self->fcount = 0;

	mylog("QResult: free memory out\n");
}

210
/*	This function is called by send_query() */
211
char
Bruce Momjian's avatar
Bruce Momjian committed
212
QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
213
{
214 215 216 217 218 219 220 221 222
	int			tuple_size;

	/* If called from send_query the first time (conn != NULL),  */
	/* then set the inTuples state, */
	/* and read the tuples.  If conn is NULL, */
	/* it implies that we are being called from next_tuple(), */
	/* like to get more rows so don't call next_tuple again! */
	if (conn != NULL)
	{
223 224
		self->conn = conn;

225
		mylog("QR_fetch_tuples: cursor = '%s', self->cursor=%u\n", (cursor == NULL) ? "" : cursor, self->cursor);
226 227 228 229

		if (self->cursor)
			free(self->cursor);

230 231 232 233
		if (globals.use_declarefetch)
		{
			if (!cursor || cursor[0] == '\0')
			{
234 235 236 237 238
				self->status = PGRES_INTERNAL_ERROR;
				QR_set_message(self, "Internal Error -- no cursor for fetch");
				return FALSE;
			}
			self->cursor = strdup(cursor);
239
		}
240 241 242 243 244

		/* Read the field attributes. */
		/* $$$$ Should do some error control HERE! $$$$ */
		if (CI_read_fields(self->fields, self->conn))
		{
245 246 247
			self->status = PGRES_FIELDS_OK;
			self->num_fields = CI_get_num_fields(self->fields);
		}
248 249
		else
		{
250 251 252 253 254 255 256
			self->status = PGRES_BAD_RESPONSE;
			QR_set_message(self, "Error reading field information");
			return FALSE;
		}

		mylog("QR_fetch_tuples: past CI_read_fields: num_fields = %d\n", self->num_fields);

257
		if (globals.use_declarefetch)
258 259 260 261
			tuple_size = self->cache_size;
		else
			tuple_size = TUPLE_MALLOC_INC;

262
		/* allocate memory for the tuple cache */
263 264
		mylog("MALLOC: tuple_size = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
		self->backend_tuples = (TupleField *) malloc(self->num_fields * sizeof(TupleField) * tuple_size);
265 266 267
		if (!self->backend_tuples)
		{
			self->status = PGRES_FATAL_ERROR;
268 269 270 271 272 273
			QR_set_message(self, "Could not get memory for tuple cache.");
			return FALSE;
		}

		self->inTuples = TRUE;

274

275 276 277
		/* Force a read to occur in next_tuple */
		self->fcount = tuple_size + 1;
		self->fetch_count = tuple_size + 1;
278
		self->base = 0;
279 280 281

		return QR_next_tuple(self);
	}
282 283 284 285
	else
	{
		/* Always have to read the field attributes. */
		/* But we dont have to reallocate memory for them! */
286

287 288
		if (!CI_read_fields(NULL, self->conn))
		{
289 290 291 292
			self->status = PGRES_BAD_RESPONSE;
			QR_set_message(self, "Error reading field information");
			return FALSE;
		}
Byron Nikolaidis's avatar
Byron Nikolaidis committed
293
		return TRUE;
294 295 296
	}
}

297 298
/*	Close the cursor and end the transaction (if no cursors left) */
/*	We only close cursor/end the transaction if a cursor was used. */
299
int
Bruce Momjian's avatar
Bruce Momjian committed
300
QR_close(QResultClass *self)
301
{
302
	QResultClass *res;
303

304 305 306
	if (globals.use_declarefetch && self->conn && self->cursor)
	{
		char		buf[64];
307

308
		sprintf(buf, "close %s", self->cursor);
309 310
		mylog("QResult: closing cursor: '%s'\n", buf);

311
		res = CC_send_query(self->conn, buf, NULL);
312 313

		self->inTuples = FALSE;
314
		self->currTuple = -1;
315

316 317 318
		free(self->cursor);
		self->cursor = NULL;

319 320
		if (res == NULL)
		{
321 322 323 324 325
			self->status = PGRES_FATAL_ERROR;
			QR_set_message(self, "Error closing cursor.");
			return FALSE;
		}

326 327 328
		/* End the transaction if there are no cursors left on this conn */
		if (CC_cursor_count(self->conn) == 0)
		{
329 330
			mylog("QResult: END transaction on conn=%u\n", self->conn);

331
			res = CC_send_query(self->conn, "END", NULL);
332 333 334

			CC_set_no_trans(self->conn);

335 336
			if (res == NULL)
			{
337 338 339 340 341
				self->status = PGRES_FATAL_ERROR;
				QR_set_message(self, "Error ending transaction.");
				return FALSE;
			}
		}
342 343 344 345 346
	}

	return TRUE;
}

347
/*	This function is called by fetch_tuples() AND SQLFetch() */
348
int
Bruce Momjian's avatar
Bruce Momjian committed
349
QR_next_tuple(QResultClass *self)
350
{
351 352 353 354
	int			id;
	QResultClass *res;
	SocketClass *sock;

355
/* Speed up access */
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
	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 static */
	char		fetch[128];
	QueryInfo	qi;

	if (fetch_count < fcount)
	{							/* return a row from cache */
372
		mylog("next_tuple: fetch_count < fcount: returning tuple %d, fcount = %d\n", fetch_count, fcount);
373
		self->tupleField = the_tuples + (fetch_count * self->num_fields);		/* next row */
374 375 376
		self->fetch_count++;
		return TRUE;
	}
377 378 379 380 381 382 383
	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 */
384
	}
385 386
	else
	{
Bruce Momjian's avatar
Bruce Momjian committed
387

388 389 390 391 392
		/*
		 * 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.
		 */
393
		self->tupleField = NULL;
394

395 396 397 398
		if (!self->inTuples)
		{
			if (!globals.use_declarefetch)
			{
399 400 401
				mylog("next_tuple: ALL_ROWS: done, fcount = %d, fetch_count = %d\n", fcount, fetch_count);
				self->tupleField = NULL;
				self->status = PGRES_END_TUPLES;
402
				return -1;		/* end of tuples */
403 404
			}

405 406
			if (self->base == fcount)
			{					/* not a correction */
407

408
				/* Determine the optimum cache size.  */
409 410 411 412 413 414 415 416
				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;
417 418 419 420
				self->fetch_count = 1;
			}
			else
			{					/* need to correct */
421 422 423 424 425 426 427 428 429 430 431 432 433

				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);
434 435 436
			if (!self->backend_tuples)
			{
				self->status = PGRES_FATAL_ERROR;
437 438 439 440
				QR_set_message(self, "Out of memory while reading tuples.");
				return FALSE;
			}
			sprintf(fetch, "fetch %d in %s", fetch_size, self->cursor);
441

442
			mylog("next_tuple: sending actual fetch (%d) query '%s'\n", fetch_size, fetch);
443

444
			/* don't read ahead for the next tuple (self) ! */
445 446 447 448
			qi.row_size = self->cache_size;
			qi.result_in = self;
			qi.cursor = NULL;
			res = CC_send_query(self->conn, fetch, &qi);
449 450
			if (res == NULL)
			{
451 452 453 454 455 456
				self->status = PGRES_FATAL_ERROR;
				QR_set_message(self, "Error fetching next group.");
				return FALSE;
			}
			self->inTuples = TRUE;
		}
457 458
		else
		{
459
			mylog("next_tuple: inTuples = true, falling through: fcount = %d, fetch_count = %d\n", self->fcount, self->fetch_count);
460 461 462 463 464 465

			/*
			 * 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.
			 */
466 467
			self->fetch_count = 0;
		}
468 469
	}

470 471
	if (!corrected)
	{
472 473
		self->base = 0;
		self->fcount = 0;
474 475 476 477 478 479
	}


	sock = CC_get_socket(self->conn);
	self->tupleField = NULL;

480 481
	for (;;)
	{
482
		id = SOCK_get_char(sock);
483

484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
		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;
					}
				}
507

508 509 510 511
				if (!QR_read_tuple(self, (char) (id == 0)))
				{
					self->status = PGRES_BAD_RESPONSE;
					QR_set_message(self, "Error reading the tuple");
512
					return FALSE;
513 514
				}

515 516
				self->fcount++;
				break;			/* continue reading */
517 518


519 520 521
			case 'C':			/* End of tuple list */
				SOCK_get_string(sock, cmdbuffer, MAX_MESSAGE_LEN);
				QR_set_command(self, cmdbuffer);
522

523
				mylog("end of tuple list -- setting inUse to false: this = %u\n", self);
524

525 526 527 528 529
				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);
530

531 532 533 534 535 536 537 538 539 540 541
					/* 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 */
				}
542

543 544 545 546
			case 'E':			/* Error */
				SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
				QR_set_message(self, msgbuffer);
				self->status = PGRES_FATAL_ERROR;
547

548 549
				if (!strncmp(msgbuffer, "FATAL", 5))
					CC_set_no_trans(self->conn);
550

551
				qlog("ERROR from backend in next_tuple: '%s'\n", msgbuffer);
552

553
				return FALSE;
554

555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
			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;
570 571 572 573 574 575
		}
	}
	return TRUE;
}

char
Bruce Momjian's avatar
Bruce Momjian committed
576
QR_read_tuple(QResultClass *self, char binary)
577
{
578 579 580 581 582 583 584 585 586 587 588 589
	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 access */
	SocketClass *sock = CC_get_socket(self->conn);
	ColumnInfoClass *flds;
590

591 592 593 594 595 596 597 598 599

	/* 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++;

	/*
600 601 602
	 * At first the server sends a bitmap that indicates which database
	 * fields are null
	 */
603 604 605 606 607 608
	SOCK_get_n_char(sock, bitmap, bitmaplen);

	bitmap_pos = 0;
	bitcnt = 0;
	bmp = bitmap[bitmap_pos];

609 610
	for (field_lf = 0; field_lf < num_fields; field_lf++)
	{
611
		/* Check if the current field is NULL */
612 613
		if (!(bmp & 0200))
		{
614 615 616
			/* YES, it is NULL ! */
			this_tuplefield[field_lf].len = 0;
			this_tuplefield[field_lf].value = 0;
617 618 619
		}
		else
		{
Bruce Momjian's avatar
Bruce Momjian committed
620

621
			/*
622 623 624
			 * NO, the field is not null. so get at first the length of
			 * the field (four bytes)
			 */
625 626 627 628
			len = SOCK_get_int(sock, VARHDRSZ);
			if (!binary)
				len -= VARHDRSZ;

629
			buffer = (char *) malloc(len + 1);
630 631 632
			SOCK_get_n_char(sock, buffer, len);
			buffer[len] = '\0';

633
			mylog("qresult: len=%d, buffer='%s'\n", len, buffer);
634 635 636

			this_tuplefield[field_lf].len = len;
			this_tuplefield[field_lf].value = buffer;
637

638 639 640 641 642 643 644 645
			/*
			 * 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!
			 */
646 647 648 649

			flds = self->fields;
			if (flds->display_size[field_lf] < len)
				flds->display_size[field_lf] = len;
650
		}
651

652
		/*
653 654
		 * Now adjust for the next bit to be scanned in the next loop.
		 */
655
		bitcnt++;
656 657
		if (BYTELEN == bitcnt)
		{
658 659 660
			bitmap_pos++;
			bmp = bitmap[bitmap_pos];
			bitcnt = 0;
661 662
		}
		else
663 664
			bmp <<= 1;
	}
665
	self->currTuple++;
666 667
	return TRUE;
}