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