1 | /* src/interfaces/ecpg/preproc/type.c */ |
2 | |
3 | #include "postgres_fe.h" |
4 | |
5 | #include "preproc_extern.h" |
6 | |
7 | #define indicator_set ind_type != NULL && ind_type->type != ECPGt_NO_INDICATOR |
8 | |
9 | static struct ECPGstruct_member struct_no_indicator = {"no_indicator" , &ecpg_no_indicator, NULL}; |
10 | |
11 | /* malloc + error check */ |
12 | void * |
13 | mm_alloc(size_t size) |
14 | { |
15 | void *ptr = malloc(size); |
16 | |
17 | if (ptr == NULL) |
18 | mmfatal(OUT_OF_MEMORY, "out of memory" ); |
19 | |
20 | return ptr; |
21 | } |
22 | |
23 | /* strdup + error check */ |
24 | char * |
25 | mm_strdup(const char *string) |
26 | { |
27 | char *new = strdup(string); |
28 | |
29 | if (new == NULL) |
30 | mmfatal(OUT_OF_MEMORY, "out of memory" ); |
31 | |
32 | return new; |
33 | } |
34 | |
35 | /* duplicate memberlist */ |
36 | struct ECPGstruct_member * |
37 | ECPGstruct_member_dup(struct ECPGstruct_member *rm) |
38 | { |
39 | struct ECPGstruct_member *new = NULL; |
40 | |
41 | while (rm) |
42 | { |
43 | struct ECPGtype *type; |
44 | |
45 | switch (rm->type->type) |
46 | { |
47 | case ECPGt_struct: |
48 | case ECPGt_union: |
49 | type = ECPGmake_struct_type(rm->type->u.members, rm->type->type, rm->type->type_name, rm->type->struct_sizeof); |
50 | break; |
51 | case ECPGt_array: |
52 | |
53 | /* |
54 | * if this array does contain a struct again, we have to |
55 | * create the struct too |
56 | */ |
57 | if (rm->type->u.element->type == ECPGt_struct || rm->type->u.element->type == ECPGt_union) |
58 | type = ECPGmake_struct_type(rm->type->u.element->u.members, rm->type->u.element->type, rm->type->u.element->type_name, rm->type->u.element->struct_sizeof); |
59 | else |
60 | type = ECPGmake_array_type(ECPGmake_simple_type(rm->type->u.element->type, rm->type->u.element->size, rm->type->u.element->counter), rm->type->size); |
61 | break; |
62 | default: |
63 | type = ECPGmake_simple_type(rm->type->type, rm->type->size, rm->type->counter); |
64 | break; |
65 | } |
66 | |
67 | ECPGmake_struct_member(rm->name, type, &new); |
68 | |
69 | rm = rm->next; |
70 | } |
71 | |
72 | return new; |
73 | } |
74 | |
75 | /* The NAME argument is copied. The type argument is preserved as a pointer. */ |
76 | void |
77 | ECPGmake_struct_member(const char *name, struct ECPGtype *type, struct ECPGstruct_member **start) |
78 | { |
79 | struct ECPGstruct_member *ptr, |
80 | *ne = |
81 | (struct ECPGstruct_member *) mm_alloc(sizeof(struct ECPGstruct_member)); |
82 | |
83 | ne->name = mm_strdup(name); |
84 | ne->type = type; |
85 | ne->next = NULL; |
86 | |
87 | for (ptr = *start; ptr && ptr->next; ptr = ptr->next); |
88 | |
89 | if (ptr) |
90 | ptr->next = ne; |
91 | else |
92 | *start = ne; |
93 | } |
94 | |
95 | struct ECPGtype * |
96 | ECPGmake_simple_type(enum ECPGttype type, char *size, int counter) |
97 | { |
98 | struct ECPGtype *ne = (struct ECPGtype *) mm_alloc(sizeof(struct ECPGtype)); |
99 | |
100 | ne->type = type; |
101 | ne->type_name = NULL; |
102 | ne->size = size; |
103 | ne->u.element = NULL; |
104 | ne->struct_sizeof = NULL; |
105 | ne->counter = counter; /* only needed for varchar and bytea */ |
106 | |
107 | return ne; |
108 | } |
109 | |
110 | struct ECPGtype * |
111 | ECPGmake_array_type(struct ECPGtype *type, char *size) |
112 | { |
113 | struct ECPGtype *ne = ECPGmake_simple_type(ECPGt_array, size, 0); |
114 | |
115 | ne->u.element = type; |
116 | |
117 | return ne; |
118 | } |
119 | |
120 | struct ECPGtype * |
121 | ECPGmake_struct_type(struct ECPGstruct_member *rm, enum ECPGttype type, char *type_name, char *struct_sizeof) |
122 | { |
123 | struct ECPGtype *ne = ECPGmake_simple_type(type, mm_strdup("1" ), 0); |
124 | |
125 | ne->type_name = mm_strdup(type_name); |
126 | ne->u.members = ECPGstruct_member_dup(rm); |
127 | ne->struct_sizeof = struct_sizeof; |
128 | |
129 | return ne; |
130 | } |
131 | |
132 | static const char * |
133 | get_type(enum ECPGttype type) |
134 | { |
135 | switch (type) |
136 | { |
137 | case ECPGt_char: |
138 | return "ECPGt_char" ; |
139 | break; |
140 | case ECPGt_unsigned_char: |
141 | return "ECPGt_unsigned_char" ; |
142 | break; |
143 | case ECPGt_short: |
144 | return "ECPGt_short" ; |
145 | break; |
146 | case ECPGt_unsigned_short: |
147 | return "ECPGt_unsigned_short" ; |
148 | break; |
149 | case ECPGt_int: |
150 | return "ECPGt_int" ; |
151 | break; |
152 | case ECPGt_unsigned_int: |
153 | return "ECPGt_unsigned_int" ; |
154 | break; |
155 | case ECPGt_long: |
156 | return "ECPGt_long" ; |
157 | break; |
158 | case ECPGt_unsigned_long: |
159 | return "ECPGt_unsigned_long" ; |
160 | break; |
161 | case ECPGt_long_long: |
162 | return "ECPGt_long_long" ; |
163 | break; |
164 | case ECPGt_unsigned_long_long: |
165 | return "ECPGt_unsigned_long_long" ; |
166 | break; |
167 | case ECPGt_float: |
168 | return "ECPGt_float" ; |
169 | break; |
170 | case ECPGt_double: |
171 | return "ECPGt_double" ; |
172 | break; |
173 | case ECPGt_bool: |
174 | return "ECPGt_bool" ; |
175 | break; |
176 | case ECPGt_varchar: |
177 | return "ECPGt_varchar" ; |
178 | case ECPGt_bytea: |
179 | return "ECPGt_bytea" ; |
180 | case ECPGt_NO_INDICATOR: /* no indicator */ |
181 | return "ECPGt_NO_INDICATOR" ; |
182 | break; |
183 | case ECPGt_char_variable: /* string that should not be quoted */ |
184 | return "ECPGt_char_variable" ; |
185 | break; |
186 | case ECPGt_const: /* constant string quoted */ |
187 | return "ECPGt_const" ; |
188 | break; |
189 | case ECPGt_decimal: |
190 | return "ECPGt_decimal" ; |
191 | break; |
192 | case ECPGt_numeric: |
193 | return "ECPGt_numeric" ; |
194 | break; |
195 | case ECPGt_interval: |
196 | return "ECPGt_interval" ; |
197 | break; |
198 | case ECPGt_descriptor: |
199 | return "ECPGt_descriptor" ; |
200 | break; |
201 | case ECPGt_sqlda: |
202 | return "ECPGt_sqlda" ; |
203 | break; |
204 | case ECPGt_date: |
205 | return "ECPGt_date" ; |
206 | break; |
207 | case ECPGt_timestamp: |
208 | return "ECPGt_timestamp" ; |
209 | break; |
210 | case ECPGt_string: |
211 | return "ECPGt_string" ; |
212 | break; |
213 | default: |
214 | mmerror(PARSE_ERROR, ET_ERROR, "unrecognized variable type code %d" , type); |
215 | } |
216 | |
217 | return NULL; |
218 | } |
219 | |
220 | /* Dump a type. |
221 | The type is dumped as: |
222 | type-tag <comma> - enum ECPGttype |
223 | reference-to-variable <comma> - char * |
224 | size <comma> - long size of this field (if varchar) |
225 | arrsize <comma> - long number of elements in the arr |
226 | offset <comma> - offset to the next element |
227 | Where: |
228 | type-tag is one of the simple types or varchar. |
229 | reference-to-variable can be a reference to a struct element. |
230 | arrsize is the size of the array in case of array fetches. Otherwise 0. |
231 | size is the maxsize in case it is a varchar. Otherwise it is the size of |
232 | the variable (required to do array fetches of structs). |
233 | */ |
234 | static void ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype type, |
235 | char *varcharsize, |
236 | char *arrsize, const char *size, const char *prefix, int); |
237 | static void ECPGdump_a_struct(FILE *o, const char *name, const char *ind_name, char *arrsize, |
238 | struct ECPGtype *type, struct ECPGtype *ind_type, const char *prefix, const char *ind_prefix); |
239 | |
240 | void |
241 | ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype *type, const int brace_level, |
242 | const char *ind_name, struct ECPGtype *ind_type, const int ind_brace_level, |
243 | const char *prefix, const char *ind_prefix, |
244 | char *arr_str_size, const char *struct_sizeof, |
245 | const char *ind_struct_sizeof) |
246 | { |
247 | struct variable *var; |
248 | |
249 | if (type->type != ECPGt_descriptor && type->type != ECPGt_sqlda && |
250 | type->type != ECPGt_char_variable && type->type != ECPGt_const && |
251 | brace_level >= 0) |
252 | { |
253 | char *str; |
254 | |
255 | str = mm_strdup(name); |
256 | var = find_variable(str); |
257 | free(str); |
258 | |
259 | if ((var->type->type != type->type) || |
260 | (var->type->type_name && !type->type_name) || |
261 | (!var->type->type_name && type->type_name) || |
262 | (var->type->type_name && type->type_name && strcmp(var->type->type_name, type->type_name) != 0)) |
263 | mmerror(PARSE_ERROR, ET_ERROR, "variable \"%s\" is hidden by a local variable of a different type" , name); |
264 | else if (var->brace_level != brace_level) |
265 | mmerror(PARSE_ERROR, ET_WARNING, "variable \"%s\" is hidden by a local variable" , name); |
266 | |
267 | if (ind_name && ind_type && ind_type->type != ECPGt_NO_INDICATOR && ind_brace_level >= 0) |
268 | { |
269 | str = mm_strdup(ind_name); |
270 | var = find_variable(str); |
271 | free(str); |
272 | |
273 | if ((var->type->type != ind_type->type) || |
274 | (var->type->type_name && !ind_type->type_name) || |
275 | (!var->type->type_name && ind_type->type_name) || |
276 | (var->type->type_name && ind_type->type_name && strcmp(var->type->type_name, ind_type->type_name) != 0)) |
277 | mmerror(PARSE_ERROR, ET_ERROR, "indicator variable \"%s\" is hidden by a local variable of a different type" , ind_name); |
278 | else if (var->brace_level != ind_brace_level) |
279 | mmerror(PARSE_ERROR, ET_WARNING, "indicator variable \"%s\" is hidden by a local variable" , ind_name); |
280 | } |
281 | } |
282 | |
283 | switch (type->type) |
284 | { |
285 | case ECPGt_array: |
286 | if (indicator_set && ind_type->type != ECPGt_array) |
287 | mmfatal(INDICATOR_NOT_ARRAY, "indicator for array/pointer has to be array/pointer" ); |
288 | switch (type->u.element->type) |
289 | { |
290 | case ECPGt_array: |
291 | mmerror(PARSE_ERROR, ET_ERROR, "nested arrays are not supported (except strings)" ); /* array of array */ |
292 | break; |
293 | case ECPGt_struct: |
294 | case ECPGt_union: |
295 | ECPGdump_a_struct(o, name, |
296 | ind_name, |
297 | type->size, |
298 | type->u.element, |
299 | (ind_type == NULL) ? NULL : ((ind_type->type == ECPGt_NO_INDICATOR) ? ind_type : ind_type->u.element), |
300 | prefix, ind_prefix); |
301 | break; |
302 | default: |
303 | if (!IS_SIMPLE_TYPE(type->u.element->type)) |
304 | base_yyerror("internal error: unknown datatype, please report this to <pgsql-bugs@lists.postgresql.org>" ); |
305 | |
306 | ECPGdump_a_simple(o, name, |
307 | type->u.element->type, |
308 | type->u.element->size, type->size, struct_sizeof ? struct_sizeof : NULL, |
309 | prefix, type->u.element->counter); |
310 | |
311 | if (ind_type != NULL) |
312 | { |
313 | if (ind_type->type == ECPGt_NO_INDICATOR) |
314 | { |
315 | char *str_neg_one = mm_strdup("-1" ); |
316 | |
317 | ECPGdump_a_simple(o, ind_name, ind_type->type, ind_type->size, str_neg_one, NULL, ind_prefix, 0); |
318 | free(str_neg_one); |
319 | } |
320 | else |
321 | { |
322 | ECPGdump_a_simple(o, ind_name, ind_type->u.element->type, |
323 | ind_type->u.element->size, ind_type->size, NULL, ind_prefix, 0); |
324 | } |
325 | } |
326 | } |
327 | break; |
328 | case ECPGt_struct: |
329 | { |
330 | char *str_one = mm_strdup("1" ); |
331 | |
332 | if (indicator_set && ind_type->type != ECPGt_struct) |
333 | mmfatal(INDICATOR_NOT_STRUCT, "indicator for struct has to be a struct" ); |
334 | |
335 | ECPGdump_a_struct(o, name, ind_name, str_one, type, ind_type, prefix, ind_prefix); |
336 | free(str_one); |
337 | } |
338 | break; |
339 | case ECPGt_union: /* cannot dump a complete union */ |
340 | base_yyerror("type of union has to be specified" ); |
341 | break; |
342 | case ECPGt_char_variable: |
343 | { |
344 | /* |
345 | * Allocate for each, as there are code-paths where the values |
346 | * get stomped on. |
347 | */ |
348 | char *str_varchar_one = mm_strdup("1" ); |
349 | char *str_arr_one = mm_strdup("1" ); |
350 | char *str_neg_one = mm_strdup("-1" ); |
351 | |
352 | if (indicator_set && (ind_type->type == ECPGt_struct || ind_type->type == ECPGt_array)) |
353 | mmfatal(INDICATOR_NOT_SIMPLE, "indicator for simple data type has to be simple" ); |
354 | |
355 | ECPGdump_a_simple(o, name, type->type, str_varchar_one, (arr_str_size && strcmp(arr_str_size, "0" ) != 0) ? arr_str_size : str_arr_one, struct_sizeof, prefix, 0); |
356 | if (ind_type != NULL) |
357 | ECPGdump_a_simple(o, ind_name, ind_type->type, ind_type->size, (arr_str_size && strcmp(arr_str_size, "0" ) != 0) ? arr_str_size : str_neg_one, ind_struct_sizeof, ind_prefix, 0); |
358 | |
359 | free(str_varchar_one); |
360 | free(str_arr_one); |
361 | free(str_neg_one); |
362 | } |
363 | break; |
364 | case ECPGt_descriptor: |
365 | { |
366 | /* |
367 | * Allocate for each, as there are code-paths where the values |
368 | * get stomped on. |
369 | */ |
370 | char *str_neg_one = mm_strdup("-1" ); |
371 | char *ind_type_neg_one = mm_strdup("-1" ); |
372 | |
373 | if (indicator_set && (ind_type->type == ECPGt_struct || ind_type->type == ECPGt_array)) |
374 | mmfatal(INDICATOR_NOT_SIMPLE, "indicator for simple data type has to be simple" ); |
375 | |
376 | ECPGdump_a_simple(o, name, type->type, NULL, str_neg_one, NULL, prefix, 0); |
377 | if (ind_type != NULL) |
378 | ECPGdump_a_simple(o, ind_name, ind_type->type, ind_type->size, ind_type_neg_one, NULL, ind_prefix, 0); |
379 | |
380 | free(str_neg_one); |
381 | free(ind_type_neg_one); |
382 | } |
383 | break; |
384 | default: |
385 | { |
386 | /* |
387 | * Allocate for each, as there are code-paths where the values |
388 | * get stomped on. |
389 | */ |
390 | char *str_neg_one = mm_strdup("-1" ); |
391 | char *ind_type_neg_one = mm_strdup("-1" ); |
392 | |
393 | if (indicator_set && (ind_type->type == ECPGt_struct || ind_type->type == ECPGt_array)) |
394 | mmfatal(INDICATOR_NOT_SIMPLE, "indicator for simple data type has to be simple" ); |
395 | |
396 | ECPGdump_a_simple(o, name, type->type, type->size, (arr_str_size && strcmp(arr_str_size, "0" ) != 0) ? arr_str_size : str_neg_one, struct_sizeof, prefix, type->counter); |
397 | if (ind_type != NULL) |
398 | ECPGdump_a_simple(o, ind_name, ind_type->type, ind_type->size, (arr_str_size && strcmp(arr_str_size, "0" ) != 0) ? arr_str_size : ind_type_neg_one, ind_struct_sizeof, ind_prefix, 0); |
399 | |
400 | free(str_neg_one); |
401 | free(ind_type_neg_one); |
402 | } |
403 | break; |
404 | } |
405 | } |
406 | |
407 | |
408 | /* If size is NULL, then the offset is 0, if not use size as a |
409 | string, it represents the offset needed if we are in an array of structs. */ |
410 | static void |
411 | ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype type, |
412 | char *varcharsize, |
413 | char *arrsize, |
414 | const char *size, |
415 | const char *prefix, |
416 | int counter) |
417 | { |
418 | if (type == ECPGt_NO_INDICATOR) |
419 | fprintf(o, "\n\tECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, " ); |
420 | else if (type == ECPGt_descriptor) |
421 | /* remember that name here already contains quotes (if needed) */ |
422 | fprintf(o, "\n\tECPGt_descriptor, %s, 1L, 1L, 1L, " , name); |
423 | else if (type == ECPGt_sqlda) |
424 | fprintf(o, "\n\tECPGt_sqlda, &%s, 0L, 0L, 0L, " , name); |
425 | else |
426 | { |
427 | char *variable = (char *) mm_alloc(strlen(name) + ((prefix == NULL) ? 0 : strlen(prefix)) + 4); |
428 | char *offset = (char *) mm_alloc(strlen(name) + strlen("sizeof(struct varchar_)" ) + 1 + strlen(varcharsize) + sizeof(int) * CHAR_BIT * 10 / 3); |
429 | char *struct_name; |
430 | |
431 | switch (type) |
432 | { |
433 | /* |
434 | * we have to use the & operator except for arrays and |
435 | * pointers |
436 | */ |
437 | |
438 | case ECPGt_varchar: |
439 | case ECPGt_bytea: |
440 | |
441 | /* |
442 | * we have to use the pointer except for arrays with given |
443 | * bounds |
444 | */ |
445 | if (((atoi(arrsize) > 0) || |
446 | (atoi(arrsize) == 0 && strcmp(arrsize, "0" ) != 0)) && |
447 | size == NULL) |
448 | sprintf(variable, "(%s%s)" , prefix ? prefix : "" , name); |
449 | else |
450 | sprintf(variable, "&(%s%s)" , prefix ? prefix : "" , name); |
451 | |
452 | /* |
453 | * If we created a varchar structure automatically, counter is |
454 | * greater than 0. |
455 | */ |
456 | if (type == ECPGt_varchar) |
457 | struct_name = "struct varchar" ; |
458 | else |
459 | struct_name = "struct bytea" ; |
460 | |
461 | if (counter) |
462 | sprintf(offset, "sizeof(%s_%d)" , struct_name, counter); |
463 | else |
464 | sprintf(offset, "sizeof(%s)" , struct_name); |
465 | break; |
466 | case ECPGt_char: |
467 | case ECPGt_unsigned_char: |
468 | case ECPGt_char_variable: |
469 | case ECPGt_string: |
470 | { |
471 | char *sizeof_name = "char" ; |
472 | |
473 | /* |
474 | * we have to use the pointer except for arrays with given |
475 | * bounds, ecpglib will distinguish between * and [] |
476 | */ |
477 | if ((atoi(varcharsize) > 1 || |
478 | (atoi(arrsize) > 0) || |
479 | (atoi(varcharsize) == 0 && strcmp(varcharsize, "0" ) != 0) || |
480 | (atoi(arrsize) == 0 && strcmp(arrsize, "0" ) != 0)) |
481 | && size == NULL) |
482 | { |
483 | sprintf(variable, "(%s%s)" , prefix ? prefix : "" , name); |
484 | if ((type == ECPGt_char || type == ECPGt_unsigned_char) && |
485 | strcmp(varcharsize, "0" ) == 0) |
486 | { |
487 | /* |
488 | * If this is an array of char *, the offset would |
489 | * be sizeof(char *) and not sizeof(char). |
490 | */ |
491 | sizeof_name = "char *" ; |
492 | } |
493 | } |
494 | else |
495 | sprintf(variable, "&(%s%s)" , prefix ? prefix : "" , name); |
496 | |
497 | sprintf(offset, "(%s)*sizeof(%s)" , strcmp(varcharsize, "0" ) == 0 ? "1" : varcharsize, sizeof_name); |
498 | break; |
499 | } |
500 | case ECPGt_numeric: |
501 | |
502 | /* |
503 | * we have to use a pointer here |
504 | */ |
505 | sprintf(variable, "&(%s%s)" , prefix ? prefix : "" , name); |
506 | sprintf(offset, "sizeof(numeric)" ); |
507 | break; |
508 | case ECPGt_interval: |
509 | |
510 | /* |
511 | * we have to use a pointer here |
512 | */ |
513 | sprintf(variable, "&(%s%s)" , prefix ? prefix : "" , name); |
514 | sprintf(offset, "sizeof(interval)" ); |
515 | break; |
516 | case ECPGt_date: |
517 | |
518 | /* |
519 | * we have to use a pointer and translate the variable type |
520 | */ |
521 | sprintf(variable, "&(%s%s)" , prefix ? prefix : "" , name); |
522 | sprintf(offset, "sizeof(date)" ); |
523 | break; |
524 | case ECPGt_timestamp: |
525 | |
526 | /* |
527 | * we have to use a pointer and translate the variable type |
528 | */ |
529 | sprintf(variable, "&(%s%s)" , prefix ? prefix : "" , name); |
530 | sprintf(offset, "sizeof(timestamp)" ); |
531 | break; |
532 | case ECPGt_const: |
533 | |
534 | /* |
535 | * just dump the const as string |
536 | */ |
537 | sprintf(variable, "\"%s\"" , name); |
538 | sprintf(offset, "strlen(\"%s\")" , name); |
539 | break; |
540 | default: |
541 | |
542 | /* |
543 | * we have to use the pointer except for arrays with given |
544 | * bounds |
545 | */ |
546 | if (((atoi(arrsize) > 0) || |
547 | (atoi(arrsize) == 0 && strcmp(arrsize, "0" ) != 0)) && |
548 | size == NULL) |
549 | sprintf(variable, "(%s%s)" , prefix ? prefix : "" , name); |
550 | else |
551 | sprintf(variable, "&(%s%s)" , prefix ? prefix : "" , name); |
552 | |
553 | sprintf(offset, "sizeof(%s)" , ecpg_type_name(type)); |
554 | break; |
555 | } |
556 | |
557 | /* |
558 | * Array size would be -1 for addresses of members within structure, |
559 | * when pointer to structure is being dumped. |
560 | */ |
561 | if (atoi(arrsize) < 0 && !size) |
562 | strcpy(arrsize, "1" ); |
563 | |
564 | /* |
565 | * If size i.e. the size of structure of which this variable is part |
566 | * of, that gives the offset to the next element, if required |
567 | */ |
568 | if (size == NULL || strlen(size) == 0) |
569 | fprintf(o, "\n\t%s,%s,(long)%s,(long)%s,%s, " , get_type(type), variable, varcharsize, arrsize, offset); |
570 | else |
571 | fprintf(o, "\n\t%s,%s,(long)%s,(long)%s,%s, " , get_type(type), variable, varcharsize, arrsize, size); |
572 | |
573 | free(variable); |
574 | free(offset); |
575 | } |
576 | } |
577 | |
578 | |
579 | /* Penetrate a struct and dump the contents. */ |
580 | static void |
581 | ECPGdump_a_struct(FILE *o, const char *name, const char *ind_name, char *arrsize, struct ECPGtype *type, struct ECPGtype *ind_type, const char *prefix, const char *ind_prefix) |
582 | { |
583 | /* |
584 | * If offset is NULL, then this is the first recursive level. If not then |
585 | * we are in a struct and the offset is used as offset. |
586 | */ |
587 | struct ECPGstruct_member *p, |
588 | *ind_p = NULL; |
589 | char *pbuf = (char *) mm_alloc(strlen(name) + ((prefix == NULL) ? 0 : strlen(prefix)) + 3); |
590 | char *ind_pbuf = (char *) mm_alloc(strlen(ind_name) + ((ind_prefix == NULL) ? 0 : strlen(ind_prefix)) + 3); |
591 | |
592 | if (atoi(arrsize) == 1) |
593 | sprintf(pbuf, "%s%s." , prefix ? prefix : "" , name); |
594 | else |
595 | sprintf(pbuf, "%s%s->" , prefix ? prefix : "" , name); |
596 | |
597 | prefix = pbuf; |
598 | |
599 | if (ind_type == &ecpg_no_indicator) |
600 | ind_p = &struct_no_indicator; |
601 | else if (ind_type != NULL) |
602 | { |
603 | if (atoi(arrsize) == 1) |
604 | sprintf(ind_pbuf, "%s%s." , ind_prefix ? ind_prefix : "" , ind_name); |
605 | else |
606 | sprintf(ind_pbuf, "%s%s->" , ind_prefix ? ind_prefix : "" , ind_name); |
607 | |
608 | ind_prefix = ind_pbuf; |
609 | ind_p = ind_type->u.members; |
610 | } |
611 | |
612 | for (p = type->u.members; p; p = p->next) |
613 | { |
614 | ECPGdump_a_type(o, p->name, p->type, -1, |
615 | (ind_p != NULL) ? ind_p->name : NULL, |
616 | (ind_p != NULL) ? ind_p->type : NULL, |
617 | -1, |
618 | prefix, ind_prefix, arrsize, type->struct_sizeof, |
619 | (ind_p != NULL) ? ind_type->struct_sizeof : NULL); |
620 | if (ind_p != NULL && ind_p != &struct_no_indicator) |
621 | { |
622 | ind_p = ind_p->next; |
623 | if (ind_p == NULL && p->next != NULL) |
624 | { |
625 | mmerror(PARSE_ERROR, ET_WARNING, "indicator struct \"%s\" has too few members" , ind_name); |
626 | ind_p = &struct_no_indicator; |
627 | } |
628 | } |
629 | } |
630 | |
631 | if (ind_type != NULL && ind_p != NULL && ind_p != &struct_no_indicator) |
632 | { |
633 | mmerror(PARSE_ERROR, ET_WARNING, "indicator struct \"%s\" has too many members" , ind_name); |
634 | } |
635 | |
636 | free(pbuf); |
637 | free(ind_pbuf); |
638 | } |
639 | |
640 | void |
641 | ECPGfree_struct_member(struct ECPGstruct_member *rm) |
642 | { |
643 | while (rm) |
644 | { |
645 | struct ECPGstruct_member *p = rm; |
646 | |
647 | rm = rm->next; |
648 | free(p->name); |
649 | free(p->type); |
650 | free(p); |
651 | } |
652 | } |
653 | |
654 | void |
655 | ECPGfree_type(struct ECPGtype *type) |
656 | { |
657 | if (!IS_SIMPLE_TYPE(type->type)) |
658 | { |
659 | switch (type->type) |
660 | { |
661 | case ECPGt_array: |
662 | switch (type->u.element->type) |
663 | { |
664 | case ECPGt_array: |
665 | base_yyerror("internal error: found multidimensional array\n" ); |
666 | break; |
667 | case ECPGt_struct: |
668 | case ECPGt_union: |
669 | /* Array of structs. */ |
670 | ECPGfree_struct_member(type->u.element->u.members); |
671 | free(type->u.element); |
672 | break; |
673 | default: |
674 | if (!IS_SIMPLE_TYPE(type->u.element->type)) |
675 | base_yyerror("internal error: unknown datatype, please report this to <pgsql-bugs@lists.postgresql.org>" ); |
676 | |
677 | free(type->u.element); |
678 | } |
679 | break; |
680 | case ECPGt_struct: |
681 | case ECPGt_union: |
682 | ECPGfree_struct_member(type->u.members); |
683 | break; |
684 | default: |
685 | mmerror(PARSE_ERROR, ET_ERROR, "unrecognized variable type code %d" , type->type); |
686 | break; |
687 | } |
688 | } |
689 | free(type); |
690 | } |
691 | |
692 | const char * |
693 | get_dtype(enum ECPGdtype type) |
694 | { |
695 | switch (type) |
696 | { |
697 | case ECPGd_count: |
698 | return "ECPGd_countr" ; |
699 | break; |
700 | case ECPGd_data: |
701 | return "ECPGd_data" ; |
702 | break; |
703 | case ECPGd_di_code: |
704 | return "ECPGd_di_code" ; |
705 | break; |
706 | case ECPGd_di_precision: |
707 | return "ECPGd_di_precision" ; |
708 | break; |
709 | case ECPGd_indicator: |
710 | return "ECPGd_indicator" ; |
711 | break; |
712 | case ECPGd_key_member: |
713 | return "ECPGd_key_member" ; |
714 | break; |
715 | case ECPGd_length: |
716 | return "ECPGd_length" ; |
717 | break; |
718 | case ECPGd_name: |
719 | return "ECPGd_name" ; |
720 | break; |
721 | case ECPGd_nullable: |
722 | return "ECPGd_nullable" ; |
723 | break; |
724 | case ECPGd_octet: |
725 | return "ECPGd_octet" ; |
726 | break; |
727 | case ECPGd_precision: |
728 | return "ECPGd_precision" ; |
729 | break; |
730 | case ECPGd_ret_length: |
731 | return "ECPGd_ret_length" ; |
732 | case ECPGd_ret_octet: |
733 | return "ECPGd_ret_octet" ; |
734 | break; |
735 | case ECPGd_scale: |
736 | return "ECPGd_scale" ; |
737 | break; |
738 | case ECPGd_type: |
739 | return "ECPGd_type" ; |
740 | break; |
741 | case ECPGd_cardinality: |
742 | return "ECPGd_cardinality" ; |
743 | default: |
744 | mmerror(PARSE_ERROR, ET_ERROR, "unrecognized descriptor item code %d" , type); |
745 | } |
746 | |
747 | return NULL; |
748 | } |
749 | |