]> granicus.if.org Git - postgresql/blob - src/interfaces/ecpg/preproc/ecpg.header
Use "%option prefix" to set API names in ecpg's lexer.
[postgresql] / src / interfaces / ecpg / preproc / ecpg.header
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  */
35 int struct_level = 0;
36 int braces_open; /* brace level counter */
37 char *current_function;
38 int ecpg_internal_var = 0;
39 char    *connection = NULL;
40 char    *input_filename = NULL;
41
42 static int      FoundInto = 0;
43 static int      initializer = 0;
44 static int      pacounter = 1;
45 static char     pacounter_buffer[sizeof(int) * CHAR_BIT * 10 / 3]; /* a rough guess at the size we need */
46 static struct this_type actual_type[STRUCT_DEPTH];
47 static char *actual_startline[STRUCT_DEPTH];
48 static int      varchar_counter = 1;
49
50 /* temporarily store struct members while creating the data structure */
51 struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = { NULL };
52
53 /* also store struct type so we can do a sizeof() later */
54 static char *ECPGstruct_sizeof = NULL;
55
56 /* for forward declarations we have to store some data as well */
57 static char *forward_name = NULL;
58
59 struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, NULL, NULL, NULL, {NULL}, 0};
60 struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL};
61
62 static struct ECPGtype ecpg_query = {ECPGt_char_variable, NULL, NULL, NULL, {NULL}, 0};
63
64 static 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  */
69 static void
70 vmmerror(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
101 void
102 mmerror(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
111 void
112 mmfatal(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
134 static char *
135 cat2_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
148 static char *
149 cat_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
168 static char *
169 make2_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
180 static char *
181 make3_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 */
195 static char *
196 make_name(void)
197 {
198         return mm_strdup(base_yytext);
199 }
200
201 static char *
202 create_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 essantially 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
239 static char *
240 adjust_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->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
492 static struct cursor *
493 add_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
526 static void
527 add_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 }