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 165 : loc_nstrdup(const char *in, size_t len)
12 : {
13 : char *out;
14 :
15 165 : out = loc_alloc(len + 1);
16 165 : memcpy(out, in, len);
17 165 : out[len] = '\0';
18 :
19 165 : return out;
20 : }
21 :
22 : struct variable *
23 531 : new_variable(const char *name, struct ECPGtype *type, int brace_level)
24 : {
25 531 : struct variable *p = (struct variable *) mm_alloc(sizeof(struct variable));
26 :
27 531 : p->name = mm_strdup(name);
28 531 : p->type = type;
29 531 : p->brace_level = brace_level;
30 :
31 531 : p->next = allvariables;
32 531 : allvariables = p;
33 :
34 531 : 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 65 : 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 65 : const char *next = strpbrk(++str, ".-["),
54 : *end,
55 : *field;
56 :
57 65 : if (next != NULL)
58 12 : field = loc_nstrdup(str, next - str);
59 : else
60 53 : field = str;
61 :
62 104 : for (; members; members = members->next)
63 : {
64 104 : if (strcmp(members->name, field) == 0)
65 : {
66 65 : if (next == NULL)
67 : {
68 : /* found the end */
69 53 : 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 53 : default:
77 53 : return new_variable(name, ECPGmake_simple_type(members->type->type, members->type->size, members->type->counter), brace_level);
78 : }
79 : }
80 : else
81 : {
82 12 : 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 36 : for (count = 1, end = next + 1; count; end++)
91 : {
92 24 : switch (*end)
93 : {
94 0 : case '[':
95 0 : count++;
96 0 : break;
97 12 : case ']':
98 12 : count--;
99 12 : break;
100 12 : default:
101 12 : break;
102 : }
103 : }
104 : }
105 : else
106 0 : end = next;
107 :
108 12 : 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 12 : case '.':
133 12 : 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 12 : 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 53 : 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 53 : prefix = loc_nstrdup(name, next - name);
168 53 : p = find_variable(prefix);
169 :
170 53 : if (*next == '-')
171 : {
172 : /* We have var->field */
173 6 : if (p->type->type != ECPGt_array)
174 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer", prefix);
175 :
176 6 : 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 6 : return find_struct_member(name, ++end, p->type->u.element->u.members, p->brace_level);
180 : }
181 : else
182 : {
183 47 : if (next == end)
184 : {
185 : /* We have var.field */
186 41 : 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 41 : return find_struct_member(name, end, p->type->u.members, p->brace_level);
190 : }
191 : else
192 : {
193 : /* We have var[n].field */
194 6 : if (p->type->type != ECPGt_array)
195 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not an array", prefix);
196 :
197 6 : 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 6 : 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 1421 : find_simple(const char *name)
208 : {
209 : struct variable *p;
210 :
211 11578 : for (p = allvariables; p; p = p->next)
212 : {
213 11578 : if (strcmp(p->name, name) == 0)
214 1421 : 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 1474 : find_variable(const char *name)
236 : {
237 : const char *next,
238 : *end;
239 : struct variable *p;
240 : int count;
241 :
242 1474 : next = strpbrk(name, ".[-");
243 1474 : if (next)
244 : {
245 : /* Deal with field/subscript decoration */
246 153 : 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 318 : for (count = 1, end = next + 1; count; end++)
253 : {
254 212 : switch (*end)
255 : {
256 0 : case '[':
257 0 : count++;
258 0 : break;
259 106 : case ']':
260 106 : count--;
261 106 : break;
262 0 : case '\0':
263 0 : mmfatal(PARSE_ERROR, "unmatched bracket in variable \"%s\"", name);
264 : break;
265 106 : default:
266 106 : break;
267 : }
268 : }
269 106 : if (*end == '.')
270 : {
271 : /* We have var[n].field */
272 6 : 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 100 : char *prefix = loc_nstrdup(name, next - name);
283 :
284 100 : p = find_simple(prefix);
285 100 : if (p == NULL)
286 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", prefix);
287 100 : if (p->type->type != ECPGt_array)
288 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer", prefix);
289 100 : 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 3 : case ECPGt_struct:
294 : case ECPGt_union:
295 3 : 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 97 : default:
297 97 : 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 47 : p = find_struct(name, next, next);
305 : }
306 : }
307 : else
308 1321 : p = find_simple(name);
309 :
310 1374 : if (p == NULL)
311 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", name);
312 :
313 1374 : return p;
314 : }
315 :
316 : void
317 334 : remove_typedefs(int brace_level)
318 : {
319 : struct typedefs *p,
320 : *prev,
321 : *next;
322 :
323 498 : for (p = types, prev = NULL; p; p = next)
324 : {
325 164 : next = p->next;
326 164 : if (p->brace_level >= brace_level)
327 : {
328 : /* remove it */
329 14 : if (prev)
330 0 : prev->next = next;
331 : else
332 14 : types = next;
333 :
334 14 : if (p->type->type_enum == ECPGt_struct || p->type->type_enum == ECPGt_union)
335 12 : ECPGfree_struct_member(p->struct_member_list);
336 14 : free(p->type->type_storage);
337 14 : free(p->type->type_str);
338 14 : free(p->type->type_dimension);
339 14 : free(p->type->type_index);
340 14 : free(p->type->type_sizeof);
341 14 : free(p->type);
342 14 : free(p->name);
343 14 : free(p);
344 : }
345 : else
346 150 : prev = p;
347 : }
348 334 : }
349 :
350 : void
351 334 : remove_variables(int brace_level)
352 : {
353 : struct variable *p,
354 : *prev,
355 : *next;
356 :
357 1691 : for (p = allvariables, prev = NULL; p; p = next)
358 : {
359 1357 : next = p->next;
360 1357 : if (p->brace_level >= brace_level)
361 : {
362 : /* remove it, but first remove any references from cursors */
363 : struct cursor *ptr;
364 :
365 805 : for (ptr = cur; ptr != NULL; ptr = ptr->next)
366 : {
367 : struct arguments *varptr,
368 : *prevvar,
369 : *nextvar;
370 :
371 377 : for (varptr = ptr->argsinsert, prevvar = NULL;
372 642 : varptr != NULL; varptr = nextvar)
373 : {
374 265 : nextvar = varptr->next;
375 265 : if (p == varptr->variable)
376 : {
377 : /* remove from list */
378 12 : if (prevvar)
379 3 : prevvar->next = nextvar;
380 : else
381 9 : ptr->argsinsert = nextvar;
382 12 : free(varptr);
383 : }
384 : else
385 253 : prevvar = varptr;
386 : }
387 377 : for (varptr = ptr->argsresult, prevvar = NULL;
388 382 : varptr != NULL; varptr = nextvar)
389 : {
390 5 : nextvar = varptr->next;
391 5 : if (p == varptr->variable)
392 : {
393 : /* remove from list */
394 3 : if (prevvar)
395 0 : prevvar->next = nextvar;
396 : else
397 3 : ptr->argsresult = nextvar;
398 3 : free(varptr);
399 : }
400 : else
401 2 : prevvar = varptr;
402 : }
403 : }
404 :
405 : /* remove it */
406 428 : if (prev)
407 167 : prev->next = next;
408 : else
409 261 : allvariables = next;
410 :
411 428 : ECPGfree_type(p->type);
412 428 : free(p->name);
413 428 : free(p);
414 : }
415 : else
416 929 : prev = p;
417 : }
418 334 : }
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 1508 : reset_variables(void)
432 : {
433 : struct arguments *p,
434 : *next;
435 :
436 1510 : for (p = argsinsert; p; p = next)
437 : {
438 2 : next = p->next;
439 2 : free(p);
440 : }
441 1508 : argsinsert = NULL;
442 1508 : for (p = argsresult; p; p = next)
443 : {
444 0 : next = p->next;
445 0 : free(p);
446 : }
447 1508 : argsresult = NULL;
448 1508 : }
449 :
450 : /*
451 : * Insert a new variable into our request list.
452 : * Note: The list is dumped from the end,
453 : * so we have to add new entries at the beginning
454 : */
455 : void
456 528 : add_variable_to_head(struct arguments **list, struct variable *var, struct variable *ind)
457 : {
458 528 : struct arguments *p = (struct arguments *) mm_alloc(sizeof(struct arguments));
459 :
460 528 : p->variable = var;
461 528 : p->indicator = ind;
462 528 : p->next = *list;
463 528 : *list = p;
464 528 : }
465 :
466 : /* Append a new variable to our request list. */
467 : void
468 99 : add_variable_to_tail(struct arguments **list, struct variable *var, struct variable *ind)
469 : {
470 : struct arguments *p,
471 99 : *new = (struct arguments *) mm_alloc(sizeof(struct arguments));
472 :
473 106 : for (p = *list; p && p->next; p = p->next);
474 :
475 99 : new->variable = var;
476 99 : new->indicator = ind;
477 99 : new->next = NULL;
478 :
479 99 : if (p)
480 26 : p->next = new;
481 : else
482 73 : *list = new;
483 99 : }
484 :
485 : void
486 17 : remove_variable_from_list(struct arguments **list, struct variable *var)
487 : {
488 : struct arguments *p,
489 17 : *prev = NULL;
490 17 : bool found = false;
491 :
492 17 : for (p = *list; p; p = p->next)
493 : {
494 17 : if (p->variable == var)
495 : {
496 17 : found = true;
497 17 : break;
498 : }
499 0 : prev = p;
500 : }
501 17 : if (found)
502 : {
503 17 : if (prev)
504 0 : prev->next = p->next;
505 : else
506 17 : *list = p->next;
507 17 : free(p);
508 : }
509 17 : }
510 :
511 : /*
512 : * Dump out a list of all the variable on this list.
513 : * This is a recursive function that works from the end of the list and
514 : * deletes the list as we go on.
515 : */
516 : void
517 1711 : dump_variables(struct arguments *list, int mode)
518 : {
519 : char *str_zero;
520 :
521 1711 : if (list == NULL)
522 1175 : return;
523 :
524 536 : str_zero = mm_strdup("0");
525 :
526 : /*
527 : * The list is build up from the beginning so lets first dump the end of
528 : * the list:
529 : */
530 :
531 536 : dump_variables(list->next, mode);
532 :
533 : /* Then the current element and its indicator */
534 536 : ECPGdump_a_type(base_yyout, list->variable->name, list->variable->type, list->variable->brace_level,
535 536 : list->indicator->name, list->indicator->type, list->indicator->brace_level,
536 : NULL, NULL, str_zero, NULL, NULL);
537 :
538 : /* Then release the list element. */
539 536 : if (mode != 0)
540 536 : free(list);
541 :
542 536 : free(str_zero);
543 : }
544 :
545 : void
546 67 : check_indicator(struct ECPGtype *var)
547 : {
548 : /* make sure this is a valid indicator variable */
549 67 : switch (var->type)
550 : {
551 : struct ECPGstruct_member *p;
552 :
553 45 : case ECPGt_short:
554 : case ECPGt_int:
555 : case ECPGt_long:
556 : case ECPGt_long_long:
557 : case ECPGt_unsigned_short:
558 : case ECPGt_unsigned_int:
559 : case ECPGt_unsigned_long:
560 : case ECPGt_unsigned_long_long:
561 45 : break;
562 :
563 11 : case ECPGt_struct:
564 : case ECPGt_union:
565 36 : for (p = var->u.members; p; p = p->next)
566 25 : check_indicator(p->type);
567 11 : break;
568 :
569 11 : case ECPGt_array:
570 11 : check_indicator(var->u.element);
571 11 : break;
572 0 : default:
573 0 : mmerror(PARSE_ERROR, ET_ERROR, "indicator variable must have an integer type");
574 0 : break;
575 : }
576 67 : }
577 :
578 : struct typedefs *
579 5978 : get_typedef(const char *name, bool noerror)
580 : {
581 : struct typedefs *this;
582 :
583 9575 : for (this = types; this != NULL; this = this->next)
584 : {
585 3633 : if (strcmp(this->name, name) == 0)
586 36 : return this;
587 : }
588 :
589 5942 : if (!noerror)
590 0 : mmfatal(PARSE_ERROR, "unrecognized data type name \"%s\"", name);
591 :
592 5942 : return NULL;
593 : }
594 :
595 : void
596 400 : adjust_array(enum ECPGttype type_enum,
597 : const char **dimension, const char **length,
598 : const char *type_dimension, const char *type_index,
599 : int pointer_len, bool type_definition)
600 : {
601 400 : if (atoi(type_index) >= 0)
602 : {
603 6 : if (atoi(*length) >= 0)
604 0 : mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
605 :
606 6 : *length = type_index;
607 : }
608 :
609 400 : if (atoi(type_dimension) >= 0)
610 : {
611 1 : if (atoi(*dimension) >= 0 && atoi(*length) >= 0)
612 0 : mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
613 :
614 1 : if (atoi(*dimension) >= 0)
615 0 : *length = *dimension;
616 :
617 1 : *dimension = type_dimension;
618 : }
619 :
620 400 : if (pointer_len > 2)
621 0 : mmfatal(PARSE_ERROR, ngettext("multilevel pointers (more than 2 levels) are not supported; found %d level",
622 : "multilevel pointers (more than 2 levels) are not supported; found %d levels", pointer_len),
623 : pointer_len);
624 :
625 400 : if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && type_enum != ECPGt_string)
626 0 : mmfatal(PARSE_ERROR, "pointer to pointer is not supported for this data type");
627 :
628 400 : if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
629 0 : mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
630 :
631 400 : if (atoi(*length) >= 0 && atoi(*dimension) >= 0 && pointer_len)
632 0 : mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
633 :
634 400 : switch (type_enum)
635 : {
636 40 : case ECPGt_struct:
637 : case ECPGt_union:
638 : /* pointer has to get dimension 0 */
639 40 : if (pointer_len)
640 : {
641 10 : *length = *dimension;
642 10 : *dimension = "0";
643 : }
644 :
645 40 : if (atoi(*length) >= 0)
646 0 : mmfatal(PARSE_ERROR, "multidimensional arrays for structures are not supported");
647 :
648 40 : break;
649 23 : case ECPGt_varchar:
650 : case ECPGt_bytea:
651 : /* pointer has to get dimension 0 */
652 23 : if (pointer_len)
653 0 : *dimension = "0";
654 :
655 : /* one index is the string length */
656 23 : if (atoi(*length) < 0)
657 : {
658 15 : *length = *dimension;
659 15 : *dimension = "-1";
660 : }
661 :
662 23 : break;
663 134 : case ECPGt_char:
664 : case ECPGt_unsigned_char:
665 : case ECPGt_string:
666 : /* char ** */
667 134 : if (pointer_len == 2)
668 : {
669 8 : *length = *dimension = "0";
670 8 : break;
671 : }
672 :
673 : /* pointer has to get length 0 */
674 126 : if (pointer_len == 1)
675 46 : *length = "0";
676 :
677 : /* one index is the string length */
678 126 : if (atoi(*length) < 0)
679 : {
680 : /*
681 : * make sure we return length = -1 for arrays without given
682 : * bounds
683 : */
684 70 : if (atoi(*dimension) < 0 && !type_definition)
685 :
686 : /*
687 : * do not change this for typedefs since it will be
688 : * changed later on when the variable is defined
689 : */
690 5 : *length = "1";
691 65 : else if (strcmp(*dimension, "0") == 0)
692 2 : *length = "-1";
693 : else
694 63 : *length = *dimension;
695 :
696 70 : *dimension = "-1";
697 : }
698 126 : break;
699 203 : default:
700 : /* a pointer has dimension = 0 */
701 203 : if (pointer_len)
702 : {
703 20 : *length = *dimension;
704 20 : *dimension = "0";
705 : }
706 :
707 203 : if (atoi(*length) >= 0)
708 0 : mmfatal(PARSE_ERROR, "multidimensional arrays for simple data types are not supported");
709 :
710 203 : break;
711 : }
712 400 : }
|