PostgreSQL Source Code git master
variable.c
Go to the documentation of this file.
1/* src/interfaces/ecpg/preproc/variable.c */
2
3#include "postgres_fe.h"
4
5#include "preproc_extern.h"
6
7static struct variable *allvariables = NULL;
8
9/* this probably belongs in util.c, but for now it's only needed here */
10static char *
11loc_nstrdup(const char *in, size_t len)
12{
13 char *out;
14
15 out = loc_alloc(len + 1);
16 memcpy(out, in, len);
17 out[len] = '\0';
18
19 return out;
20}
21
22struct variable *
23new_variable(const char *name, struct ECPGtype *type, int brace_level)
24{
25 struct variable *p = (struct variable *) mm_alloc(sizeof(struct variable));
26
27 p->name = mm_strdup(name);
28 p->type = type;
30
31 p->next = allvariables;
32 allvariables = p;
33
34 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 */
48static struct variable *
49find_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 const char *next = strpbrk(++str, ".-["),
54 *end,
55 *field;
56
57 if (next != NULL)
58 field = loc_nstrdup(str, next - str);
59 else
60 field = str;
61
62 for (; members; members = members->next)
63 {
64 if (strcmp(members->name, field) == 0)
65 {
66 if (next == NULL)
67 {
68 /* found the end */
69 switch (members->type->type)
70 {
71 case ECPGt_array:
73 case ECPGt_struct:
74 case ECPGt_union:
75 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 default:
77 return new_variable(name, ECPGmake_simple_type(members->type->type, members->type->size, members->type->counter), brace_level);
78 }
79 }
80 else
81 {
82 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 for (count = 1, end = next + 1; count; end++)
91 {
92 switch (*end)
93 {
94 case '[':
95 count++;
96 break;
97 case ']':
98 count--;
99 break;
100 default:
101 break;
102 }
103 }
104 }
105 else
106 end = next;
107
108 switch (*end)
109 {
110 case '\0': /* found the end, but this time it has to be
111 * an array element */
112 if (members->type->type != ECPGt_array)
113 mmfatal(PARSE_ERROR, "incorrectly formed variable \"%s\"", name);
114
115 switch (members->type->u.element->type)
116 {
117 case ECPGt_array:
119 case ECPGt_struct:
120 case ECPGt_union:
122 default:
123 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 case '-':
127 if (members->type->type == ECPGt_array)
128 return find_struct_member(name, ++end, members->type->u.element->u.members, brace_level);
129 else
130 return find_struct_member(name, ++end, members->type->u.members, brace_level);
131 break;
132 case '.':
133 if (members->type->type == ECPGt_array)
134 return find_struct_member(name, end, members->type->u.element->u.members, brace_level);
135 else
136 return find_struct_member(name, end, members->type->u.members, brace_level);
137 break;
138 default:
139 mmfatal(PARSE_ERROR, "incorrectly formed variable \"%s\"", name);
140 break;
141 }
142 }
143 }
144 }
145
146 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 */
160static struct variable *
161find_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 prefix = loc_nstrdup(name, next - name);
168 p = find_variable(prefix);
169
170 if (*next == '-')
171 {
172 /* We have var->field */
173 if (p->type->type != ECPGt_array)
174 mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer", prefix);
175
176 if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
177 mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer to a structure or a union", prefix);
178
179 return find_struct_member(name, ++end, p->type->u.element->u.members, p->brace_level);
180 }
181 else
182 {
183 if (next == end)
184 {
185 /* We have var.field */
186 if (p->type->type != ECPGt_struct && p->type->type != ECPGt_union)
187 mmfatal(PARSE_ERROR, "variable \"%s\" is neither a structure nor a union", prefix);
188
189 return find_struct_member(name, end, p->type->u.members, p->brace_level);
190 }
191 else
192 {
193 /* We have var[n].field */
194 if (p->type->type != ECPGt_array)
195 mmfatal(PARSE_ERROR, "variable \"%s\" is not an array", prefix);
196
197 if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
198 mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer to a structure or a union", prefix);
199
200 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 */
206static struct variable *
207find_simple(const char *name)
208{
209 struct variable *p;
210
211 for (p = allvariables; p; p = p->next)
212 {
213 if (strcmp(p->name, name) == 0)
214 return p;
215 }
216
217 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 */
234struct variable *
235find_variable(const char *name)
236{
237 const char *next,
238 *end;
239 struct variable *p;
240 int count;
241
242 next = strpbrk(name, ".[-");
243 if (next)
244 {
245 /* Deal with field/subscript decoration */
246 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 for (count = 1, end = next + 1; count; end++)
253 {
254 switch (*end)
255 {
256 case '[':
257 count++;
258 break;
259 case ']':
260 count--;
261 break;
262 case '\0':
263 mmfatal(PARSE_ERROR, "unmatched bracket in variable \"%s\"", name);
264 break;
265 default:
266 break;
267 }
268 }
269 if (*end == '.')
270 {
271 /* We have var[n].field */
272 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 char *prefix = loc_nstrdup(name, next - name);
283
284 p = find_simple(prefix);
285 if (p == NULL)
286 mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", prefix);
287 if (p->type->type != ECPGt_array)
288 mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer", prefix);
289 switch (p->type->u.element->type)
290 {
291 case ECPGt_array:
292 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 case ECPGt_struct:
294 case ECPGt_union:
295 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 default:
297 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 p = find_struct(name, next, next);
305 }
306 }
307 else
308 p = find_simple(name);
309
310 if (p == NULL)
311 mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", name);
312
313 return p;
314}
315
316void
318{
319 struct typedefs *p,
320 *prev,
321 *next;
322
323 for (p = types, prev = NULL; p; p = next)
324 {
325 next = p->next;
326 if (p->brace_level >= brace_level)
327 {
328 /* remove it */
329 if (prev)
330 prev->next = next;
331 else
332 types = next;
333
337 free(p->type->type_str);
339 free(p->type->type_index);
340 free(p->type->type_sizeof);
341 free(p->type);
342 free(p->name);
343 free(p);
344 }
345 else
346 prev = p;
347 }
348}
349
350void
352{
353 struct variable *p,
354 *prev,
355 *next;
356
357 for (p = allvariables, prev = NULL; p; p = next)
358 {
359 next = p->next;
360 if (p->brace_level >= brace_level)
361 {
362 /* remove it, but first remove any references from cursors */
363 struct cursor *ptr;
364
365 for (ptr = cur; ptr != NULL; ptr = ptr->next)
366 {
367 struct arguments *varptr,
368 *prevvar,
369 *nextvar;
370
371 for (varptr = ptr->argsinsert, prevvar = NULL;
372 varptr != NULL; varptr = nextvar)
373 {
374 nextvar = varptr->next;
375 if (p == varptr->variable)
376 {
377 /* remove from list */
378 if (prevvar)
379 prevvar->next = nextvar;
380 else
381 ptr->argsinsert = nextvar;
382 free(varptr);
383 }
384 else
385 prevvar = varptr;
386 }
387 for (varptr = ptr->argsresult, prevvar = NULL;
388 varptr != NULL; varptr = nextvar)
389 {
390 nextvar = varptr->next;
391 if (p == varptr->variable)
392 {
393 /* remove from list */
394 if (prevvar)
395 prevvar->next = nextvar;
396 else
397 ptr->argsresult = nextvar;
398 free(varptr);
399 }
400 else
401 prevvar = varptr;
402 }
403 }
404
405 /* remove it */
406 if (prev)
407 prev->next = next;
408 else
410
412 free(p->name);
413 free(p);
414 }
415 else
416 prev = p;
417 }
418}
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
427struct arguments *argsinsert = NULL;
428struct arguments *argsresult = NULL;
429
430void
432{
433 struct arguments *p,
434 *next;
435
436 for (p = argsinsert; p; p = next)
437 {
438 next = p->next;
439 free(p);
440 }
441 argsinsert = NULL;
442 for (p = argsresult; p; p = next)
443 {
444 next = p->next;
445 free(p);
446 }
447 argsresult = NULL;
448}
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 */
453void
455{
456 struct arguments *p = (struct arguments *) mm_alloc(sizeof(struct arguments));
457
458 p->variable = var;
459 p->indicator = ind;
460 p->next = *list;
461 *list = p;
462}
463
464/* Append a new variable to our request list. */
465void
467{
468 struct arguments *p,
469 *new = (struct arguments *) mm_alloc(sizeof(struct arguments));
470
471 for (p = *list; p && p->next; p = p->next);
472
473 new->variable = var;
474 new->indicator = ind;
475 new->next = NULL;
476
477 if (p)
478 p->next = new;
479 else
480 *list = new;
481}
482
483void
485{
486 struct arguments *p,
487 *prev = NULL;
488 bool found = false;
489
490 for (p = *list; p; p = p->next)
491 {
492 if (p->variable == var)
493 {
494 found = true;
495 break;
496 }
497 prev = p;
498 }
499 if (found)
500 {
501 if (prev)
502 prev->next = p->next;
503 else
504 *list = p->next;
505 free(p);
506 }
507}
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 */
513void
515{
516 char *str_zero;
517
518 if (list == NULL)
519 return;
520
521 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 dump_variables(list->next, mode);
529
530 /* Then the current element and its indicator */
531 ECPGdump_a_type(base_yyout, list->variable->name, list->variable->type, list->variable->brace_level,
532 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 if (mode != 0)
537 free(list);
538
539 free(str_zero);
540}
541
542void
544{
545 /* make sure this is a valid indicator variable */
546 switch (var->type)
547 {
548 struct ECPGstruct_member *p;
549
550 case ECPGt_short:
551 case ECPGt_int:
552 case ECPGt_long:
553 case ECPGt_long_long:
558 break;
559
560 case ECPGt_struct:
561 case ECPGt_union:
562 for (p = var->u.members; p; p = p->next)
564 break;
565
566 case ECPGt_array:
568 break;
569 default:
570 mmerror(PARSE_ERROR, ET_ERROR, "indicator variable must have an integer type");
571 break;
572 }
573}
574
575struct typedefs *
576get_typedef(const char *name, bool noerror)
577{
578 struct typedefs *this;
579
580 for (this = types; this != NULL; this = this->next)
581 {
582 if (strcmp(this->name, name) == 0)
583 return this;
584 }
585
586 if (!noerror)
587 mmfatal(PARSE_ERROR, "unrecognized data type name \"%s\"", name);
588
589 return NULL;
590}
591
592void
593adjust_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 if (atoi(type_index) >= 0)
599 {
600 if (atoi(*length) >= 0)
601 mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
602
603 *length = type_index;
604 }
605
606 if (atoi(type_dimension) >= 0)
607 {
608 if (atoi(*dimension) >= 0 && atoi(*length) >= 0)
609 mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
610
611 if (atoi(*dimension) >= 0)
612 *length = *dimension;
613
614 *dimension = type_dimension;
615 }
616
617 if (pointer_len > 2)
618 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 if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && type_enum != ECPGt_string)
623 mmfatal(PARSE_ERROR, "pointer to pointer is not supported for this data type");
624
625 if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
626 mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
627
628 if (atoi(*length) >= 0 && atoi(*dimension) >= 0 && pointer_len)
629 mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
630
631 switch (type_enum)
632 {
633 case ECPGt_struct:
634 case ECPGt_union:
635 /* pointer has to get dimension 0 */
636 if (pointer_len)
637 {
638 *length = *dimension;
639 *dimension = "0";
640 }
641
642 if (atoi(*length) >= 0)
643 mmfatal(PARSE_ERROR, "multidimensional arrays for structures are not supported");
644
645 break;
646 case ECPGt_varchar:
647 case ECPGt_bytea:
648 /* pointer has to get dimension 0 */
649 if (pointer_len)
650 *dimension = "0";
651
652 /* one index is the string length */
653 if (atoi(*length) < 0)
654 {
655 *length = *dimension;
656 *dimension = "-1";
657 }
658
659 break;
660 case ECPGt_char:
662 case ECPGt_string:
663 /* char ** */
664 if (pointer_len == 2)
665 {
666 *length = *dimension = "0";
667 break;
668 }
669
670 /* pointer has to get length 0 */
671 if (pointer_len == 1)
672 *length = "0";
673
674 /* one index is the string length */
675 if (atoi(*length) < 0)
676 {
677 /*
678 * make sure we return length = -1 for arrays without given
679 * bounds
680 */
681 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 *length = "1";
688 else if (strcmp(*dimension, "0") == 0)
689 *length = "-1";
690 else
691 *length = *dimension;
692
693 *dimension = "-1";
694 }
695 break;
696 default:
697 /* a pointer has dimension = 0 */
698 if (pointer_len)
699 {
700 *length = *dimension;
701 *dimension = "0";
702 }
703
704 if (atoi(*length) >= 0)
705 mmfatal(PARSE_ERROR, "multidimensional arrays for simple data types are not supported");
706
707 break;
708 }
709}
static int32 next
Definition: blutils.c:224
#define ngettext(s, p, n)
Definition: c.h:1179
struct typedefs * types
Definition: ecpg.c:30
struct cursor * cur
Definition: ecpg.c:29
ECPGttype
Definition: ecpgtype.h:42
@ ECPGt_long_long
Definition: ecpgtype.h:45
@ ECPGt_short
Definition: ecpgtype.h:43
@ ECPGt_bytea
Definition: ecpgtype.h:67
@ ECPGt_union
Definition: ecpgtype.h:58
@ ECPGt_varchar
Definition: ecpgtype.h:48
@ ECPGt_struct
Definition: ecpgtype.h:57
@ ECPGt_unsigned_short
Definition: ecpgtype.h:43
@ ECPGt_int
Definition: ecpgtype.h:44
@ ECPGt_long
Definition: ecpgtype.h:44
@ ECPGt_unsigned_char
Definition: ecpgtype.h:43
@ ECPGt_array
Definition: ecpgtype.h:56
@ ECPGt_unsigned_long
Definition: ecpgtype.h:44
@ ECPGt_unsigned_long_long
Definition: ecpgtype.h:45
@ ECPGt_unsigned_int
Definition: ecpgtype.h:44
@ ECPGt_char
Definition: ecpgtype.h:43
@ ECPGt_string
Definition: ecpgtype.h:65
const char * str
#define free(a)
Definition: header.h:65
struct variable * new_variable(const char *name, struct ECPGtype *type, int brace_level)
Definition: variable.c:23
static struct variable * allvariables
Definition: variable.c:7
static struct variable * find_struct_member(const char *name, const char *str, struct ECPGstruct_member *members, int brace_level)
Definition: variable.c:49
static struct variable * find_struct(const char *name, const char *next, const char *end)
Definition: variable.c:161
void add_variable_to_tail(struct arguments **list, struct variable *var, struct variable *ind)
Definition: variable.c:466
void dump_variables(struct arguments *list, int mode)
Definition: variable.c:514
static struct variable * find_simple(const char *name)
Definition: variable.c:207
void adjust_array(enum ECPGttype type_enum, const char **dimension, const char **length, const char *type_dimension, const char *type_index, int pointer_len, bool type_definition)
Definition: variable.c:593
struct typedefs * get_typedef(const char *name, bool noerror)
Definition: variable.c:576
void reset_variables(void)
Definition: variable.c:431
void remove_variables(int brace_level)
Definition: variable.c:351
struct arguments * argsresult
Definition: variable.c:428
void remove_variable_from_list(struct arguments **list, struct variable *var)
Definition: variable.c:484
void add_variable_to_head(struct arguments **list, struct variable *var, struct variable *ind)
Definition: variable.c:454
struct arguments * argsinsert
Definition: variable.c:427
static char * loc_nstrdup(const char *in, size_t len)
Definition: variable.c:11
void remove_typedefs(int brace_level)
Definition: variable.c:317
void check_indicator(struct ECPGtype *var)
Definition: variable.c:543
struct variable * find_variable(const char *name)
Definition: variable.c:235
static PgChecksumMode mode
Definition: pg_checksums.c:56
const void size_t len
void * loc_alloc(size_t size)
Definition: util.c:138
char * mm_strdup(const char *string)
Definition: util.c:97
void pg_noreturn void mmfatal(int error_code, const char *error,...) pg_attribute_printf(2
void mmerror(int error_code, enum errortype type, const char *error,...) pg_attribute_printf(3
void * mm_alloc(size_t size)
Definition: util.c:85
#define PARSE_ERROR
FILE * base_yyout
char * name
Definition: type.h:12
struct ECPGtype * type
Definition: type.h:13
struct ECPGstruct_member * next
Definition: type.h:14
Definition: type.h:18
char * type_name
Definition: type.h:20
char * struct_sizeof
Definition: type.h:24
enum ECPGttype type
Definition: type.h:19
struct ECPGstruct_member * members
Definition: type.h:30
char * size
Definition: type.h:22
struct ECPGtype * element
Definition: type.h:28
union ECPGtype::@175 u
int counter
Definition: type.h:32
struct variable * indicator
Definition: type.h:200
struct arguments * next
Definition: type.h:201
struct variable * variable
Definition: type.h:199
Definition: type.h:138
struct arguments * argsinsert
Definition: type.h:144
struct cursor * next
Definition: type.h:148
struct arguments * argsresult
Definition: type.h:146
char * type_index
Definition: type.h:127
char * type_dimension
Definition: type.h:126
char * type_sizeof
Definition: type.h:128
char * type_str
Definition: type.h:125
char * type_storage
Definition: type.h:123
enum ECPGttype type_enum
Definition: type.h:124
Definition: type.h:159
int brace_level
Definition: type.h:163
char * name
Definition: type.h:160
struct ECPGstruct_member * struct_member_list
Definition: type.h:162
struct typedefs * next
Definition: type.h:164
struct this_type * type
Definition: type.h:161
char * name
Definition: type.h:191
struct variable * next
enum ECPGttype type
int brace_level
Definition: type.h:193
struct ECPGtype * ECPGmake_simple_type(enum ECPGttype type, const char *size, int counter)
Definition: type.c:72
void ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype *type, const int brace_level, const char *ind_name, struct ECPGtype *ind_type, const int ind_brace_level, const char *prefix, const char *ind_prefix, char *arr_str_size, const char *struct_sizeof, const char *ind_struct_sizeof)
Definition: type.c:218
void ECPGfree_struct_member(struct ECPGstruct_member *rm)
Definition: type.c:618
void ECPGfree_type(struct ECPGtype *type)
Definition: type.c:632
struct ECPGtype * ECPGmake_array_type(struct ECPGtype *type, const char *size)
Definition: type.c:87
struct ECPGtype * ECPGmake_struct_type(struct ECPGstruct_member *rm, enum ECPGttype type, const char *type_name, const char *struct_sizeof)
Definition: type.c:97
@ ET_ERROR
Definition: type.h:220
const char * type
const char * name