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 958 : new_variable(const char *name, struct ECPGtype *type, int brace_level)
11 : {
12 958 : struct variable *p = (struct variable *) mm_alloc(sizeof(struct variable));
13 :
14 958 : p->name = mm_strdup(name);
15 958 : p->type = type;
16 958 : p->brace_level = brace_level;
17 :
18 958 : p->next = allvariables;
19 958 : allvariables = p;
20 :
21 958 : return p;
22 : }
23 :
24 : static struct variable *
25 58 : find_struct_member(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(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 2704 : find_simple(char *name)
178 : {
179 : struct variable *p;
180 :
181 21288 : for (p = allvariables; p; p = p->next)
182 : {
183 21288 : if (strcmp(p->name, name) == 0)
184 2704 : 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 2762 : find_variable(char *name)
194 : {
195 : char *next,
196 : *end;
197 : struct variable *p;
198 : int count;
199 :
200 2762 : next = strpbrk(name, ".[-");
201 2762 : 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 200 : default:
220 200 : break;
221 : }
222 : }
223 200 : if (*end == '.')
224 0 : p = find_struct(name, next, end);
225 : else
226 : {
227 200 : char c = *next;
228 :
229 200 : *next = '\0';
230 200 : p = find_simple(name);
231 200 : if (p == NULL)
232 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", name);
233 :
234 200 : *next = c;
235 200 : switch (p->type->u.element->type)
236 : {
237 0 : case ECPGt_array:
238 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);
239 6 : case ECPGt_struct:
240 : case ECPGt_union:
241 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);
242 194 : default:
243 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);
244 : }
245 : }
246 : }
247 : else
248 58 : p = find_struct(name, next, next);
249 : }
250 : else
251 2504 : p = find_simple(name);
252 :
253 2562 : if (p == NULL)
254 0 : mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", name);
255 :
256 2562 : return p;
257 : }
258 :
259 : void
260 646 : remove_typedefs(int brace_level)
261 : {
262 : struct typedefs *p,
263 : *prev;
264 :
265 952 : for (p = prev = types; p;)
266 : {
267 306 : if (p->brace_level >= brace_level)
268 : {
269 : /* remove it */
270 26 : if (p == types)
271 26 : prev = types = p->next;
272 : else
273 0 : prev->next = p->next;
274 :
275 26 : if (p->type->type_enum == ECPGt_struct || p->type->type_enum == ECPGt_union)
276 24 : free(p->struct_member_list);
277 26 : free(p->type);
278 26 : free(p->name);
279 26 : free(p);
280 26 : if (prev == types)
281 26 : p = types;
282 : else
283 0 : p = prev ? prev->next : NULL;
284 : }
285 : else
286 : {
287 280 : prev = p;
288 280 : p = prev->next;
289 : }
290 : }
291 646 : }
292 :
293 : void
294 646 : remove_variables(int brace_level)
295 : {
296 : struct variable *p,
297 : *prev;
298 :
299 3096 : for (p = prev = allvariables; p;)
300 : {
301 2450 : if (p->brace_level >= brace_level)
302 : {
303 : /* is it still referenced by a cursor? */
304 : struct cursor *ptr;
305 :
306 1504 : for (ptr = cur; ptr != NULL; ptr = ptr->next)
307 : {
308 : struct arguments *varptr,
309 : *prevvar;
310 :
311 1236 : for (varptr = prevvar = ptr->argsinsert; varptr != NULL; varptr = varptr->next)
312 : {
313 514 : if (p == varptr->variable)
314 : {
315 : /* remove from list */
316 20 : if (varptr == ptr->argsinsert)
317 14 : ptr->argsinsert = varptr->next;
318 : else
319 6 : prevvar->next = varptr->next;
320 : }
321 : }
322 732 : for (varptr = prevvar = ptr->argsresult; varptr != NULL; varptr = varptr->next)
323 : {
324 10 : if (p == varptr->variable)
325 : {
326 : /* remove from list */
327 6 : if (varptr == ptr->argsresult)
328 6 : ptr->argsresult = varptr->next;
329 : else
330 0 : prevvar->next = varptr->next;
331 : }
332 : }
333 : }
334 :
335 : /* remove it */
336 782 : if (p == allvariables)
337 460 : prev = allvariables = p->next;
338 : else
339 322 : prev->next = p->next;
340 :
341 782 : ECPGfree_type(p->type);
342 782 : free(p->name);
343 782 : free(p);
344 782 : if (prev == allvariables)
345 516 : p = allvariables;
346 : else
347 266 : p = prev ? prev->next : NULL;
348 : }
349 : else
350 : {
351 1668 : prev = p;
352 1668 : p = prev->next;
353 : }
354 : }
355 646 : }
356 :
357 :
358 : /*
359 : * Here are the variables that need to be handled on every request.
360 : * These are of two kinds: input and output.
361 : * I will make two lists for them.
362 : */
363 :
364 : struct arguments *argsinsert = NULL;
365 : struct arguments *argsresult = NULL;
366 :
367 : void
368 3936 : reset_variables(void)
369 : {
370 3936 : argsinsert = NULL;
371 3936 : argsresult = NULL;
372 3936 : }
373 :
374 : /* Insert a new variable into our request list.
375 : * Note: The list is dumped from the end,
376 : * so we have to add new entries at the beginning */
377 : void
378 1000 : add_variable_to_head(struct arguments **list, struct variable *var, struct variable *ind)
379 : {
380 1000 : struct arguments *p = (struct arguments *) mm_alloc(sizeof(struct arguments));
381 :
382 1000 : p->variable = var;
383 1000 : p->indicator = ind;
384 1000 : p->next = *list;
385 1000 : *list = p;
386 1000 : }
387 :
388 : /* Append a new variable to our request list. */
389 : void
390 190 : add_variable_to_tail(struct arguments **list, struct variable *var, struct variable *ind)
391 : {
392 : struct arguments *p,
393 190 : *new = (struct arguments *) mm_alloc(sizeof(struct arguments));
394 :
395 204 : for (p = *list; p && p->next; p = p->next);
396 :
397 190 : new->variable = var;
398 190 : new->indicator = ind;
399 190 : new->next = NULL;
400 :
401 190 : if (p)
402 52 : p->next = new;
403 : else
404 138 : *list = new;
405 190 : }
406 :
407 : void
408 34 : remove_variable_from_list(struct arguments **list, struct variable *var)
409 : {
410 : struct arguments *p,
411 34 : *prev = NULL;
412 34 : bool found = false;
413 :
414 34 : for (p = *list; p; p = p->next)
415 : {
416 34 : if (p->variable == var)
417 : {
418 34 : found = true;
419 34 : break;
420 : }
421 0 : prev = p;
422 : }
423 34 : if (found)
424 : {
425 34 : if (prev)
426 0 : prev->next = p->next;
427 : else
428 34 : *list = p->next;
429 : }
430 34 : }
431 :
432 : /* Dump out a list of all the variable on this list.
433 : This is a recursive function that works from the end of the list and
434 : deletes the list as we go on.
435 : */
436 : void
437 3254 : dump_variables(struct arguments *list, int mode)
438 : {
439 : char *str_zero;
440 :
441 3254 : if (list == NULL)
442 2234 : return;
443 :
444 1020 : str_zero = mm_strdup("0");
445 :
446 : /*
447 : * The list is build up from the beginning so lets first dump the end of
448 : * the list:
449 : */
450 :
451 1020 : dump_variables(list->next, mode);
452 :
453 : /* Then the current element and its indicator */
454 1020 : ECPGdump_a_type(base_yyout, list->variable->name, list->variable->type, list->variable->brace_level,
455 1020 : list->indicator->name, list->indicator->type, list->indicator->brace_level,
456 : NULL, NULL, str_zero, NULL, NULL);
457 :
458 : /* Then release the list element. */
459 1020 : if (mode != 0)
460 1020 : free(list);
461 :
462 1020 : free(str_zero);
463 : }
464 :
465 : void
466 134 : check_indicator(struct ECPGtype *var)
467 : {
468 : /* make sure this is a valid indicator variable */
469 134 : switch (var->type)
470 : {
471 : struct ECPGstruct_member *p;
472 :
473 90 : case ECPGt_short:
474 : case ECPGt_int:
475 : case ECPGt_long:
476 : case ECPGt_long_long:
477 : case ECPGt_unsigned_short:
478 : case ECPGt_unsigned_int:
479 : case ECPGt_unsigned_long:
480 : case ECPGt_unsigned_long_long:
481 90 : break;
482 :
483 22 : case ECPGt_struct:
484 : case ECPGt_union:
485 72 : for (p = var->u.members; p; p = p->next)
486 50 : check_indicator(p->type);
487 22 : break;
488 :
489 22 : case ECPGt_array:
490 22 : check_indicator(var->u.element);
491 22 : break;
492 0 : default:
493 0 : mmerror(PARSE_ERROR, ET_ERROR, "indicator variable must have an integer type");
494 0 : break;
495 : }
496 134 : }
497 :
498 : struct typedefs *
499 11018 : get_typedef(const char *name, bool noerror)
500 : {
501 : struct typedefs *this;
502 :
503 17812 : for (this = types; this != NULL; this = this->next)
504 : {
505 6854 : if (strcmp(this->name, name) == 0)
506 60 : return this;
507 : }
508 :
509 10958 : if (!noerror)
510 0 : mmfatal(PARSE_ERROR, "unrecognized data type name \"%s\"", name);
511 :
512 10958 : return NULL;
513 : }
514 :
515 : void
516 742 : adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *type_dimension, char *type_index, int pointer_len, bool type_definition)
517 : {
518 742 : if (atoi(type_index) >= 0)
519 : {
520 12 : if (atoi(*length) >= 0)
521 0 : mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
522 :
523 12 : *length = type_index;
524 : }
525 :
526 742 : if (atoi(type_dimension) >= 0)
527 : {
528 2 : if (atoi(*dimension) >= 0 && atoi(*length) >= 0)
529 0 : mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
530 :
531 2 : if (atoi(*dimension) >= 0)
532 0 : *length = *dimension;
533 :
534 2 : *dimension = type_dimension;
535 : }
536 :
537 742 : if (pointer_len > 2)
538 0 : mmfatal(PARSE_ERROR, ngettext("multilevel pointers (more than 2 levels) are not supported; found %d level",
539 : "multilevel pointers (more than 2 levels) are not supported; found %d levels", pointer_len),
540 : pointer_len);
541 :
542 742 : if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && type_enum != ECPGt_string)
543 0 : mmfatal(PARSE_ERROR, "pointer to pointer is not supported for this data type");
544 :
545 742 : if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
546 0 : mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
547 :
548 742 : if (atoi(*length) >= 0 && atoi(*dimension) >= 0 && pointer_len)
549 0 : mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
550 :
551 742 : switch (type_enum)
552 : {
553 68 : case ECPGt_struct:
554 : case ECPGt_union:
555 : /* pointer has to get dimension 0 */
556 68 : if (pointer_len)
557 : {
558 18 : *length = *dimension;
559 18 : *dimension = mm_strdup("0");
560 : }
561 :
562 68 : if (atoi(*length) >= 0)
563 0 : mmfatal(PARSE_ERROR, "multidimensional arrays for structures are not supported");
564 :
565 68 : break;
566 46 : case ECPGt_varchar:
567 : case ECPGt_bytea:
568 : /* pointer has to get dimension 0 */
569 46 : if (pointer_len)
570 0 : *dimension = mm_strdup("0");
571 :
572 : /* one index is the string length */
573 46 : if (atoi(*length) < 0)
574 : {
575 30 : *length = *dimension;
576 30 : *dimension = mm_strdup("-1");
577 : }
578 :
579 46 : break;
580 236 : case ECPGt_char:
581 : case ECPGt_unsigned_char:
582 : case ECPGt_string:
583 : /* char ** */
584 236 : if (pointer_len == 2)
585 : {
586 16 : *length = *dimension = mm_strdup("0");
587 16 : break;
588 : }
589 :
590 : /* pointer has to get length 0 */
591 220 : if (pointer_len == 1)
592 72 : *length = mm_strdup("0");
593 :
594 : /* one index is the string length */
595 220 : if (atoi(*length) < 0)
596 : {
597 : /*
598 : * make sure we return length = -1 for arrays without given
599 : * bounds
600 : */
601 128 : if (atoi(*dimension) < 0 && !type_definition)
602 :
603 : /*
604 : * do not change this for typedefs since it will be
605 : * changed later on when the variable is defined
606 : */
607 10 : *length = mm_strdup("1");
608 118 : else if (strcmp(*dimension, "0") == 0)
609 4 : *length = mm_strdup("-1");
610 : else
611 114 : *length = *dimension;
612 :
613 128 : *dimension = mm_strdup("-1");
614 : }
615 220 : break;
616 392 : default:
617 : /* a pointer has dimension = 0 */
618 392 : if (pointer_len)
619 : {
620 38 : *length = *dimension;
621 38 : *dimension = mm_strdup("0");
622 : }
623 :
624 392 : if (atoi(*length) >= 0)
625 0 : mmfatal(PARSE_ERROR, "multidimensional arrays for simple data types are not supported");
626 :
627 392 : break;
628 : }
629 742 : }
|