parse.c 20.2 KB
Newer Older
1 2
/*--------
 * Module:			parse.c
Byron Nikolaidis's avatar
Byron Nikolaidis committed
3
 *
4 5
 * Description:		This module contains routines related to parsing SQL
 *					statements.  This can be useful for two reasons:
Byron Nikolaidis's avatar
Byron Nikolaidis committed
6
 *
7 8
 *					1. So the query does not actually have to be executed
 *					to return data about it
Byron Nikolaidis's avatar
Byron Nikolaidis committed
9
 *
10 11 12 13 14
 *					2. To be able to return information about precision,
 *					nullability, aliases, etc. in the functions
 *					SQLDescribeCol and SQLColAttributes.  Currently,
 *					Postgres doesn't return any information about
 *					these things in a query.
Byron Nikolaidis's avatar
Byron Nikolaidis committed
15
 *
16
 * Classes:			none
Byron Nikolaidis's avatar
Byron Nikolaidis committed
17
 *
18
 * API functions:	none
Byron Nikolaidis's avatar
Byron Nikolaidis committed
19
 *
20
 * Comments:		See "notice.txt" for copyright and license information.
21
 *--------
Byron Nikolaidis's avatar
Byron Nikolaidis committed
22
 */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
23 24
/* Multibyte support	Eiji Tokuya 2001-03-15 */

25
#include "psqlodbc.h"
Byron Nikolaidis's avatar
Byron Nikolaidis committed
26 27 28

#include <stdio.h>
#include <string.h>
29
#include <ctype.h>
Byron Nikolaidis's avatar
Byron Nikolaidis committed
30 31 32 33 34

#include "statement.h"
#include "connection.h"
#include "qresult.h"
#include "pgtypes.h"
35
#include "pgapifunc.h"
Byron Nikolaidis's avatar
Byron Nikolaidis committed
36

Hiroshi Inoue's avatar
Hiroshi Inoue committed
37 38 39 40
#ifdef MULTIBYTE
#include "multibyte.h"
#endif

41 42
#ifndef WIN32
#ifndef HAVE_STRICMP
43
#define stricmp(s1,s2)		strcasecmp(s1,s2)
Byron Nikolaidis's avatar
Byron Nikolaidis committed
44 45 46 47 48 49 50 51
#define strnicmp(s1,s2,n)	strncasecmp(s1,s2,n)
#endif
#endif

#define FLD_INCR	32
#define TAB_INCR	8
#define COL_INCR	16

52 53 54
char	   *getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric);
void		getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k);
char		searchColInfo(COL_INFO *col_info, FIELD_INFO *fi);
55

56

