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