/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.header,v 1.7 2009/06/10 23:11:52 petere Exp $ */ /* Copyright comment */ %{ #include "postgres_fe.h" #include "extern.h" #include /* Location tracking support --- simpler than bison's default */ #define YYLLOC_DEFAULT(Current, Rhs, N) \ do { \ if (N) \ (Current) = (Rhs)[1]; \ else \ (Current) = (Rhs)[0]; \ } while (0) /* * The %name-prefix option below will make bison call base_yylex, but we * really want it to call filtered_base_yylex (see parser.c). */ #define base_yylex filtered_base_yylex /* * This is only here so the string gets into the POT. Bison uses it * internally. */ #define bison_gettext_dummy gettext_noop("syntax error") /* * Variables containing simple states. */ int struct_level = 0; int braces_open; /* brace level counter */ int ecpg_informix_var = 0; char *connection = NULL; char *input_filename = NULL; static int QueryIsRule = 0, FoundInto = 0; static int initializer = 0; static int pacounter = 1; static char pacounter_buffer[sizeof(int) * CHAR_BIT * 10 / 3]; /* a rough guess at the size we need */ static struct this_type actual_type[STRUCT_DEPTH]; static char *actual_startline[STRUCT_DEPTH]; /* temporarily store struct members while creating the data structure */ struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = { NULL }; /* also store struct type so we can do a sizeof() later */ static char *ECPGstruct_sizeof = NULL; /* for forward declarations we have to store some data as well */ static char *forward_name = NULL; struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, NULL, NULL, {NULL}, 0}; struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL}; struct ECPGtype ecpg_query = {ECPGt_char_variable, NULL, NULL, {NULL}, 0}; /* * Handle parsing errors and warnings */ void mmerror(int error_code, enum errortype type, const char *error, ...) { va_list ap; /* internationalize the error message string */ error = _(error); fprintf(stderr, "%s:%d: ", input_filename, yylineno); switch(type) { case ET_WARNING: fprintf(stderr, _("WARNING: ")); break; case ET_ERROR: case ET_FATAL: fprintf(stderr, _("ERROR: ")); break; } va_start(ap, error); vfprintf(stderr, error, ap); va_end(ap); fprintf(stderr, "\n"); switch(type) { case ET_WARNING: break; case ET_ERROR: ret_value = error_code; break; case ET_FATAL: if (yyin) fclose(yyin); if (yyout) fclose(yyout); if (strcmp(output_filename, "-") != 0 && unlink(output_filename) != 0) fprintf(stderr, _("could not remove output file \"%s\"\n"), output_filename); exit(error_code); } } /* * string concatenation */ static char * cat2_str(char *str1, char *str2) { char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) + 2); strcpy(res_str, str1); if (strlen(str1) != 0 && strlen(str2) != 0) strcat(res_str, " "); strcat(res_str, str2); free(str1); free(str2); return(res_str); } static char * cat_str(int count, ...) { va_list args; int i; char *res_str; va_start(args, count); res_str = va_arg(args, char *); /* now add all other strings */ for (i = 1; i < count; i++) res_str = cat2_str(res_str, va_arg(args, char *)); va_end(args); return(res_str); } char * make_str(const char *str) { char * res_str = (char *)mm_alloc(strlen(str) + 1); strcpy(res_str, str); return res_str; } static char * make2_str(char *str1, char *str2) { char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) + 1); strcpy(res_str, str1); strcat(res_str, str2); free(str1); free(str2); return(res_str); } static char * make3_str(char *str1, char *str2, char *str3) { char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) +strlen(str3) + 1); strcpy(res_str, str1); strcat(res_str, str2); strcat(res_str, str3); free(str1); free(str2); free(str3); return(res_str); } /* and the rest */ static char * make_name(void) { char * name = (char *)mm_alloc(yyleng + 1); strncpy(name, yytext, yyleng); name[yyleng] = '\0'; return(name); } static char * create_questionmarks(char *name, bool array) { struct variable *p = find_variable(name); int count; char *result = EMPTY; /* In case we have a struct, we have to print as many "?" as there are attributes in the struct * An array is only allowed together with an element argument * This is essantially only used for inserts, but using a struct as input parameter is an error anywhere else * so we don't have to worry here. */ if (p->type->type == ECPGt_struct || (array && p->type->type == ECPGt_array && p->type->u.element->type == ECPGt_struct)) { struct ECPGstruct_member *m; if (p->type->type == ECPGt_struct) m = p->type->u.members; else m = p->type->u.element->u.members; for (count = 0; m != NULL; m=m->next, count++); } else count = 1; for (; count > 0; count --) { sprintf(pacounter_buffer, "$%d", pacounter++); result = cat_str(3, result, strdup(pacounter_buffer), make_str(" , ")); } /* removed the trailing " ," */ result[strlen(result)-3] = '\0'; return(result); } static char * adjust_informix(struct arguments *list) { /* Informix accepts DECLARE with variables that are out of scope when OPEN is called. * for instance you can declare variables in a function, and then subsequently use them * { * declare_vars(); * exec sql ... which uses vars declared in the above function * * This breaks standard and leads to some very dangerous programming. * Since they do, we have to work around and accept their syntax as well. * But we will do so ONLY in Informix mode. * We have to change the variables to our own struct and just store the pointer instead of the variable */ struct arguments *ptr; char *result = make_str(""); for (ptr = list; ptr != NULL; ptr = ptr->next) { char temp[20]; /* this should be sufficient unless you have 8 byte integers */ char *original_var; /* change variable name to "ECPG_informix_get_var()" */ original_var = ptr->variable->name; sprintf(temp, "%d))", ecpg_informix_var); if ((ptr->variable->type->type != ECPGt_varchar && ptr->variable->type->type != ECPGt_char && ptr->variable->type->type != ECPGt_unsigned_char) && atoi(ptr->variable->type->size) > 1) { ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type, make_str("1"), ptr->variable->type->u.element->lineno), ptr->variable->type->size), 0); sprintf(temp, "%d, (", ecpg_informix_var++); } else if ((ptr->variable->type->type == ECPGt_varchar || ptr->variable->type->type == ECPGt_char || ptr->variable->type->type == ECPGt_unsigned_char) && atoi(ptr->variable->type->size) > 1) { ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->variable->type->type, ptr->variable->type->size, ptr->variable->type->lineno), 0); sprintf(temp, "%d, (", ecpg_informix_var++); } else { ptr->variable = new_variable(cat_str(4, make_str("*("), mm_strdup(ecpg_type_name(ptr->variable->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->variable->type->type, ptr->variable->type->size, ptr->variable->type->lineno), 0); sprintf(temp, "%d, &(", ecpg_informix_var++); } /* create call to "ECPG_informix_set_var(, . )" */ result = cat_str(5, result, make_str("ECPG_informix_set_var("), mm_strdup(temp), mm_strdup(original_var), make_str("), __LINE__);\n")); /* now the indicator if there is one */ if (ptr->indicator->type->type != ECPGt_NO_INDICATOR) { /* change variable name to "ECPG_informix_get_var()" */ original_var = ptr->indicator->name; sprintf(temp, "%d))", ecpg_informix_var); /* create call to "ECPG_informix_set_var(, . )" */ if (atoi(ptr->indicator->type->size) > 1) { ptr->indicator = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->indicator->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->indicator->type->type, ptr->indicator->type->size, ptr->variable->type->lineno), 0); sprintf(temp, "%d, (", ecpg_informix_var++); } else { ptr->indicator = new_variable(cat_str(4, make_str("*("), mm_strdup(ecpg_type_name(ptr->indicator->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->indicator->type->type, ptr->indicator->type->size, ptr->variable->type->lineno), 0); sprintf(temp, "%d, &(", ecpg_informix_var++); } result = cat_str(5, result, make_str("ECPG_informix_set_var("), mm_strdup(temp), mm_strdup(original_var), make_str("), __LINE__);\n")); } } return result; } static struct cursor * add_additional_variables(char *name, bool insert) { struct cursor *ptr; struct arguments *p; for (ptr = cur; ptr != NULL; ptr=ptr->next) { if (strcmp(ptr->name, name) == 0) break; } if (ptr == NULL) { mmerror(PARSE_ERROR, ET_ERROR, "cursor \"%s\" does not exist", name); return NULL; } if (insert) { /* add all those input variables that were given earlier * note that we have to append here but have to keep the existing order */ for (p = ptr->argsinsert; p; p = p->next) add_variable_to_tail(&argsinsert, p->variable, p->indicator); } /* add all those output variables that were given earlier */ for (p = ptr->argsresult; p; p = p->next) add_variable_to_tail(&argsresult, p->variable, p->indicator); return ptr; } static void add_typedef(char *name, char * dimension, char * length, enum ECPGttype type_enum, char *type_dimension, char *type_index, int initializer, int array) { /* add entry to list */ struct typedefs *ptr, *this; if ((type_enum == ECPGt_struct || type_enum == ECPGt_union) && initializer == 1) mmerror(PARSE_ERROR, ET_ERROR, "initializer not allowed in type definition"); else { for (ptr = types; ptr != NULL; ptr = ptr->next) { if (strcmp(name, ptr->name) == 0) /* re-definition is a bug */ mmerror(PARSE_ERROR, ET_ERROR, "type \"%s\" is already defined", name); } adjust_array(type_enum, &dimension, &length, type_dimension, type_index, array, true); this = (struct typedefs *) mm_alloc(sizeof(struct typedefs)); /* initial definition */ this->next = types; this->name = name; this->brace_level = braces_open; this->type = (struct this_type *) mm_alloc(sizeof(struct this_type)); this->type->type_enum = type_enum; this->type->type_str = mm_strdup(name); this->type->type_dimension = dimension; /* dimension of array */ this->type->type_index = length; /* length of string */ this->type->type_sizeof = ECPGstruct_sizeof; this->struct_member_list = (type_enum == ECPGt_struct || type_enum == ECPGt_union) ? ECPGstruct_member_dup(struct_member_list[struct_level]) : NULL; if (type_enum != ECPGt_varchar && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && atoi(this->type->type_index) >= 0) mmerror(PARSE_ERROR, ET_ERROR, "multidimensional arrays for simple data types are not supported"); types = this; } } %} %expect 0 %name-prefix="base_yy" %locations %union { double dval; char *str; int ival; struct when action; struct index index; int tagname; struct this_type type; enum ECPGttype type_enum; enum ECPGdtype dtype_enum; struct fetch_desc descriptor; struct su_symbol struct_union; struct prep prep; }