Byron Nikolaidis's avatar
Byron Nikolaidis committed
57 58 59
char *
getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric)
{
60 61 62 63
	int			i = 0;
	int			out = 0;
	char		qc,
				in_escape = FALSE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
64 65 66 67 68 69 70

	if (smax <= 1)
		return NULL;

	smax--;

	/* skip leading delimiters */
71 72
	while (isspace((unsigned char) s[i]) || s[i] == ',')
	{
73
		/* mylog("skipping '%c'\n", s[i]); */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
74 75 76
		i++;
	}

77
	if (s[i] == '\0')
78
	{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
79 80 81 82
		token[0] = '\0';
		return NULL;
	}

83 84 85 86 87 88
	if (quote)
		*quote = FALSE;
	if (dquote)
		*dquote = FALSE;
	if (numeric)
		*numeric = FALSE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
89 90

	/* get the next token */
91 92 93
	while (!isspace((unsigned char) s[i]) && s[i] != ',' &&
		   s[i] != '\0' && out != smax)
	{
94 95 96 97 98 99 100
#ifdef MULTIBYTE
		if (multibyte_char_check(s[i]) != 0)
		{
			token[out++] = s[i++];
			continue;
		}
#endif			
101 102 103
		/* Handle quoted stuff */
		if (out == 0 && (s[i] == '\"' || s[i] == '\''))
		{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
104
			qc = s[i];
105 106 107 108
			if (qc == '\"')
			{
				if (dquote)
					*dquote = TRUE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
109
			}
110 111 112 113
			if (qc == '\'')
			{
				if (quote)
					*quote = TRUE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
114 115
			}

116 117 118
			i++;				/* dont return the quote */
			while (s[i] != '\0' && out != smax)
			{
Hiroshi Inoue's avatar
Hiroshi Inoue committed
119
#ifdef MULTIBYTE
120
				if (multibyte_char_check(s[i]) != 0)
121
				{
122 123 124 125 126 127
					token[out++] = s[i++];
					continue;
				}
#endif			
				if (s[i] == qc && !in_escape)
					break;
128 129
				if (s[i] == '\\' && !in_escape)
				{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
130
					in_escape = TRUE;
131
				}
132 133 134
				else
				{
					in_escape = FALSE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
135 136 137 138 139 140 141 142 143
					token[out++] = s[i];
				}
				i++;
			}
			if (s[i] == qc)
				i++;
			break;
		}

144 145 146 147 148
		/* Check for numeric literals */
		if (out == 0 && isdigit((unsigned char) s[i]))
		{
			if (numeric)
				*numeric = TRUE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
149
			token[out++] = s[i++];
150
			while (isalnum((unsigned char) s[i]) || s[i] == '.')
Byron Nikolaidis's avatar
Byron Nikolaidis committed
151 152 153 154 155
				token[out++] = s[i++];

			break;
		}

156 157
		if (ispunct((unsigned char) s[i]) && s[i] != '_')
		{
158 159
			mylog("got ispunct: s[%d] = '%c'\n", i, s[i]);

160 161
			if (out == 0)
			{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
162 163 164 165 166 167 168 169 170 171 172 173 174
				token[out++] = s[i++];
				break;
			}
			else
				break;
		}

		if (out != smax)
			token[out++] = s[i];

		i++;
	}

175
	/* mylog("done -- s[%d] = '%c'\n", i, s[i]); */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
176 177 178

	token[out] = '\0';

179 180
	/* find the delimiter  */
	while (isspace((unsigned char) s[i]))
Byron Nikolaidis's avatar
Byron Nikolaidis committed
181 182
		i++;

183 184 185 186 187
	/* return the most priority delimiter */
	if (s[i] == ',')
	{
		if (delim)
			*delim = s[i];
Byron Nikolaidis's avatar
Byron Nikolaidis committed
188
	}
189 190 191 192
	else if (s[i] == '\0')
	{
		if (delim)
			*delim = '\0';
Byron Nikolaidis's avatar
Byron Nikolaidis committed
193
	}
194 195 196 197
	else
	{
		if (delim)
			*delim = ' ';
Byron Nikolaidis's avatar
Byron Nikolaidis committed
198 199 200
	}

	/* skip trailing blanks  */
201
	while (isspace((unsigned char) s[i]))
Byron Nikolaidis's avatar
Byron Nikolaidis committed
202 203 204 205 206 207
		i++;

	return &s[i];
}


