summaryrefslogtreecommitdiffstats
path: root/src/interfaces/ecpg/preproc/ecpg.header
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/ecpg/preproc/ecpg.header')
-rw-r--r--src/interfaces/ecpg/preproc/ecpg.header626
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;
+}