| 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; |
| 16 | p->brace_level = brace_level; |
| 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: |
| 47 | return new_variable(name, ECPGmake_array_type(ECPGmake_simple_type(members->type->u.element->type, members->type->u.element->size, members->type->u.element->counter), members->type->size), brace_level); |
| 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: |
| 94 | return new_variable(name, ECPGmake_array_type(ECPGmake_simple_type(members->type->u.element->u.element->type, members->type->u.element->u.element->size, members->type->u.element->u.element->counter), members->type->u.element->size), brace_level); |
| 95 | case ECPGt_struct: |
| 96 | case ECPGt_union: |
| 97 | return new_variable(name, ECPGmake_struct_type(members->type->u.element->u.members, members->type->u.element->type, members->type->u.element->type_name, members->type->u.element->struct_sizeof), brace_level); |
| 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 * |
| 178 | find_simple(char *name) |
| 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 * |
| 194 | find_variable(char *name) |
| 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 |
| 261 | remove_typedefs(int brace_level) |
| 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) |
| 277 | free(p->struct_member_list); |
| 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 |
| 295 | remove_variables(int brace_level) |
| 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 |
| 369 | reset_variables(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 |
| 409 | remove_variable_from_list(struct arguments **list, struct variable *var) |
| 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 |
| 438 | dump_variables(struct arguments *list, int mode) |
| 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 |
| 467 | check_indicator(struct ECPGtype *var) |
| 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: |
| 478 | case ECPGt_unsigned_short: |
| 479 | case ECPGt_unsigned_int: |
| 480 | case ECPGt_unsigned_long: |
| 481 | case ECPGt_unsigned_long_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(char *name) |
| 501 | { |
| 502 | struct typedefs *this; |
| 503 | |
| 504 | for (this = types; this && strcmp(this->name, name) != 0; this = this->next); |
| 505 | if (!this) |
| 506 | mmfatal(PARSE_ERROR, "unrecognized data type name \"%s\"" , name); |
| 507 | |
| 508 | return this; |
| 509 | } |
| 510 | |
| 511 | void |
| 512 | adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *type_dimension, char *type_index, int pointer_len, bool type_definition) |
| 513 | { |
| 514 | if (atoi(type_index) >= 0) |
| 515 | { |
| 516 | if (atoi(*length) >= 0) |
| 517 | mmfatal(PARSE_ERROR, "multidimensional arrays are not supported" ); |
| 518 | |
| 519 | *length = type_index; |
| 520 | } |
| 521 | |
| 522 | if (atoi(type_dimension) >= 0) |
| 523 | { |
| 524 | if (atoi(*dimension) >= 0 && atoi(*length) >= 0) |
| 525 | mmfatal(PARSE_ERROR, "multidimensional arrays are not supported" ); |
| 526 | |
| 527 | if (atoi(*dimension) >= 0) |
| 528 | *length = *dimension; |
| 529 | |
| 530 | *dimension = type_dimension; |
| 531 | } |
| 532 | |
| 533 | if (pointer_len > 2) |
| 534 | mmfatal(PARSE_ERROR, ngettext("multilevel pointers (more than 2 levels) are not supported; found %d level" , |
| 535 | "multilevel pointers (more than 2 levels) are not supported; found %d levels" , pointer_len), |
| 536 | pointer_len); |
| 537 | |
| 538 | if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && type_enum != ECPGt_string) |
| 539 | mmfatal(PARSE_ERROR, "pointer to pointer is not supported for this data type" ); |
| 540 | |
| 541 | if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0)) |
| 542 | mmfatal(PARSE_ERROR, "multidimensional arrays are not supported" ); |
| 543 | |
| 544 | if (atoi(*length) >= 0 && atoi(*dimension) >= 0 && pointer_len) |
| 545 | mmfatal(PARSE_ERROR, "multidimensional arrays are not supported" ); |
| 546 | |
| 547 | switch (type_enum) |
| 548 | { |
| 549 | case ECPGt_struct: |
| 550 | case ECPGt_union: |
| 551 | /* pointer has to get dimension 0 */ |
| 552 | if (pointer_len) |
| 553 | { |
| 554 | *length = *dimension; |
| 555 | *dimension = mm_strdup("0" ); |
| 556 | } |
| 557 | |
| 558 | if (atoi(*length) >= 0) |
| 559 | mmfatal(PARSE_ERROR, "multidimensional arrays for structures are not supported" ); |
| 560 | |
| 561 | break; |
| 562 | case ECPGt_varchar: |
| 563 | case ECPGt_bytea: |
| 564 | /* pointer has to get dimension 0 */ |
| 565 | if (pointer_len) |
| 566 | *dimension = mm_strdup("0" ); |
| 567 | |
| 568 | /* one index is the string length */ |
| 569 | if (atoi(*length) < 0) |
| 570 | { |
| 571 | *length = *dimension; |
| 572 | *dimension = mm_strdup("-1" ); |
| 573 | } |
| 574 | |
| 575 | break; |
| 576 | case ECPGt_char: |
| 577 | case ECPGt_unsigned_char: |
| 578 | case ECPGt_string: |
| 579 | /* char ** */ |
| 580 | if (pointer_len == 2) |
| 581 | { |
| 582 | *length = *dimension = mm_strdup("0" ); |
| 583 | break; |
| 584 | } |
| 585 | |
| 586 | /* pointer has to get length 0 */ |
| 587 | if (pointer_len == 1) |
| 588 | *length = mm_strdup("0" ); |
| 589 | |
| 590 | /* one index is the string length */ |
| 591 | if (atoi(*length) < 0) |
| 592 | { |
| 593 | /* |
| 594 | * make sure we return length = -1 for arrays without given |
| 595 | * bounds |
| 596 | */ |
| 597 | if (atoi(*dimension) < 0 && !type_definition) |
| 598 | |
| 599 | /* |
| 600 | * do not change this for typedefs since it will be |
| 601 | * changed later on when the variable is defined |
| 602 | */ |
| 603 | *length = mm_strdup("1" ); |
| 604 | else if (strcmp(*dimension, "0" ) == 0) |
| 605 | *length = mm_strdup("-1" ); |
| 606 | else |
| 607 | *length = *dimension; |
| 608 | |
| 609 | *dimension = mm_strdup("-1" ); |
| 610 | } |
| 611 | break; |
| 612 | default: |
| 613 | /* a pointer has dimension = 0 */ |
| 614 | if (pointer_len) |
| 615 | { |
| 616 | *length = *dimension; |
| 617 | *dimension = mm_strdup("0" ); |
| 618 | } |
| 619 | |
| 620 | if (atoi(*length) >= 0) |
| 621 | mmfatal(PARSE_ERROR, "multidimensional arrays for simple data types are not supported" ); |
| 622 | |
| 623 | break; |
| 624 | } |
| 625 | } |
| 626 | |