Line data Source code
1 : /* src/interfaces/ecpg/preproc/variable.c */
2 :
3 : #include "postgres_fe.h"
4 :
5 : #include "preproc_extern.h"
6 :
7 : static struct variable *allvariables = NULL;
8 :
9 : /* this probably belongs in util.c, but for now it's only needed here */
10 : static char *
11 330 : loc_nstrdup(const char *in, size_t len)
12 : {
13 : char *out;
14 :
15 330 : out = loc_alloc(len + 1);
16 330 : memcpy(out, in, len);
17 330 : out[len] = '\0';
18 :
19 330 : return out;
20 : }
21 :
22 : struct variable *
23 1040 : new_variable(const char *name, struct ECPGtype *type, int brace_level)
24 : {
25 1040 : struct variable *p = (struct variable *) mm_alloc(sizeof(struct variable));
26 :
27 1040 : p->name = mm_strdup(name);
28 1040 : p->type = type;
29 1040 : p->brace_level = brace_level;
30 :
31 1040 : p->next = allvariables;
32 1040 : allvariables = p;
33 :
34 1040 : return p;
35 : }
36 :
37 : /*
38 : * Perform lookup of a field within a struct
39 : *
40 : * 'name' is the entire C variable name
41 : * 'str' points just before the next field name to parse
42 : * 'members' and 'brace_level' describe the struct we are looking into
43 : *
44 : * Returns NULL if field is not found.
45 : *
46 : * This recurses if needed to handle sub-fields.
47 : */
48 : static struct variable *
49 130 : find_struct_member(const char *name, const char *str,
50 : struct ECPGstruct_member *members, int brace_level)
51 : {
52 : /* ++ here skips over the '.', or the '>' of '->' */
53 130 : const char *next = strpbrk(++str, ".-["),
54 : *end,
55 : *field;
56 :
57 130 : if (next != NULL)
58 24 : field = loc_nstrdup(str, next - str);
59 : else
60 106 : field = str;
61 :
62 208 : for (; members; members = members->next)
63 : {
64 208 : if (strcmp(members->name, field) == 0)
65 : {
66 130 : if (next == NULL)
67 : {
68 : /* found the end */
69 106 : switch (members->type->type)
70 : {
71 0 : case ECPGt_array:
72 0 : return new_variable(name, ECPGmake_array_type(ECPGmake_simple_type(members->type->u.element->type, members->type->u.element->size, members->type->u.element->counter), members->type->size), brace_level);
73 0 : case ECPGt_struct:
74 : case ECPGt_union:
75 0 : return new_variable(name, ECPGmake_struct_type(members->type->u.members, members->type->type, members->type->type_name, members->type->struct_sizeof), brace_level);
76 106 : default:
77 106 : return new_variable(name, ECPGmake_simple_type(members->type->type, members->type->size, members->type->counter), brace_level);
78 : }
79 : }
80 : else
81 : {
82 24 : if (*next == '[')
83 : {
84 : int count;
85 :
86 : /*
87 : * We don't care about what's inside the array brackets so
88 : * just scan to find the matching right bracket.
89 : */
90 72 : for (count = 1, end = next + 1; count; end++)
91 : {
92 48 : switch (*end)
93 : {
94 0 : case '[':
95 0 : count++;
96 0 : break;
97 24 : case ']':
98 24 : count--;
99 24 : break;
100 24 : default:
101 24 : break;
102 : }
103 : }
104 : }
105 : else
106 0 : end = next;
107 :
108 24 : switch (*end)
109 : {
110 0 : case '\0': /* found the end, but this time it has to be
111 : * an array element */
112 0 : if (members->type->type != ECPGt_array)
113 0 : mmfatal(PARSE_ERROR, "incorrectly formed variable \"%s\"", name);
114 :
115 0 : switch (members->type->u.element->type)
116 : {
117 0 : case ECPGt_array:
118 0 : return new_variable(name, ECPGmake_array_type(ECPGmake_simple_type(members->type->u.element->u.element->type, members->type->u.element->u.element->size, members->type->u.element->u.element->counter), members->type->u.element->size), brace_level);
119 0 : case ECPGt_struct:
120 : case ECPGt_union:
121 0 : return new_variable(name, ECPGmake_struct_type(members->type->u.element->u.members, members->type->u.element->type, members->type->u.element->type_name, members->type->u.element->struct_sizeof), brace_level);
122 0 : default:
123 0 : return new_variable(name, ECPGmake_simple_type(members->type->u.element->type, members->type->u.element->size, members->type->u.element->counter), brace_level);
124 : }
125 : break;
126 0 : case '-':
127 0 : if (members->type->type == ECPGt_array)
128 0 : return find_struct_member(name, ++end, members->type->u.element->u.members, brace_level);
129 : else
130 0 : return find_struct_member(name, ++end, members->type->u.members, brace_level);
131 : break;
132 24 : case '.':
133 24 : if (members->type->type == ECPGt_array)
134 0 : return find_struct_member(name, end, members->type->u.element->u.members, brace_level);
135 : else
136 24 : return find_struct_member(name, end, members->type->u.members, brace_level);
137 : break;
138 0 : default:
139 0 : mmfatal(PARSE_ERROR, "incorrectly formed variable \"%s\"", name);
140 : break;
141 : }
142 : }
143 : }
144 : }
145 :
146 0 : return NULL;
147 : }
148 :
149 : /*
150 : * Do struct lookup when we have found var.field, var->field, or var[n].field
151 : *
152 : * 'name' is the entire C variable name
153 : * 'next' points at the character after the base name
154 : * 'end' points at the character after the subscript, if there was a
155 : * subscript, else it's the same as 'next'.
156 : *
157 : * This is used only at the first level of field reference; sub-fields will
158 : * be handled by internal recursion in find_struct_member.
159 : */
160 : static struct variable *
161 106 : find_struct(const char *name, const char *next, const char *end)
162 : {
163 : char *prefix;
164 : struct variable *p;
165 :
166 : /* first get the mother structure entry */
167 106 : prefix = loc_nstrdup(name, next - name);
168 106 : p = find_variable(prefix);
169 :
170 106 : if (*next == '-')
171 : {
172 : /* We have var->field */
173 12 : if (p->type->type != ECPGt_array)
174 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer", prefix);
175 :
176 12 : if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
177 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer to a structure or a union", prefix);
178 :
179 12 : return find_struct_member(name, ++end, p->type->u.element->u.members, p->brace_level);
180 : }
181 : else
182 : {
183 94 : if (next == end)
184 : {
185 : /* We have var.field */
186 82 : if (p->type->type != ECPGt_struct && p->type->type != ECPGt_union)
187 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is neither a structure nor a union", prefix);
188 :
189 82 : return find_struct_member(name, end, p->type->u.members, p->brace_level);
190 : }
191 : else
192 : {
193 : /* We have var[n].field */
194 12 : if (p->type->type != ECPGt_array)
195 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not an array", prefix);
196 :
197 12 : if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
198 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer to a structure or a union", prefix);
199 :
200 12 : return find_struct_member(name, end, p->type->u.element->u.members, p->brace_level);
201 : }
202 : }
203 : }
204 :
205 : /* Look up a variable given its base name */
206 : static struct variable *
207 2782 : find_simple(const char *name)
208 : {
209 : struct variable *p;
210 :
211 23006 : for (p = allvariables; p; p = p->next)
212 : {
213 23006 : if (strcmp(p->name, name) == 0)
214 2782 : return p;
215 : }
216 :
217 0 : return NULL;
218 : }
219 :
220 : /*
221 : * Build a "struct variable" for a C variable reference.
222 : *
223 : * The given "name" string is a CVARIABLE per pgc.l, so it can include not
224 : * only a base variable name but also ".field", "->field", or "[subscript]"
225 : * decoration. We don't need to understand that fully, because we always
226 : * duplicate the whole string into the name field of the result variable
227 : * and emit it literally to the output file; the C compiler will make sense
228 : * of it later. What we do need to do here is identify the type of the
229 : * target field or array element so that we can attach a correct ECPGtype
230 : * struct to the result.
231 : *
232 : * Note that this function will end the program in case of an unknown variable.
233 : */
234 : struct variable *
235 2888 : find_variable(const char *name)
236 : {
237 : const char *next,
238 : *end;
239 : struct variable *p;
240 : int count;
241 :
242 2888 : next = strpbrk(name, ".[-");
243 2888 : if (next)
244 : {
245 : /* Deal with field/subscript decoration */
246 306 : if (*next == '[')
247 : {
248 : /*
249 : * We don't care about what's inside the array brackets so just
250 : * scan to find the matching right bracket.
251 : */
252 636 : for (count = 1, end = next + 1; count; end++)
253 : {
254 424 : switch (*end)
255 : {
256 0 : case '[':
257 0 : count++;
258 0 : break;
259 212 : case ']':
260 212 : count--;
261 212 : break;
262 0 : case '\0':
263 0 : mmfatal(PARSE_ERROR, "unmatched bracket in variable \"%s\"", name);
264 : break;
265 212 : default:
266 212 : break;
267 : }
268 : }
269 212 : if (*end == '.')
270 : {
271 : /* We have var[n].field */
272 12 : p = find_struct(name, next, end);
273 : }
274 : else
275 : {
276 : /*
277 : * Note: this part assumes we must just have var[n] without
278 : * any further decoration, which fails to handle cases such as
279 : * var[n]->field. For now, that's okay because
280 : * pointer-to-pointer variables are rejected elsewhere.
281 : */
282 200 : char *prefix = loc_nstrdup(name, next - name);
283 :
284 200 : p = find_simple(prefix);
285 200 : if (p == NULL)
286 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", prefix);
287 200 : if (p->type->type != ECPGt_array)
288 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer", prefix);
289 200 : switch (p->type->u.element->type)
290 : {
291 0 : case ECPGt_array:
292 0 : return new_variable(name, ECPGmake_array_type(ECPGmake_simple_type(p->type->u.element->u.element->type, p->type->u.element->u.element->size, p->type->u.element->u.element->counter), p->type->u.element->size), p->brace_level);
293 6 : case ECPGt_struct:
294 : case ECPGt_union:
295 6 : return new_variable(name, ECPGmake_struct_type(p->type->u.element->u.members, p->type->u.element->type, p->type->u.element->type_name, p->type->u.element->struct_sizeof), p->brace_level);
296 194 : default:
297 194 : return new_variable(name, ECPGmake_simple_type(p->type->u.element->type, p->type->u.element->size, p->type->u.element->counter), p->brace_level);
298 : }
299 : }
300 : }
301 : else
302 : {
303 : /* Must be var.field or var->field */
304 94 : p = find_struct(name, next, next);
305 : }
306 : }
307 : else
308 2582 : p = find_simple(name);
309 :
310 2688 : if (p == NULL)
311 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", name);
312 :
313 2688 : return p;
314 : }
315 :
316 : void
317 662 : remove_typedefs(int brace_level)
318 : {
319 : struct typedefs *p,
320 : *prev,
321 : *next;
322 :
323 990 : for (p = types, prev = NULL; p; p = next)
324 : {
325 328 : next = p->next;
326 328 : if (p->brace_level >= brace_level)
327 : {
328 : /* remove it */
329 28 : if (prev)
330 0 : prev->next = next;
331 : else
332 28 : types = next;
333 :
334 28 : if (p->type->type_enum == ECPGt_struct || p->type->type_enum == ECPGt_union)
335 24 : ECPGfree_struct_member(p->struct_member_list);
336 28 : free(p->type->type_storage);
337 28 : free(p->type->type_str);
338 28 : free(p->type->type_dimension);
339 28 : free(p->type->type_index);
340 28 : free(p->type->type_sizeof);
341 28 : free(p->type);
342 28 : free(p->name);
343 28 : free(p);
344 : }
345 : else
346 300 : prev = p;
347 : }
348 662 : }
349 :
350 : void
351 662 : remove_variables(int brace_level)
352 : {
353 : struct variable *p,
354 : *prev,
355 : *next;
356 :
357 3346 : for (p = allvariables, prev = NULL; p; p = next)
358 : {
359 2684 : next = p->next;
360 2684 : if (p->brace_level >= brace_level)
361 : {
362 : /* remove it, but first remove any references from cursors */
363 : struct cursor *ptr;
364 :
365 1578 : for (ptr = cur; ptr != NULL; ptr = ptr->next)
366 : {
367 : struct arguments *varptr,
368 : *prevvar,
369 : *nextvar;
370 :
371 738 : for (varptr = ptr->argsinsert, prevvar = NULL;
372 1260 : varptr != NULL; varptr = nextvar)
373 : {
374 522 : nextvar = varptr->next;
375 522 : if (p == varptr->variable)
376 : {
377 : /* remove from list */
378 24 : if (prevvar)
379 6 : prevvar->next = nextvar;
380 : else
381 18 : ptr->argsinsert = nextvar;
382 24 : free(varptr);
383 : }
384 : else
385 498 : prevvar = varptr;
386 : }
387 738 : for (varptr = ptr->argsresult, prevvar = NULL;
388 748 : varptr != NULL; varptr = nextvar)
389 : {
390 10 : nextvar = varptr->next;
391 10 : if (p == varptr->variable)
392 : {
393 : /* remove from list */
394 6 : if (prevvar)
395 0 : prevvar->next = nextvar;
396 : else
397 6 : ptr->argsresult = nextvar;
398 6 : free(varptr);
399 : }
400 : else
401 4 : prevvar = varptr;
402 : }
403 : }
404 :
405 : /* remove it */
406 840 : if (prev)
407 326 : prev->next = next;
408 : else
409 514 : allvariables = next;
410 :
411 840 : ECPGfree_type(p->type);
412 840 : free(p->name);
413 840 : free(p);
414 : }
415 : else
416 1844 : prev = p;
417 : }
418 662 : }
419 :
420 :
421 : /*
422 : * Here are the variables that need to be handled on every request.
423 : * These are of two kinds: input and output.
424 : * I will make two lists for them.
425 : */
426 :
427 : struct arguments *argsinsert = NULL;
428 : struct arguments *argsresult = NULL;
429 :
430 : void
431 2916 : reset_variables(void)
432 : {
433 : struct arguments *p,
434 : *next;
435 :
436 2920 : for (p = argsinsert; p; p = next)
437 : {
438 4 : next = p->next;
439 4 : free(p);
440 : }
441 2916 : argsinsert = NULL;
442 2916 : for (p = argsresult; p; p = next)
443 : {
444 0 : next = p->next;
445 0 : free(p);
446 : }
447 2916 : argsresult = NULL;
448 2916 : }
449 :
450 : /* Insert a new variable into our request list.
451 : * Note: The list is dumped from the end,
452 : * so we have to add new entries at the beginning */
453 : void
454 1030 : add_variable_to_head(struct arguments **list, struct variable *var, struct variable *ind)
455 : {
456 1030 : struct arguments *p = (struct arguments *) mm_alloc(sizeof(struct arguments));
457 :
458 1030 : p->variable = var;
459 1030 : p->indicator = ind;
460 1030 : p->next = *list;
461 1030 : *list = p;
462 1030 : }
463 :
464 : /* Append a new variable to our request list. */
465 : void
466 194 : add_variable_to_tail(struct arguments **list, struct variable *var, struct variable *ind)
467 : {
468 : struct arguments *p,
469 194 : *new = (struct arguments *) mm_alloc(sizeof(struct arguments));
470 :
471 208 : for (p = *list; p && p->next; p = p->next);
472 :
473 194 : new->variable = var;
474 194 : new->indicator = ind;
475 194 : new->next = NULL;
476 :
477 194 : if (p)
478 52 : p->next = new;
479 : else
480 142 : *list = new;
481 194 : }
482 :
483 : void
484 34 : remove_variable_from_list(struct arguments **list, struct variable *var)
485 : {
486 : struct arguments *p,
487 34 : *prev = NULL;
488 34 : bool found = false;
489 :
490 34 : for (p = *list; p; p = p->next)
491 : {
492 34 : if (p->variable == var)
493 : {
494 34 : found = true;
495 34 : break;
496 : }
497 0 : prev = p;
498 : }
499 34 : if (found)
500 : {
501 34 : if (prev)
502 0 : prev->next = p->next;
503 : else
504 34 : *list = p->next;
505 34 : free(p);
506 : }
507 34 : }
508 :
509 : /* Dump out a list of all the variable on this list.
510 : This is a recursive function that works from the end of the list and
511 : deletes the list as we go on.
512 : */
513 : void
514 3312 : dump_variables(struct arguments *list, int mode)
515 : {
516 : char *str_zero;
517 :
518 3312 : if (list == NULL)
519 2266 : return;
520 :
521 1046 : str_zero = mm_strdup("0");
522 :
523 : /*
524 : * The list is build up from the beginning so lets first dump the end of
525 : * the list:
526 : */
527 :
528 1046 : dump_variables(list->next, mode);
529 :
530 : /* Then the current element and its indicator */
531 1046 : ECPGdump_a_type(base_yyout, list->variable->name, list->variable->type, list->variable->brace_level,
532 1046 : list->indicator->name, list->indicator->type, list->indicator->brace_level,
533 : NULL, NULL, str_zero, NULL, NULL);
534 :
535 : /* Then release the list element. */
536 1046 : if (mode != 0)
537 1046 : free(list);
538 :
539 1046 : free(str_zero);
540 : }
541 :
542 : void
543 134 : check_indicator(struct ECPGtype *var)
544 : {
545 : /* make sure this is a valid indicator variable */
546 134 : switch (var->type)
547 : {
548 : struct ECPGstruct_member *p;
549 :
550 90 : case ECPGt_short:
551 : case ECPGt_int:
552 : case ECPGt_long:
553 : case ECPGt_long_long:
554 : case ECPGt_unsigned_short:
555 : case ECPGt_unsigned_int:
556 : case ECPGt_unsigned_long:
557 : case ECPGt_unsigned_long_long:
558 90 : break;
559 :
560 22 : case ECPGt_struct:
561 : case ECPGt_union:
562 72 : for (p = var->u.members; p; p = p->next)
563 50 : check_indicator(p->type);
564 22 : break;
565 :
566 22 : case ECPGt_array:
567 22 : check_indicator(var->u.element);
568 22 : break;
569 0 : default:
570 0 : mmerror(PARSE_ERROR, ET_ERROR, "indicator variable must have an integer type");
571 0 : break;
572 : }
573 134 : }
574 :
575 : struct typedefs *
576 11366 : get_typedef(const char *name, bool noerror)
577 : {
578 : struct typedefs *this;
579 :
580 18560 : for (this = types; this != NULL; this = this->next)
581 : {
582 7266 : if (strcmp(this->name, name) == 0)
583 72 : return this;
584 : }
585 :
586 11294 : if (!noerror)
587 0 : mmfatal(PARSE_ERROR, "unrecognized data type name \"%s\"", name);
588 :
589 11294 : return NULL;
590 : }
591 :
592 : void
593 784 : adjust_array(enum ECPGttype type_enum,
594 : const char **dimension, const char **length,
595 : const char *type_dimension, const char *type_index,
596 : int pointer_len, bool type_definition)
597 : {
598 784 : if (atoi(type_index) >= 0)
599 : {
600 12 : if (atoi(*length) >= 0)
601 0 : mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
602 :
603 12 : *length = type_index;
604 : }
605 :
606 784 : if (atoi(type_dimension) >= 0)
607 : {
608 2 : if (atoi(*dimension) >= 0 && atoi(*length) >= 0)
609 0 : mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
610 :
611 2 : if (atoi(*dimension) >= 0)
612 0 : *length = *dimension;
613 :
614 2 : *dimension = type_dimension;
615 : }
616 :
617 784 : if (pointer_len > 2)
618 0 : mmfatal(PARSE_ERROR, ngettext("multilevel pointers (more than 2 levels) are not supported; found %d level",
619 : "multilevel pointers (more than 2 levels) are not supported; found %d levels", pointer_len),
620 : pointer_len);
621 :
622 784 : if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && type_enum != ECPGt_string)
623 0 : mmfatal(PARSE_ERROR, "pointer to pointer is not supported for this data type");
624 :
625 784 : if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
626 0 : mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
627 :
628 784 : if (atoi(*length) >= 0 && atoi(*dimension) >= 0 && pointer_len)
629 0 : mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
630 :
631 784 : switch (type_enum)
632 : {
633 80 : case ECPGt_struct:
634 : case ECPGt_union:
635 : /* pointer has to get dimension 0 */
636 80 : if (pointer_len)
637 : {
638 20 : *length = *dimension;
639 20 : *dimension = "0";
640 : }
641 :
642 80 : if (atoi(*length) >= 0)
643 0 : mmfatal(PARSE_ERROR, "multidimensional arrays for structures are not supported");
644 :
645 80 : break;
646 46 : case ECPGt_varchar:
647 : case ECPGt_bytea:
648 : /* pointer has to get dimension 0 */
649 46 : if (pointer_len)
650 0 : *dimension = "0";
651 :
652 : /* one index is the string length */
653 46 : if (atoi(*length) < 0)
654 : {
655 30 : *length = *dimension;
656 30 : *dimension = "-1";
657 : }
658 :
659 46 : break;
660 258 : case ECPGt_char:
661 : case ECPGt_unsigned_char:
662 : case ECPGt_string:
663 : /* char ** */
664 258 : if (pointer_len == 2)
665 : {
666 16 : *length = *dimension = "0";
667 16 : break;
668 : }
669 :
670 : /* pointer has to get length 0 */
671 242 : if (pointer_len == 1)
672 90 : *length = "0";
673 :
674 : /* one index is the string length */
675 242 : if (atoi(*length) < 0)
676 : {
677 : /*
678 : * make sure we return length = -1 for arrays without given
679 : * bounds
680 : */
681 132 : if (atoi(*dimension) < 0 && !type_definition)
682 :
683 : /*
684 : * do not change this for typedefs since it will be
685 : * changed later on when the variable is defined
686 : */
687 10 : *length = "1";
688 122 : else if (strcmp(*dimension, "0") == 0)
689 4 : *length = "-1";
690 : else
691 118 : *length = *dimension;
692 :
693 132 : *dimension = "-1";
694 : }
695 242 : break;
696 400 : default:
697 : /* a pointer has dimension = 0 */
698 400 : if (pointer_len)
699 : {
700 40 : *length = *dimension;
701 40 : *dimension = "0";
702 : }
703 :
704 400 : if (atoi(*length) >= 0)
705 0 : mmfatal(PARSE_ERROR, "multidimensional arrays for simple data types are not supported");
706 :
707 400 : break;
708 : }
709 784 : }
|