1/* src/interfaces/ecpg/preproc/ecpg.trailer */
2
3statements: /*EMPTY*/
4				| statements statement
5		;
6
7statement: ecpgstart at toplevel_stmt ';'
8				{
9					if (connection)
10						free(connection);
11					connection = NULL;
12				}
13				| ecpgstart toplevel_stmt ';'
14				{
15					if (connection)
16						free(connection);
17					connection = NULL;
18				}
19				| ecpgstart ECPGVarDeclaration
20				{
21					fprintf(base_yyout, "%s", $2);
22					free($2);
23					output_line_number();
24				}
25				| ECPGDeclaration
26				| c_thing               { fprintf(base_yyout, "%s", $1); free($1); }
27				| CPP_LINE              { fprintf(base_yyout, "%s", $1); free($1); }
28				| '{'                   { braces_open++; fputs("{", base_yyout); }
29				| '}'
30		{
31			remove_typedefs(braces_open);
32			remove_variables(braces_open--);
33			if (braces_open == 0)
34			{
35				free(current_function);
36				current_function = NULL;
37			}
38			fputs("}", base_yyout);
39		}
40		;
41
42CreateAsStmt: CREATE OptTemp TABLE create_as_target AS {FoundInto = 0;} SelectStmt opt_with_data
43		{
44			if (FoundInto == 1)
45				mmerror(PARSE_ERROR, ET_ERROR, "CREATE TABLE AS cannot specify INTO");
46
47			$$ = cat_str(7, mm_strdup("create"), $2, mm_strdup("table"), $4, mm_strdup("as"), $7, $8);
48		}
49		|  CREATE OptTemp TABLE IF_P NOT EXISTS create_as_target AS {FoundInto = 0;} SelectStmt opt_with_data
50		{
51			if (FoundInto == 1)
52				mmerror(PARSE_ERROR, ET_ERROR, "CREATE TABLE AS cannot specify INTO");
53
54			$$ = cat_str(7, mm_strdup("create"), $2, mm_strdup("table if not exists"), $7, mm_strdup("as"), $10, $11);
55		}
56		;
57
58at: AT connection_object
59		{
60			connection = $2;
61			/*
62			 * Do we have a variable as connection target?  Remove the variable
63			 * from the variable list or else it will be used twice.
64			 */
65			if (argsinsert != NULL)
66				argsinsert = NULL;
67		}
68		;
69
70/*
71 * the exec sql connect statement: connect to the given database
72 */
73ECPGConnect: SQL_CONNECT TO connection_target opt_connection_name opt_user
74			{ $$ = cat_str(5, $3, mm_strdup(","), $5, mm_strdup(","), $4); }
75		| SQL_CONNECT TO DEFAULT
76			{ $$ = mm_strdup("NULL, NULL, NULL, \"DEFAULT\""); }
77		  /* also allow ORACLE syntax */
78		| SQL_CONNECT ora_user
79			{ $$ = cat_str(3, mm_strdup("NULL,"), $2, mm_strdup(", NULL")); }
80		| DATABASE connection_target
81			{ $$ = cat2_str($2, mm_strdup(", NULL, NULL, NULL")); }
82		;
83
84connection_target: opt_database_name opt_server opt_port
85		{
86			/* old style: dbname[@server][:port] */
87			if (strlen($2) > 0 && *($2) != '@')
88				mmerror(PARSE_ERROR, ET_ERROR, "expected \"@\", found \"%s\"", $2);
89
90			/* C strings need to be handled differently */
91			if ($1[0] == '\"')
92				$$ = $1;
93			else
94				$$ = make3_str(mm_strdup("\""), make3_str($1, $2, $3), mm_strdup("\""));
95		}
96		|  db_prefix ':' server opt_port '/' opt_database_name opt_options
97		{
98			/* new style: <tcp|unix>:postgresql://server[:port][/dbname] */
99			if (strncmp($1, "unix:postgresql", strlen("unix:postgresql")) != 0 && strncmp($1, "tcp:postgresql", strlen("tcp:postgresql")) != 0)
100				mmerror(PARSE_ERROR, ET_ERROR, "only protocols \"tcp\" and \"unix\" and database type \"postgresql\" are supported");
101
102			if (strncmp($3, "//", strlen("//")) != 0)
103				mmerror(PARSE_ERROR, ET_ERROR, "expected \"://\", found \"%s\"", $3);
104
105			if (strncmp($1, "unix", strlen("unix")) == 0 &&
106				strncmp($3 + strlen("//"), "localhost", strlen("localhost")) != 0 &&
107				strncmp($3 + strlen("//"), "127.0.0.1", strlen("127.0.0.1")) != 0)
108				mmerror(PARSE_ERROR, ET_ERROR, "Unix-domain sockets only work on \"localhost\" but not on \"%s\"", $3 + strlen("//"));
109
110			$$ = make3_str(make3_str(mm_strdup("\""), $1, mm_strdup(":")), $3, make3_str(make3_str($4, mm_strdup("/"), $6), $7, mm_strdup("\"")));
111		}
112		| char_variable
113		{
114			$$ = $1;
115		}
116		| ecpg_sconst
117		{
118			/* We can only process double quoted strings not single quotes ones,
119			 * so we change the quotes.
120			 * Note, that the rule for ecpg_sconst adds these single quotes. */
121			$1[0] = '\"';
122			$1[strlen($1)-1] = '\"';
123			$$ = $1;
124		}
125		;
126
127opt_database_name: name				{ $$ = $1; }
128		| /*EMPTY*/			{ $$ = EMPTY; }
129		;
130
131db_prefix: ecpg_ident cvariable
132		{
133			if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0)
134				mmerror(PARSE_ERROR, ET_ERROR, "expected \"postgresql\", found \"%s\"", $2);
135
136			if (strcmp($1, "tcp") != 0 && strcmp($1, "unix") != 0)
137				mmerror(PARSE_ERROR, ET_ERROR, "invalid connection type: %s", $1);
138
139			$$ = make3_str($1, mm_strdup(":"), $2);
140		}
141		;
142
143server: Op server_name
144		{
145			if (strcmp($1, "@") != 0 && strcmp($1, "//") != 0)
146				mmerror(PARSE_ERROR, ET_ERROR, "expected \"@\" or \"://\", found \"%s\"", $1);
147
148			$$ = make2_str($1, $2);
149		}
150		;
151
152opt_server: server			{ $$ = $1; }
153		| /*EMPTY*/			{ $$ = EMPTY; }
154		;
155
156server_name: ColId					{ $$ = $1; }
157		| ColId '.' server_name		{ $$ = make3_str($1, mm_strdup("."), $3); }
158		| IP						{ $$ = make_name(); }
159		;
160
161opt_port: ':' Iconst		{ $$ = make2_str(mm_strdup(":"), $2); }
162		| /*EMPTY*/	{ $$ = EMPTY; }
163		;
164
165opt_connection_name: AS connection_object	{ $$ = $2; }
166		| /*EMPTY*/			{ $$ = mm_strdup("NULL"); }
167		;
168
169opt_user: USER ora_user		{ $$ = $2; }
170		| /*EMPTY*/			{ $$ = mm_strdup("NULL, NULL"); }
171		;
172
173ora_user: user_name
174			{ $$ = cat2_str($1, mm_strdup(", NULL")); }
175		| user_name '/' user_name
176			{ $$ = cat_str(3, $1, mm_strdup(","), $3); }
177		| user_name SQL_IDENTIFIED BY user_name
178			{ $$ = cat_str(3, $1, mm_strdup(","), $4); }
179		| user_name USING user_name
180			{ $$ = cat_str(3, $1, mm_strdup(","), $3); }
181		;
182
183user_name: RoleId
184		{
185			if ($1[0] == '\"')
186				$$ = $1;
187			else
188				$$ = make3_str(mm_strdup("\""), $1, mm_strdup("\""));
189		}
190		| ecpg_sconst
191		{
192			if ($1[0] == '\"')
193				$$ = $1;
194			else
195				$$ = make3_str(mm_strdup("\""), $1, mm_strdup("\""));
196		}
197		| civar
198		{
199			enum ECPGttype type = argsinsert->variable->type->type;
200
201			/* if array see what's inside */
202			if (type == ECPGt_array)
203				type = argsinsert->variable->type->u.element->type;
204
205			/* handle varchars */
206			if (type == ECPGt_varchar)
207				$$ = make2_str(mm_strdup(argsinsert->variable->name), mm_strdup(".arr"));
208			else
209				$$ = mm_strdup(argsinsert->variable->name);
210		}
211		;
212
213char_variable: cvariable
214		{
215			/* check if we have a string variable */
216			struct variable *p = find_variable($1);
217			enum ECPGttype type = p->type->type;
218
219			/* If we have just one character this is not a string */
220			if (atol(p->type->size) == 1)
221					mmerror(PARSE_ERROR, ET_ERROR, "invalid data type");
222			else
223			{
224				/* if array see what's inside */
225				if (type == ECPGt_array)
226					type = p->type->u.element->type;
227
228				switch (type)
229				{
230					case ECPGt_char:
231					case ECPGt_unsigned_char:
232					case ECPGt_string:
233						$$ = $1;
234						break;
235					case ECPGt_varchar:
236						$$ = make2_str($1, mm_strdup(".arr"));
237						break;
238					default:
239						mmerror(PARSE_ERROR, ET_ERROR, "invalid data type");
240						$$ = $1;
241						break;
242				}
243			}
244		}
245		;
246
247opt_options: Op connect_options
248		{
249			if (strlen($1) == 0)
250				mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement");
251
252			if (strcmp($1, "?") != 0)
253				mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", $1);
254
255			$$ = make2_str(mm_strdup("?"), $2);
256		}
257		| /*EMPTY*/	{ $$ = EMPTY; }
258		;
259
260connect_options:  ColId opt_opt_value
261			{
262				$$ = make2_str($1, $2);
263			}
264		| ColId opt_opt_value Op connect_options
265			{
266				if (strlen($3) == 0)
267					mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement");
268
269				if (strcmp($3, "&") != 0)
270					mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", $3);
271
272				$$ = cat_str(3, make2_str($1, $2), $3, $4);
273			}
274		;
275
276opt_opt_value: /*EMPTY*/
277			{ $$ = EMPTY; }
278		| '=' Iconst
279			{ $$ = make2_str(mm_strdup("="), $2); }
280		| '=' ecpg_ident
281			{ $$ = make2_str(mm_strdup("="), $2); }
282		| '=' civar
283			{ $$ = make2_str(mm_strdup("="), $2); }
284		;
285
286prepared_name: name
287		{
288			if ($1[0] == '\"' && $1[strlen($1)-1] == '\"') /* already quoted? */
289				$$ = $1;
290			else /* not quoted => convert to lowercase */
291			{
292				size_t i;
293
294				for (i = 0; i< strlen($1); i++)
295					$1[i] = tolower((unsigned char) $1[i]);
296
297				$$ = make3_str(mm_strdup("\""), $1, mm_strdup("\""));
298			}
299		}
300		| char_variable { $$ = $1; }
301		;
302
303/*
304 * Declare Statement
305 */
306ECPGDeclareStmt: DECLARE prepared_name STATEMENT
307		{
308			struct declared_list *ptr = NULL;
309			/* Check whether the declared name has been defined or not */
310			for (ptr = g_declared_list; ptr != NULL; ptr = ptr->next)
311			{
312				if (strcmp($2, ptr->name) == 0)
313				{
314					/* re-definition is not allowed */
315					mmerror(PARSE_ERROR, ET_ERROR, "name \"%s\" is already declared", ptr->name);
316				}
317			}
318
319			/* Add a new declared name into the g_declared_list */
320			ptr = NULL;
321			ptr = (struct declared_list *)mm_alloc(sizeof(struct declared_list));
322			if (ptr)
323			{
324				/* initial definition */
325				ptr -> name = $2;
326				if (connection)
327					ptr -> connection = mm_strdup(connection);
328				else
329					ptr -> connection = NULL;
330
331				ptr -> next = g_declared_list;
332				g_declared_list = ptr;
333			}
334
335			$$ = cat_str(3 , mm_strdup("/* declare "), mm_strdup($2), mm_strdup(" as an SQL identifier */"));
336		}
337;
338
339/*
340 * Declare a prepared cursor. The syntax is different from the standard
341 * declare statement, so we create a new rule.
342 */
343ECPGCursorStmt:  DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared_name
344		{
345			struct cursor *ptr, *this;
346			char *cursor_marker = $2[0] == ':' ? mm_strdup("$0") : mm_strdup($2);
347			int (* strcmp_fn)(const char *, const char *) = (($2[0] == ':' || $2[0] == '"') ? strcmp : pg_strcasecmp);
348			struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
349			char *comment;
350			char *con;
351
352			if (INFORMIX_MODE && pg_strcasecmp($2, "database") == 0)
353                                mmfatal(PARSE_ERROR, "\"database\" cannot be used as cursor name in INFORMIX mode");
354
355                        check_declared_list($7);
356			con = connection ? connection : "NULL";
357			for (ptr = cur; ptr != NULL; ptr = ptr->next)
358			{
359				if (strcmp_fn($2, ptr->name) == 0)
360				{
361					/* re-definition is a bug */
362					if ($2[0] == ':')
363						mmerror(PARSE_ERROR, ET_ERROR, "using variable \"%s\" in different declare statements is not supported", $2+1);
364					else
365						mmerror(PARSE_ERROR, ET_ERROR, "cursor \"%s\" is already defined", $2);
366				}
367			}
368
369			this = (struct cursor *) mm_alloc(sizeof(struct cursor));
370
371			/* initial definition */
372			this->next = cur;
373			this->name = $2;
374			this->function = (current_function ? mm_strdup(current_function) : NULL);
375			this->connection = connection ? mm_strdup(connection) : NULL;
376			this->command =  cat_str(6, mm_strdup("declare"), cursor_marker, $3, mm_strdup("cursor"), $5, mm_strdup("for $1"));
377			this->argsresult = NULL;
378			this->argsresult_oos = NULL;
379
380			thisquery->type = &ecpg_query;
381			thisquery->brace_level = 0;
382			thisquery->next = NULL;
383			thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(, , __LINE__)") + strlen(con) + strlen($7));
384			sprintf(thisquery->name, "ECPGprepared_statement(%s, %s, __LINE__)", con, $7);
385
386			this->argsinsert = NULL;
387			this->argsinsert_oos = NULL;
388			if ($2[0] == ':')
389			{
390				struct variable *var = find_variable($2 + 1);
391				remove_variable_from_list(&argsinsert, var);
392				add_variable_to_head(&(this->argsinsert), var, &no_indicator);
393			}
394			add_variable_to_head(&(this->argsinsert), thisquery, &no_indicator);
395
396			cur = this;
397
398			comment = cat_str(3, mm_strdup("/*"), mm_strdup(this->command), mm_strdup("*/"));
399
400			$$ = cat_str(2, adjust_outofscope_cursor_vars(this),
401					comment);
402		}
403		;
404
405ECPGExecuteImmediateStmt: EXECUTE IMMEDIATE execstring
406			{
407			  /* execute immediate means prepare the statement and
408			   * immediately execute it */
409			  $$ = $3;
410			};
411/*
412 * variable declaration outside exec sql declare block
413 */
414ECPGVarDeclaration: single_vt_declaration;
415
416single_vt_declaration: type_declaration		{ $$ = $1; }
417		| var_declaration		{ $$ = $1; }
418		;
419
420precision:	NumericOnly	{ $$ = $1; };
421
422opt_scale:	',' NumericOnly	{ $$ = $2; }
423		| /* EMPTY */	{ $$ = EMPTY; }
424		;
425
426ecpg_interval:	opt_interval	{ $$ = $1; }
427		| YEAR_P TO MINUTE_P	{ $$ = mm_strdup("year to minute"); }
428		| YEAR_P TO SECOND_P	{ $$ = mm_strdup("year to second"); }
429		| DAY_P TO DAY_P		{ $$ = mm_strdup("day to day"); }
430		| MONTH_P TO MONTH_P	{ $$ = mm_strdup("month to month"); }
431		;
432
433/*
434 * variable declaration inside exec sql declare block
435 */
436ECPGDeclaration: sql_startdeclare
437		{ fputs("/* exec sql begin declare section */", base_yyout); }
438		var_type_declarations sql_enddeclare
439		{
440			fprintf(base_yyout, "%s/* exec sql end declare section */", $3);
441			free($3);
442			output_line_number();
443		}
444		;
445
446sql_startdeclare: ecpgstart BEGIN_P DECLARE SQL_SECTION ';' {};
447
448sql_enddeclare: ecpgstart END_P DECLARE SQL_SECTION ';' {};
449
450var_type_declarations:	/*EMPTY*/			{ $$ = EMPTY; }
451		| vt_declarations			{ $$ = $1; }
452		;
453
454vt_declarations:  single_vt_declaration			{ $$ = $1; }
455		| CPP_LINE				{ $$ = $1; }
456		| vt_declarations single_vt_declaration	{ $$ = cat2_str($1, $2); }
457		| vt_declarations CPP_LINE		{ $$ = cat2_str($1, $2); }
458		;
459
460variable_declarations:	var_declaration	{ $$ = $1; }
461		| variable_declarations var_declaration	{ $$ = cat2_str($1, $2); }
462		;
463
464type_declaration: S_TYPEDEF
465	{
466		/* reset this variable so we see if there was */
467		/* an initializer specified */
468		initializer = 0;
469	}
470	var_type opt_pointer ECPGColLabelCommon opt_array_bounds ';'
471	{
472		add_typedef($5, $6.index1, $6.index2, $3.type_enum, $3.type_dimension, $3.type_index, initializer, *$4 ? 1 : 0);
473
474		fprintf(base_yyout, "typedef %s %s %s %s;\n", $3.type_str, *$4 ? "*" : "", $5, $6.str);
475		output_line_number();
476		$$ = mm_strdup("");
477	};
478
479var_declaration: storage_declaration
480		var_type
481		{
482			actual_type[struct_level].type_enum = $2.type_enum;
483			actual_type[struct_level].type_str = $2.type_str;
484			actual_type[struct_level].type_dimension = $2.type_dimension;
485			actual_type[struct_level].type_index = $2.type_index;
486			actual_type[struct_level].type_sizeof = $2.type_sizeof;
487
488			actual_startline[struct_level] = hashline_number();
489		}
490		variable_list ';'
491		{
492			$$ = cat_str(5, actual_startline[struct_level], $1, $2.type_str, $4, mm_strdup(";\n"));
493		}
494		| var_type
495		{
496			actual_type[struct_level].type_enum = $1.type_enum;
497			actual_type[struct_level].type_str = $1.type_str;
498			actual_type[struct_level].type_dimension = $1.type_dimension;
499			actual_type[struct_level].type_index = $1.type_index;
500			actual_type[struct_level].type_sizeof = $1.type_sizeof;
501
502			actual_startline[struct_level] = hashline_number();
503		}
504		variable_list ';'
505		{
506			$$ = cat_str(4, actual_startline[struct_level], $1.type_str, $3, mm_strdup(";\n"));
507		}
508		| struct_union_type_with_symbol ';'
509		{
510			$$ = cat2_str($1, mm_strdup(";"));
511		}
512		;
513
514opt_bit_field:	':' Iconst	{ $$ =cat2_str(mm_strdup(":"), $2); }
515		| /* EMPTY */	{ $$ = EMPTY; }
516		;
517
518storage_declaration: storage_clause storage_modifier
519			{$$ = cat2_str ($1, $2); }
520		| storage_clause		{$$ = $1; }
521		| storage_modifier		{$$ = $1; }
522		;
523
524storage_clause : S_EXTERN	{ $$ = mm_strdup("extern"); }
525		| S_STATIC			{ $$ = mm_strdup("static"); }
526		| S_REGISTER		{ $$ = mm_strdup("register"); }
527		| S_AUTO			{ $$ = mm_strdup("auto"); }
528		;
529
530storage_modifier : S_CONST	{ $$ = mm_strdup("const"); }
531		| S_VOLATILE		{ $$ = mm_strdup("volatile"); }
532		;
533
534var_type:	simple_type
535		{
536			$$.type_enum = $1;
537			$$.type_str = mm_strdup(ecpg_type_name($1));
538			$$.type_dimension = mm_strdup("-1");
539			$$.type_index = mm_strdup("-1");
540			$$.type_sizeof = NULL;
541		}
542		| struct_union_type
543		{
544			$$.type_str = $1;
545			$$.type_dimension = mm_strdup("-1");
546			$$.type_index = mm_strdup("-1");
547
548			if (strncmp($1, "struct", sizeof("struct")-1) == 0)
549			{
550				$$.type_enum = ECPGt_struct;
551				$$.type_sizeof = ECPGstruct_sizeof;
552			}
553			else
554			{
555				$$.type_enum = ECPGt_union;
556				$$.type_sizeof = NULL;
557			}
558		}
559		| enum_type
560		{
561			$$.type_str = $1;
562			$$.type_enum = ECPGt_int;
563			$$.type_dimension = mm_strdup("-1");
564			$$.type_index = mm_strdup("-1");
565			$$.type_sizeof = NULL;
566		}
567		| ECPGColLabelCommon '(' precision opt_scale ')'
568		{
569			if (strcmp($1, "numeric") == 0)
570			{
571				$$.type_enum = ECPGt_numeric;
572				$$.type_str = mm_strdup("numeric");
573			}
574			else if (strcmp($1, "decimal") == 0)
575			{
576				$$.type_enum = ECPGt_decimal;
577				$$.type_str = mm_strdup("decimal");
578			}
579			else
580			{
581				mmerror(PARSE_ERROR, ET_ERROR, "only data types numeric and decimal have precision/scale argument");
582				$$.type_enum = ECPGt_numeric;
583				$$.type_str = mm_strdup("numeric");
584			}
585
586			$$.type_dimension = mm_strdup("-1");
587			$$.type_index = mm_strdup("-1");
588			$$.type_sizeof = NULL;
589		}
590		| ECPGColLabelCommon ecpg_interval
591		{
592			if (strlen($2) != 0 && strcmp ($1, "datetime") != 0 && strcmp ($1, "interval") != 0)
593				mmerror (PARSE_ERROR, ET_ERROR, "interval specification not allowed here");
594
595			/*
596			 * Check for type names that the SQL grammar treats as
597			 * unreserved keywords
598			 */
599			if (strcmp($1, "varchar") == 0)
600			{
601				$$.type_enum = ECPGt_varchar;
602				$$.type_str = EMPTY; /*mm_strdup("varchar");*/
603				$$.type_dimension = mm_strdup("-1");
604				$$.type_index = mm_strdup("-1");
605				$$.type_sizeof = NULL;
606			}
607			else if (strcmp($1, "bytea") == 0)
608			{
609				$$.type_enum = ECPGt_bytea;
610				$$.type_str = EMPTY;
611				$$.type_dimension = mm_strdup("-1");
612				$$.type_index = mm_strdup("-1");
613				$$.type_sizeof = NULL;
614			}
615			else if (strcmp($1, "float") == 0)
616			{
617				$$.type_enum = ECPGt_float;
618				$$.type_str = mm_strdup("float");
619				$$.type_dimension = mm_strdup("-1");
620				$$.type_index = mm_strdup("-1");
621				$$.type_sizeof = NULL;
622			}
623			else if (strcmp($1, "double") == 0)
624			{
625				$$.type_enum = ECPGt_double;
626				$$.type_str = mm_strdup("double");
627				$$.type_dimension = mm_strdup("-1");
628				$$.type_index = mm_strdup("-1");
629				$$.type_sizeof = NULL;
630			}
631			else if (strcmp($1, "numeric") == 0)
632			{
633				$$.type_enum = ECPGt_numeric;
634				$$.type_str = mm_strdup("numeric");
635				$$.type_dimension = mm_strdup("-1");
636				$$.type_index = mm_strdup("-1");
637				$$.type_sizeof = NULL;
638			}
639			else if (strcmp($1, "decimal") == 0)
640			{
641				$$.type_enum = ECPGt_decimal;
642				$$.type_str = mm_strdup("decimal");
643				$$.type_dimension = mm_strdup("-1");
644				$$.type_index = mm_strdup("-1");
645				$$.type_sizeof = NULL;
646			}
647			else if (strcmp($1, "date") == 0)
648			{
649				$$.type_enum = ECPGt_date;
650				$$.type_str = mm_strdup("date");
651				$$.type_dimension = mm_strdup("-1");
652				$$.type_index = mm_strdup("-1");
653				$$.type_sizeof = NULL;
654			}
655			else if (strcmp($1, "timestamp") == 0)
656			{
657				$$.type_enum = ECPGt_timestamp;
658				$$.type_str = mm_strdup("timestamp");
659				$$.type_dimension = mm_strdup("-1");
660				$$.type_index = mm_strdup("-1");
661				$$.type_sizeof = NULL;
662			}
663			else if (strcmp($1, "interval") == 0)
664			{
665				$$.type_enum = ECPGt_interval;
666				$$.type_str = mm_strdup("interval");
667				$$.type_dimension = mm_strdup("-1");
668				$$.type_index = mm_strdup("-1");
669				$$.type_sizeof = NULL;
670			}
671			else if (strcmp($1, "datetime") == 0)
672			{
673				$$.type_enum = ECPGt_timestamp;
674				$$.type_str = mm_strdup("timestamp");
675				$$.type_dimension = mm_strdup("-1");
676				$$.type_index = mm_strdup("-1");
677				$$.type_sizeof = NULL;
678			}
679			else if ((strcmp($1, "string") == 0) && INFORMIX_MODE)
680			{
681				$$.type_enum = ECPGt_string;
682				$$.type_str = mm_strdup("char");
683				$$.type_dimension = mm_strdup("-1");
684				$$.type_index = mm_strdup("-1");
685				$$.type_sizeof = NULL;
686			}
687			else
688			{
689				/* this is for typedef'ed types */
690				struct typedefs *this = get_typedef($1);
691
692				$$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? EMPTY : mm_strdup(this->name);
693				$$.type_enum = this->type->type_enum;
694				$$.type_dimension = this->type->type_dimension;
695				$$.type_index = this->type->type_index;
696				if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0)
697					$$.type_sizeof = this->type->type_sizeof;
698				else
699					$$.type_sizeof = cat_str(3, mm_strdup("sizeof("), mm_strdup(this->name), mm_strdup(")"));
700
701				struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
702			}
703		}
704		| s_struct_union_symbol
705		{
706			/* this is for named structs/unions */
707			char *name;
708			struct typedefs *this;
709			bool forward = (forward_name != NULL && strcmp($1.symbol, forward_name) == 0 && strcmp($1.su, "struct") == 0);
710
711			name = cat2_str($1.su, $1.symbol);
712			/* Do we have a forward definition? */
713			if (!forward)
714			{
715				/* No */
716
717				this = get_typedef(name);
718				$$.type_str = mm_strdup(this->name);
719				$$.type_enum = this->type->type_enum;
720				$$.type_dimension = this->type->type_dimension;
721				$$.type_index = this->type->type_index;
722				$$.type_sizeof = this->type->type_sizeof;
723				struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
724				free(name);
725			}
726			else
727			{
728				$$.type_str = name;
729				$$.type_enum = ECPGt_long;
730				$$.type_dimension = mm_strdup("-1");
731				$$.type_index = mm_strdup("-1");
732				$$.type_sizeof = mm_strdup("");
733				struct_member_list[struct_level] = NULL;
734			}
735		}
736		;
737
738enum_type: ENUM_P symbol enum_definition
739			{ $$ = cat_str(3, mm_strdup("enum"), $2, $3); }
740		| ENUM_P enum_definition
741			{ $$ = cat2_str(mm_strdup("enum"), $2); }
742		| ENUM_P symbol
743			{ $$ = cat2_str(mm_strdup("enum"), $2); }
744		;
745
746enum_definition: '{' c_list '}'
747			{ $$ = cat_str(3, mm_strdup("{"), $2, mm_strdup("}")); };
748
749struct_union_type_with_symbol: s_struct_union_symbol
750		{
751			struct_member_list[struct_level++] = NULL;
752			if (struct_level >= STRUCT_DEPTH)
753				 mmerror(PARSE_ERROR, ET_ERROR, "too many levels in nested structure/union definition");
754			forward_name = mm_strdup($1.symbol);
755		}
756		'{' variable_declarations '}'
757		{
758			struct typedefs *ptr, *this;
759			struct this_type su_type;
760
761			ECPGfree_struct_member(struct_member_list[struct_level]);
762			struct_member_list[struct_level] = NULL;
763			struct_level--;
764			if (strncmp($1.su, "struct", sizeof("struct")-1) == 0)
765				su_type.type_enum = ECPGt_struct;
766			else
767				su_type.type_enum = ECPGt_union;
768			su_type.type_str = cat2_str($1.su, $1.symbol);
769			free(forward_name);
770			forward_name = NULL;
771
772			/* This is essentially a typedef but needs the keyword struct/union as well.
773			 * So we create the typedef for each struct definition with symbol */
774			for (ptr = types; ptr != NULL; ptr = ptr->next)
775			{
776					if (strcmp(su_type.type_str, ptr->name) == 0)
777							/* re-definition is a bug */
778							mmerror(PARSE_ERROR, ET_ERROR, "type \"%s\" is already defined", su_type.type_str);
779			}
780
781			this = (struct typedefs *) mm_alloc(sizeof(struct typedefs));
782
783			/* initial definition */
784			this->next = types;
785			this->name = mm_strdup(su_type.type_str);
786			this->brace_level = braces_open;
787			this->type = (struct this_type *) mm_alloc(sizeof(struct this_type));
788			this->type->type_enum = su_type.type_enum;
789			this->type->type_str = mm_strdup(su_type.type_str);
790			this->type->type_dimension = mm_strdup("-1"); /* dimension of array */
791			this->type->type_index = mm_strdup("-1");	/* length of string */
792			this->type->type_sizeof = ECPGstruct_sizeof;
793			this->struct_member_list = struct_member_list[struct_level];
794
795			types = this;
796			$$ = cat_str(4, su_type.type_str, mm_strdup("{"), $4, mm_strdup("}"));
797		}
798		;
799
800struct_union_type: struct_union_type_with_symbol	{ $$ = $1; }
801		| s_struct_union
802		{
803			struct_member_list[struct_level++] = NULL;
804			if (struct_level >= STRUCT_DEPTH)
805				 mmerror(PARSE_ERROR, ET_ERROR, "too many levels in nested structure/union definition");
806		}
807		'{' variable_declarations '}'
808		{
809			ECPGfree_struct_member(struct_member_list[struct_level]);
810			struct_member_list[struct_level] = NULL;
811			struct_level--;
812			$$ = cat_str(4, $1, mm_strdup("{"), $4, mm_strdup("}"));
813		}
814		;
815
816s_struct_union_symbol: SQL_STRUCT symbol
817		{
818			$$.su = mm_strdup("struct");
819			$$.symbol = $2;
820			ECPGstruct_sizeof = cat_str(3, mm_strdup("sizeof("), cat2_str(mm_strdup($$.su), mm_strdup($$.symbol)), mm_strdup(")"));
821		}
822		| UNION symbol
823		{
824			$$.su = mm_strdup("union");
825			$$.symbol = $2;
826		}
827		;
828
829s_struct_union: SQL_STRUCT
830		{
831			ECPGstruct_sizeof = mm_strdup(""); /* This must not be NULL to distinguish from simple types. */
832			$$ = mm_strdup("struct");
833		}
834		| UNION
835		{
836			$$ = mm_strdup("union");
837		}
838		;
839
840simple_type: unsigned_type					{ $$=$1; }
841		|	opt_signed signed_type			{ $$=$2; }
842		;
843
844unsigned_type: SQL_UNSIGNED SQL_SHORT		{ $$ = ECPGt_unsigned_short; }
845		| SQL_UNSIGNED SQL_SHORT INT_P	{ $$ = ECPGt_unsigned_short; }
846		| SQL_UNSIGNED						{ $$ = ECPGt_unsigned_int; }
847		| SQL_UNSIGNED INT_P				{ $$ = ECPGt_unsigned_int; }
848		| SQL_UNSIGNED SQL_LONG				{ $$ = ECPGt_unsigned_long; }
849		| SQL_UNSIGNED SQL_LONG INT_P		{ $$ = ECPGt_unsigned_long; }
850		| SQL_UNSIGNED SQL_LONG SQL_LONG	{ $$ = ECPGt_unsigned_long_long; }
851		| SQL_UNSIGNED SQL_LONG SQL_LONG INT_P { $$ = ECPGt_unsigned_long_long; }
852		| SQL_UNSIGNED CHAR_P			{ $$ = ECPGt_unsigned_char; }
853		;
854
855signed_type: SQL_SHORT				{ $$ = ECPGt_short; }
856		| SQL_SHORT INT_P			{ $$ = ECPGt_short; }
857		| INT_P						{ $$ = ECPGt_int; }
858		| SQL_LONG					{ $$ = ECPGt_long; }
859		| SQL_LONG INT_P			{ $$ = ECPGt_long; }
860		| SQL_LONG SQL_LONG			{ $$ = ECPGt_long_long; }
861		| SQL_LONG SQL_LONG INT_P	{ $$ = ECPGt_long_long; }
862		| SQL_BOOL					{ $$ = ECPGt_bool; }
863		| CHAR_P					{ $$ = ECPGt_char; }
864		| DOUBLE_P					{ $$ = ECPGt_double; }
865		;
866
867opt_signed: SQL_SIGNED
868		|	/* EMPTY */
869		;
870
871variable_list: variable
872			{ $$ = $1; }
873		| variable_list ',' variable
874		{
875			if (actual_type[struct_level].type_enum == ECPGt_varchar || actual_type[struct_level].type_enum == ECPGt_bytea)
876				$$ = cat_str(3, $1, mm_strdup(";"), $3);
877			else
878				$$ = cat_str(3, $1, mm_strdup(","), $3);
879		}
880		;
881
882variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initializer
883		{
884			struct ECPGtype * type;
885			char *dimension = $3.index1;	/* dimension of array */
886			char *length = $3.index2;		/* length of string */
887			char *dim_str;
888			char *vcn;
889			int *varlen_type_counter;
890			char *struct_name;
891
892			adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension, actual_type[struct_level].type_index, strlen($1), false);
893			switch (actual_type[struct_level].type_enum)
894			{
895				case ECPGt_struct:
896				case ECPGt_union:
897					if (atoi(dimension) < 0)
898						type = ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum, actual_type[struct_level].type_str, actual_type[struct_level].type_sizeof);
899					else
900						type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum, actual_type[struct_level].type_str, actual_type[struct_level].type_sizeof), dimension);
901
902					$$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5);
903					break;
904
905				case ECPGt_varchar:
906				case ECPGt_bytea:
907					if (actual_type[struct_level].type_enum == ECPGt_varchar)
908					{
909						varlen_type_counter = &varchar_counter;
910						struct_name = " struct varchar_";
911					}
912					else
913					{
914						varlen_type_counter = &bytea_counter;
915						struct_name = " struct bytea_";
916					}
917					if (atoi(dimension) < 0)
918						type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, *varlen_type_counter);
919					else
920						type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, *varlen_type_counter), dimension);
921
922					if (strcmp(dimension, "0") == 0 || abs(atoi(dimension)) == 1)
923							dim_str=mm_strdup("");
924					else
925							dim_str=cat_str(3, mm_strdup("["), mm_strdup(dimension), mm_strdup("]"));
926					/* cannot check for atoi <= 0 because a defined constant will yield 0 here as well */
927					if (atoi(length) < 0 || strcmp(length, "0") == 0)
928						mmerror(PARSE_ERROR, ET_ERROR, "pointers to varchar are not implemented");
929
930					/* make sure varchar struct name is unique by adding a unique counter to its definition */
931					vcn = (char *) mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
932					sprintf(vcn, "%d", *varlen_type_counter);
933					if (strcmp(dimension, "0") == 0)
934						$$ = cat_str(7, make2_str(mm_strdup(struct_name), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length), mm_strdup("]; } *"), mm_strdup($2), $4, $5);
935					else
936						$$ = cat_str(8, make2_str(mm_strdup(struct_name), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length), mm_strdup("]; } "), mm_strdup($2), dim_str, $4, $5);
937					(*varlen_type_counter)++;
938					break;
939
940				case ECPGt_char:
941				case ECPGt_unsigned_char:
942				case ECPGt_string:
943					if (atoi(dimension) == -1)
944					{
945						int i = strlen($5);
946
947						if (atoi(length) == -1 && i > 0) /* char <var>[] = "string" */
948						{
949							/* if we have an initializer but no string size set, let's use the initializer's length */
950							free(length);
951							length = mm_alloc(i+sizeof("sizeof()"));
952							sprintf(length, "sizeof(%s)", $5+2);
953						}
954						type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0);
955					}
956					else
957						type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0), dimension);
958
959					$$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5);
960					break;
961
962				default:
963					if (atoi(dimension) < 0)
964						type = ECPGmake_simple_type(actual_type[struct_level].type_enum, mm_strdup("1"), 0);
965					else
966						type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, mm_strdup("1"), 0), dimension);
967
968					$$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5);
969					break;
970			}
971
972			if (struct_level == 0)
973				new_variable($2, type, braces_open);
974			else
975				ECPGmake_struct_member($2, type, &(struct_member_list[struct_level - 1]));
976
977			free($2);
978		}
979		;
980
981opt_initializer: /*EMPTY*/
982			{ $$ = EMPTY; }
983		| '=' c_term
984		{
985			initializer = 1;
986			$$ = cat2_str(mm_strdup("="), $2);
987		}
988		;
989
990opt_pointer: /*EMPTY*/				{ $$ = EMPTY; }
991		| '*'						{ $$ = mm_strdup("*"); }
992		| '*' '*'					{ $$ = mm_strdup("**"); }
993		;
994
995/*
996 * We try to simulate the correct DECLARE syntax here so we get dynamic SQL
997 */
998ECPGDeclare: DECLARE STATEMENT ecpg_ident
999		{
1000			/* this is only supported for compatibility */
1001			$$ = cat_str(3, mm_strdup("/* declare statement"), $3, mm_strdup("*/"));
1002		}
1003		;
1004/*
1005 * the exec sql disconnect statement: disconnect from the given database
1006 */
1007ECPGDisconnect: SQL_DISCONNECT dis_name { $$ = $2; }
1008		;
1009
1010dis_name: connection_object			{ $$ = $1; }
1011		| CURRENT_P			{ $$ = mm_strdup("\"CURRENT\""); }
1012		| ALL				{ $$ = mm_strdup("\"ALL\""); }
1013		| /* EMPTY */			{ $$ = mm_strdup("\"CURRENT\""); }
1014		;
1015
1016connection_object: name				{ $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); }
1017		| DEFAULT			{ $$ = mm_strdup("\"DEFAULT\""); }
1018		| char_variable			{ $$ = $1; }
1019		;
1020
1021execstring: char_variable
1022			{ $$ = $1; }
1023		|	CSTRING
1024			{ $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); }
1025		;
1026
1027/*
1028 * the exec sql free command to deallocate a previously
1029 * prepared statement
1030 */
1031ECPGFree:	SQL_FREE cursor_name	{ $$ = $2; }
1032		| SQL_FREE ALL	{ $$ = mm_strdup("all"); }
1033		;
1034
1035/*
1036 * open is an open cursor, at the moment this has to be removed
1037 */
1038ECPGOpen: SQL_OPEN cursor_name opt_ecpg_using
1039		{
1040			if ($2[0] == ':')
1041				remove_variable_from_list(&argsinsert, find_variable($2 + 1));
1042			$$ = $2;
1043		}
1044		;
1045
1046opt_ecpg_using: /*EMPTY*/	{ $$ = EMPTY; }
1047		| ecpg_using		{ $$ = $1; }
1048		;
1049
1050ecpg_using:	USING using_list	{ $$ = EMPTY; }
1051		| using_descriptor		{ $$ = $1; }
1052		;
1053
1054using_descriptor: USING SQL_P SQL_DESCRIPTOR quoted_ident_stringvar
1055		{
1056			add_variable_to_head(&argsinsert, descriptor_variable($4,0), &no_indicator);
1057			$$ = EMPTY;
1058		}
1059		| USING SQL_DESCRIPTOR name
1060		{
1061			add_variable_to_head(&argsinsert, sqlda_variable($3), &no_indicator);
1062			$$ = EMPTY;
1063		}
1064		;
1065
1066into_descriptor: INTO SQL_P SQL_DESCRIPTOR quoted_ident_stringvar
1067		{
1068			add_variable_to_head(&argsresult, descriptor_variable($4,1), &no_indicator);
1069			$$ = EMPTY;
1070		}
1071		| INTO SQL_DESCRIPTOR name
1072		{
1073			add_variable_to_head(&argsresult, sqlda_variable($3), &no_indicator);
1074			$$ = EMPTY;
1075		}
1076		;
1077
1078into_sqlda: INTO name
1079		{
1080			add_variable_to_head(&argsresult, sqlda_variable($2), &no_indicator);
1081			$$ = EMPTY;
1082		}
1083		;
1084
1085using_list: UsingValue | UsingValue ',' using_list;
1086
1087UsingValue: UsingConst
1088		{
1089			char *length = mm_alloc(32);
1090
1091			sprintf(length, "%zu", strlen($1));
1092			add_variable_to_head(&argsinsert, new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator);
1093		}
1094		| civar { $$ = EMPTY; }
1095		| civarind { $$ = EMPTY; }
1096		;
1097
1098UsingConst: Iconst			{ $$ = $1; }
1099		| '+' Iconst		{ $$ = cat_str(2, mm_strdup("+"), $2); }
1100		| '-' Iconst		{ $$ = cat_str(2, mm_strdup("-"), $2); }
1101		| ecpg_fconst		{ $$ = $1; }
1102		| '+' ecpg_fconst	{ $$ = cat_str(2, mm_strdup("+"), $2); }
1103		| '-' ecpg_fconst	{ $$ = cat_str(2, mm_strdup("-"), $2); }
1104		| ecpg_sconst		{ $$ = $1; }
1105		| ecpg_bconst		{ $$ = $1; }
1106		| ecpg_xconst		{ $$ = $1; }
1107		;
1108
1109/*
1110 * We accept DESCRIBE [OUTPUT] but do nothing with DESCRIBE INPUT so far.
1111 */
1112ECPGDescribe: SQL_DESCRIBE INPUT_P prepared_name using_descriptor
1113	{
1114		$$.input = 1;
1115		$$.stmt_name = $3;
1116	}
1117	| SQL_DESCRIBE opt_output prepared_name using_descriptor
1118	{
1119		struct variable *var;
1120		var = argsinsert->variable;
1121		remove_variable_from_list(&argsinsert, var);
1122		add_variable_to_head(&argsresult, var, &no_indicator);
1123
1124		$$.input = 0;
1125		$$.stmt_name = $3;
1126	}
1127	| SQL_DESCRIBE opt_output prepared_name into_descriptor
1128	{
1129		$$.input = 0;
1130		$$.stmt_name = $3;
1131	}
1132	| SQL_DESCRIBE INPUT_P prepared_name into_sqlda
1133	{
1134		$$.input = 1;
1135		$$.stmt_name = $3;
1136	}
1137	| SQL_DESCRIBE opt_output prepared_name into_sqlda
1138	{
1139		$$.input = 0;
1140		$$.stmt_name = $3;
1141	}
1142	;
1143
1144opt_output:	SQL_OUTPUT	{ $$ = mm_strdup("output"); }
1145	|	/* EMPTY */	{ $$ = EMPTY; }
1146	;
1147
1148/*
1149 * dynamic SQL: descriptor based access
1150 *	originally written by Christof Petig <christof.petig@wtal.de>
1151 *			and Peter Eisentraut <peter.eisentraut@credativ.de>
1152 */
1153
1154/*
1155 * allocate a descriptor
1156 */
1157ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar
1158		{
1159			add_descriptor($3,connection);
1160			$$ = $3;
1161		}
1162		;
1163
1164
1165/*
1166 * deallocate a descriptor
1167 */
1168ECPGDeallocateDescr:	DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar
1169		{
1170			drop_descriptor($3,connection);
1171			$$ = $3;
1172		}
1173		;
1174
1175/*
1176 * manipulate a descriptor header
1177 */
1178
1179ECPGGetDescriptorHeader: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar ECPGGetDescHeaderItems
1180			{  $$ = $3; }
1181		;
1182
1183ECPGGetDescHeaderItems: ECPGGetDescHeaderItem
1184		| ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem
1185		;
1186
1187ECPGGetDescHeaderItem: cvariable '=' desc_header_item
1188			{ push_assignment($1, $3); }
1189		;
1190
1191
1192ECPGSetDescriptorHeader: SET SQL_DESCRIPTOR quoted_ident_stringvar ECPGSetDescHeaderItems
1193			{ $$ = $3; }
1194		;
1195
1196ECPGSetDescHeaderItems: ECPGSetDescHeaderItem
1197		| ECPGSetDescHeaderItems ',' ECPGSetDescHeaderItem
1198		;
1199
1200ECPGSetDescHeaderItem: desc_header_item '=' IntConstVar
1201		{
1202			push_assignment($3, $1);
1203		}
1204		;
1205
1206IntConstVar: Iconst
1207		{
1208			char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
1209
1210			sprintf(length, "%zu", strlen($1));
1211			new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
1212			$$ = $1;
1213		}
1214		| cvariable
1215		{
1216			$$ = $1;
1217		}
1218		;
1219
1220desc_header_item:	SQL_COUNT			{ $$ = ECPGd_count; }
1221		;
1222
1223/*
1224 * manipulate a descriptor
1225 */
1226
1227ECPGGetDescriptor:	SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGGetDescItems
1228			{  $$.str = $5; $$.name = $3; }
1229		;
1230
1231ECPGGetDescItems: ECPGGetDescItem
1232		| ECPGGetDescItems ',' ECPGGetDescItem
1233		;
1234
1235ECPGGetDescItem: cvariable '=' descriptor_item	{ push_assignment($1, $3); };
1236
1237
1238ECPGSetDescriptor:	SET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGSetDescItems
1239			{  $$.str = $5; $$.name = $3; }
1240		;
1241
1242ECPGSetDescItems: ECPGSetDescItem
1243		| ECPGSetDescItems ',' ECPGSetDescItem
1244		;
1245
1246ECPGSetDescItem: descriptor_item '=' AllConstVar
1247		{
1248			push_assignment($3, $1);
1249		}
1250		;
1251
1252AllConstVar: ecpg_fconst
1253		{
1254			char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
1255
1256			sprintf(length, "%zu", strlen($1));
1257			new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
1258			$$ = $1;
1259		}
1260
1261		| IntConstVar
1262		{
1263			$$ = $1;
1264		}
1265
1266		| '-' ecpg_fconst
1267		{
1268			char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
1269			char *var = cat2_str(mm_strdup("-"), $2);
1270
1271			sprintf(length, "%zu", strlen(var));
1272			new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
1273			$$ = var;
1274		}
1275
1276		| '-' Iconst
1277		{
1278			char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
1279			char *var = cat2_str(mm_strdup("-"), $2);
1280
1281			sprintf(length, "%zu", strlen(var));
1282			new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
1283			$$ = var;
1284		}
1285
1286		| ecpg_sconst
1287		{
1288			char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
1289			char *var = $1 + 1;
1290
1291			var[strlen(var) - 1] = '\0';
1292			sprintf(length, "%zu", strlen(var));
1293			new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
1294			$$ = var;
1295		}
1296		;
1297
1298descriptor_item:	SQL_CARDINALITY			{ $$ = ECPGd_cardinality; }
1299		| DATA_P				{ $$ = ECPGd_data; }
1300		| SQL_DATETIME_INTERVAL_CODE		{ $$ = ECPGd_di_code; }
1301		| SQL_DATETIME_INTERVAL_PRECISION	{ $$ = ECPGd_di_precision; }
1302		| SQL_INDICATOR				{ $$ = ECPGd_indicator; }
1303		| SQL_KEY_MEMBER			{ $$ = ECPGd_key_member; }
1304		| SQL_LENGTH				{ $$ = ECPGd_length; }
1305		| NAME_P				{ $$ = ECPGd_name; }
1306		| SQL_NULLABLE				{ $$ = ECPGd_nullable; }
1307		| SQL_OCTET_LENGTH			{ $$ = ECPGd_octet; }
1308		| PRECISION				{ $$ = ECPGd_precision; }
1309		| SQL_RETURNED_LENGTH			{ $$ = ECPGd_length; }
1310		| SQL_RETURNED_OCTET_LENGTH		{ $$ = ECPGd_ret_octet; }
1311		| SQL_SCALE				{ $$ = ECPGd_scale; }
1312		| TYPE_P				{ $$ = ECPGd_type; }
1313		;
1314
1315/*
1316 * set/reset the automatic transaction mode, this needs a different handling
1317 * as the other set commands
1318 */
1319ECPGSetAutocommit:	SET SQL_AUTOCOMMIT '=' on_off	{ $$ = $4; }
1320		|  SET SQL_AUTOCOMMIT TO on_off   { $$ = $4; }
1321		;
1322
1323on_off: ON				{ $$ = mm_strdup("on"); }
1324		| OFF			{ $$ = mm_strdup("off"); }
1325		;
1326
1327/*
1328 * set the actual connection, this needs a different handling as the other
1329 * set commands
1330 */
1331ECPGSetConnection:	SET CONNECTION TO connection_object { $$ = $4; }
1332		| SET CONNECTION '=' connection_object { $$ = $4; }
1333		| SET CONNECTION  connection_object { $$ = $3; }
1334		;
1335
1336/*
1337 * define a new type for embedded SQL
1338 */
1339ECPGTypedef: TYPE_P
1340		{
1341			/* reset this variable so we see if there was */
1342			/* an initializer specified */
1343			initializer = 0;
1344		}
1345		ECPGColLabelCommon IS var_type opt_array_bounds opt_reference
1346		{
1347			add_typedef($3, $6.index1, $6.index2, $5.type_enum, $5.type_dimension, $5.type_index, initializer, *$7 ? 1 : 0);
1348
1349			if (auto_create_c == false)
1350				$$ = cat_str(7, mm_strdup("/* exec sql type"), mm_strdup($3), mm_strdup("is"), mm_strdup($5.type_str), mm_strdup($6.str), $7, mm_strdup("*/"));
1351			else
1352				$$ = cat_str(6, mm_strdup("typedef "), mm_strdup($5.type_str), *$7?mm_strdup("*"):mm_strdup(""), mm_strdup($3), mm_strdup($6.str), mm_strdup(";"));
1353		}
1354		;
1355
1356opt_reference: SQL_REFERENCE		{ $$ = mm_strdup("reference"); }
1357		| /*EMPTY*/					{ $$ = EMPTY; }
1358		;
1359
1360/*
1361 * define the type of one variable for embedded SQL
1362 */
1363ECPGVar: SQL_VAR
1364		{
1365			/* reset this variable so we see if there was */
1366			/* an initializer specified */
1367			initializer = 0;
1368		}
1369		ColLabel IS var_type opt_array_bounds opt_reference
1370		{
1371			struct variable *p = find_variable($3);
1372			char *dimension = $6.index1;
1373			char *length = $6.index2;
1374			struct ECPGtype * type;
1375
1376			if (($5.type_enum == ECPGt_struct ||
1377				 $5.type_enum == ECPGt_union) &&
1378				initializer == 1)
1379				mmerror(PARSE_ERROR, ET_ERROR, "initializer not allowed in EXEC SQL VAR command");
1380			else
1381			{
1382				adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *$7?1:0, false);
1383
1384				switch ($5.type_enum)
1385				{
1386					case ECPGt_struct:
1387					case ECPGt_union:
1388						if (atoi(dimension) < 0)
1389							type = ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum, $5.type_str, $5.type_sizeof);
1390						else
1391							type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum, $5.type_str, $5.type_sizeof), dimension);
1392						break;
1393
1394					case ECPGt_varchar:
1395					case ECPGt_bytea:
1396						if (atoi(dimension) == -1)
1397							type = ECPGmake_simple_type($5.type_enum, length, 0);
1398						else
1399							type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, length, 0), dimension);
1400						break;
1401
1402					case ECPGt_char:
1403					case ECPGt_unsigned_char:
1404					case ECPGt_string:
1405						if (atoi(dimension) == -1)
1406							type = ECPGmake_simple_type($5.type_enum, length, 0);
1407						else
1408							type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, length, 0), dimension);
1409						break;
1410
1411					default:
1412						if (atoi(length) >= 0)
1413							mmerror(PARSE_ERROR, ET_ERROR, "multidimensional arrays for simple data types are not supported");
1414
1415						if (atoi(dimension) < 0)
1416							type = ECPGmake_simple_type($5.type_enum, mm_strdup("1"), 0);
1417						else
1418							type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, mm_strdup("1"), 0), dimension);
1419						break;
1420				}
1421
1422				ECPGfree_type(p->type);
1423				p->type = type;
1424			}
1425
1426			$$ = cat_str(7, mm_strdup("/* exec sql var"), mm_strdup($3), mm_strdup("is"), mm_strdup($5.type_str), mm_strdup($6.str), $7, mm_strdup("*/"));
1427		}
1428		;
1429
1430/*
1431 * whenever statement: decide what to do in case of error/no data found
1432 * according to SQL standards we lack: SQLSTATE, CONSTRAINT and SQLEXCEPTION
1433 */
1434ECPGWhenever: SQL_WHENEVER SQL_SQLERROR action
1435		{
1436			when_error.code = $<action>3.code;
1437			when_error.command = $<action>3.command;
1438			$$ = cat_str(3, mm_strdup("/* exec sql whenever sqlerror "), $3.str, mm_strdup("; */"));
1439		}
1440		| SQL_WHENEVER NOT SQL_FOUND action
1441		{
1442			when_nf.code = $<action>4.code;
1443			when_nf.command = $<action>4.command;
1444			$$ = cat_str(3, mm_strdup("/* exec sql whenever not found "), $4.str, mm_strdup("; */"));
1445		}
1446		| SQL_WHENEVER SQL_SQLWARNING action
1447		{
1448			when_warn.code = $<action>3.code;
1449			when_warn.command = $<action>3.command;
1450			$$ = cat_str(3, mm_strdup("/* exec sql whenever sql_warning "), $3.str, mm_strdup("; */"));
1451		}
1452		;
1453
1454action : CONTINUE_P
1455		{
1456			$<action>$.code = W_NOTHING;
1457			$<action>$.command = NULL;
1458			$<action>$.str = mm_strdup("continue");
1459		}
1460		| SQL_SQLPRINT
1461		{
1462			$<action>$.code = W_SQLPRINT;
1463			$<action>$.command = NULL;
1464			$<action>$.str = mm_strdup("sqlprint");
1465		}
1466		| SQL_STOP
1467		{
1468			$<action>$.code = W_STOP;
1469			$<action>$.command = NULL;
1470			$<action>$.str = mm_strdup("stop");
1471		}
1472		| SQL_GOTO name
1473		{
1474			$<action>$.code = W_GOTO;
1475			$<action>$.command = mm_strdup($2);
1476			$<action>$.str = cat2_str(mm_strdup("goto "), $2);
1477		}
1478		| SQL_GO TO name
1479		{
1480			$<action>$.code = W_GOTO;
1481			$<action>$.command = mm_strdup($3);
1482			$<action>$.str = cat2_str(mm_strdup("goto "), $3);
1483		}
1484		| DO name '(' c_args ')'
1485		{
1486			$<action>$.code = W_DO;
1487			$<action>$.command = cat_str(4, $2, mm_strdup("("), $4, mm_strdup(")"));
1488			$<action>$.str = cat2_str(mm_strdup("do"), mm_strdup($<action>$.command));
1489		}
1490		| DO SQL_BREAK
1491		{
1492			$<action>$.code = W_BREAK;
1493			$<action>$.command = NULL;
1494			$<action>$.str = mm_strdup("break");
1495		}
1496		| DO CONTINUE_P
1497		{
1498			$<action>$.code = W_CONTINUE;
1499			$<action>$.command = NULL;
1500			$<action>$.str = mm_strdup("continue");
1501		}
1502		| CALL name '(' c_args ')'
1503		{
1504			$<action>$.code = W_DO;
1505			$<action>$.command = cat_str(4, $2, mm_strdup("("), $4, mm_strdup(")"));
1506			$<action>$.str = cat2_str(mm_strdup("call"), mm_strdup($<action>$.command));
1507		}
1508		| CALL name
1509		{
1510			$<action>$.code = W_DO;
1511			$<action>$.command = cat2_str($2, mm_strdup("()"));
1512			$<action>$.str = cat2_str(mm_strdup("call"), mm_strdup($<action>$.command));
1513		}
1514		;
1515
1516/* some other stuff for ecpg */
1517
1518/* additional unreserved keywords */
1519ECPGKeywords: ECPGKeywords_vanames	{ $$ = $1; }
1520		| ECPGKeywords_rest	{ $$ = $1; }
1521		;
1522
1523ECPGKeywords_vanames:  SQL_BREAK		{ $$ = mm_strdup("break"); }
1524		| SQL_CARDINALITY				{ $$ = mm_strdup("cardinality"); }
1525		| SQL_COUNT						{ $$ = mm_strdup("count"); }
1526		| SQL_DATETIME_INTERVAL_CODE	{ $$ = mm_strdup("datetime_interval_code"); }
1527		| SQL_DATETIME_INTERVAL_PRECISION	{ $$ = mm_strdup("datetime_interval_precision"); }
1528		| SQL_FOUND						{ $$ = mm_strdup("found"); }
1529		| SQL_GO						{ $$ = mm_strdup("go"); }
1530		| SQL_GOTO						{ $$ = mm_strdup("goto"); }
1531		| SQL_IDENTIFIED				{ $$ = mm_strdup("identified"); }
1532		| SQL_INDICATOR				{ $$ = mm_strdup("indicator"); }
1533		| SQL_KEY_MEMBER			{ $$ = mm_strdup("key_member"); }
1534		| SQL_LENGTH				{ $$ = mm_strdup("length"); }
1535		| SQL_NULLABLE				{ $$ = mm_strdup("nullable"); }
1536		| SQL_OCTET_LENGTH			{ $$ = mm_strdup("octet_length"); }
1537		| SQL_RETURNED_LENGTH		{ $$ = mm_strdup("returned_length"); }
1538		| SQL_RETURNED_OCTET_LENGTH	{ $$ = mm_strdup("returned_octet_length"); }
1539		| SQL_SCALE					{ $$ = mm_strdup("scale"); }
1540		| SQL_SECTION				{ $$ = mm_strdup("section"); }
1541		| SQL_SQLERROR				{ $$ = mm_strdup("sqlerror"); }
1542		| SQL_SQLPRINT				{ $$ = mm_strdup("sqlprint"); }
1543		| SQL_SQLWARNING			{ $$ = mm_strdup("sqlwarning"); }
1544		| SQL_STOP					{ $$ = mm_strdup("stop"); }
1545		;
1546
1547ECPGKeywords_rest:  SQL_CONNECT		{ $$ = mm_strdup("connect"); }
1548		| SQL_DESCRIBE				{ $$ = mm_strdup("describe"); }
1549		| SQL_DISCONNECT			{ $$ = mm_strdup("disconnect"); }
1550		| SQL_OPEN					{ $$ = mm_strdup("open"); }
1551		| SQL_VAR					{ $$ = mm_strdup("var"); }
1552		| SQL_WHENEVER				{ $$ = mm_strdup("whenever"); }
1553		;
1554
1555/* additional keywords that can be SQL type names (but not ECPGColLabels) */
1556ECPGTypeName:  SQL_BOOL				{ $$ = mm_strdup("bool"); }
1557		| SQL_LONG					{ $$ = mm_strdup("long"); }
1558		| SQL_OUTPUT				{ $$ = mm_strdup("output"); }
1559		| SQL_SHORT					{ $$ = mm_strdup("short"); }
1560		| SQL_STRUCT				{ $$ = mm_strdup("struct"); }
1561		| SQL_SIGNED				{ $$ = mm_strdup("signed"); }
1562		| SQL_UNSIGNED				{ $$ = mm_strdup("unsigned"); }
1563		;
1564
1565symbol: ColLabel					{ $$ = $1; }
1566		;
1567
1568ECPGColId: ecpg_ident				{ $$ = $1; }
1569		| unreserved_keyword		{ $$ = $1; }
1570		| col_name_keyword			{ $$ = $1; }
1571		| ECPGunreserved_interval	{ $$ = $1; }
1572		| ECPGKeywords				{ $$ = $1; }
1573		| ECPGCKeywords				{ $$ = $1; }
1574		| CHAR_P					{ $$ = mm_strdup("char"); }
1575		| VALUES					{ $$ = mm_strdup("values"); }
1576		;
1577
1578/*
1579 * Name classification hierarchy.
1580 *
1581 * These productions should match those in the core grammar, except that
1582 * we use all_unreserved_keyword instead of unreserved_keyword, and
1583 * where possible include ECPG keywords as well as core keywords.
1584 */
1585
1586/* Column identifier --- names that can be column, table, etc names.
1587 */
1588ColId:	ecpg_ident					{ $$ = $1; }
1589		| all_unreserved_keyword	{ $$ = $1; }
1590		| col_name_keyword			{ $$ = $1; }
1591		| ECPGKeywords				{ $$ = $1; }
1592		| ECPGCKeywords				{ $$ = $1; }
1593		| CHAR_P					{ $$ = mm_strdup("char"); }
1594		| VALUES					{ $$ = mm_strdup("values"); }
1595		;
1596
1597/* Type/function identifier --- names that can be type or function names.
1598 */
1599type_function_name:	ecpg_ident		{ $$ = $1; }
1600		| all_unreserved_keyword	{ $$ = $1; }
1601		| type_func_name_keyword	{ $$ = $1; }
1602		| ECPGKeywords				{ $$ = $1; }
1603		| ECPGCKeywords				{ $$ = $1; }
1604		| ECPGTypeName				{ $$ = $1; }
1605		;
1606
1607/* Column label --- allowed labels in "AS" clauses.
1608 * This presently includes *all* Postgres keywords.
1609 */
1610ColLabel:  ECPGColLabel				{ $$ = $1; }
1611		| ECPGTypeName				{ $$ = $1; }
1612		| CHAR_P					{ $$ = mm_strdup("char"); }
1613		| CURRENT_P					{ $$ = mm_strdup("current"); }
1614		| INPUT_P					{ $$ = mm_strdup("input"); }
1615		| INT_P						{ $$ = mm_strdup("int"); }
1616		| TO						{ $$ = mm_strdup("to"); }
1617		| UNION						{ $$ = mm_strdup("union"); }
1618		| VALUES					{ $$ = mm_strdup("values"); }
1619		| ECPGCKeywords				{ $$ = $1; }
1620		| ECPGunreserved_interval	{ $$ = $1; }
1621		;
1622
1623ECPGColLabel:  ECPGColLabelCommon	{ $$ = $1; }
1624		| unreserved_keyword		{ $$ = $1; }
1625		| reserved_keyword			{ $$ = $1; }
1626		| ECPGKeywords_rest			{ $$ = $1; }
1627		| CONNECTION				{ $$ = mm_strdup("connection"); }
1628		;
1629
1630ECPGColLabelCommon:  ecpg_ident		{ $$ = $1; }
1631		| col_name_keyword			{ $$ = $1; }
1632		| type_func_name_keyword	{ $$ = $1; }
1633		| ECPGKeywords_vanames		{ $$ = $1; }
1634		;
1635
1636ECPGCKeywords: S_AUTO				{ $$ = mm_strdup("auto"); }
1637		| S_CONST					{ $$ = mm_strdup("const"); }
1638		| S_EXTERN					{ $$ = mm_strdup("extern"); }
1639		| S_REGISTER				{ $$ = mm_strdup("register"); }
1640		| S_STATIC					{ $$ = mm_strdup("static"); }
1641		| S_TYPEDEF					{ $$ = mm_strdup("typedef"); }
1642		| S_VOLATILE				{ $$ = mm_strdup("volatile"); }
1643		;
1644
1645/* "Unreserved" keywords --- available for use as any kind of name.
1646 */
1647
1648/*
1649 * The following symbols must be excluded from ECPGColLabel and directly
1650 * included into ColLabel to enable C variables to get names from ECPGColLabel:
1651 * DAY_P, HOUR_P, MINUTE_P, MONTH_P, SECOND_P, YEAR_P.
1652 *
1653 * We also have to exclude CONNECTION, CURRENT, and INPUT for various reasons.
1654 * CONNECTION can be added back in all_unreserved_keyword, but CURRENT and
1655 * INPUT are reserved for ecpg purposes.
1656 *
1657 * The mentioned exclusions are done by $replace_line settings in parse.pl.
1658 */
1659all_unreserved_keyword: unreserved_keyword	{ $$ = $1; }
1660		| ECPGunreserved_interval			{ $$ = $1; }
1661		| CONNECTION						{ $$ = mm_strdup("connection"); }
1662		;
1663
1664ECPGunreserved_interval: DAY_P				{ $$ = mm_strdup("day"); }
1665		| HOUR_P							{ $$ = mm_strdup("hour"); }
1666		| MINUTE_P							{ $$ = mm_strdup("minute"); }
1667		| MONTH_P							{ $$ = mm_strdup("month"); }
1668		| SECOND_P							{ $$ = mm_strdup("second"); }
1669		| YEAR_P							{ $$ = mm_strdup("year"); }
1670		;
1671
1672
1673into_list : coutputvariable | into_list ',' coutputvariable
1674		;
1675
1676ecpgstart: SQL_START	{
1677				reset_variables();
1678				pacounter = 1;
1679			}
1680		;
1681
1682c_args: /*EMPTY*/		{ $$ = EMPTY; }
1683		| c_list		{ $$ = $1; }
1684		;
1685
1686coutputvariable: cvariable indicator
1687			{ add_variable_to_head(&argsresult, find_variable($1), find_variable($2)); }
1688		| cvariable
1689			{ add_variable_to_head(&argsresult, find_variable($1), &no_indicator); }
1690		;
1691
1692
1693civarind: cvariable indicator
1694		{
1695			if (find_variable($2)->type->type == ECPGt_array)
1696				mmerror(PARSE_ERROR, ET_ERROR, "arrays of indicators are not allowed on input");
1697
1698			add_variable_to_head(&argsinsert, find_variable($1), find_variable($2));
1699			$$ = create_questionmarks($1, false);
1700		}
1701		;
1702
1703char_civar: char_variable
1704		{
1705			char *ptr = strstr($1, ".arr");
1706
1707			if (ptr) /* varchar, we need the struct name here, not the struct element */
1708				*ptr = '\0';
1709			add_variable_to_head(&argsinsert, find_variable($1), &no_indicator);
1710			$$ = $1;
1711		}
1712		;
1713
1714civar: cvariable
1715		{
1716			add_variable_to_head(&argsinsert, find_variable($1), &no_indicator);
1717			$$ = create_questionmarks($1, false);
1718		}
1719		;
1720
1721indicator: cvariable				{ check_indicator((find_variable($1))->type); $$ = $1; }
1722		| SQL_INDICATOR cvariable	{ check_indicator((find_variable($2))->type); $$ = $2; }
1723		| SQL_INDICATOR name		{ check_indicator((find_variable($2))->type); $$ = $2; }
1724		;
1725
1726cvariable:	CVARIABLE
1727		{
1728			/* As long as multidimensional arrays are not implemented we have to check for those here */
1729			char *ptr = $1;
1730			int brace_open=0, brace = false;
1731
1732			for (; *ptr; ptr++)
1733			{
1734				switch (*ptr)
1735				{
1736					case '[':
1737							if (brace)
1738								mmfatal(PARSE_ERROR, "multidimensional arrays for simple data types are not supported");
1739							brace_open++;
1740							break;
1741					case ']':
1742							brace_open--;
1743							if (brace_open == 0)
1744								brace = true;
1745							break;
1746					case '\t':
1747					case ' ':
1748							break;
1749					default:
1750							if (brace_open == 0)
1751								brace = false;
1752							break;
1753				}
1754			}
1755			$$ = $1;
1756		}
1757		;
1758
1759ecpg_param:	PARAM		{ $$ = make_name(); } ;
1760
1761ecpg_bconst:	BCONST		{ $$ = $1; } ;
1762
1763ecpg_fconst:	FCONST		{ $$ = make_name(); } ;
1764
1765ecpg_sconst:	SCONST		{ $$ = $1; } ;
1766
1767ecpg_xconst:	XCONST		{ $$ = $1; } ;
1768
1769ecpg_ident:	IDENT		{ $$ = $1; }
1770		| CSTRING	{ $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); }
1771		;
1772
1773quoted_ident_stringvar: name
1774			{ $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); }
1775		| char_variable
1776			{ $$ = make3_str(mm_strdup("("), $1, mm_strdup(")")); }
1777		;
1778
1779/*
1780 * C stuff
1781 */
1782
1783c_stuff_item: c_anything			{ $$ = $1; }
1784		| '(' ')'			{ $$ = mm_strdup("()"); }
1785		| '(' c_stuff ')'
1786			{ $$ = cat_str(3, mm_strdup("("), $2, mm_strdup(")")); }
1787		;
1788
1789c_stuff: c_stuff_item			{ $$ = $1; }
1790		| c_stuff c_stuff_item
1791			{ $$ = cat2_str($1, $2); }
1792		;
1793
1794c_list: c_term				{ $$ = $1; }
1795		| c_list ',' c_term	{ $$ = cat_str(3, $1, mm_strdup(","), $3); }
1796		;
1797
1798c_term:  c_stuff			{ $$ = $1; }
1799		| '{' c_list '}'	{ $$ = cat_str(3, mm_strdup("{"), $2, mm_strdup("}")); }
1800		;
1801
1802c_thing:	c_anything		{ $$ = $1; }
1803		|	'('		{ $$ = mm_strdup("("); }
1804		|	')'		{ $$ = mm_strdup(")"); }
1805		|	','		{ $$ = mm_strdup(","); }
1806		|	';'		{ $$ = mm_strdup(";"); }
1807		;
1808
1809c_anything:  ecpg_ident				{ $$ = $1; }
1810		| Iconst			{ $$ = $1; }
1811		| ecpg_fconst			{ $$ = $1; }
1812		| ecpg_sconst			{ $$ = $1; }
1813		| '*'				{ $$ = mm_strdup("*"); }
1814		| '+'				{ $$ = mm_strdup("+"); }
1815		| '-'				{ $$ = mm_strdup("-"); }
1816		| '/'				{ $$ = mm_strdup("/"); }
1817		| '%'				{ $$ = mm_strdup("%"); }
1818		| NULL_P			{ $$ = mm_strdup("NULL"); }
1819		| S_ADD				{ $$ = mm_strdup("+="); }
1820		| S_AND				{ $$ = mm_strdup("&&"); }
1821		| S_ANYTHING			{ $$ = make_name(); }
1822		| S_AUTO			{ $$ = mm_strdup("auto"); }
1823		| S_CONST			{ $$ = mm_strdup("const"); }
1824		| S_DEC				{ $$ = mm_strdup("--"); }
1825		| S_DIV				{ $$ = mm_strdup("/="); }
1826		| S_DOTPOINT			{ $$ = mm_strdup(".*"); }
1827		| S_EQUAL			{ $$ = mm_strdup("=="); }
1828		| S_EXTERN			{ $$ = mm_strdup("extern"); }
1829		| S_INC				{ $$ = mm_strdup("++"); }
1830		| S_LSHIFT			{ $$ = mm_strdup("<<"); }
1831		| S_MEMBER			{ $$ = mm_strdup("->"); }
1832		| S_MEMPOINT			{ $$ = mm_strdup("->*"); }
1833		| S_MOD				{ $$ = mm_strdup("%="); }
1834		| S_MUL				{ $$ = mm_strdup("*="); }
1835		| S_NEQUAL			{ $$ = mm_strdup("!="); }
1836		| S_OR				{ $$ = mm_strdup("||"); }
1837		| S_REGISTER			{ $$ = mm_strdup("register"); }
1838		| S_RSHIFT			{ $$ = mm_strdup(">>"); }
1839		| S_STATIC			{ $$ = mm_strdup("static"); }
1840		| S_SUB				{ $$ = mm_strdup("-="); }
1841		| S_TYPEDEF			{ $$ = mm_strdup("typedef"); }
1842		| S_VOLATILE			{ $$ = mm_strdup("volatile"); }
1843		| SQL_BOOL			{ $$ = mm_strdup("bool"); }
1844		| ENUM_P			{ $$ = mm_strdup("enum"); }
1845		| HOUR_P			{ $$ = mm_strdup("hour"); }
1846		| INT_P				{ $$ = mm_strdup("int"); }
1847		| SQL_LONG			{ $$ = mm_strdup("long"); }
1848		| MINUTE_P			{ $$ = mm_strdup("minute"); }
1849		| MONTH_P			{ $$ = mm_strdup("month"); }
1850		| SECOND_P			{ $$ = mm_strdup("second"); }
1851		| SQL_SHORT			{ $$ = mm_strdup("short"); }
1852		| SQL_SIGNED			{ $$ = mm_strdup("signed"); }
1853		| SQL_STRUCT			{ $$ = mm_strdup("struct"); }
1854		| SQL_UNSIGNED			{ $$ = mm_strdup("unsigned"); }
1855		| YEAR_P			{ $$ = mm_strdup("year"); }
1856		| CHAR_P			{ $$ = mm_strdup("char"); }
1857		| FLOAT_P			{ $$ = mm_strdup("float"); }
1858		| TO				{ $$ = mm_strdup("to"); }
1859		| UNION				{ $$ = mm_strdup("union"); }
1860		| VARCHAR			{ $$ = mm_strdup("varchar"); }
1861		| '['				{ $$ = mm_strdup("["); }
1862		| ']'				{ $$ = mm_strdup("]"); }
1863		| '='				{ $$ = mm_strdup("="); }
1864		| ':'				{ $$ = mm_strdup(":"); }
1865		;
1866
1867DeallocateStmt: DEALLOCATE prepared_name	{ check_declared_list($2); $$ = $2; }
1868		| DEALLOCATE PREPARE prepared_name	{ check_declared_list($3); $$ = $3; }
1869		| DEALLOCATE ALL					{ $$ = mm_strdup("all"); }
1870		| DEALLOCATE PREPARE ALL			{ $$ = mm_strdup("all"); }
1871		;
1872
1873Iresult: Iconst						{ $$ = $1; }
1874		| '(' Iresult ')'			{ $$ = cat_str(3, mm_strdup("("), $2, mm_strdup(")")); }
1875		| Iresult '+' Iresult		{ $$ = cat_str(3, $1, mm_strdup("+"), $3); }
1876		| Iresult '-' Iresult		{ $$ = cat_str(3, $1, mm_strdup("-"), $3); }
1877		| Iresult '*' Iresult		{ $$ = cat_str(3, $1, mm_strdup("*"), $3); }
1878		| Iresult '/' Iresult		{ $$ = cat_str(3, $1, mm_strdup("/"), $3); }
1879		| Iresult '%' Iresult		{ $$ = cat_str(3, $1, mm_strdup("%"), $3); }
1880		| ecpg_sconst				{ $$ = $1; }
1881		| ColId						{ $$ = $1; }
1882		| ColId '(' var_type ')'	{ if (pg_strcasecmp($1, "sizeof") != 0)
1883							mmerror(PARSE_ERROR, ET_ERROR, "operator not allowed in variable definition");
1884						  else
1885							$$ = cat_str(4, $1, mm_strdup("("), $3.type_str, mm_strdup(")"));
1886						}
1887		;
1888
1889execute_rest: /* EMPTY */	{ $$ = EMPTY; }
1890	| ecpg_using opt_ecpg_into  { $$ = EMPTY; }
1891	| ecpg_into ecpg_using  { $$ = EMPTY; }
1892	| ecpg_into				{ $$ = EMPTY; }
1893	;
1894
1895ecpg_into: INTO into_list	{ $$ = EMPTY; }
1896	| into_descriptor		{ $$ = $1; }
1897	;
1898
1899opt_ecpg_into:	/* EMPTY */	{ $$ = EMPTY; }
1900	| ecpg_into		{ $$ = $1; }
1901	;
1902
1903ecpg_fetch_into: ecpg_into	{ $$ = $1; }
1904	| using_descriptor
1905	{
1906		struct variable *var;
1907
1908		var = argsinsert->variable;
1909		remove_variable_from_list(&argsinsert, var);
1910		add_variable_to_head(&argsresult, var, &no_indicator);
1911		$$ = $1;
1912	}
1913	;
1914
1915opt_ecpg_fetch_into:	/* EMPTY */	{ $$ = EMPTY; }
1916	| ecpg_fetch_into		{ $$ = $1; }
1917	;
1918
1919%%
1920
1921void base_yyerror(const char *error)
1922{
1923	/* translator: %s is typically the translation of "syntax error" */
1924	mmerror(PARSE_ERROR, ET_ERROR, "%s at or near \"%s\"",
1925			_(error), token_start ? token_start : base_yytext);
1926}
1927
1928void parser_init(void)
1929{
1930 /* This function is empty. It only exists for compatibility with the backend parser right now. */
1931}
1932