PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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;
373 {
375 if (p == varptr->variable)
376 {
377 /* remove from list */
378 if (prevvar)
380 else
381 ptr->argsinsert = nextvar;
382 free(varptr);
383 }
384 else
385 prevvar = varptr;
386 }
387 for (varptr = ptr->argsresult, prevvar = NULL;
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
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 }
442 for (p = argsresult; p; p = next)
443 {
444 next = p->next;
445 free(p);
446 }
448}
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 */
455void
456add_variable_to_head(struct arguments **list, struct variable *var, struct variable *ind)
457{
458 struct arguments *p = (struct arguments *) mm_alloc(sizeof(struct arguments));
459
460 p->variable = var;
461 p->indicator = ind;
462 p->next = *list;
463 *list = p;
464}
465
466/* Append a new variable to our request list. */
467void
468add_variable_to_tail(struct arguments **list, struct variable *var, struct variable *ind)
469{
470 struct arguments *p,
471 *new = (struct arguments *) mm_alloc(sizeof(struct arguments));
472
473 for (p = *list; p && p->next; p = p->next);
474
475 new->variable = var;
476 new->indicator = ind;
477 new->next = NULL;
478
479 if (p)
480 p->next = new;
481 else
482 *list = new;
483}
484
485void
487{
488 struct arguments *p,
489 *prev = NULL;
490 bool found = false;
491
492 for (p = *list; p; p = p->next)
493 {
494 if (p->variable == var)
495 {
496 found = true;
497 break;
498 }
499 prev = p;
500 }
501 if (found)
502 {
503 if (prev)
504 prev->next = p->next;
505 else
506 *list = p->next;
507 free(p);
508 }
509}
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 */
516void
517dump_variables(struct arguments *list, int mode)
518{
519 char *str_zero;
520
521 if (list == NULL)
522 return;
523
524 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 dump_variables(list->next, mode);
532
533 /* Then the current element and its indicator */
534 ECPGdump_a_type(base_yyout, list->variable->name, list->variable->type, list->variable->brace_level,
535 list->indicator->name, list->indicator->type, list->indicator->brace_level,
537
538 /* Then release the list element. */
539 if (mode != 0)
540 free(list);
541
542 free(str_zero);
543}
544
545void
547{
548 /* make sure this is a valid indicator variable */
549 switch (var->type)
550 {
551 struct ECPGstruct_member *p;
552
553 case ECPGt_short:
554 case ECPGt_int:
555 case ECPGt_long:
556 case ECPGt_long_long:
561 break;
562
563 case ECPGt_struct:
564 case ECPGt_union:
565 for (p = var->u.members; p; p = p->next)
567 break;
568
569 case ECPGt_array:
571 break;
572 default:
573 mmerror(PARSE_ERROR, ET_ERROR, "indicator variable must have an integer type");
574 break;
575 }
576}
577
578struct typedefs *
579get_typedef(const char *name, bool noerror)
580{
581 struct typedefs *this;
582
583 for (this = types; this != NULL; this = this->next)
584 {
585 if (strcmp(this->name, name) == 0)
586 return this;
587 }
588
589 if (!noerror)
590 mmfatal(PARSE_ERROR, "unrecognized data type name \"%s\"", name);
591
592 return NULL;
593}
594
595void
596adjust_array(enum ECPGttype type_enum,
597 const char **dimension, const char **length,
598 const char *type_dimension, const char *type_index,
600{
601 if (atoi(type_index) >= 0)
602 {
603 if (atoi(*length) >= 0)
604 mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
605
606 *length = type_index;
607 }
608
609 if (atoi(type_dimension) >= 0)
610 {
611 if (atoi(*dimension) >= 0 && atoi(*length) >= 0)
612 mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
613
614 if (atoi(*dimension) >= 0)
615 *length = *dimension;
616
617 *dimension = type_dimension;
618 }
619
620 if (pointer_len > 2)
621 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),
624
625 if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && type_enum != ECPGt_string)
626 mmfatal(PARSE_ERROR, "pointer to pointer is not supported for this data type");
627
628 if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
629 mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
630
631 if (atoi(*length) >= 0 && atoi(*dimension) >= 0 && pointer_len)
632 mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
633
634 switch (type_enum)
635 {
636 case ECPGt_struct:
637 case ECPGt_union:
638 /* pointer has to get dimension 0 */
639 if (pointer_len)
640 {
641 *length = *dimension;
642 *dimension = "0";
643 }
644
645 if (atoi(*length) >= 0)
646 mmfatal(PARSE_ERROR, "multidimensional arrays for structures are not supported");
647
648 break;
649 case ECPGt_varchar:
650 case ECPGt_bytea:
651 /* pointer has to get dimension 0 */
652 if (pointer_len)
653 *dimension = "0";
654
655 /* one index is the string length */
656 if (atoi(*length) < 0)
657 {
658 *length = *dimension;
659 *dimension = "-1";
660 }
661
662 break;
663 case ECPGt_char:
665 case ECPGt_string:
666 /* char ** */
667 if (pointer_len == 2)
668 {
669 *length = *dimension = "0";
670 break;
671 }
672
673 /* pointer has to get length 0 */
674 if (pointer_len == 1)
675 *length = "0";
676
677 /* one index is the string length */
678 if (atoi(*length) < 0)
679 {
680 /*
681 * make sure we return length = -1 for arrays without given
682 * bounds
683 */
684 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 *length = "1";
691 else if (strcmp(*dimension, "0") == 0)
692 *length = "-1";
693 else
694 *length = *dimension;
695
696 *dimension = "-1";
697 }
698 break;
699 default:
700 /* a pointer has dimension = 0 */
701 if (pointer_len)
702 {
703 *length = *dimension;
704 *dimension = "0";
705 }
706
707 if (atoi(*length) >= 0)
708 mmfatal(PARSE_ERROR, "multidimensional arrays for simple data types are not supported");
709
710 break;
711 }
712}
static int32 next
Definition blutils.c:225
#define ngettext(s, p, n)
Definition c.h:1270
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
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
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:468
void dump_variables(struct arguments *list, int mode)
Definition variable.c:517
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:596
struct typedefs * get_typedef(const char *name, bool noerror)
Definition variable.c:579
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:486
void add_variable_to_head(struct arguments **list, struct variable *var, struct variable *ind)
Definition variable.c:456
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:546
struct variable * find_variable(const char *name)
Definition variable.c:235
static PgChecksumMode mode
const void size_t len
static int fb(int x)
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
#define free(a)
char * name
Definition type.h:12
struct ECPGtype * type
Definition type.h:13
struct ECPGstruct_member * next
Definition type.h:14
char * type_name
Definition type.h:20
char * struct_sizeof
Definition type.h:24
enum ECPGttype type
Definition type.h:19
union ECPGtype::@181 u
struct ECPGstruct_member * members
Definition type.h:30
char * size
Definition type.h:22
struct ECPGtype * element
Definition type.h:28
int counter
Definition type.h:32
struct variable * indicator
Definition type.h:201
struct arguments * next
Definition type.h:202
struct variable * variable
Definition type.h:200
Definition type.h:139
struct arguments * argsinsert
Definition type.h:145
struct cursor * next
Definition type.h:149
struct arguments * argsresult
Definition type.h:147
char * type_index
Definition type.h:128
char * type_dimension
Definition type.h:127
char * type_sizeof
Definition type.h:129
char * type_str
Definition type.h:126
char * type_storage
Definition type.h:124
enum ECPGttype type_enum
Definition type.h:125
int brace_level
Definition type.h:164
char * name
Definition type.h:161
struct ECPGstruct_member * struct_member_list
Definition type.h:163
struct typedefs * next
Definition type.h:165
struct this_type * type
Definition type.h:162
char * name
Definition type.h:192
struct variable * next
enum ECPGttype type
int brace_level
Definition type.h:194
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:219
void ECPGfree_struct_member(struct ECPGstruct_member *rm)
Definition type.c:621
void ECPGfree_type(struct ECPGtype *type)
Definition type.c:635
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:221
const char * type
const char * name