208
#if 0
Byron Nikolaidis's avatar
Byron Nikolaidis committed
209 210 211 212 213 214 215 216 217 218 219 220 221
QR_set_num_fields(stmt->result, 14);
QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
QR_set_field_info(stmt->result, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
QR_set_field_info(stmt->result, 4, "DATA_TYPE", PG_TYPE_INT2, 2);
QR_set_field_info(stmt->result, 5, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
QR_set_field_info(stmt->result, 6, "PRECISION", PG_TYPE_INT4, 4);
QR_set_field_info(stmt->result, 7, "LENGTH", PG_TYPE_INT4, 4);
QR_set_field_info(stmt->result, 8, "SCALE", PG_TYPE_INT2, 2);
QR_set_field_info(stmt->result, 9, "RADIX", PG_TYPE_INT2, 2);
QR_set_field_info(stmt->result, 10, "NULLABLE", PG_TYPE_INT2, 2);
QR_set_field_info(stmt->result, 11, "REMARKS", PG_TYPE_TEXT, 254);
222
/*	User defined fields */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
223 224
QR_set_field_info(stmt->result, 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
QR_set_field_info(stmt->result, 13, "FIELD_TYPE", PG_TYPE_INT4, 4);
225
#endif
Byron Nikolaidis's avatar
Byron Nikolaidis committed
226 227

void
Bruce Momjian's avatar
Bruce Momjian committed
228
getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k)
Byron Nikolaidis's avatar
Byron Nikolaidis committed
229 230 231 232
{
	if (fi->name[0] == '\0')
		strcpy(fi->name, QR_get_value_manual(col_info->result, k, 3));

233 234 235 236 237
	fi->type = atoi(QR_get_value_manual(col_info->result, k, 13));
	fi->precision = atoi(QR_get_value_manual(col_info->result, k, 6));
	fi->length = atoi(QR_get_value_manual(col_info->result, k, 7));
	fi->nullable = atoi(QR_get_value_manual(col_info->result, k, 10));
	fi->display_size = atoi(QR_get_value_manual(col_info->result, k, 12));
Byron Nikolaidis's avatar
Byron Nikolaidis committed
238 239
}

240

Byron Nikolaidis's avatar
Byron Nikolaidis committed
241
char
Bruce Momjian's avatar
Bruce Momjian committed
242
searchColInfo(COL_INFO *col_info, FIELD_INFO *fi)
Byron Nikolaidis's avatar
Byron Nikolaidis committed
243
{
244 245 246
	int			k,
				cmp;
	char	   *col;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
247

248 249
	for (k = 0; k < QR_get_num_tuples(col_info->result); k++)
	{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
250
		col = QR_get_value_manual(col_info->result, k, 3);
251 252 253 254 255
		if (fi->dquote)
			cmp = strcmp(col, fi->name);
		else
			cmp = stricmp(col, fi->name);
		if (!cmp)
256
		{
257 258
			if (!fi->dquote)
				strcpy(fi->name, col);
Byron Nikolaidis's avatar
Byron Nikolaidis committed
259 260 261 262 263 264 265 266 267 268 269 270
			getColInfo(col_info, fi, k);

			mylog("PARSE: searchColInfo: \n");
			return TRUE;
		}
	}

	return FALSE;
}


char
Bruce Momjian's avatar
Bruce Momjian committed
271
parse_statement(StatementClass *stmt)
Byron Nikolaidis's avatar
Byron Nikolaidis committed
272
{
273 274 275 276 277 278 279
	static char *func = "parse_statement";
	char		token[256];
	char		delim,
				quote,
				dquote,
				numeric,
				unquoted;
280
	char	   *ptr, *pptr = NULL;
281 282 283 284
	char		in_select = FALSE,
				in_distinct = FALSE,
				in_on = FALSE,
				in_from = FALSE,
285
				from_found = FALSE,
286 287 288 289 290 291 292 293 294 295 296
				in_where = FALSE,
				in_table = FALSE;
	char		in_field = FALSE,
				in_expr = FALSE,
				in_func = FALSE,
				in_dot = FALSE,
				in_as = FALSE;
	int			j,
				i,
				k = 0,
				n,
297
				first_where = 0,
298 299 300 301 302 303 304 305
				blevel = 0;
	FIELD_INFO **fi;
	TABLE_INFO **ti;
	char		parse;
	ConnectionClass *conn = stmt->hdbc;
	HSTMT		hcol_stmt;
	StatementClass *col_stmt;
	RETCODE		result;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
306

307 308
	mylog("%s: entering...\n", func);

Byron Nikolaidis's avatar
Byron Nikolaidis committed
309 310 311 312 313 314 315
	ptr = stmt->statement;
	fi = stmt->fi;
	ti = stmt->ti;

	stmt->nfld = 0;
	stmt->ntab = 0;

316 317 318 319
#ifdef MULTIBYTE
	multibyte_init();
#endif
	while (pptr = ptr, (ptr = getNextToken(pptr, token, sizeof(token), &delim, &quote, &dquote, &numeric)) != NULL)
320 321
	{
		unquoted = !(quote || dquote);
Byron Nikolaidis's avatar
Byron Nikolaidis committed
322 323 324

		mylog("unquoted=%d, quote=%d, dquote=%d, numeric=%d, delim='%c', token='%s', ptr='%s'\n", unquoted, quote, dquote, numeric, delim, token, ptr);

325
		if (in_select && unquoted && blevel == 0)
326
		{
327 328 329
			if (!stricmp(token, "distinct"))
			{
				in_distinct = TRUE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
330

331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
				mylog("DISTINCT\n");
				continue;
			}
			if (!stricmp(token, "into"))
			{
				in_select = FALSE;
				mylog("INTO\n");
				stmt->statement_type = STMT_TYPE_CREATE;
				stmt->parse_status = STMT_PARSE_FATAL;
				return FALSE;
			}
			if (!stricmp(token, "from"))
			{
				in_select = FALSE;
				in_from = TRUE;
				if (!from_found &&
				    (!strnicmp(pptr, "from", 4)))
				{
					mylog("First ");
					from_found = TRUE;
				}
Byron Nikolaidis's avatar
Byron Nikolaidis committed
352

353 354 355
				mylog("FROM\n");
				continue;
			}
Byron Nikolaidis's avatar
Byron Nikolaidis committed
356
		}
357
		if (unquoted && blevel == 0)
358
		{
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
			if ((!stricmp(token, "where") ||
				!stricmp(token, "union") ||
				!stricmp(token, "intersect") ||
				!stricmp(token, "except") ||
				!stricmp(token, "order") ||
				!stricmp(token, "group") ||
				!stricmp(token, "having")))
			{
				in_select = FALSE;
				in_from = FALSE;
				in_where = TRUE;

				if (!first_where &&
				    (!stricmp(token, "where")))
					first_where = ptr - stmt->statement;
				    
				mylog("WHERE...\n");
				break;
			}
Byron Nikolaidis's avatar
Byron Nikolaidis committed
378
		}
379
		if (in_select && (in_expr || in_func))
380
		{
381 382 383 384
			/* just eat the expression */
			mylog("in_expr=%d or func=%d\n", in_expr, in_func);
			if (!unquoted)
				continue;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
385

386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
			if (token[0] == '(')
			{
				blevel++;
				mylog("blevel++ = %d\n", blevel);
			}
			else if (token[0] == ')')
			{
				blevel--;
				mylog("blevel-- = %d\n", blevel);
			}
			if (blevel == 0)
			{
				if (delim == ',')
				{
					mylog("**** Got comma in_expr/func\n");
					in_func = FALSE;
					in_expr = FALSE;
					in_field = FALSE;
				}
				else if (!stricmp(token, "as"))
				{
					mylog("got AS in_expr\n");
					in_func = FALSE;
					in_expr = FALSE;
					in_as = TRUE;
					in_field = TRUE;
				}
			}
Byron Nikolaidis's avatar
Byron Nikolaidis committed
414 415 416
			continue;
		}

417
		if (unquoted && !stricmp(token, "select"))
418
		{
419
			in_select = TRUE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
420

421 422
			mylog("SELECT\n");
			continue;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
423
		}
424 425 426 427
		if (in_select)
		{
			if (in_distinct)
			{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
428 429
				mylog("in distinct\n");

430 431
				if (unquoted && !stricmp(token, "on"))
				{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
432 433 434 435
					in_on = TRUE;
					mylog("got on\n");
					continue;
				}
436 437
				if (in_on)
				{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
438 439
					in_distinct = FALSE;
					in_on = FALSE;
440
					continue;	/* just skip the unique on field */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
441 442 443 444 445
				}
				mylog("done distinct\n");
				in_distinct = FALSE;
			}

446 447 448
			if (!in_field)
			{
				if (!token[0])
Byron Nikolaidis's avatar
Byron Nikolaidis committed
449 450
					continue;

451 452
				if (!(stmt->nfld % FLD_INCR))
				{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
453 454
					mylog("reallocing at nfld=%d\n", stmt->nfld);
					fi = (FIELD_INFO **) realloc(fi, (stmt->nfld + FLD_INCR) * sizeof(FIELD_INFO *));
455 456
					if (!fi)
					{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
457 458 459 460 461 462
						stmt->parse_status = STMT_PARSE_FATAL;
						return FALSE;
					}
					stmt->fi = fi;
				}

463 464 465
				fi[stmt->nfld] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
				if (fi[stmt->nfld] == NULL)
				{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
466 467 468 469
					stmt->parse_status = STMT_PARSE_FATAL;
					return FALSE;
				}

470
				/* Initialize the field info */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
471 472
				memset(fi[stmt->nfld], 0, sizeof(FIELD_INFO));

473
				/* double quotes are for qualifiers */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
474 475 476
				if (dquote)
					fi[stmt->nfld]->dquote = TRUE;

477 478
				if (quote)
				{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
479
					fi[stmt->nfld++]->quote = TRUE;
480
in_expr = TRUE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
481 482
					continue;
				}
483 484
				else if (numeric)
				{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
485 486 487
					mylog("**** got numeric: nfld = %d\n", stmt->nfld);
					fi[stmt->nfld]->numeric = TRUE;
				}
488 489
				else if (token[0] == '(')
				{				/* expression */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
490 491 492 493 494 495
					mylog("got EXPRESSION\n");
					fi[stmt->nfld++]->expr = TRUE;
					in_expr = TRUE;
					blevel = 1;
					continue;
				}
496 497
				else
				{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
498 499 500 501 502
					strcpy(fi[stmt->nfld]->name, token);
					fi[stmt->nfld]->dot[0] = '\0';
				}
				mylog("got field='%s', dot='%s'\n", fi[stmt->nfld]->name, fi[stmt->nfld]->dot);

503
				if (delim == ',')
Byron Nikolaidis's avatar
Byron Nikolaidis committed
504
					mylog("comma (1)\n");
505
				else
Byron Nikolaidis's avatar
Byron Nikolaidis committed
506 507 508 509 510
					in_field = TRUE;
				stmt->nfld++;
				continue;
			}

511 512 513
			/*
			 * We are in a field now
			 */
514 515
			if (in_dot)
			{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
516 517 518 519 520 521
				stmt->nfld--;
				strcpy(fi[stmt->nfld]->dot, fi[stmt->nfld]->name);
				strcpy(fi[stmt->nfld]->name, token);
				stmt->nfld++;
				in_dot = FALSE;

522 523
				if (delim == ',')
				{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
524 525 526 527 528 529
					mylog("in_dot: got comma\n");
					in_field = FALSE;
				}
				continue;
			}

530 531
			if (in_as)
			{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
532 533 534 535 536 537 538 539
				stmt->nfld--;
				strcpy(fi[stmt->nfld]->alias, token);
				mylog("alias for field '%s' is '%s'\n", fi[stmt->nfld]->name, fi[stmt->nfld]->alias);
				in_as = FALSE;
				in_field = FALSE;

				stmt->nfld++;

540
				if (delim == ',')
Byron Nikolaidis's avatar
Byron Nikolaidis committed
541 542 543 544
					mylog("comma(2)\n");
				continue;
			}

545 546 547
			/* Function */
			if (token[0] == '(')
			{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
548 549
				in_func = TRUE;
				blevel = 1;
550 551 552 553 554 555 556
				fi[stmt->nfld - 1]->func = TRUE;

				/*
				 * name will have the function name -- maybe useful some
				 * day
				 */
				mylog("**** got function = '%s'\n", fi[stmt->nfld - 1]->name);
Byron Nikolaidis's avatar
Byron Nikolaidis committed
557 558 559
				continue;
			}

560 561 562
			if (token[0] == '.')
			{
				in_dot = TRUE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
563 564 565 566
				mylog("got dot\n");
				continue;
			}

567 568
			if (!stricmp(token, "as"))
			{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
569 570 571 572 573
				in_as = TRUE;
				mylog("got AS\n");
				continue;
			}

574
			/* otherwise, it's probably an expression */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
575
			in_expr = TRUE;
576 577
			fi[stmt->nfld - 1]->expr = TRUE;
			fi[stmt->nfld - 1]->name[0] = '\0';
Byron Nikolaidis's avatar
Byron Nikolaidis committed
578 579 580
			mylog("*** setting expression\n");
		}

581 582 583 584 585
		if (in_from)
		{
			if (!in_table)
			{
				if (!token[0])
Byron Nikolaidis's avatar
Byron Nikolaidis committed
586 587
					continue;

588 589
				if (!(stmt->ntab % TAB_INCR))
				{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
590
					ti = (TABLE_INFO **) realloc(ti, (stmt->ntab + TAB_INCR) * sizeof(TABLE_INFO *));
591 592
					if (!ti)
					{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
593 594 595 596 597 598
						stmt->parse_status = STMT_PARSE_FATAL;
						return FALSE;
					}
					stmt->ti = ti;
				}
				ti[stmt->ntab] = (TABLE_INFO *) malloc(sizeof(TABLE_INFO));
599 600
				if (ti[stmt->ntab] == NULL)
				{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
601 602 603 604 605 606 607
					stmt->parse_status = STMT_PARSE_FATAL;
					return FALSE;
				}

				ti[stmt->ntab]->alias[0] = '\0';

				strcpy(ti[stmt->ntab]->name, token);
608 609
				if (!dquote)
				{
610 611
					char	   *ptr;

612 613 614 615
					/* lower case table name */
					for (ptr = ti[stmt->ntab]->name; *ptr; ptr++)
						*ptr = tolower((unsigned char) *ptr);
				}
Byron Nikolaidis's avatar
Byron Nikolaidis committed
616 617
				mylog("got table = '%s'\n", ti[stmt->ntab]->name);

618
				if (delim == ',')
Byron Nikolaidis's avatar
Byron Nikolaidis committed
619
					mylog("more than 1 tables\n");
620
				else
Byron Nikolaidis's avatar
Byron Nikolaidis committed
621 622 623 624 625
					in_table = TRUE;
				stmt->ntab++;
				continue;
			}

626 627
			strcpy(ti[stmt->ntab - 1]->alias, token);
			mylog("alias for table '%s' is '%s'\n", ti[stmt->ntab - 1]->name, ti[stmt->ntab - 1]->alias);
Byron Nikolaidis's avatar
Byron Nikolaidis committed
628
			in_table = FALSE;
629
			if (delim == ',')
Byron Nikolaidis's avatar
Byron Nikolaidis committed
630 631 632 633
				mylog("more than 1 tables\n");
		}
	}

634 635 636
	/*
	 * Resolve any possible field names with tables
	 */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
637 638 639

	parse = TRUE;

640 641 642 643 644
	/* Resolve field names with tables */
	for (i = 0; i < stmt->nfld; i++)
	{
		if (fi[i]->func || fi[i]->expr || fi[i]->numeric)
		{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
645 646 647 648 649
			fi[i]->ti = NULL;
			fi[i]->type = -1;
			parse = FALSE;
			continue;
		}
650 651
		else if (fi[i]->quote)
		{						/* handle as text */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
652
			fi[i]->ti = NULL;
653
			/*
Byron Nikolaidis's avatar
Byron Nikolaidis committed
654 655
			fi[i]->type = PG_TYPE_TEXT;
			fi[i]->precision = 0;
656 657 658
			the following may be better */
			fi[i]->type = PG_TYPE_UNKNOWN;
			fi[i]->precision = 254;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
659
			continue;
660 661 662 663 664 665 666 667
		}
		/* it's a dot, resolve to table or alias */
		else if (fi[i]->dot[0])
		{
			for (k = 0; k < stmt->ntab; k++)
			{
				if (!stricmp(ti[k]->name, fi[i]->dot))
				{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
668 669 670
					fi[i]->ti = ti[k];
					break;
				}
671 672
				else if (!stricmp(ti[k]->alias, fi[i]->dot))
				{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
673 674 675 676 677 678 679 680 681 682 683 684
					fi[i]->ti = ti[k];
					break;
				}
			}
		}
		else if (stmt->ntab == 1)
			fi[i]->ti = ti[0];
	}

	mylog("--------------------------------------------\n");
	mylog("nfld=%d, ntab=%d\n", stmt->nfld, stmt->ntab);

685 686
	for (i = 0; i < stmt->nfld; i++)
	{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
687 688
		mylog("Field %d:  expr=%d, func=%d, quote=%d, dquote=%d, numeric=%d, name='%s', alias='%s', dot='%s'\n", i, fi[i]->expr, fi[i]->func, fi[i]->quote, fi[i]->dquote, fi[i]->numeric, fi[i]->name, fi[i]->alias, fi[i]->dot);
		if (fi[i]->ti)
689
			mylog("     ----> table_name='%s', table_alias='%s'\n", fi[i]->ti->name, fi[i]->ti->alias);
Byron Nikolaidis's avatar
Byron Nikolaidis committed
690 691
	}

692
	for (i = 0; i < stmt->ntab; i++)
Byron Nikolaidis's avatar
Byron Nikolaidis committed
693 694 695
		mylog("Table %d: name='%s', alias='%s'\n", i, ti[i]->name, ti[i]->alias);


696 697 698
	/*
	 * Now save the SQLColumns Info for the parse tables
	 */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
699

700 701 702 703 704
	/* Call SQLColumns for each table and store the result */
	for (i = 0; i < stmt->ntab; i++)
	{
		/* See if already got it */
		char		found = FALSE;
705

706 707 708 709
		for (k = 0; k < conn->ntables; k++)
		{
			if (!stricmp(conn->col_info[k]->name, ti[i]->name))
			{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
710 711 712 713 714
				mylog("FOUND col_info table='%s'\n", ti[i]->name);
				found = TRUE;
				break;
			}
		}
715 716 717

		if (!found)
		{
718
			mylog("PARSE: Getting PG_Columns for table[%d]='%s'\n", i, ti[i]->name);
Byron Nikolaidis's avatar
Byron Nikolaidis committed
719

720
			result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
721 722
			if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
			{
723
				stmt->errormsg = "PGAPI_AllocStmt failed in parse_statement for columns.";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
724 725 726 727 728 729 730 731
				stmt->errornumber = STMT_NO_MEMORY_ERROR;
				stmt->parse_status = STMT_PARSE_FATAL;
				return FALSE;
			}

			col_stmt = (StatementClass *) hcol_stmt;
			col_stmt->internal = TRUE;

732
			result = PGAPI_Columns(hcol_stmt, "", 0, "", 0,
Byron Nikolaidis's avatar
Byron Nikolaidis committed
733
						ti[i]->name, (SWORD) strlen(ti[i]->name), "", 0);
734

735
			mylog("        Past PG_Columns\n");
736 737
			if (result == SQL_SUCCESS)
			{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
738
				mylog("      Success\n");
739 740
				if (!(conn->ntables % COL_INCR))
				{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
741 742 743
					mylog("PARSE: Allocing col_info at ntables=%d\n", conn->ntables);

					conn->col_info = (COL_INFO **) realloc(conn->col_info, (conn->ntables + COL_INCR) * sizeof(COL_INFO *));
744 745
					if (!conn->col_info)
					{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
746 747 748 749 750 751 752
						stmt->parse_status = STMT_PARSE_FATAL;
						return FALSE;
					}
				}

				mylog("PARSE: malloc at conn->col_info[%d]\n", conn->ntables);
				conn->col_info[conn->ntables] = (COL_INFO *) malloc(sizeof(COL_INFO));
753 754
				if (!conn->col_info[conn->ntables])
				{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
755 756 757 758
					stmt->parse_status = STMT_PARSE_FATAL;
					return FALSE;
				}

759 760 761 762
				/*
				 * Store the table name and the SQLColumns result
				 * structure
				 */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
763 764 765
				strcpy(conn->col_info[conn->ntables]->name, ti[i]->name);
				conn->col_info[conn->ntables]->result = col_stmt->result;

766 767 768 769
				/*
				 * The connection will now free the result structures, so
				 * make sure that the statement doesn't free it
				 */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
770 771 772 773
				col_stmt->result = NULL;

				conn->ntables++;

774
				PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
Byron Nikolaidis's avatar
Byron Nikolaidis committed
775 776
				mylog("Created col_info table='%s', ntables=%d\n", ti[i]->name, conn->ntables);
			}
777 778
			else
			{
779
				PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
Byron Nikolaidis's avatar
Byron Nikolaidis committed
780 781 782 783
				break;
			}
		}

784
		/* Associate a table from the statement with a SQLColumn info */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
785 786 787 788
		ti[i]->col_info = conn->col_info[k];
		mylog("associate col_info: i=%d, k=%d\n", i, k);
	}

789
	mylog("Done PG_Columns\n");
Byron Nikolaidis's avatar
Byron Nikolaidis committed
790

791 792 793
	/*
	 * Now resolve the fields to point to column info
	 */
794 795 796 797 798
	for (i = 0; i < stmt->nfld;)
	{
		/* Dont worry about functions or quotes */
		if (fi[i]->func || fi[i]->quote || fi[i]->numeric)
		{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
799 800 801 802
			i++;
			continue;
		}

803 804 805 806 807 808 809 810 811
		/* Stars get expanded to all fields in the table */
		else if (fi[i]->name[0] == '*')
		{
			char		do_all_tables;
			int			total_cols,
						old_alloc,
						new_size,
						cols;
			int			increased_cols;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
812 813 814

			mylog("expanding field %d\n", i);

815
			total_cols = 0;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
816

817 818
			if (fi[i]->ti)		/* The star represents only the qualified
								 * table */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
819 820
				total_cols = QR_get_num_tuples(fi[i]->ti->col_info->result);

821 822
			else
			{					/* The star represents all tables */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
823

824 825
				/* Calculate the total number of columns after expansion */
				for (k = 0; k < stmt->ntab; k++)
Byron Nikolaidis's avatar
Byron Nikolaidis committed
826 827
					total_cols += QR_get_num_tuples(ti[k]->col_info->result);
			}
828
			increased_cols = total_cols - 1;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
829

830 831
			/* Allocate some more field pointers if necessary */
			old_alloc = ((stmt->nfld - 1) / FLD_INCR + 1) * FLD_INCR;
832
			new_size = stmt->nfld + increased_cols;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
833

834 835 836 837 838
			mylog("k=%d, increased_cols=%d, old_alloc=%d, new_size=%d\n", k, increased_cols, old_alloc, new_size);

			if (new_size > old_alloc)
			{
				int			new_alloc = ((new_size / FLD_INCR) + 1) * FLD_INCR;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
839

840 841
				mylog("need more cols: new_alloc = %d\n", new_alloc);
				fi = (FIELD_INFO **) realloc(fi, new_alloc * sizeof(FIELD_INFO *));
842 843
				if (!fi)
				{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
844 845 846
					stmt->parse_status = STMT_PARSE_FATAL;
					return FALSE;
				}
847
				stmt->fi = fi;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
848 849
			}

850 851 852 853 854 855
			/*
			 * copy any other fields (if there are any) up past the
			 * expansion
			 */
			for (j = stmt->nfld - 1; j > i; j--)
			{
856 857
				mylog("copying field %d to %d\n", j, increased_cols + j);
				fi[increased_cols + j] = fi[j];
Byron Nikolaidis's avatar
Byron Nikolaidis committed
858 859 860
			}
			mylog("done copying fields\n");

861
			/* Set the new number of fields */
862
			stmt->nfld += increased_cols;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
863 864 865
			mylog("stmt->nfld now at %d\n", stmt->nfld);


866
			/* copy the new field info */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
867 868
			do_all_tables = (fi[i]->ti ? FALSE : TRUE);

869 870
			for (k = 0; k < (do_all_tables ? stmt->ntab : 1); k++)
			{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
871 872 873 874
				TABLE_INFO *the_ti = do_all_tables ? ti[k] : fi[i]->ti;

				cols = QR_get_num_tuples(the_ti->col_info->result);

875 876
				for (n = 0; n < cols; n++)
				{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
877
					mylog("creating field info: n=%d\n", n);
878
					/* skip malloc (already did it for the Star) */
879 880
					if (k > 0 || n > 0)
					{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
881
						mylog("allocating field info at %d\n", n + i);
882 883 884
						fi[n + i] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
						if (fi[n + i] == NULL)
						{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
885 886 887 888
							stmt->parse_status = STMT_PARSE_FATAL;
							return FALSE;
						}
					}
889
					/* Initialize the new space (or the * field) */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
890 891 892 893 894 895 896 897 898 899 900 901 902 903 904
					memset(fi[n + i], 0, sizeof(FIELD_INFO));
					fi[n + i]->ti = the_ti;

					mylog("about to copy at %d\n", n + i);

					getColInfo(the_ti->col_info, fi[n + i], n);

					mylog("done copying\n");
				}

				i += cols;
				mylog("i now at %d\n", i);
			}
		}

905 906 907 908 909 910 911 912
		/*
		 * We either know which table the field was in because it was
		 * qualified with a table name or alias -OR- there was only 1
		 * table.
		 */
		else if (fi[i]->ti)
		{
			if (!searchColInfo(fi[i]->ti->col_info, fi[i]))
Byron Nikolaidis's avatar
Byron Nikolaidis committed
913 914 915 916 917
				parse = FALSE;

			i++;
		}

918 919 920
		/* Don't know the table -- search all tables in "from" list */
		else
		{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
921
			parse = FALSE;
922 923 924 925
			for (k = 0; k < stmt->ntab; k++)
			{
				if (searchColInfo(ti[k]->col_info, fi[i]))
				{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
926 927 928 929 930 931 932 933 934
					fi[i]->ti = ti[k];	/* now know the table */
					parse = TRUE;
					break;
				}
			}
			i++;
		}
	}

935
	if (!parse)
Byron Nikolaidis's avatar
Byron Nikolaidis committed
936 937 938 939 940 941 942
		stmt->parse_status = STMT_PARSE_INCOMPLETE;
	else
		stmt->parse_status = STMT_PARSE_COMPLETE;

	mylog("done parse_statement: parse=%d, parse_status=%d\n", parse, stmt->parse_status);
	return parse;
}