| 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 | |