1/* src/interfaces/ecpg/preproc/ecpg.header */ 2 3/* Copyright comment */ 4%{ 5#include "postgres_fe.h" 6 7#include "extern.h" 8#include "ecpg_config.h" 9#include <unistd.h> 10 11/* Location tracking support --- simpler than bison's default */ 12#define YYLLOC_DEFAULT(Current, Rhs, N) \ 13 do { \ 14 if (N) \ 15 (Current) = (Rhs)[1]; \ 16 else \ 17 (Current) = (Rhs)[0]; \ 18 } while (0) 19 20/* 21 * The %name-prefix option below will make bison call base_yylex, but we 22 * really want it to call filtered_base_yylex (see parser.c). 23 */ 24#define base_yylex filtered_base_yylex 25 26/* 27 * This is only here so the string gets into the POT. Bison uses it 28 * internally. 29 */ 30#define bison_gettext_dummy gettext_noop("syntax error") 31 32/* 33 * Variables containing simple states. 34 */ 35int struct_level = 0; 36int braces_open; /* brace level counter */ 37char *current_function; 38int ecpg_internal_var = 0; 39char *connection = NULL; 40char *input_filename = NULL; 41 42static int FoundInto = 0; 43static int initializer = 0; 44static int pacounter = 1; 45static char pacounter_buffer[sizeof(int) * CHAR_BIT * 10 / 3]; /* a rough guess at the size we need */ 46static struct this_type actual_type[STRUCT_DEPTH]; 47static char *actual_startline[STRUCT_DEPTH]; 48static int varchar_counter = 1; 49 50/* temporarily store struct members while creating the data structure */ 51struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = { NULL }; 52 53/* also store struct type so we can do a sizeof() later */ 54static char *ECPGstruct_sizeof = NULL; 55 56/* for forward declarations we have to store some data as well */ 57static char *forward_name = NULL; 58 59struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, NULL, NULL, NULL, {NULL}, 0}; 60struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL}; 61 62static struct ECPGtype ecpg_query = {ECPGt_char_variable, NULL, NULL, NULL, {NULL}, 0}; 63 64static void vmmerror(int error_code, enum errortype type, const char *error, va_list ap) pg_attribute_printf(3, 0); 65 66/* 67 * Handle parsing errors and warnings 68 */ 69static void 70vmmerror(int error_code, enum errortype type, const char *error, va_list ap) 71{ 72 /* localize the error message string */ 73 error = _(error); 74 75 fprintf(stderr, "%s:%d: ", input_filename, base_yylineno); 76 77 switch(type) 78 { 79 case ET_WARNING: 80 fprintf(stderr, _("WARNING: ")); 81 break; 82 case ET_ERROR: 83 fprintf(stderr, _("ERROR: ")); 84 break; 85 } 86 87 vfprintf(stderr, error, ap); 88 89 fprintf(stderr, "\n"); 90 91 switch(type) 92 { 93 case ET_WARNING: 94 break; 95 case ET_ERROR: 96 ret_value = error_code; 97 break; 98 } 99} 100 101void 102mmerror(int error_code, enum errortype type, const char *error, ...) 103{ 104 va_list ap; 105 106 va_start(ap, error); 107 vmmerror(error_code, type, error, ap); 108 va_end(ap); 109} 110 111void 112mmfatal(int error_code, const char *error, ...) 113{ 114 va_list ap; 115 116 va_start(ap, error); 117 vmmerror(error_code, ET_ERROR, error, ap); 118 va_end(ap); 119 120 if (base_yyin) 121 fclose(base_yyin); 122 if (base_yyout) 123 fclose(base_yyout); 124 125 if (strcmp(output_filename, "-") != 0 && unlink(output_filename) != 0) 126 fprintf(stderr, _("could not remove output file \"%s\"\n"), output_filename); 127 exit(error_code); 128} 129 130/* 131 * string concatenation 132 */ 133 134static char * 135cat2_str(char *str1, char *str2) 136{ 137 char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) + 2); 138 139 strcpy(res_str, str1); 140 if (strlen(str1) != 0 && strlen(str2) != 0) 141 strcat(res_str, " "); 142 strcat(res_str, str2); 143 free(str1); 144 free(str2); 145 return(res_str); 146} 147 148static char * 149cat_str(int count, ...) 150{ 151 va_list args; 152 int i; 153 char *res_str; 154 155 va_start(args, count); 156 157 res_str = va_arg(args, char *); 158 159 /* now add all other strings */ 160 for (i = 1; i < count; i++) 161 res_str = cat2_str(res_str, va_arg(args, char *)); 162 163 va_end(args); 164 165 return(res_str); 166} 167 168static char * 169make2_str(char *str1, char *str2) 170{ 171 char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) + 1); 172 173 strcpy(res_str, str1); 174 strcat(res_str, str2); 175 free(str1); 176 free(str2); 177 return(res_str); 178} 179 180static char * 181make3_str(char *str1, char *str2, char *str3) 182{ 183 char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) +strlen(str3) + 1); 184 185 strcpy(res_str, str1); 186 strcat(res_str, str2); 187 strcat(res_str, str3); 188 free(str1); 189 free(str2); 190 free(str3); 191 return(res_str); 192} 193 194/* and the rest */ 195static char * 196make_name(void) 197{ 198 return mm_strdup(base_yytext); 199} 200 201static char * 202create_questionmarks(char *name, bool array) 203{ 204 struct variable *p = find_variable(name); 205 int count; 206 char *result = EMPTY; 207 208 /* In case we have a struct, we have to print as many "?" as there are attributes in the struct 209 * An array is only allowed together with an element argument 210 * This is essentially only used for inserts, but using a struct as input parameter is an error anywhere else 211 * so we don't have to worry here. */ 212 213 if (p->type->type == ECPGt_struct || (array && p->type->type == ECPGt_array && p->type->u.element->type == ECPGt_struct)) 214 { 215 struct ECPGstruct_member *m; 216 217 if (p->type->type == ECPGt_struct) 218 m = p->type->u.members; 219 else 220 m = p->type->u.element->u.members; 221 222 for (count = 0; m != NULL; m=m->next, count++); 223 } 224 else 225 count = 1; 226 227 for (; count > 0; count --) 228 { 229 sprintf(pacounter_buffer, "$%d", pacounter++); 230 result = cat_str(3, result, mm_strdup(pacounter_buffer), mm_strdup(" , ")); 231 } 232 233 /* removed the trailing " ," */ 234 235 result[strlen(result)-3] = '\0'; 236 return(result); 237} 238 239static char * 240adjust_outofscope_cursor_vars(struct cursor *cur) 241{ 242 /* Informix accepts DECLARE with variables that are out of scope when OPEN is called. 243 * For instance you can DECLARE a cursor in one function, and OPEN/FETCH/CLOSE 244 * it in another functions. This is very useful for e.g. event-driver programming, 245 * but may also lead to dangerous programming. The limitation when this is allowed 246 * and doesn't cause problems have to be documented, like the allocated variables 247 * must not be realloc()'ed. 248 * 249 * We have to change the variables to our own struct and just store the pointer 250 * instead of the variable. Do it only for local variables, not for globals. 251 */ 252 253 char *result = EMPTY; 254 int insert; 255 256 for (insert = 1; insert >= 0; insert--) 257 { 258 struct arguments *list; 259 struct arguments *ptr; 260 struct arguments *newlist = NULL; 261 struct variable *newvar, *newind; 262 263 list = (insert ? cur->argsinsert : cur->argsresult); 264 265 for (ptr = list; ptr != NULL; ptr = ptr->next) 266 { 267 char var_text[20]; 268 char *original_var; 269 bool skip_set_var = false; 270 bool var_ptr = false; 271 272 /* change variable name to "ECPGget_var(<counter>)" */ 273 original_var = ptr->variable->name; 274 sprintf(var_text, "%d))", ecpg_internal_var); 275 276 /* Don't emit ECPGset_var() calls for global variables */ 277 if (ptr->variable->brace_level == 0) 278 { 279 newvar = ptr->variable; 280 skip_set_var = true; 281 } 282 else if ((ptr->variable->type->type == ECPGt_char_variable) 283 && (strncmp(ptr->variable->name, "ECPGprepared_statement", strlen("ECPGprepared_statement")) == 0)) 284 { 285 newvar = ptr->variable; 286 skip_set_var = true; 287 } 288 else if ((ptr->variable->type->type != ECPGt_varchar 289 && ptr->variable->type->type != ECPGt_char 290 && ptr->variable->type->type != ECPGt_unsigned_char 291 && ptr->variable->type->type != ECPGt_string) 292 && atoi(ptr->variable->type->size) > 1) 293 { 294 newvar = new_variable(cat_str(4, mm_strdup("("), 295 mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)), 296 mm_strdup(" *)(ECPGget_var("), 297 mm_strdup(var_text)), 298 ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type, 299 mm_strdup("1"), 300 ptr->variable->type->u.element->counter), 301 ptr->variable->type->size), 302 0); 303 } 304 else if ((ptr->variable->type->type == ECPGt_varchar 305 || ptr->variable->type->type == ECPGt_char 306 || ptr->variable->type->type == ECPGt_unsigned_char 307 || ptr->variable->type->type == ECPGt_string) 308 && atoi(ptr->variable->type->size) > 1) 309 { 310 newvar = new_variable(cat_str(4, mm_strdup("("), 311 mm_strdup(ecpg_type_name(ptr->variable->type->type)), 312 mm_strdup(" *)(ECPGget_var("), 313 mm_strdup(var_text)), 314 ECPGmake_simple_type(ptr->variable->type->type, 315 ptr->variable->type->size, 316 ptr->variable->type->counter), 317 0); 318 if (ptr->variable->type->type == ECPGt_varchar) 319 var_ptr = true; 320 } 321 else if (ptr->variable->type->type == ECPGt_struct 322 || ptr->variable->type->type == ECPGt_union) 323 { 324 newvar = new_variable(cat_str(5, mm_strdup("(*("), 325 mm_strdup(ptr->variable->type->type_name), 326 mm_strdup(" *)(ECPGget_var("), 327 mm_strdup(var_text), 328 mm_strdup(")")), 329 ECPGmake_struct_type(ptr->variable->type->u.members, 330 ptr->variable->type->type, 331 ptr->variable->type->type_name, 332 ptr->variable->type->struct_sizeof), 333 0); 334 var_ptr = true; 335 } 336 else if (ptr->variable->type->type == ECPGt_array) 337 { 338 if (ptr->variable->type->u.element->type == ECPGt_struct 339 || ptr->variable->type->u.element->type == ECPGt_union) 340 { 341 newvar = new_variable(cat_str(5, mm_strdup("(*("), 342 mm_strdup(ptr->variable->type->u.element->type_name), 343 mm_strdup(" *)(ECPGget_var("), 344 mm_strdup(var_text), 345 mm_strdup(")")), 346 ECPGmake_struct_type(ptr->variable->type->u.element->u.members, 347 ptr->variable->type->u.element->type, 348 ptr->variable->type->u.element->type_name, 349 ptr->variable->type->u.element->struct_sizeof), 350 0); 351 } 352 else 353 { 354 newvar = new_variable(cat_str(4, mm_strdup("("), 355 mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)), 356 mm_strdup(" *)(ECPGget_var("), 357 mm_strdup(var_text)), 358 ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type, 359 ptr->variable->type->u.element->size, 360 ptr->variable->type->u.element->counter), 361 ptr->variable->type->size), 362 0); 363 var_ptr = true; 364 } 365 } 366 else 367 { 368 newvar = new_variable(cat_str(4, mm_strdup("*("), 369 mm_strdup(ecpg_type_name(ptr->variable->type->type)), 370 mm_strdup(" *)(ECPGget_var("), 371 mm_strdup(var_text)), 372 ECPGmake_simple_type(ptr->variable->type->type, 373 ptr->variable->type->size, 374 ptr->variable->type->counter), 375 0); 376 var_ptr = true; 377 } 378 379 /* create call to "ECPGset_var(<counter>, <connection>, <pointer>. <line number>)" */ 380 if (!skip_set_var) 381 { 382 sprintf(var_text, "%d, %s", ecpg_internal_var++, var_ptr ? "&(" : "("); 383 result = cat_str(5, result, mm_strdup("ECPGset_var("), 384 mm_strdup(var_text), mm_strdup(original_var), 385 mm_strdup("), __LINE__);\n")); 386 } 387 388 /* now the indicator if there is one and it's not a global variable */ 389 if ((ptr->indicator->type->type == ECPGt_NO_INDICATOR) || (ptr->indicator->brace_level == 0)) 390 { 391 newind = ptr->indicator; 392 } 393 else 394 { 395 /* change variable name to "ECPGget_var(<counter>)" */ 396 original_var = ptr->indicator->name; 397 sprintf(var_text, "%d))", ecpg_internal_var); 398 var_ptr = false; 399 400 if (ptr->indicator->type->type == ECPGt_struct 401 || ptr->indicator->type->type == ECPGt_union) 402 { 403 newind = new_variable(cat_str(5, mm_strdup("(*("), 404 mm_strdup(ptr->indicator->type->type_name), 405 mm_strdup(" *)(ECPGget_var("), 406 mm_strdup(var_text), 407 mm_strdup(")")), 408 ECPGmake_struct_type(ptr->indicator->type->u.members, 409 ptr->indicator->type->type, 410 ptr->indicator->type->type_name, 411 ptr->indicator->type->struct_sizeof), 412 0); 413 var_ptr = true; 414 } 415 else if (ptr->indicator->type->type == ECPGt_array) 416 { 417 if (ptr->indicator->type->u.element->type == ECPGt_struct 418 || ptr->indicator->type->u.element->type == ECPGt_union) 419 { 420 newind = new_variable(cat_str(5, mm_strdup("(*("), 421 mm_strdup(ptr->indicator->type->u.element->type_name), 422 mm_strdup(" *)(ECPGget_var("), 423 mm_strdup(var_text), 424 mm_strdup(")")), 425 ECPGmake_struct_type(ptr->indicator->type->u.element->u.members, 426 ptr->indicator->type->u.element->type, 427 ptr->indicator->type->u.element->type_name, 428 ptr->indicator->type->u.element->struct_sizeof), 429 0); 430 } 431 else 432 { 433 newind = new_variable(cat_str(4, mm_strdup("("), 434 mm_strdup(ecpg_type_name(ptr->indicator->type->u.element->type)), 435 mm_strdup(" *)(ECPGget_var("), mm_strdup(var_text)), 436 ECPGmake_array_type(ECPGmake_simple_type(ptr->indicator->type->u.element->type, 437 ptr->indicator->type->u.element->size, 438 ptr->indicator->type->u.element->counter), 439 ptr->indicator->type->size), 440 0); 441 var_ptr = true; 442 } 443 } 444 else if (atoi(ptr->indicator->type->size) > 1) 445 { 446 newind = new_variable(cat_str(4, mm_strdup("("), 447 mm_strdup(ecpg_type_name(ptr->indicator->type->type)), 448 mm_strdup(" *)(ECPGget_var("), 449 mm_strdup(var_text)), 450 ECPGmake_simple_type(ptr->indicator->type->type, 451 ptr->indicator->type->size, 452 ptr->variable->type->counter), 453 0); 454 } 455 else 456 { 457 newind = new_variable(cat_str(4, mm_strdup("*("), 458 mm_strdup(ecpg_type_name(ptr->indicator->type->type)), 459 mm_strdup(" *)(ECPGget_var("), 460 mm_strdup(var_text)), 461 ECPGmake_simple_type(ptr->indicator->type->type, 462 ptr->indicator->type->size, 463 ptr->variable->type->counter), 464 0); 465 var_ptr = true; 466 } 467 468 /* create call to "ECPGset_var(<counter>, <pointer>. <line number>)" */ 469 sprintf(var_text, "%d, %s", ecpg_internal_var++, var_ptr ? "&(" : "("); 470 result = cat_str(5, result, mm_strdup("ECPGset_var("), 471 mm_strdup(var_text), mm_strdup(original_var), 472 mm_strdup("), __LINE__);\n")); 473 } 474 475 add_variable_to_tail(&newlist, newvar, newind); 476 } 477 478 if (insert) 479 cur->argsinsert_oos = newlist; 480 else 481 cur->argsresult_oos = newlist; 482 } 483 484 return result; 485} 486 487/* This tests whether the cursor was declared and opened in the same function. */ 488#define SAMEFUNC(cur) \ 489 ((cur->function == NULL) || \ 490 (cur->function != NULL && strcmp(cur->function, current_function) == 0)) 491 492static struct cursor * 493add_additional_variables(char *name, bool insert) 494{ 495 struct cursor *ptr; 496 struct arguments *p; 497 int (* strcmp_fn)(const char *, const char *) = ((name[0] == ':' || name[0] == '"') ? strcmp : pg_strcasecmp); 498 499 for (ptr = cur; ptr != NULL; ptr=ptr->next) 500 { 501 if (strcmp_fn(ptr->name, name) == 0) 502 break; 503 } 504 505 if (ptr == NULL) 506 { 507 mmerror(PARSE_ERROR, ET_ERROR, "cursor \"%s\" does not exist", name); 508 return NULL; 509 } 510 511 if (insert) 512 { 513 /* add all those input variables that were given earlier 514 * note that we have to append here but have to keep the existing order */ 515 for (p = (SAMEFUNC(ptr) ? ptr->argsinsert : ptr->argsinsert_oos); p; p = p->next) 516 add_variable_to_tail(&argsinsert, p->variable, p->indicator); 517 } 518 519 /* add all those output variables that were given earlier */ 520 for (p = (SAMEFUNC(ptr) ? ptr->argsresult : ptr->argsresult_oos); p; p = p->next) 521 add_variable_to_tail(&argsresult, p->variable, p->indicator); 522 523 return ptr; 524} 525 526static void 527add_typedef(char *name, char *dimension, char *length, enum ECPGttype type_enum, 528 char *type_dimension, char *type_index, int initializer, int array) 529{ 530 /* add entry to list */ 531 struct typedefs *ptr, *this; 532 533 if ((type_enum == ECPGt_struct || 534 type_enum == ECPGt_union) && 535 initializer == 1) 536 mmerror(PARSE_ERROR, ET_ERROR, "initializer not allowed in type definition"); 537 else if (INFORMIX_MODE && strcmp(name, "string") == 0) 538 mmerror(PARSE_ERROR, ET_ERROR, "type name \"string\" is reserved in Informix mode"); 539 else 540 { 541 for (ptr = types; ptr != NULL; ptr = ptr->next) 542 { 543 if (strcmp(name, ptr->name) == 0) 544 /* re-definition is a bug */ 545 mmerror(PARSE_ERROR, ET_ERROR, "type \"%s\" is already defined", name); 546 } 547 adjust_array(type_enum, &dimension, &length, type_dimension, type_index, array, true); 548 549 this = (struct typedefs *) mm_alloc(sizeof(struct typedefs)); 550 551 /* initial definition */ 552 this->next = types; 553 this->name = name; 554 this->brace_level = braces_open; 555 this->type = (struct this_type *) mm_alloc(sizeof(struct this_type)); 556 this->type->type_enum = type_enum; 557 this->type->type_str = mm_strdup(name); 558 this->type->type_dimension = dimension; /* dimension of array */ 559 this->type->type_index = length; /* length of string */ 560 this->type->type_sizeof = ECPGstruct_sizeof; 561 this->struct_member_list = (type_enum == ECPGt_struct || type_enum == ECPGt_union) ? 562 ECPGstruct_member_dup(struct_member_list[struct_level]) : NULL; 563 564 if (type_enum != ECPGt_varchar && 565 type_enum != ECPGt_char && 566 type_enum != ECPGt_unsigned_char && 567 type_enum != ECPGt_string && 568 atoi(this->type->type_index) >= 0) 569 mmerror(PARSE_ERROR, ET_ERROR, "multidimensional arrays for simple data types are not supported"); 570 571 types = this; 572 } 573} 574%} 575 576%expect 0 577%name-prefix="base_yy" 578%locations 579 580%union { 581 double dval; 582 char *str; 583 int ival; 584 struct when action; 585 struct index index; 586 int tagname; 587 struct this_type type; 588 enum ECPGttype type_enum; 589 enum ECPGdtype dtype_enum; 590 struct fetch_desc descriptor; 591 struct su_symbol struct_union; 592 struct prep prep; 593} 594