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