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 : struct variable *
10 964 : new_variable(const char *name, struct ECPGtype *type, int brace_level)
11 : {
12 964 : struct variable *p = (struct variable *) mm_alloc(sizeof(struct variable));
13 :
14 964 : p->name = mm_strdup(name);
15 964 : p->type = type;
16 964 : p->brace_level = brace_level;
17 :
18 964 : p->next = allvariables;
19 964 : allvariables = p;
20 :
21 964 : return p;
22 : }
23 :
24 : static struct variable *
25 58 : find_struct_member(const char *name, char *str, struct ECPGstruct_member *members, int brace_level)
26 : {
27 58 : char *next = strpbrk(++str, ".-["),
28 : *end,
29 58 : c = '\0';
30 :
31 58 : if (next != NULL)
32 : {
33 0 : c = *next;
34 0 : *next = '\0';
35 : }
36 :
37 112 : for (; members; members = members->next)
38 : {
39 112 : if (strcmp(members->name, str) == 0)
40 : {
41 58 : if (next == NULL)
42 : {
43 : /* found the end */
44 58 : switch (members->type->type)
45 : {
46 0 : case ECPGt_array:
47 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);
48 0 : case ECPGt_struct:
49 : case ECPGt_union:
50 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);
51 58 : default:
52 58 : return new_variable(name, ECPGmake_simple_type(members->type->type, members->type->size, members->type->counter), brace_level);
53 : }
54 : }
55 : else
56 : {
57 0 : *next = c;
58 0 : if (c == '[')
59 : {
60 : int count;
61 :
62 : /*
63 : * We don't care about what's inside the array braces so
64 : * just eat up the character
65 : */
66 0 : for (count = 1, end = next + 1; count; end++)
67 : {
68 0 : switch (*end)
69 : {
70 0 : case '[':
71 0 : count++;
72 0 : break;
73 0 : case ']':
74 0 : count--;
75 0 : break;
76 0 : default:
77 0 : break;
78 : }
79 : }
80 : }
81 : else
82 0 : end = next;
83 :
84 0 : switch (*end)
85 : {
86 0 : case '\0': /* found the end, but this time it has to be
87 : * an array element */
88 0 : if (members->type->type != ECPGt_array)
89 0 : mmfatal(PARSE_ERROR, "incorrectly formed variable \"%s\"", name);
90 :
91 0 : switch (members->type->u.element->type)
92 : {
93 0 : case ECPGt_array:
94 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);
95 0 : case ECPGt_struct:
96 : case ECPGt_union:
97 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);
98 0 : default:
99 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);
100 : }
101 : break;
102 0 : case '-':
103 0 : if (members->type->type == ECPGt_array)
104 0 : return find_struct_member(name, ++end, members->type->u.element->u.members, brace_level);
105 : else
106 0 : return find_struct_member(name, ++end, members->type->u.members, brace_level);
107 : break;
108 0 : case '.':
109 0 : if (members->type->type == ECPGt_array)
110 0 : return find_struct_member(name, end, members->type->u.element->u.members, brace_level);
111 : else
112 0 : return find_struct_member(name, end, members->type->u.members, brace_level);
113 : break;
114 0 : default:
115 0 : mmfatal(PARSE_ERROR, "incorrectly formed variable \"%s\"", name);
116 : break;
117 : }
118 : }
119 : }
120 : }
121 :
122 0 : return NULL;
123 : }
124 :
125 : static struct variable *
126 58 : find_struct(const char *name, char *next, char *end)
127 : {
128 : struct variable *p;
129 58 : char c = *next;
130 :
131 : /* first get the mother structure entry */
132 58 : *next = '\0';
133 58 : p = find_variable(name);
134 :
135 58 : if (c == '-')
136 : {
137 0 : if (p->type->type != ECPGt_array)
138 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer", name);
139 :
140 0 : if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
141 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer to a structure or a union", name);
142 :
143 : /* restore the name, we will need it later */
144 0 : *next = c;
145 :
146 0 : return find_struct_member(name, ++end, p->type->u.element->u.members, p->brace_level);
147 : }
148 : else
149 : {
150 58 : if (next == end)
151 : {
152 58 : if (p->type->type != ECPGt_struct && p->type->type != ECPGt_union)
153 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is neither a structure nor a union", name);
154 :
155 : /* restore the name, we will need it later */
156 58 : *next = c;
157 :
158 58 : return find_struct_member(name, end, p->type->u.members, p->brace_level);
159 : }
160 : else
161 : {
162 0 : if (p->type->type != ECPGt_array)
163 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not an array", name);
164 :
165 0 : if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
166 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer to a structure or a union", name);
167 :
168 : /* restore the name, we will need it later */
169 0 : *next = c;
170 :
171 0 : return find_struct_member(name, end, p->type->u.element->u.members, p->brace_level);
172 : }
173 : }
174 : }
175 :
176 : static struct variable *
177 2724 : find_simple(const char *name)
178 : {
179 : struct variable *p;
180 :
181 21320 : for (p = allvariables; p; p = p->next)
182 : {
183 21320 : if (strcmp(p->name, name) == 0)
184 2724 : return p;
185 : }
186 :
187 0 : return NULL;
188 : }
189 :
190 : /* Note that this function will end the program in case of an unknown */
191 : /* variable */
192 : struct variable *
193 2782 : find_variable(const char *name)
194 : {
195 : char *next,
196 : *end;
197 : struct variable *p;
198 : int count;
199 :
200 2782 : next = strpbrk(name, ".[-");
201 2782 : if (next)
202 : {
203 258 : if (*next == '[')
204 : {
205 : /*
206 : * We don't care about what's inside the array braces so just eat
207 : * up the characters
208 : */
209 600 : for (count = 1, end = next + 1; count; end++)
210 : {
211 400 : switch (*end)
212 : {
213 0 : case '[':
214 0 : count++;
215 0 : break;
216 200 : case ']':
217 200 : count--;
218 200 : break;
219 0 : case '\0':
220 0 : mmfatal(PARSE_ERROR, "unmatched brace in variable \"%s\"", name);
221 : break;
222 200 : default:
223 200 : break;
224 : }
225 : }
226 200 : if (*end == '.')
227 0 : p = find_struct(name, next, end);
228 : else
229 : {
230 200 : char c = *next;
231 :
232 200 : *next = '\0';
233 200 : p = find_simple(name);
234 200 : if (p == NULL)
235 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", name);
236 200 : if (p->type->type != ECPGt_array)
237 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer", name);
238 200 : *next = c;
239 200 : switch (p->type->u.element->type)
240 : {
241 0 : case ECPGt_array:
242 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);
243 6 : case ECPGt_struct:
244 : case ECPGt_union:
245 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);
246 194 : default:
247 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);
248 : }
249 : }
250 : }
251 : else
252 58 : p = find_struct(name, next, next);
253 : }
254 : else
255 2524 : p = find_simple(name);
256 :
257 2582 : if (p == NULL)
258 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", name);
259 :
260 2582 : return p;
261 : }
262 :
263 : void
264 660 : remove_typedefs(int brace_level)
265 : {
266 : struct typedefs *p,
267 : *prev;
268 :
269 966 : for (p = prev = types; p;)
270 : {
271 306 : if (p->brace_level >= brace_level)
272 : {
273 : /* remove it */
274 26 : if (p == types)
275 26 : prev = types = p->next;
276 : else
277 0 : prev->next = p->next;
278 :
279 26 : if (p->type->type_enum == ECPGt_struct || p->type->type_enum == ECPGt_union)
280 24 : free(p->struct_member_list);
281 26 : free(p->type);
282 26 : free(p->name);
283 26 : free(p);
284 26 : if (prev == types)
285 26 : p = types;
286 : else
287 0 : p = prev ? prev->next : NULL;
288 : }
289 : else
290 : {
291 280 : prev = p;
292 280 : p = prev->next;
293 : }
294 : }
295 660 : }
296 :
297 : void
298 660 : remove_variables(int brace_level)
299 : {
300 : struct variable *p,
301 : *prev;
302 :
303 3116 : for (p = prev = allvariables; p;)
304 : {
305 2456 : if (p->brace_level >= brace_level)
306 : {
307 : /* is it still referenced by a cursor? */
308 : struct cursor *ptr;
309 :
310 1506 : for (ptr = cur; ptr != NULL; ptr = ptr->next)
311 : {
312 : struct arguments *varptr,
313 : *prevvar;
314 :
315 1236 : for (varptr = prevvar = ptr->argsinsert; varptr != NULL; varptr = varptr->next)
316 : {
317 514 : if (p == varptr->variable)
318 : {
319 : /* remove from list */
320 20 : if (varptr == ptr->argsinsert)
321 14 : ptr->argsinsert = varptr->next;
322 : else
323 6 : prevvar->next = varptr->next;
324 : }
325 : }
326 732 : for (varptr = prevvar = ptr->argsresult; varptr != NULL; varptr = varptr->next)
327 : {
328 10 : if (p == varptr->variable)
329 : {
330 : /* remove from list */
331 6 : if (varptr == ptr->argsresult)
332 6 : ptr->argsresult = varptr->next;
333 : else
334 0 : prevvar->next = varptr->next;
335 : }
336 : }
337 : }
338 :
339 : /* remove it */
340 784 : if (p == allvariables)
341 462 : prev = allvariables = p->next;
342 : else
343 322 : prev->next = p->next;
344 :
345 784 : ECPGfree_type(p->type);
346 784 : free(p->name);
347 784 : free(p);
348 784 : if (prev == allvariables)
349 518 : p = allvariables;
350 : else
351 266 : p = prev ? prev->next : NULL;
352 : }
353 : else
354 : {
355 1672 : prev = p;
356 1672 : p = prev->next;
357 : }
358 : }
359 660 : }
360 :
361 :
362 : /*
363 : * Here are the variables that need to be handled on every request.
364 : * These are of two kinds: input and output.
365 : * I will make two lists for them.
366 : */
367 :
368 : struct arguments *argsinsert = NULL;
369 : struct arguments *argsresult = NULL;
370 :
371 : void
372 3974 : reset_variables(void)
373 : {
374 3974 : argsinsert = NULL;
375 3974 : argsresult = NULL;
376 3974 : }
377 :
378 : /* Insert a new variable into our request list.
379 : * Note: The list is dumped from the end,
380 : * so we have to add new entries at the beginning */
381 : void
382 1010 : add_variable_to_head(struct arguments **list, struct variable *var, struct variable *ind)
383 : {
384 1010 : struct arguments *p = (struct arguments *) mm_alloc(sizeof(struct arguments));
385 :
386 1010 : p->variable = var;
387 1010 : p->indicator = ind;
388 1010 : p->next = *list;
389 1010 : *list = p;
390 1010 : }
391 :
392 : /* Append a new variable to our request list. */
393 : void
394 190 : add_variable_to_tail(struct arguments **list, struct variable *var, struct variable *ind)
395 : {
396 : struct arguments *p,
397 190 : *new = (struct arguments *) mm_alloc(sizeof(struct arguments));
398 :
399 204 : for (p = *list; p && p->next; p = p->next);
400 :
401 190 : new->variable = var;
402 190 : new->indicator = ind;
403 190 : new->next = NULL;
404 :
405 190 : if (p)
406 52 : p->next = new;
407 : else
408 138 : *list = new;
409 190 : }
410 :
411 : void
412 34 : remove_variable_from_list(struct arguments **list, struct variable *var)
413 : {
414 : struct arguments *p,
415 34 : *prev = NULL;
416 34 : bool found = false;
417 :
418 34 : for (p = *list; p; p = p->next)
419 : {
420 34 : if (p->variable == var)
421 : {
422 34 : found = true;
423 34 : break;
424 : }
425 0 : prev = p;
426 : }
427 34 : if (found)
428 : {
429 34 : if (prev)
430 0 : prev->next = p->next;
431 : else
432 34 : *list = p->next;
433 : }
434 34 : }
435 :
436 : /* Dump out a list of all the variable on this list.
437 : This is a recursive function that works from the end of the list and
438 : deletes the list as we go on.
439 : */
440 : void
441 3284 : dump_variables(struct arguments *list, int mode)
442 : {
443 : char *str_zero;
444 :
445 3284 : if (list == NULL)
446 2254 : return;
447 :
448 1030 : str_zero = mm_strdup("0");
449 :
450 : /*
451 : * The list is build up from the beginning so lets first dump the end of
452 : * the list:
453 : */
454 :
455 1030 : dump_variables(list->next, mode);
456 :
457 : /* Then the current element and its indicator */
458 1030 : ECPGdump_a_type(base_yyout, list->variable->name, list->variable->type, list->variable->brace_level,
459 1030 : list->indicator->name, list->indicator->type, list->indicator->brace_level,
460 : NULL, NULL, str_zero, NULL, NULL);
461 :
462 : /* Then release the list element. */
463 1030 : if (mode != 0)
464 1030 : free(list);
465 :
466 1030 : free(str_zero);
467 : }
468 :
469 : void
470 134 : check_indicator(struct ECPGtype *var)
471 : {
472 : /* make sure this is a valid indicator variable */
473 134 : switch (var->type)
474 : {
475 : struct ECPGstruct_member *p;
476 :
477 90 : case ECPGt_short:
478 : case ECPGt_int:
479 : case ECPGt_long:
480 : case ECPGt_long_long:
481 : case ECPGt_unsigned_short:
482 : case ECPGt_unsigned_int:
483 : case ECPGt_unsigned_long:
484 : case ECPGt_unsigned_long_long:
485 90 : break;
486 :
487 22 : case ECPGt_struct:
488 : case ECPGt_union:
489 72 : for (p = var->u.members; p; p = p->next)
490 50 : check_indicator(p->type);
491 22 : break;
492 :
493 22 : case ECPGt_array:
494 22 : check_indicator(var->u.element);
495 22 : break;
496 0 : default:
497 0 : mmerror(PARSE_ERROR, ET_ERROR, "indicator variable must have an integer type");
498 0 : break;
499 : }
500 134 : }
501 :
502 : struct typedefs *
503 11144 : get_typedef(const char *name, bool noerror)
504 : {
505 : struct typedefs *this;
506 :
507 17938 : for (this = types; this != NULL; this = this->next)
508 : {
509 6854 : if (strcmp(this->name, name) == 0)
510 60 : return this;
511 : }
512 :
513 11084 : if (!noerror)
514 0 : mmfatal(PARSE_ERROR, "unrecognized data type name \"%s\"", name);
515 :
516 11084 : return NULL;
517 : }
518 :
519 : void
520 748 : adjust_array(enum ECPGttype type_enum,
521 : const char **dimension, const char **length,
522 : const char *type_dimension, const char *type_index,
523 : int pointer_len, bool type_definition)
524 : {
525 748 : if (atoi(type_index) >= 0)
526 : {
527 12 : if (atoi(*length) >= 0)
528 0 : mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
529 :
530 12 : *length = type_index;
531 : }
532 :
533 748 : if (atoi(type_dimension) >= 0)
534 : {
535 2 : if (atoi(*dimension) >= 0 && atoi(*length) >= 0)
536 0 : mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
537 :
538 2 : if (atoi(*dimension) >= 0)
539 0 : *length = *dimension;
540 :
541 2 : *dimension = type_dimension;
542 : }
543 :
544 748 : if (pointer_len > 2)
545 0 : mmfatal(PARSE_ERROR, ngettext("multilevel pointers (more than 2 levels) are not supported; found %d level",
546 : "multilevel pointers (more than 2 levels) are not supported; found %d levels", pointer_len),
547 : pointer_len);
548 :
549 748 : if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && type_enum != ECPGt_string)
550 0 : mmfatal(PARSE_ERROR, "pointer to pointer is not supported for this data type");
551 :
552 748 : if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
553 0 : mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
554 :
555 748 : if (atoi(*length) >= 0 && atoi(*dimension) >= 0 && pointer_len)
556 0 : mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
557 :
558 748 : switch (type_enum)
559 : {
560 68 : case ECPGt_struct:
561 : case ECPGt_union:
562 : /* pointer has to get dimension 0 */
563 68 : if (pointer_len)
564 : {
565 18 : *length = *dimension;
566 18 : *dimension = "0";
567 : }
568 :
569 68 : if (atoi(*length) >= 0)
570 0 : mmfatal(PARSE_ERROR, "multidimensional arrays for structures are not supported");
571 :
572 68 : break;
573 46 : case ECPGt_varchar:
574 : case ECPGt_bytea:
575 : /* pointer has to get dimension 0 */
576 46 : if (pointer_len)
577 0 : *dimension = "0";
578 :
579 : /* one index is the string length */
580 46 : if (atoi(*length) < 0)
581 : {
582 30 : *length = *dimension;
583 30 : *dimension = "-1";
584 : }
585 :
586 46 : break;
587 238 : case ECPGt_char:
588 : case ECPGt_unsigned_char:
589 : case ECPGt_string:
590 : /* char ** */
591 238 : if (pointer_len == 2)
592 : {
593 16 : *length = *dimension = "0";
594 16 : break;
595 : }
596 :
597 : /* pointer has to get length 0 */
598 222 : if (pointer_len == 1)
599 72 : *length = "0";
600 :
601 : /* one index is the string length */
602 222 : if (atoi(*length) < 0)
603 : {
604 : /*
605 : * make sure we return length = -1 for arrays without given
606 : * bounds
607 : */
608 130 : if (atoi(*dimension) < 0 && !type_definition)
609 :
610 : /*
611 : * do not change this for typedefs since it will be
612 : * changed later on when the variable is defined
613 : */
614 10 : *length = "1";
615 120 : else if (strcmp(*dimension, "0") == 0)
616 4 : *length = "-1";
617 : else
618 116 : *length = *dimension;
619 :
620 130 : *dimension = "-1";
621 : }
622 222 : break;
623 396 : default:
624 : /* a pointer has dimension = 0 */
625 396 : if (pointer_len)
626 : {
627 40 : *length = *dimension;
628 40 : *dimension = "0";
629 : }
630 :
631 396 : if (atoi(*length) >= 0)
632 0 : mmfatal(PARSE_ERROR, "multidimensional arrays for simple data types are not supported");
633 :
634 396 : break;
635 : }
636 748 : }
|