1/* src/interfaces/ecpg/preproc/ecpg.header */
2
3/* Copyright comment */
4%{
5#include "postgres_fe.h"
6
7#include "extern.h"
8#include "ecpg_config.h"
9#include <unistd.h>
10
11/* Location tracking support --- simpler than bison's default */
12#define YYLLOC_DEFAULT(Current, Rhs, N) \
13	do { \
14		if (N)						\
15			(Current) = (Rhs)[1];	\
16		else						\
17			(Current) = (Rhs)[0];	\
18	} while (0)
19
20/*
21 * The %name-prefix option below will make bison call base_yylex, but we
22 * really want it to call filtered_base_yylex (see parser.c).
23 */
24#define base_yylex filtered_base_yylex
25
26/*
27 * This is only here so the string gets into the POT.  Bison uses it
28 * internally.
29 */
30#define bison_gettext_dummy gettext_noop("syntax error")
31
32/*
33 * Variables containing simple states.
34 */
35int struct_level = 0;
36int braces_open; /* brace level counter */
37char *current_function;
38int ecpg_internal_var = 0;
39char	*connection = NULL;
40char	*input_filename = NULL;
41
42static int	FoundInto = 0;
43static int	initializer = 0;
44static int	pacounter = 1;
45static char	pacounter_buffer[sizeof(int) * CHAR_BIT * 10 / 3]; /* a rough guess at the size we need */
46static struct this_type actual_type[STRUCT_DEPTH];
47static char *actual_startline[STRUCT_DEPTH];
48static int	varchar_counter = 1;
49
50/* temporarily store struct members while creating the data structure */
51struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = { NULL };
52
53/* also store struct type so we can do a sizeof() later */
54static char *ECPGstruct_sizeof = NULL;
55
56/* for forward declarations we have to store some data as well */
57static char *forward_name = NULL;
58
59struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, NULL, NULL, NULL, {NULL}, 0};
60struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL};
61
62static struct ECPGtype ecpg_query = {ECPGt_char_variable, NULL, NULL, NULL, {NULL}, 0};
63
64static void vmmerror(int error_code, enum errortype type, const char *error, va_list ap) pg_attribute_printf(3, 0);
65
66/*
67 * Handle parsing errors and warnings
68 */
69static void
70vmmerror(int error_code, enum errortype type, const char *error, va_list ap)
71{
72	/* localize the error message string */
73	error = _(error);
74
75	fprintf(stderr, "%s:%d: ", input_filename, base_yylineno);
76
77	switch(type)
78	{
79		case ET_WARNING:
80			fprintf(stderr, _("WARNING: "));
81			break;
82		case ET_ERROR:
83			fprintf(stderr, _("ERROR: "));
84			break;
85	}
86
87	vfprintf(stderr, error, ap);
88
89	fprintf(stderr, "\n");
90
91	switch(type)
92	{
93		case ET_WARNING:
94			break;
95		case ET_ERROR:
96			ret_value = error_code;
97			break;
98	}
99}
100
101void
102mmerror(int error_code, enum errortype type, const char *error, ...)
103{
104	va_list		ap;
105
106	va_start(ap, error);
107	vmmerror(error_code, type, error, ap);
108	va_end(ap);
109}
110
111void
112mmfatal(int error_code, const char *error, ...)
113{
114	va_list		ap;
115
116	va_start(ap, error);
117	vmmerror(error_code, ET_ERROR, error, ap);
118	va_end(ap);
119
120	if (base_yyin)
121		fclose(base_yyin);
122	if (base_yyout)
123		fclose(base_yyout);
124
125	if (strcmp(output_filename, "-") != 0 && unlink(output_filename) != 0)
126		fprintf(stderr, _("could not remove output file \"%s\"\n"), output_filename);
127	exit(error_code);
128}
129
130/*
131 * string concatenation
132 */
133
134static char *
135cat2_str(char *str1, char *str2)
136{
137	char * res_str	= (char *)mm_alloc(strlen(str1) + strlen(str2) + 2);
138
139	strcpy(res_str, str1);
140	if (strlen(str1) != 0 && strlen(str2) != 0)
141		strcat(res_str, " ");
142	strcat(res_str, str2);
143	free(str1);
144	free(str2);
145	return res_str;
146}
147
148static char *
149cat_str(int count, ...)
150{
151	va_list		args;
152	int			i;
153	char		*res_str;
154
155	va_start(args, count);
156
157	res_str = va_arg(args, char *);
158
159	/* now add all other strings */
160	for (i = 1; i < count; i++)
161		res_str = cat2_str(res_str, va_arg(args, char *));
162
163	va_end(args);
164
165	return res_str;
166}
167
168static char *
169make2_str(char *str1, char *str2)
170{
171	char * res_str	= (char *)mm_alloc(strlen(str1) + strlen(str2) + 1);
172
173	strcpy(res_str, str1);
174	strcat(res_str, str2);
175	free(str1);
176	free(str2);
177	return res_str;
178}
179
180static char *
181make3_str(char *str1, char *str2, char *str3)
182{
183	char * res_str	= (char *)mm_alloc(strlen(str1) + strlen(str2) +strlen(str3) + 1);
184
185	strcpy(res_str, str1);
186	strcat(res_str, str2);
187	strcat(res_str, str3);
188	free(str1);
189	free(str2);
190	free(str3);
191	return res_str;
192}
193
194/* and the rest */
195static char *
196make_name(void)
197{
198	return mm_strdup(base_yytext);
199}
200
201static char *
202create_questionmarks(char *name, bool array)
203{
204	struct variable *p = find_variable(name);
205	int count;
206	char *result = EMPTY;
207
208	/* In case we have a struct, we have to print as many "?" as there are attributes in the struct
209	 * An array is only allowed together with an element argument
210	 * This is essentially only used for inserts, but using a struct as input parameter is an error anywhere else
211	 * so we don't have to worry here. */
212
213	if (p->type->type == ECPGt_struct || (array && p->type->type == ECPGt_array && p->type->u.element->type == ECPGt_struct))
214	{
215		struct ECPGstruct_member *m;
216
217		if (p->type->type == ECPGt_struct)
218			m = p->type->u.members;
219		else
220			m = p->type->u.element->u.members;
221
222		for (count = 0; m != NULL; m=m->next, count++);
223	}
224	else
225		count = 1;
226
227	for (; count > 0; count --)
228	{
229		sprintf(pacounter_buffer, "$%d", pacounter++);
230		result = cat_str(3, result, mm_strdup(pacounter_buffer), mm_strdup(" , "));
231	}
232
233	/* removed the trailing " ," */
234
235	result[strlen(result)-3] = '\0';
236	return result;
237}
238
239static char *
240adjust_outofscope_cursor_vars(struct cursor *cur)
241{
242	/* Informix accepts DECLARE with variables that are out of scope when OPEN is called.
243	 * For instance you can DECLARE a cursor in one function, and OPEN/FETCH/CLOSE
244	 * it in another functions. This is very useful for e.g. event-driver programming,
245	 * but may also lead to dangerous programming. The limitation when this is allowed
246	 * and doesn't cause problems have to be documented, like the allocated variables
247	 * must not be realloc()'ed.
248	 *
249	 * We have to change the variables to our own struct and just store the pointer
250	 * instead of the variable. Do it only for local variables, not for globals.
251	 */
252
253	char *result = EMPTY;
254	int insert;
255
256	for (insert = 1; insert >= 0; insert--)
257	{
258		struct arguments *list;
259		struct arguments *ptr;
260		struct arguments *newlist = NULL;
261		struct variable *newvar, *newind;
262
263		list = (insert ? cur->argsinsert : cur->argsresult);
264
265		for (ptr = list; ptr != NULL; ptr = ptr->next)
266		{
267			char var_text[20];
268			char *original_var;
269			bool skip_set_var = false;
270			bool var_ptr = false;
271
272			/* change variable name to "ECPGget_var(<counter>)" */
273			original_var = ptr->variable->name;
274			sprintf(var_text, "%d))", ecpg_internal_var);
275
276			/* Don't emit ECPGset_var() calls for global variables */
277			if (ptr->variable->brace_level == 0)
278			{
279				newvar = ptr->variable;
280				skip_set_var = true;
281			}
282			else if ((ptr->variable->type->type == ECPGt_char_variable)
283					 && (strncmp(ptr->variable->name, "ECPGprepared_statement", strlen("ECPGprepared_statement")) == 0))
284			{
285				newvar = ptr->variable;
286				skip_set_var = true;
287			}
288			else if ((ptr->variable->type->type != ECPGt_varchar
289					  && ptr->variable->type->type != ECPGt_char
290					  && ptr->variable->type->type != ECPGt_unsigned_char
291					  && ptr->variable->type->type != ECPGt_string)
292					 && atoi(ptr->variable->type->size) > 1)
293			{
294				newvar = new_variable(cat_str(4, mm_strdup("("),
295											  mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)),
296											  mm_strdup(" *)(ECPGget_var("),
297											  mm_strdup(var_text)),
298									  ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type,
299																			   mm_strdup("1"),
300																			   ptr->variable->type->u.element->counter),
301														  ptr->variable->type->size),
302									  0);
303			}
304			else if ((ptr->variable->type->type == ECPGt_varchar
305					  || ptr->variable->type->type == ECPGt_char
306					  || ptr->variable->type->type == ECPGt_unsigned_char
307					  || ptr->variable->type->type == ECPGt_string)
308					 && atoi(ptr->variable->type->size) > 1)
309			{
310				newvar = new_variable(cat_str(4, mm_strdup("("),
311											  mm_strdup(ecpg_type_name(ptr->variable->type->type)),
312											  mm_strdup(" *)(ECPGget_var("),
313											  mm_strdup(var_text)),
314									  ECPGmake_simple_type(ptr->variable->type->type,
315														   ptr->variable->type->size,
316														   ptr->variable->type->counter),
317									  0);
318				if (ptr->variable->type->type == ECPGt_varchar)
319					var_ptr = true;
320			}
321			else if (ptr->variable->type->type == ECPGt_struct
322					 || ptr->variable->type->type == ECPGt_union)
323			{
324				newvar = new_variable(cat_str(5, mm_strdup("(*("),
325											  mm_strdup(ptr->variable->type->type_name),
326											  mm_strdup(" *)(ECPGget_var("),
327											  mm_strdup(var_text),
328											  mm_strdup(")")),
329									  ECPGmake_struct_type(ptr->variable->type->u.members,
330														   ptr->variable->type->type,
331														   ptr->variable->type->type_name,
332														   ptr->variable->type->struct_sizeof),
333									  0);
334				var_ptr = true;
335			}
336			else if (ptr->variable->type->type == ECPGt_array)
337			{
338				if (ptr->variable->type->u.element->type == ECPGt_struct
339					|| ptr->variable->type->u.element->type == ECPGt_union)
340				{
341					newvar = new_variable(cat_str(5, mm_strdup("(*("),
342											  mm_strdup(ptr->variable->type->u.element->type_name),
343											  mm_strdup(" *)(ECPGget_var("),
344											  mm_strdup(var_text),
345											  mm_strdup(")")),
346										  ECPGmake_struct_type(ptr->variable->type->u.element->u.members,
347															   ptr->variable->type->u.element->type,
348															   ptr->variable->type->u.element->type_name,
349															   ptr->variable->type->u.element->struct_sizeof),
350										  0);
351				}
352				else
353				{
354					newvar = new_variable(cat_str(4, mm_strdup("("),
355												  mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)),
356												  mm_strdup(" *)(ECPGget_var("),
357												  mm_strdup(var_text)),
358										  ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type,
359																				   ptr->variable->type->u.element->size,
360																				   ptr->variable->type->u.element->counter),
361															  ptr->variable->type->size),
362										  0);
363					var_ptr = true;
364				}
365			}
366			else
367			{
368				newvar = new_variable(cat_str(4, mm_strdup("*("),
369											  mm_strdup(ecpg_type_name(ptr->variable->type->type)),
370											  mm_strdup(" *)(ECPGget_var("),
371											  mm_strdup(var_text)),
372									  ECPGmake_simple_type(ptr->variable->type->type,
373														   ptr->variable->type->size,
374														   ptr->variable->type->counter),
375									  0);
376				var_ptr = true;
377			}
378
379			/* create call to "ECPGset_var(<counter>, <connection>, <pointer>. <line number>)" */
380			if (!skip_set_var)
381			{
382				sprintf(var_text, "%d, %s", ecpg_internal_var++, var_ptr ? "&(" : "(");
383				result = cat_str(5, result, mm_strdup("ECPGset_var("),
384								 mm_strdup(var_text), mm_strdup(original_var),
385								 mm_strdup("), __LINE__);\n"));
386			}
387
388			/* now the indicator if there is one and it's not a global variable */
389			if ((ptr->indicator->type->type == ECPGt_NO_INDICATOR) || (ptr->indicator->brace_level == 0))
390			{
391				newind = ptr->indicator;
392			}
393			else
394			{
395				/* change variable name to "ECPGget_var(<counter>)" */
396				original_var = ptr->indicator->name;
397				sprintf(var_text, "%d))", ecpg_internal_var);
398				var_ptr = false;
399
400				if (ptr->indicator->type->type == ECPGt_struct
401					|| ptr->indicator->type->type == ECPGt_union)
402				{
403					newind = new_variable(cat_str(5, mm_strdup("(*("),
404											  mm_strdup(ptr->indicator->type->type_name),
405											  mm_strdup(" *)(ECPGget_var("),
406											  mm_strdup(var_text),
407											  mm_strdup(")")),
408										  ECPGmake_struct_type(ptr->indicator->type->u.members,
409															   ptr->indicator->type->type,
410															   ptr->indicator->type->type_name,
411															   ptr->indicator->type->struct_sizeof),
412										  0);
413					var_ptr = true;
414				}
415				else if (ptr->indicator->type->type == ECPGt_array)
416				{
417					if (ptr->indicator->type->u.element->type == ECPGt_struct
418						|| ptr->indicator->type->u.element->type == ECPGt_union)
419					{
420						newind = new_variable(cat_str(5, mm_strdup("(*("),
421											  mm_strdup(ptr->indicator->type->u.element->type_name),
422											  mm_strdup(" *)(ECPGget_var("),
423											  mm_strdup(var_text),
424											  mm_strdup(")")),
425											  ECPGmake_struct_type(ptr->indicator->type->u.element->u.members,
426																   ptr->indicator->type->u.element->type,
427																   ptr->indicator->type->u.element->type_name,
428																   ptr->indicator->type->u.element->struct_sizeof),
429											  0);
430					}
431					else
432					{
433						newind = new_variable(cat_str(4, mm_strdup("("),
434													  mm_strdup(ecpg_type_name(ptr->indicator->type->u.element->type)),
435													  mm_strdup(" *)(ECPGget_var("), mm_strdup(var_text)),
436											  ECPGmake_array_type(ECPGmake_simple_type(ptr->indicator->type->u.element->type,
437																					   ptr->indicator->type->u.element->size,
438																					   ptr->indicator->type->u.element->counter),
439																  ptr->indicator->type->size),
440											  0);
441						var_ptr = true;
442					}
443				}
444				else if (atoi(ptr->indicator->type->size) > 1)
445				{
446					newind = new_variable(cat_str(4, mm_strdup("("),
447												  mm_strdup(ecpg_type_name(ptr->indicator->type->type)),
448												  mm_strdup(" *)(ECPGget_var("),
449												  mm_strdup(var_text)),
450										  ECPGmake_simple_type(ptr->indicator->type->type,
451															   ptr->indicator->type->size,
452															   ptr->variable->type->counter),
453										  0);
454				}
455				else
456				{
457					newind = new_variable(cat_str(4, mm_strdup("*("),
458												  mm_strdup(ecpg_type_name(ptr->indicator->type->type)),
459												  mm_strdup(" *)(ECPGget_var("),
460												  mm_strdup(var_text)),
461										  ECPGmake_simple_type(ptr->indicator->type->type,
462															   ptr->indicator->type->size,
463															   ptr->variable->type->counter),
464										  0);
465					var_ptr = true;
466				}
467
468				/* create call to "ECPGset_var(<counter>, <pointer>. <line number>)" */
469				sprintf(var_text, "%d, %s", ecpg_internal_var++, var_ptr ? "&(" : "(");
470				result = cat_str(5, result, mm_strdup("ECPGset_var("),
471								 mm_strdup(var_text), mm_strdup(original_var),
472								 mm_strdup("), __LINE__);\n"));
473			}
474
475			add_variable_to_tail(&newlist, newvar, newind);
476		}
477
478		if (insert)
479			cur->argsinsert_oos = newlist;
480		else
481			cur->argsresult_oos = newlist;
482	}
483
484	return result;
485}
486
487/* This tests whether the cursor was declared and opened in the same function. */
488#define SAMEFUNC(cur)	\
489	((cur->function == NULL) ||		\
490	 (cur->function != NULL && strcmp(cur->function, current_function) == 0))
491
492static struct cursor *
493add_additional_variables(char *name, bool insert)
494{
495	struct cursor *ptr;
496	struct arguments *p;
497	int (* strcmp_fn)(const char *, const char *) = ((name[0] == ':' || name[0] == '"') ? strcmp : pg_strcasecmp);
498
499	for (ptr = cur; ptr != NULL; ptr=ptr->next)
500	{
501		if (strcmp_fn(ptr->name, name) == 0)
502			break;
503	}
504
505	if (ptr == NULL)
506	{
507		mmerror(PARSE_ERROR, ET_ERROR, "cursor \"%s\" does not exist", name);
508		return NULL;
509	}
510
511	if (insert)
512	{
513		/* add all those input variables that were given earlier
514		 * note that we have to append here but have to keep the existing order */
515		for (p = (SAMEFUNC(ptr) ? ptr->argsinsert : ptr->argsinsert_oos); p; p = p->next)
516			add_variable_to_tail(&argsinsert, p->variable, p->indicator);
517	}
518
519	/* add all those output variables that were given earlier */
520	for (p = (SAMEFUNC(ptr) ? ptr->argsresult : ptr->argsresult_oos); p; p = p->next)
521		add_variable_to_tail(&argsresult, p->variable, p->indicator);
522
523	return ptr;
524}
525
526static void
527add_typedef(char *name, char *dimension, char *length, enum ECPGttype type_enum,
528			char *type_dimension, char *type_index, int initializer, int array)
529{
530	/* add entry to list */
531	struct typedefs *ptr, *this;
532
533	if ((type_enum == ECPGt_struct ||
534		 type_enum == ECPGt_union) &&
535		initializer == 1)
536		mmerror(PARSE_ERROR, ET_ERROR, "initializer not allowed in type definition");
537	else if (INFORMIX_MODE && strcmp(name, "string") == 0)
538		mmerror(PARSE_ERROR, ET_ERROR, "type name \"string\" is reserved in Informix mode");
539	else
540	{
541		for (ptr = types; ptr != NULL; ptr = ptr->next)
542		{
543			if (strcmp(name, ptr->name) == 0)
544				/* re-definition is a bug */
545				mmerror(PARSE_ERROR, ET_ERROR, "type \"%s\" is already defined", name);
546		}
547		adjust_array(type_enum, &dimension, &length, type_dimension, type_index, array, true);
548
549		this = (struct typedefs *) mm_alloc(sizeof(struct typedefs));
550
551		/* initial definition */
552		this->next = types;
553		this->name = name;
554		this->brace_level = braces_open;
555		this->type = (struct this_type *) mm_alloc(sizeof(struct this_type));
556		this->type->type_enum = type_enum;
557		this->type->type_str = mm_strdup(name);
558		this->type->type_dimension = dimension; /* dimension of array */
559		this->type->type_index = length;	/* length of string */
560		this->type->type_sizeof = ECPGstruct_sizeof;
561		this->struct_member_list = (type_enum == ECPGt_struct || type_enum == ECPGt_union) ?
562		ECPGstruct_member_dup(struct_member_list[struct_level]) : NULL;
563
564		if (type_enum != ECPGt_varchar &&
565			type_enum != ECPGt_char &&
566			type_enum != ECPGt_unsigned_char &&
567			type_enum != ECPGt_string &&
568			atoi(this->type->type_index) >= 0)
569			mmerror(PARSE_ERROR, ET_ERROR, "multidimensional arrays for simple data types are not supported");
570
571		types = this;
572	}
573}
574%}
575
576%expect 0
577%name-prefix="base_yy"
578%locations
579
580%union {
581	double	dval;
582	char	*str;
583	int		ival;
584	struct	when		action;
585	struct	index		index;
586	int		tagname;
587	struct	this_type	type;
588	enum	ECPGttype	type_enum;
589	enum	ECPGdtype	dtype_enum;
590	struct	fetch_desc	descriptor;
591	struct  su_symbol	struct_union;
592	struct	prep		prep;
593}
594