Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postgres/src/interfaces/ecpg/preproc/   (Postgres Database Version 18.4©)  Datei vom 11.4.2026 mit Größe 18 kB image not shown  

Quelle  ecpg.header   Sprache: unbekannt

 
Spracherkennung für: .header vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

/* src/interfaces/ecpg/preproc/ecpg.header */

/* Copyright comment */
%{
#include "postgres_fe.h"

#include "preproc_extern.h"
#include "preproc.h"
#include "ecpg_config.h"
#include <unistd.h>

/* silence -Wmissing-variable-declarations */
extern int base_yychar;
extern int base_yynerrs;


/*
 * 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 struct this_type actual_type[STRUCT_DEPTH];
static char *actual_startline[STRUCT_DEPTH];
static int varchar_counter = 1;
static int bytea_counter = 1;

/*
 * We temporarily store struct members here while parsing struct declarations.
 * The struct_member_list (at a given nesting depth) is constructed while
 * scanning the fields within "struct { .... }", but we can't remove it upon
 * seeing the right brace.  It's kept around and copied into the variables
 * or typedefs that follow, in order to handle cases like
 * "struct foo { ... } foovar1, foovar2;".  We recycle the storage only
 * upon closing the current nesting level or starting the next struct
 * declaration within the same nesting level.
 * For cases like "struct foo foovar1, foovar2;", we copy the saved struct
 * field list for the typedef or struct tag into the struct_member_list
 * global variable, and then copy it again to the newly-declared variables.
 */
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 bool check_declared_list(const char *name);
static void update_connection(const char *newconn);


/*
 * "Location tracking" support.  We commandeer Bison's location tracking
 * mechanism to manage the output string for productions that ordinarily would
 * return a <str> result.  This allows the majority of those productions to
 * have default semantic actions, reducing the size of the parser, and also
 * greatly reducing its compilation time on some versions of clang.
 *
 * To do this, we make YYLTYPE be a pointer to a malloc'd string, and then
 * merge the location strings of the input tokens in the default YYLLOC
 * computation.  Productions that are okay with the standard merge need not
 * do anything more; otherwise, they can override it by assigning to @$.
 */
#define YYLLOC_DEFAULT(Current, Rhs, N) yylloc_default(&(Current), Rhs, N)

static void
yylloc_default(YYLTYPE *target, YYLTYPE *rhs, int N)
{
 if (N > 1)
 {
  /* Concatenate non-empty inputs with one space between them */
  char    *result,
       *ptr;
  size_t  needed = 0;

  for (int i = 1; i <= N; i++)
  {
   size_t  thislen = strlen(rhs[i]);

   if (needed > 0 && thislen > 0)
    needed++;
   needed += thislen;
  }
  result = (char *) loc_alloc(needed + 1);
  ptr = result;
  for (int i = 1; i <= N; i++)
  {
   size_t  thislen = strlen(rhs[i]);

   if (ptr > result && thislen > 0)
    *ptr++ = ' ';
   memcpy(ptr, rhs[i], thislen);
   ptr += thislen;
  }
  *ptr = '\0';
  *target = result;
 }
 else if (N == 1)
 {
  /* Just re-use the single input */
  *target = rhs[1];
 }
 else
 {
  /* No need to allocate any space */
  *target = "";
 }
}

/* and the rest */
static char *
create_questionmarks(const char *name, bool array)
{
 struct variable *p = find_variable(name);
 int   count;
 char    *result = "";

 /*
  * 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--)
 {
  char buf[32];

  snprintf(buf, sizeof(buf), "$%d", pacounter++);
  result = cat_str(3, result, buf, " , ");
 }

 /* remove 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 = "";
 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;
   snprintf(var_text, sizeof(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, "(",
             ecpg_type_name(ptr->variable->type->u.element->type),
             " *)(ECPGget_var(",
             var_text),
           ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type,
                      "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, "(",
             ecpg_type_name(ptr->variable->type->type),
             " *)(ECPGget_var(",
             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, "(*(",
             ptr->variable->type->type_name,
             " *)(ECPGget_var(",
             var_text,
             ")"),
           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, "(*(",
              ptr->variable->type->u.element->type_name,
              " *)(ECPGget_var(",
              var_text,
              ")"),
            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, "(",
              ecpg_type_name(ptr->variable->type->u.element->type),
              " *)(ECPGget_var(",
              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, "*(",
             ecpg_type_name(ptr->variable->type->type),
             " *)(ECPGget_var(",
             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)
   {
    snprintf(var_text, sizeof(var_text), "%d, %s",
       ecpg_internal_var++, var_ptr ? "&(" : "(");
    result = cat_str(5, result, "ECPGset_var(",
         var_text, original_var,
         "), __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;
    snprintf(var_text, sizeof(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, "(*(",
              ptr->indicator->type->type_name,
              " *)(ECPGget_var(",
              var_text,
              ")"),
            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, "(*(",
               ptr->indicator->type->u.element->type_name,
               " *)(ECPGget_var(",
               var_text,
               ")"),
             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, "(",
               ecpg_type_name(ptr->indicator->type->u.element->type),
               " *)(ECPGget_var(",
               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, "(",
              ecpg_type_name(ptr->indicator->type->type),
              " *)(ECPGget_var(",
              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, "*(",
              ecpg_type_name(ptr->indicator->type->type),
              " *)(ECPGget_var(",
              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>)"
     */
    snprintf(var_text, sizeof(var_text), "%d, %s",
       ecpg_internal_var++, var_ptr ? "&(" : "(");
    result = cat_str(5, result, "ECPGset_var(",
         var_text, original_var,
         "), __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 && current_function != NULL && \
   strcmp(cur->function, current_function) == 0))

static struct cursor *
add_additional_variables(const 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(const char *name, const char *dimension, const char *length,
   enum ECPGttype type_enum,
   const char *type_dimension, const 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 = mm_strdup(name);
  this->brace_level = braces_open;
  this->type = (struct this_type *) mm_alloc(sizeof(struct this_type));
  this->type->type_storage = NULL;
  this->type->type_enum = type_enum;
  this->type->type_str = mm_strdup(name);
  this->type->type_dimension = mm_strdup(dimension); /* dimension of array */
  this->type->type_index = mm_strdup(length); /* length of string */
  this->type->type_sizeof = ECPGstruct_sizeof ? mm_strdup(ECPGstruct_sizeof) : NULL;
  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);
   update_connection(ptr->connection);
   return true;
  }
 }
 return false;
}

/*
 * If newconn isn't NULL, update the global "connection" variable to that;
 * otherwise do nothing.
 */
static void
update_connection(const char *newconn)
{
 if (newconn)
 {
  free(connection);
  connection = mm_strdup(newconn);
 }
}
%}

%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;
}

[Dauer der Verarbeitung: 0.18 Sekunden, vorverarbeitet 2026-08-07]