diff options
Diffstat (limited to 'src/interfaces/ecpg/preproc/ecpg.header')
-rw-r--r-- | src/interfaces/ecpg/preproc/ecpg.header | 626 |
1 files changed, 626 insertions, 0 deletions
diff --git a/src/interfaces/ecpg/preproc/ecpg.header b/src/interfaces/ecpg/preproc/ecpg.header new file mode 100644 index 0000000..b8508a9 --- /dev/null +++ b/src/interfaces/ecpg/preproc/ecpg.header @@ -0,0 +1,626 @@ +/* src/interfaces/ecpg/preproc/ecpg.header */ + +/* Copyright comment */ +%{ +#include "postgres_fe.h" + +#include "preproc_extern.h" +#include "ecpg_config.h" +#include <unistd.h> + +/* 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 */ +char *current_function; +int ecpg_internal_var = 0; +char *connection = NULL; +char *input_filename = NULL; + +static int 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]; +static int varchar_counter = 1; +static int bytea_counter = 1; + +/* 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, {NULL}, 0}; +struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL}; + +static struct ECPGtype ecpg_query = {ECPGt_char_variable, NULL, NULL, NULL, {NULL}, 0}; + +static void vmmerror(int error_code, enum errortype type, const char *error, va_list ap) pg_attribute_printf(3, 0); + +static bool check_declared_list(const char*); + +/* + * Handle parsing errors and warnings + */ +static void +vmmerror(int error_code, enum errortype type, const char *error, va_list ap) +{ + /* localize the error message string */ + error = _(error); + + fprintf(stderr, "%s:%d: ", input_filename, base_yylineno); + + switch(type) + { + case ET_WARNING: + fprintf(stderr, _("WARNING: ")); + break; + case ET_ERROR: + fprintf(stderr, _("ERROR: ")); + break; + } + + vfprintf(stderr, error, ap); + + fprintf(stderr, "\n"); + + switch(type) + { + case ET_WARNING: + break; + case ET_ERROR: + ret_value = error_code; + break; + } +} + +void +mmerror(int error_code, enum errortype type, const char *error, ...) +{ + va_list ap; + + va_start(ap, error); + vmmerror(error_code, type, error, ap); + va_end(ap); +} + +void +mmfatal(int error_code, const char *error, ...) +{ + va_list ap; + + va_start(ap, error); + vmmerror(error_code, ET_ERROR, error, ap); + va_end(ap); + + if (base_yyin) + fclose(base_yyin); + if (base_yyout) + fclose(base_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; +} + +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) +{ + return mm_strdup(base_yytext); +} + +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 essentially 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, mm_strdup(pacounter_buffer), mm_strdup(" , ")); + } + + /* removed the trailing " ," */ + + result[strlen(result)-3] = '\0'; + return result; +} + +static char * +adjust_outofscope_cursor_vars(struct cursor *cur) +{ + /* Informix accepts DECLARE with variables that are out of scope when OPEN is called. + * For instance you can DECLARE a cursor in one function, and OPEN/FETCH/CLOSE + * it in another functions. This is very useful for e.g. event-driver programming, + * but may also lead to dangerous programming. The limitation when this is allowed + * and doesn't cause problems have to be documented, like the allocated variables + * must not be realloc()'ed. + * + * We have to change the variables to our own struct and just store the pointer + * instead of the variable. Do it only for local variables, not for globals. + */ + + char *result = EMPTY; + int insert; + + for (insert = 1; insert >= 0; insert--) + { + struct arguments *list; + struct arguments *ptr; + struct arguments *newlist = NULL; + struct variable *newvar, *newind; + + list = (insert ? cur->argsinsert : cur->argsresult); + + for (ptr = list; ptr != NULL; ptr = ptr->next) + { + char var_text[20]; + char *original_var; + bool skip_set_var = false; + bool var_ptr = false; + + /* change variable name to "ECPGget_var(<counter>)" */ + original_var = ptr->variable->name; + sprintf(var_text, "%d))", ecpg_internal_var); + + /* Don't emit ECPGset_var() calls for global variables */ + if (ptr->variable->brace_level == 0) + { + newvar = ptr->variable; + skip_set_var = true; + } + else if ((ptr->variable->type->type == ECPGt_char_variable) + && (strncmp(ptr->variable->name, "ECPGprepared_statement", strlen("ECPGprepared_statement")) == 0)) + { + newvar = ptr->variable; + skip_set_var = true; + } + else if ((ptr->variable->type->type != ECPGt_varchar + && ptr->variable->type->type != ECPGt_char + && ptr->variable->type->type != ECPGt_unsigned_char + && ptr->variable->type->type != ECPGt_string + && ptr->variable->type->type != ECPGt_bytea) + && atoi(ptr->variable->type->size) > 1) + { + newvar = new_variable(cat_str(4, mm_strdup("("), + mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)), + mm_strdup(" *)(ECPGget_var("), + mm_strdup(var_text)), + ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type, + mm_strdup("1"), + ptr->variable->type->u.element->counter), + ptr->variable->type->size), + 0); + } + else if ((ptr->variable->type->type == ECPGt_varchar + || ptr->variable->type->type == ECPGt_char + || ptr->variable->type->type == ECPGt_unsigned_char + || ptr->variable->type->type == ECPGt_string + || ptr->variable->type->type == ECPGt_bytea) + && atoi(ptr->variable->type->size) > 1) + { + newvar = new_variable(cat_str(4, mm_strdup("("), + mm_strdup(ecpg_type_name(ptr->variable->type->type)), + mm_strdup(" *)(ECPGget_var("), + mm_strdup(var_text)), + ECPGmake_simple_type(ptr->variable->type->type, + ptr->variable->type->size, + ptr->variable->type->counter), + 0); + if (ptr->variable->type->type == ECPGt_varchar || + ptr->variable->type->type == ECPGt_bytea) + var_ptr = true; + } + else if (ptr->variable->type->type == ECPGt_struct + || ptr->variable->type->type == ECPGt_union) + { + newvar = new_variable(cat_str(5, mm_strdup("(*("), + mm_strdup(ptr->variable->type->type_name), + mm_strdup(" *)(ECPGget_var("), + mm_strdup(var_text), + mm_strdup(")")), + ECPGmake_struct_type(ptr->variable->type->u.members, + ptr->variable->type->type, + ptr->variable->type->type_name, + ptr->variable->type->struct_sizeof), + 0); + var_ptr = true; + } + else if (ptr->variable->type->type == ECPGt_array) + { + if (ptr->variable->type->u.element->type == ECPGt_struct + || ptr->variable->type->u.element->type == ECPGt_union) + { + newvar = new_variable(cat_str(5, mm_strdup("(*("), + mm_strdup(ptr->variable->type->u.element->type_name), + mm_strdup(" *)(ECPGget_var("), + mm_strdup(var_text), + mm_strdup(")")), + ECPGmake_struct_type(ptr->variable->type->u.element->u.members, + ptr->variable->type->u.element->type, + ptr->variable->type->u.element->type_name, + ptr->variable->type->u.element->struct_sizeof), + 0); + } + else + { + newvar = new_variable(cat_str(4, mm_strdup("("), + mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)), + mm_strdup(" *)(ECPGget_var("), + mm_strdup(var_text)), + ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type, + ptr->variable->type->u.element->size, + ptr->variable->type->u.element->counter), + ptr->variable->type->size), + 0); + var_ptr = true; + } + } + else + { + newvar = new_variable(cat_str(4, mm_strdup("*("), + mm_strdup(ecpg_type_name(ptr->variable->type->type)), + mm_strdup(" *)(ECPGget_var("), + mm_strdup(var_text)), + ECPGmake_simple_type(ptr->variable->type->type, + ptr->variable->type->size, + ptr->variable->type->counter), + 0); + var_ptr = true; + } + + /* create call to "ECPGset_var(<counter>, <connection>, <pointer>. <line number>)" */ + if (!skip_set_var) + { + sprintf(var_text, "%d, %s", ecpg_internal_var++, var_ptr ? "&(" : "("); + result = cat_str(5, result, mm_strdup("ECPGset_var("), + mm_strdup(var_text), mm_strdup(original_var), + mm_strdup("), __LINE__);\n")); + } + + /* now the indicator if there is one and it's not a global variable */ + if ((ptr->indicator->type->type == ECPGt_NO_INDICATOR) || (ptr->indicator->brace_level == 0)) + { + newind = ptr->indicator; + } + else + { + /* change variable name to "ECPGget_var(<counter>)" */ + original_var = ptr->indicator->name; + sprintf(var_text, "%d))", ecpg_internal_var); + var_ptr = false; + + if (ptr->indicator->type->type == ECPGt_struct + || ptr->indicator->type->type == ECPGt_union) + { + newind = new_variable(cat_str(5, mm_strdup("(*("), + mm_strdup(ptr->indicator->type->type_name), + mm_strdup(" *)(ECPGget_var("), + mm_strdup(var_text), + mm_strdup(")")), + ECPGmake_struct_type(ptr->indicator->type->u.members, + ptr->indicator->type->type, + ptr->indicator->type->type_name, + ptr->indicator->type->struct_sizeof), + 0); + var_ptr = true; + } + else if (ptr->indicator->type->type == ECPGt_array) + { + if (ptr->indicator->type->u.element->type == ECPGt_struct + || ptr->indicator->type->u.element->type == ECPGt_union) + { + newind = new_variable(cat_str(5, mm_strdup("(*("), + mm_strdup(ptr->indicator->type->u.element->type_name), + mm_strdup(" *)(ECPGget_var("), + mm_strdup(var_text), + mm_strdup(")")), + ECPGmake_struct_type(ptr->indicator->type->u.element->u.members, + ptr->indicator->type->u.element->type, + ptr->indicator->type->u.element->type_name, + ptr->indicator->type->u.element->struct_sizeof), + 0); + } + else + { + newind = new_variable(cat_str(4, mm_strdup("("), + mm_strdup(ecpg_type_name(ptr->indicator->type->u.element->type)), + mm_strdup(" *)(ECPGget_var("), mm_strdup(var_text)), + ECPGmake_array_type(ECPGmake_simple_type(ptr->indicator->type->u.element->type, + ptr->indicator->type->u.element->size, + ptr->indicator->type->u.element->counter), + ptr->indicator->type->size), + 0); + var_ptr = true; + } + } + else if (atoi(ptr->indicator->type->size) > 1) + { + newind = new_variable(cat_str(4, mm_strdup("("), + mm_strdup(ecpg_type_name(ptr->indicator->type->type)), + mm_strdup(" *)(ECPGget_var("), + mm_strdup(var_text)), + ECPGmake_simple_type(ptr->indicator->type->type, + ptr->indicator->type->size, + ptr->variable->type->counter), + 0); + } + else + { + newind = new_variable(cat_str(4, mm_strdup("*("), + mm_strdup(ecpg_type_name(ptr->indicator->type->type)), + mm_strdup(" *)(ECPGget_var("), + mm_strdup(var_text)), + ECPGmake_simple_type(ptr->indicator->type->type, + ptr->indicator->type->size, + ptr->variable->type->counter), + 0); + var_ptr = true; + } + + /* create call to "ECPGset_var(<counter>, <pointer>. <line number>)" */ + sprintf(var_text, "%d, %s", ecpg_internal_var++, var_ptr ? "&(" : "("); + result = cat_str(5, result, mm_strdup("ECPGset_var("), + mm_strdup(var_text), mm_strdup(original_var), + mm_strdup("), __LINE__);\n")); + } + + add_variable_to_tail(&newlist, newvar, newind); + } + + if (insert) + cur->argsinsert_oos = newlist; + else + cur->argsresult_oos = newlist; + } + + return result; +} + +/* This tests whether the cursor was declared and opened in the same function. */ +#define SAMEFUNC(cur) \ + ((cur->function == NULL) || \ + (cur->function != NULL && strcmp(cur->function, current_function) == 0)) + +static struct cursor * +add_additional_variables(char *name, bool insert) +{ + struct cursor *ptr; + struct arguments *p; + int (* strcmp_fn)(const char *, const char *) = ((name[0] == ':' || name[0] == '"') ? strcmp : pg_strcasecmp); + + for (ptr = cur; ptr != NULL; ptr=ptr->next) + { + if (strcmp_fn(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 = (SAMEFUNC(ptr) ? ptr->argsinsert : ptr->argsinsert_oos); p; p = p->next) + add_variable_to_tail(&argsinsert, p->variable, p->indicator); + } + + /* add all those output variables that were given earlier */ + for (p = (SAMEFUNC(ptr) ? ptr->argsresult : ptr->argsresult_oos); 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 if (INFORMIX_MODE && strcmp(name, "string") == 0) + mmerror(PARSE_ERROR, ET_ERROR, "type name \"string\" is reserved in Informix mode"); + 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_bytea && + type_enum != ECPGt_char && + type_enum != ECPGt_unsigned_char && + type_enum != ECPGt_string && + atoi(this->type->type_index) >= 0) + mmerror(PARSE_ERROR, ET_ERROR, "multidimensional arrays for simple data types are not supported"); + + types = this; + } +} + +/* + * check an SQL identifier is declared or not. + * If it is already declared, the global variable + * connection will be changed to the related connection. + */ +static bool +check_declared_list(const char *name) +{ + struct declared_list *ptr = NULL; + for (ptr = g_declared_list; ptr != NULL; ptr = ptr -> next) + { + if (!ptr->connection) + continue; + if (strcmp(name, ptr -> name) == 0) + { + if (connection && strcmp(ptr->connection, connection) != 0) + mmerror(PARSE_ERROR, ET_WARNING, "connection %s is overwritten with %s by DECLARE statement %s", connection, ptr->connection, name); + connection = mm_strdup(ptr -> connection); + return true; + } + } + return false; +} +%} + +%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; + struct exec exec; + struct describe describe; +} |