ecpg: improve preprocessor's memory management.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 14 Oct 2024 17:55:08 +0000 (13:55 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 14 Oct 2024 17:55:08 +0000 (13:55 -0400)
Invent a notion of "local" storage that will automatically be
reclaimed at the end of each statement.  Use this for location
strings as well as other visibly short-lived data within the parser.

Also, make cat_str and make_str return local storage and not free
their inputs, which allows dispensing with a whole lot of retail
mm_strdup calls.  We do have to add some new ones in places where
a local-lifetime string needs to be added to a longer-lived data
structure, but on balance there are a lot less mm_strdup calls than
before.

In hopes of flushing out places where changes were necessary,
I changed YYLTYPE from "char *" to "const char *", which forced
const-ification of various function arguments that probably
should've been like that all along.

This still leaks somewhat more memory than v17, but that will be
cleaned up in future commits.

Discussion: https://postgr.es/m/2011420.1713493114@sss.pgh.pa.us

12 files changed:
src/interfaces/ecpg/preproc/descriptor.c
src/interfaces/ecpg/preproc/ecpg.addons
src/interfaces/ecpg/preproc/ecpg.header
src/interfaces/ecpg/preproc/ecpg.trailer
src/interfaces/ecpg/preproc/output.c
src/interfaces/ecpg/preproc/parser.c
src/interfaces/ecpg/preproc/preproc_extern.h
src/interfaces/ecpg/preproc/type.c
src/interfaces/ecpg/preproc/type.h
src/interfaces/ecpg/preproc/util.c
src/interfaces/ecpg/preproc/variable.c
src/tools/pgindent/typedefs.list

index f4b1878289cb11b681a3394425cfcd27e7268823..9b87d07d09fe692d7541931b688404eef74c6e3e 100644 (file)
 static struct assignment *assignments;
 
 void
-push_assignment(char *var, enum ECPGdtype value)
+push_assignment(const char *var, enum ECPGdtype value)
 {
    struct assignment *new = (struct assignment *) mm_alloc(sizeof(struct assignment));
 
    new->next = assignments;
-   new->variable = mm_alloc(strlen(var) + 1);
-   strcpy(new->variable, var);
+   new->variable = mm_strdup(var);
    new->value = value;
    assignments = new;
 }
@@ -73,7 +72,7 @@ ECPGnumeric_lvalue(char *name)
 static struct descriptor *descriptors;
 
 void
-add_descriptor(char *name, char *connection)
+add_descriptor(const char *name, const char *connection)
 {
    struct descriptor *new;
 
@@ -83,20 +82,16 @@ add_descriptor(char *name, char *connection)
    new = (struct descriptor *) mm_alloc(sizeof(struct descriptor));
 
    new->next = descriptors;
-   new->name = mm_alloc(strlen(name) + 1);
-   strcpy(new->name, name);
+   new->name = mm_strdup(name);
    if (connection)
-   {
-       new->connection = mm_alloc(strlen(connection) + 1);
-       strcpy(new->connection, connection);
-   }
+       new->connection = mm_strdup(connection);
    else
-       new->connection = connection;
+       new->connection = NULL;
    descriptors = new;
 }
 
 void
-drop_descriptor(char *name, char *connection)
+drop_descriptor(const char *name, const char *connection)
 {
    struct descriptor *i;
    struct descriptor **lastptr = &descriptors;
@@ -126,9 +121,8 @@ drop_descriptor(char *name, char *connection)
        mmerror(PARSE_ERROR, ET_WARNING, "descriptor %s bound to the default connection does not exist", name);
 }
 
-struct descriptor
-          *
-lookup_descriptor(char *name, char *connection)
+struct descriptor *
+lookup_descriptor(const char *name, const char *connection)
 {
    struct descriptor *i;
 
@@ -159,7 +153,7 @@ lookup_descriptor(char *name, char *connection)
 }
 
 void
-output_get_descr_header(char *desc_name)
+output_get_descr_header(const char *desc_name)
 {
    struct assignment *results;
 
@@ -178,7 +172,7 @@ output_get_descr_header(char *desc_name)
 }
 
 void
-output_get_descr(char *desc_name, char *index)
+output_get_descr(const char *desc_name, const char *index)
 {
    struct assignment *results;
 
@@ -211,7 +205,7 @@ output_get_descr(char *desc_name, char *index)
 }
 
 void
-output_set_descr_header(char *desc_name)
+output_set_descr_header(const char *desc_name)
 {
    struct assignment *results;
 
@@ -272,7 +266,7 @@ descriptor_item_name(enum ECPGdtype itemcode)
 }
 
 void
-output_set_descr(char *desc_name, char *index)
+output_set_descr(const char *desc_name, const char *index)
 {
    struct assignment *results;
 
index 24ee54554e37b07a4a4fbda3369e1875aa6f30eb..9c120fead24e79429e87c5f8f66e5bf0901f13a5 100644 (file)
@@ -45,18 +45,16 @@ ECPG: stmtExecuteStmt block
            else
            {
                /* case of ecpg_ident or CSTRING */
-               char       *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
-               char       *str = mm_strdup($1.name + 1);
+               char        length[32];
+               char       *str;
 
-               /*
-                * It must be cut off double quotation because new_variable()
-                * double-quotes.
-                */
+               /* Remove double quotes from name */
+               str = loc_strdup($1.name + 1);
                str[strlen(str) - 1] = '\0';
-               sprintf(length, "%zu", strlen(str));
+               snprintf(length, sizeof(length), "%zu", strlen(str));
                add_variable_to_tail(&argsinsert, new_variable(str, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator);
            }
-           output_statement(cat_str(3, mm_strdup("execute"), mm_strdup("$0"), $1.type), 0, ECPGst_exec_with_exprlist);
+           output_statement(cat_str(3, "execute", "$0", $1.type), 0, ECPGst_exec_with_exprlist);
        }
    }
 ECPG: stmtPrepareStmt block
@@ -66,7 +64,7 @@ ECPG: stmtPrepareStmt block
            output_prepare_statement($1.name, $1.stmt);
        else if (strlen($1.type) == 0)
        {
-           char       *stmt = cat_str(3, mm_strdup("\""), $1.stmt, mm_strdup("\""));
+           char       *stmt = cat_str(3, "\"", $1.stmt, "\"");
 
            output_prepare_statement($1.name, stmt);
        }
@@ -77,18 +75,16 @@ ECPG: stmtPrepareStmt block
                add_variable_to_tail(&argsinsert, find_variable($1.name), &no_indicator);
            else
            {
-               char       *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
-               char       *str = mm_strdup($1.name + 1);
+               char        length[32];
+               char       *str;
 
-               /*
-                * It must be cut off double quotation because new_variable()
-                * double-quotes.
-                */
+               /* Remove double quotes from name */
+               str = loc_strdup($1.name + 1);
                str[strlen(str) - 1] = '\0';
-               sprintf(length, "%zu", strlen(str));
+               snprintf(length, sizeof(length), "%zu", strlen(str));
                add_variable_to_tail(&argsinsert, new_variable(str, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator);
            }
-           output_statement(cat_str(5, mm_strdup("prepare"), mm_strdup("$0"), $1.type, mm_strdup("as"), $1.stmt), 0, ECPGst_prepare);
+           output_statement(cat_str(5, "prepare", "$0", $1.type, "as", $1.stmt), 0, ECPGst_prepare);
        }
    }
 ECPG: stmtTransactionStmt block
@@ -142,8 +138,6 @@ ECPG: stmtViewStmt rule
        fputs("ECPGt_EORT);", base_yyout);
        fprintf(base_yyout, "}");
        output_line_number();
-
-       free($1.stmt_name);
    }
    | ECPGDisconnect
    {
@@ -175,8 +169,6 @@ ECPG: stmtViewStmt rule
    {
        lookup_descriptor($1.name, connection);
        output_get_descr($1.name, $1.str);
-       free($1.name);
-       free($1.str);
    }
    | ECPGGetDescriptorHeader
    {
@@ -190,7 +182,7 @@ ECPG: stmtViewStmt rule
        if ((ptr = add_additional_variables(@1, true)) != NULL)
        {
            connection = ptr->connection ? mm_strdup(ptr->connection) : NULL;
-           output_statement(mm_strdup(ptr->command), 0, ECPGst_normal);
+           output_statement(ptr->command, 0, ECPGst_normal);
            ptr->opened = true;
        }
    }
@@ -211,8 +203,6 @@ ECPG: stmtViewStmt rule
    {
        lookup_descriptor($1.name, connection);
        output_set_descr($1.name, $1.str);
-       free($1.name);
-       free($1.str);
    }
    | ECPGSetDescriptorHeader
    {
@@ -243,9 +233,9 @@ ECPG: stmtViewStmt rule
    }
 ECPG: where_or_current_clauseWHERECURRENT_POFcursor_name block
    {
-       char       *cursor_marker = @4[0] == ':' ? mm_strdup("$0") : @4;
+       const char *cursor_marker = @4[0] == ':' ? "$0" : @4;
 
-       @$ = cat_str(2, mm_strdup("where current of"), cursor_marker);
+       @$ = cat_str(2, "where current of", cursor_marker);
    }
 ECPG: CopyStmtCOPYopt_binaryqualified_nameopt_column_listcopy_fromopt_programcopy_file_namecopy_delimiteropt_withcopy_optionswhere_clause addon
        if (strcmp(@6, "from") == 0 &&
@@ -253,21 +243,21 @@ ECPG: CopyStmtCOPYopt_binaryqualified_nameopt_column_listcopy_fromopt_programcop
            mmerror(PARSE_ERROR, ET_WARNING, "COPY FROM STDIN is not implemented");
 ECPG: var_valueNumericOnly addon
        if (@1[0] == '$')
-           @$ = mm_strdup("$0");
+           @$ = "$0";
 ECPG: fetch_argscursor_name addon
        struct cursor *ptr = add_additional_variables(@1, false);
 
        if (ptr->connection)
            connection = mm_strdup(ptr->connection);
        if (@1[0] == ':')
-           @$ = mm_strdup("$0");
+           @$ = "$0";
 ECPG: fetch_argsfrom_incursor_name addon
        struct cursor *ptr = add_additional_variables(@2, false);
 
        if (ptr->connection)
            connection = mm_strdup(ptr->connection);
        if (@2[0] == ':')
-           @$ = cat2_str(mm_strdup(@1), mm_strdup("$0"));
+           @$ = cat2_str(@1, "$0");
 ECPG: fetch_argsNEXTopt_from_incursor_name addon
 ECPG: fetch_argsPRIORopt_from_incursor_name addon
 ECPG: fetch_argsFIRST_Popt_from_incursor_name addon
@@ -278,7 +268,7 @@ ECPG: fetch_argsALLopt_from_incursor_name addon
        if (ptr->connection)
            connection = mm_strdup(ptr->connection);
        if (@3[0] == ':')
-           @$ = cat_str(3, mm_strdup(@1), mm_strdup(@2), mm_strdup("$0"));
+           @$ = cat_str(3, @1, @2, "$0");
 ECPG: fetch_argsSignedIconstopt_from_incursor_name addon
        struct cursor *ptr = add_additional_variables(@3, false);
        bool    replace = false;
@@ -287,16 +277,16 @@ ECPG: fetch_argsSignedIconstopt_from_incursor_name addon
            connection = mm_strdup(ptr->connection);
        if (@3[0] == ':')
        {
-           @3 = mm_strdup("$0");
+           @3 = "$0";
            replace = true;
        }
        if (@1[0] == '$')
        {
-           @1 = mm_strdup("$0");
+           @1 = "$0";
            replace = true;
        }
        if (replace)
-           @$ = cat_str(3, mm_strdup(@1), mm_strdup(@2), mm_strdup(@3));
+           @$ = cat_str(3, @1, @2, @3);
 ECPG: fetch_argsFORWARDALLopt_from_incursor_name addon
 ECPG: fetch_argsBACKWARDALLopt_from_incursor_name addon
        struct cursor *ptr = add_additional_variables(@4, false);
@@ -304,7 +294,7 @@ ECPG: fetch_argsBACKWARDALLopt_from_incursor_name addon
        if (ptr->connection)
            connection = mm_strdup(ptr->connection);
        if (@4[0] == ':')
-           @$ = cat_str(4, mm_strdup(@1), mm_strdup(@2), mm_strdup(@3), mm_strdup("$0"));
+           @$ = cat_str(4, @1, @2, @3, "$0");
 ECPG: fetch_argsABSOLUTE_PSignedIconstopt_from_incursor_name addon
 ECPG: fetch_argsRELATIVE_PSignedIconstopt_from_incursor_name addon
 ECPG: fetch_argsFORWARDSignedIconstopt_from_incursor_name addon
@@ -316,20 +306,20 @@ ECPG: fetch_argsBACKWARDSignedIconstopt_from_incursor_name addon
            connection = mm_strdup(ptr->connection);
        if (@4[0] == ':')
        {
-           @4 = mm_strdup("$0");
+           @4 = "$0";
            replace = true;
        }
        if (@2[0] == '$')
        {
-           @2 = mm_strdup("$0");
+           @2 = "$0";
            replace = true;
        }
        if (replace)
-           @$ = cat_str(4, mm_strdup(@1), mm_strdup(@2), mm_strdup(@3), mm_strdup(@4));
+           @$ = cat_str(4, @1, @2, @3, @4);
 ECPG: cursor_namename block
    | char_civar
    {
-       char       *curname = mm_alloc(strlen(@1) + 2);
+       char       *curname = loc_alloc(strlen(@1) + 2);
 
        sprintf(curname, ":%s", @1);
        @$ = curname;
@@ -367,7 +357,7 @@ ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectSt
    {
        struct cursor *ptr,
                   *this;
-       char       *cursor_marker = @2[0] == ':' ? mm_strdup("$0") : mm_strdup(@2);
+       const char *cursor_marker = @2[0] == ':' ? "$0" : @2;
        char       *comment,
                   *c1,
                   *c2;
@@ -394,7 +384,7 @@ ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectSt
        this->function = (current_function ? mm_strdup(current_function) : NULL);
        this->connection = connection ? mm_strdup(connection) : NULL;
        this->opened = false;
-       this->command = cat_str(7, mm_strdup("declare"), cursor_marker, @3, mm_strdup("cursor"), @5, mm_strdup("for"), @7);
+       this->command = mm_strdup(cat_str(7, "declare", cursor_marker, @3, "cursor", @5, "for", @7));
        this->argsinsert = argsinsert;
        this->argsinsert_oos = NULL;
        this->argsresult = argsresult;
@@ -402,20 +392,20 @@ ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectSt
        argsinsert = argsresult = NULL;
        cur = this;
 
-       c1 = mm_strdup(this->command);
-       if ((c2 = strstr(c1, "*/")) != NULL)
+       c1 = loc_strdup(this->command);
+       while ((c2 = strstr(c1, "*/")) != NULL)
        {
            /* We put this text into a comment, so we better remove [*][/]. */
            c2[0] = '.';
            c2[1] = '.';
        }
-       comment = cat_str(3, mm_strdup("/*"), c1, mm_strdup("*/"));
+       comment = cat_str(3, "/*", c1, "*/");
 
        @$ = cat2_str(adjust_outofscope_cursor_vars(this), comment);
    }
 ECPG: ClosePortalStmtCLOSEcursor_name block
    {
-       char       *cursor_marker = @2[0] == ':' ? mm_strdup("$0") : @2;
+       const char *cursor_marker = @2[0] == ':' ? "$0" : @2;
        struct cursor *ptr = NULL;
 
        for (ptr = cur; ptr != NULL; ptr = ptr->next)
@@ -427,23 +417,23 @@ ECPG: ClosePortalStmtCLOSEcursor_name block
                break;
            }
        }
-       @$ = cat2_str(mm_strdup("close"), cursor_marker);
+       @$ = cat2_str("close", cursor_marker);
    }
 ECPG: opt_hold block
    {
        if (compat == ECPG_COMPAT_INFORMIX_SE && autocommit)
-           @$ = mm_strdup("with hold");
+           @$ = "with hold";
        else
-           @$ = EMPTY;
+           @$ = "";
    }
 ECPG: into_clauseINTOOptTempTableName block
    {
        FoundInto = 1;
-       @$ = cat2_str(mm_strdup("into"), @2);
+       @$ = cat2_str("into", @2);
    }
    | ecpg_into
    {
-       @$ = EMPTY;
+       @$ = "";
    }
 ECPG: TypenameSimpleTypenameopt_array_bounds block
    {
@@ -451,37 +441,33 @@ ECPG: TypenameSimpleTypenameopt_array_bounds block
    }
 ECPG: TypenameSETOFSimpleTypenameopt_array_bounds block
    {
-       @$ = cat_str(3, mm_strdup("setof"), @2, $3.str);
+       @$ = cat_str(3, "setof", @2, $3.str);
    }
 ECPG: opt_array_boundsopt_array_bounds'['']' block
    {
        $$.index1 = $1.index1;
        $$.index2 = $1.index2;
        if (strcmp($$.index1, "-1") == 0)
-           $$.index1 = mm_strdup("0");
+           $$.index1 = "0";
        else if (strcmp($1.index2, "-1") == 0)
-           $$.index2 = mm_strdup("0");
-       $$.str = cat_str(2, $1.str, mm_strdup("[]"));
+           $$.index2 = "0";
+       $$.str = cat_str(2, $1.str, "[]");
    }
    | opt_array_bounds '[' Iresult ']'
    {
        $$.index1 = $1.index1;
        $$.index2 = $1.index2;
        if (strcmp($1.index1, "-1") == 0)
-           $$.index1 = mm_strdup(@3);
+           $$.index1 = @3;
        else if (strcmp($1.index2, "-1") == 0)
-           $$.index2 = mm_strdup(@3);
-       $$.str = cat_str(4, $1.str, mm_strdup("["), @3, mm_strdup("]"));
+           $$.index2 = @3;
+       $$.str = cat_str(4, $1.str, "[", @3, "]");
    }
 ECPG: opt_array_bounds block
    {
-       $$.index1 = mm_strdup("-1");
-       $$.index2 = mm_strdup("-1");
-       $$.str = EMPTY;
-   }
-ECPG: IconstICONST block
-   {
-       @$ = make_name();
+       $$.index1 = "-1";
+       $$.index2 = "-1";
+       $$.str = "";
    }
 ECPG: AexprConstNULL_P rule
    | civar
@@ -494,83 +480,83 @@ ECPG: FetchStmtMOVEfetch_args rule
    | FETCH fetch_args ecpg_fetch_into
    | FETCH FORWARD cursor_name opt_ecpg_fetch_into
    {
-       char       *cursor_marker = @3[0] == ':' ? mm_strdup("$0") : @3;
+       const char *cursor_marker = @3[0] == ':' ? "$0" : @3;
        struct cursor *ptr = add_additional_variables(@3, false);
 
        if (ptr->connection)
            connection = mm_strdup(ptr->connection);
 
-       @$ = cat_str(2, mm_strdup("fetch forward"), cursor_marker);
+       @$ = cat_str(2, "fetch forward", cursor_marker);
    }
    | FETCH FORWARD from_in cursor_name opt_ecpg_fetch_into
    {
-       char       *cursor_marker = @4[0] == ':' ? mm_strdup("$0") : @4;
+       const char *cursor_marker = @4[0] == ':' ? "$0" : @4;
        struct cursor *ptr = add_additional_variables(@4, false);
 
        if (ptr->connection)
            connection = mm_strdup(ptr->connection);
 
-       @$ = cat_str(2, mm_strdup("fetch forward from"), cursor_marker);
+       @$ = cat_str(2, "fetch forward from", cursor_marker);
    }
    | FETCH BACKWARD cursor_name opt_ecpg_fetch_into
    {
-       char       *cursor_marker = @3[0] == ':' ? mm_strdup("$0") : @3;
+       const char *cursor_marker = @3[0] == ':' ? "$0" : @3;
        struct cursor *ptr = add_additional_variables(@3, false);
 
        if (ptr->connection)
            connection = mm_strdup(ptr->connection);
 
-       @$ = cat_str(2, mm_strdup("fetch backward"), cursor_marker);
+       @$ = cat_str(2, "fetch backward", cursor_marker);
    }
    | FETCH BACKWARD from_in cursor_name opt_ecpg_fetch_into
    {
-       char       *cursor_marker = @4[0] == ':' ? mm_strdup("$0") : @4;
+       const char *cursor_marker = @4[0] == ':' ? "$0" : @4;
        struct cursor *ptr = add_additional_variables(@4, false);
 
        if (ptr->connection)
            connection = mm_strdup(ptr->connection);
 
-       @$ = cat_str(2, mm_strdup("fetch backward from"), cursor_marker);
+       @$ = cat_str(2, "fetch backward from", cursor_marker);
    }
    | MOVE FORWARD cursor_name
    {
-       char       *cursor_marker = @3[0] == ':' ? mm_strdup("$0") : @3;
+       const char *cursor_marker = @3[0] == ':' ? "$0" : @3;
        struct cursor *ptr = add_additional_variables(@3, false);
 
        if (ptr->connection)
            connection = mm_strdup(ptr->connection);
 
-       @$ = cat_str(2, mm_strdup("move forward"), cursor_marker);
+       @$ = cat_str(2, "move forward", cursor_marker);
    }
    | MOVE FORWARD from_in cursor_name
    {
-       char       *cursor_marker = @4[0] == ':' ? mm_strdup("$0") : @4;
+       const char *cursor_marker = @4[0] == ':' ? "$0" : @4;
        struct cursor *ptr = add_additional_variables(@4, false);
 
        if (ptr->connection)
            connection = mm_strdup(ptr->connection);
 
-       @$ = cat_str(2, mm_strdup("move forward from"), cursor_marker);
+       @$ = cat_str(2, "move forward from", cursor_marker);
    }
    | MOVE BACKWARD cursor_name
    {
-       char       *cursor_marker = @3[0] == ':' ? mm_strdup("$0") : @3;
+       const char *cursor_marker = @3[0] == ':' ? "$0" : @3;
        struct cursor *ptr = add_additional_variables(@3, false);
 
        if (ptr->connection)
            connection = mm_strdup(ptr->connection);
 
-       @$ = cat_str(2, mm_strdup("move backward"), cursor_marker);
+       @$ = cat_str(2, "move backward", cursor_marker);
    }
    | MOVE BACKWARD from_in cursor_name
    {
-       char       *cursor_marker = @4[0] == ':' ? mm_strdup("$0") : @4;
+       const char *cursor_marker = @4[0] == ':' ? "$0" : @4;
        struct cursor *ptr = add_additional_variables(@4, false);
 
        if (ptr->connection)
            connection = mm_strdup(ptr->connection);
 
-       @$ = cat_str(2, mm_strdup("move backward from"), cursor_marker);
+       @$ = cat_str(2, "move backward from", cursor_marker);
    }
 ECPG: limit_clauseLIMITselect_limit_value','select_offset_value block
    {
index 929ffa97aa077aafaf761be58c2cb06ffa3cdc19..d3df8eabbb731914d75825e17daaa26587c1fc43 100644 (file)
@@ -39,8 +39,6 @@ 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;
@@ -95,7 +93,7 @@ yylloc_default(YYLTYPE *target, YYLTYPE *rhs, int N)
                needed++;
            needed += thislen;
        }
-       result = (char *) mm_alloc(needed + 1);
+       result = (char *) loc_alloc(needed + 1);
        ptr = result;
        for (int i = 1; i <= N; i++)
        {
@@ -115,22 +113,19 @@ yylloc_default(YYLTYPE *target, YYLTYPE *rhs, int N)
        *target = rhs[1];
    }
    else
-       *target = EMPTY;
+   {
+       /* No need to allocate any space */
+       *target = "";
+   }
 }
 
 /* and the rest */
 static char *
-make_name(void)
-{
-   return mm_strdup(base_yytext);
-}
-
-static char *
-create_questionmarks(char *name, bool array)
+create_questionmarks(const char *name, bool array)
 {
    struct variable *p = find_variable(name);
    int         count;
-   char       *result = EMPTY;
+   char       *result = "";
 
    /*
     * In case we have a struct, we have to print as many "?" as there are
@@ -158,12 +153,13 @@ create_questionmarks(char *name, bool array)
 
    for (; count > 0; count--)
    {
-       sprintf(pacounter_buffer, "$%d", pacounter++);
-       result = cat_str(3, result, mm_strdup(pacounter_buffer), mm_strdup(" , "));
-   }
+       char    buf[32];
 
-   /* removed the trailing " ," */
+       snprintf(buf, sizeof(buf), "$%d", pacounter++);
+       result = cat_str(3, result, buf, " , ");
+   }
 
+   /* remove the trailing " ," */
    result[strlen(result) - 3] = '\0';
    return result;
 }
@@ -183,8 +179,7 @@ adjust_outofscope_cursor_vars(struct cursor *cur)
     * pointer instead of the variable. Do it only for local variables, not
     * for globals.
     */
-
-   char       *result = EMPTY;
+   char       *result = "";
    int         insert;
 
    for (insert = 1; insert >= 0; insert--)
@@ -206,7 +201,7 @@ adjust_outofscope_cursor_vars(struct cursor *cur)
 
            /* change variable name to "ECPGget_var(<counter>)" */
            original_var = ptr->variable->name;
-           sprintf(var_text, "%d))", ecpg_internal_var);
+           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)
@@ -227,12 +222,12 @@ adjust_outofscope_cursor_vars(struct cursor *cur)
                      && 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)),
+               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,
-                                                                              mm_strdup("1"),
+                                                                              "1",
                                                                               ptr->variable->type->u.element->counter),
                                                          ptr->variable->type->size),
                                      0);
@@ -244,10 +239,10 @@ adjust_outofscope_cursor_vars(struct cursor *cur)
                      || 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)),
+               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),
@@ -259,11 +254,11 @@ adjust_outofscope_cursor_vars(struct cursor *cur)
            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(")")),
+               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,
@@ -276,11 +271,11 @@ adjust_outofscope_cursor_vars(struct cursor *cur)
                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(")")),
+                   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,
@@ -289,10 +284,10 @@ adjust_outofscope_cursor_vars(struct cursor *cur)
                }
                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)),
+                   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),
@@ -303,10 +298,10 @@ adjust_outofscope_cursor_vars(struct cursor *cur)
            }
            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)),
+               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),
@@ -320,10 +315,11 @@ adjust_outofscope_cursor_vars(struct cursor *cur)
             */
            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"));
+               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");
            }
 
            /*
@@ -338,17 +334,17 @@ adjust_outofscope_cursor_vars(struct cursor *cur)
            {
                /* change variable name to "ECPGget_var(<counter>)" */
                original_var = ptr->indicator->name;
-               sprintf(var_text, "%d))", ecpg_internal_var);
+               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, mm_strdup("(*("),
-                                                 mm_strdup(ptr->indicator->type->type_name),
-                                                 mm_strdup(" *)(ECPGget_var("),
-                                                 mm_strdup(var_text),
-                                                 mm_strdup(")")),
+                   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,
@@ -361,11 +357,11 @@ adjust_outofscope_cursor_vars(struct cursor *cur)
                    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(")")),
+                       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,
@@ -374,9 +370,10 @@ adjust_outofscope_cursor_vars(struct cursor *cur)
                    }
                    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)),
+                       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),
@@ -387,10 +384,10 @@ adjust_outofscope_cursor_vars(struct cursor *cur)
                }
                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)),
+                   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),
@@ -398,10 +395,10 @@ adjust_outofscope_cursor_vars(struct cursor *cur)
                }
                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)),
+                   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),
@@ -413,10 +410,11 @@ adjust_outofscope_cursor_vars(struct cursor *cur)
                 * 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"));
+               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);
@@ -437,7 +435,7 @@ adjust_outofscope_cursor_vars(struct cursor *cur)
     (cur->function != NULL && strcmp(cur->function, current_function) == 0))
 
 static struct cursor *
-add_additional_variables(char *name, bool insert)
+add_additional_variables(const char *name, bool insert)
 {
    struct cursor *ptr;
    struct arguments *p;
@@ -475,8 +473,10 @@ add_additional_variables(char *name, bool insert)
 }
 
 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_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,
@@ -496,19 +496,20 @@ add_typedef(char *name, char *dimension, char *length, enum ECPGttype type_enum,
                /* 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);
+       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->name = mm_strdup(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_dimension = mm_strdup(dimension); /* dimension of array */
+       this->type->type_index = mm_strdup(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;
index 2a3949ca035e00c29f11dc7f578d6044f1c7ab74..0a77559e83b4a2f5ededfa9566e53a4f44603697 100644 (file)
@@ -2,6 +2,12 @@
 
 statements: /* EMPTY */
    | statements statement
+   {
+       /* Reclaim local storage used while processing statement */
+       reclaim_local_storage();
+       /* Clean up now-dangling location pointer */
+       @$ = "";
+   }
    ;
 
 statement: ecpgstart at toplevel_stmt ';'
@@ -68,7 +74,7 @@ CreateAsStmt: CREATE OptTemp TABLE create_as_target AS
 
 at: AT connection_object
    {
-       connection = @2;
+       connection = mm_strdup(@2);
 
        /*
         * Do we have a variable as connection target?  Remove the variable
@@ -84,20 +90,20 @@ at: AT connection_object
  */
 ECPGConnect: SQL_CONNECT TO connection_target opt_connection_name opt_user
    {
-       @$ = cat_str(5, @3, mm_strdup(","), @5, mm_strdup(","), @4);
+       @$ = cat_str(5, @3, ",", @5, ",", @4);
    }
    | SQL_CONNECT TO DEFAULT
    {
-       @$ = mm_strdup("NULL, NULL, NULL, \"DEFAULT\"");
+       @$ = "NULL, NULL, NULL, \"DEFAULT\"";
    }
    /* also allow ORACLE syntax */
    | SQL_CONNECT ora_user
    {
-       @$ = cat_str(3, mm_strdup("NULL,"), @2, mm_strdup(", NULL"));
+       @$ = cat_str(3, "NULL,", @2, ", NULL");
    }
    | DATABASE connection_target
    {
-       @$ = cat2_str(@2, mm_strdup(", NULL, NULL, NULL"));
+       @$ = cat2_str(@2, ", NULL, NULL, NULL");
    }
    ;
 
@@ -111,7 +117,7 @@ connection_target: opt_database_name opt_server opt_port
        if (@1[0] == '\"')
            @$ = @1;
        else
-           @$ = make3_str(mm_strdup("\""), make3_str(@1, @2, @3), mm_strdup("\""));
+           @$ = make3_str("\"", make3_str(@1, @2, @3), "\"");
    }
    | db_prefix ':' server opt_port '/' opt_database_name opt_options
    {
@@ -127,19 +133,21 @@ connection_target: opt_database_name opt_server opt_port
            strncmp(@3 + strlen("//"), "127.0.0.1", strlen("127.0.0.1")) != 0)
            mmerror(PARSE_ERROR, ET_ERROR, "Unix-domain sockets only work on \"localhost\" but not on \"%s\"", @3 + strlen("//"));
 
-       @$ = make3_str(make3_str(mm_strdup("\""), @1, mm_strdup(":")), @3, make3_str(make3_str(@4, mm_strdup("/"), @6), @7, mm_strdup("\"")));
+       @$ = make3_str(make3_str("\"", @1, ":"), @3, make3_str(make3_str(@4, "/", @6), @7, "\""));
    }
    | char_variable
    | ecpg_sconst
    {
        /*
-        * We can only process double quoted strings not single quotes ones,
-        * so we change the quotes. Note, that the rule for ecpg_sconst adds
+        * We can only process double quoted strings not single quoted ones,
+        * so we change the quotes. Note that the rule for ecpg_sconst adds
         * these single quotes.
         */
-       @1[0] = '\"';
-       @1[strlen(@1) - 1] = '\"';
-       @$ = @1;
+       char   *str = loc_strdup(@1);
+
+       str[0] = '\"';
+       str[strlen(str) - 1] = '\"';
+       @$ = str;
    }
    ;
 
@@ -155,7 +163,7 @@ db_prefix: ecpg_ident cvariable
        if (strcmp(@1, "tcp") != 0 && strcmp(@1, "unix") != 0)
            mmerror(PARSE_ERROR, ET_ERROR, "invalid connection type: %s", @1);
 
-       @$ = make3_str(@1, mm_strdup(":"), @2);
+       @$ = make3_str(@1, ":", @2);
    }
    ;
 
@@ -175,14 +183,11 @@ opt_server: server
 server_name: ColId
    | ColId '.' server_name
    | IP
-   {
-       @$ = make_name();
-   }
    ;
 
 opt_port: ':' Iconst
    {
-       @$ = make2_str(mm_strdup(":"), @2);
+       @$ = make2_str(":", @2);
    }
    | /* EMPTY */
    ;
@@ -193,7 +198,7 @@ opt_connection_name: AS connection_object
    }
    | /* EMPTY */
    {
-       @$ = mm_strdup("NULL");
+       @$ = "NULL";
    }
    ;
 
@@ -203,25 +208,25 @@ opt_user: USER ora_user
    }
    | /* EMPTY */
    {
-       @$ = mm_strdup("NULL, NULL");
+       @$ = "NULL, NULL";
    }
    ;
 
 ora_user: user_name
    {
-       @$ = cat2_str(@1, mm_strdup(", NULL"));
+       @$ = cat2_str(@1, ", NULL");
    }
    | user_name '/' user_name
    {
-       @$ = cat_str(3, @1, mm_strdup(","), @3);
+       @$ = cat_str(3, @1, ",", @3);
    }
    | user_name SQL_IDENTIFIED BY user_name
    {
-       @$ = cat_str(3, @1, mm_strdup(","), @4);
+       @$ = cat_str(3, @1, ",", @4);
    }
    | user_name USING user_name
    {
-       @$ = cat_str(3, @1, mm_strdup(","), @3);
+       @$ = cat_str(3, @1, ",", @3);
    }
    ;
 
@@ -230,14 +235,14 @@ user_name: RoleId
        if (@1[0] == '\"')
            @$ = @1;
        else
-           @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\""));
+           @$ = make3_str("\"", @1, "\"");
    }
    | ecpg_sconst
    {
        if (@1[0] == '\"')
            @$ = @1;
        else
-           @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\""));
+           @$ = make3_str("\"", @1, "\"");
    }
    | civar
    {
@@ -249,9 +254,9 @@ user_name: RoleId
 
        /* handle varchars */
        if (type == ECPGt_varchar)
-           @$ = make2_str(mm_strdup(argsinsert->variable->name), mm_strdup(".arr"));
+           @$ = make2_str(argsinsert->variable->name, ".arr");
        else
-           @$ = mm_strdup(argsinsert->variable->name);
+           @$ = argsinsert->variable->name;
    }
    ;
 
@@ -278,7 +283,7 @@ char_variable: cvariable
                    @$ = @1;
                    break;
                case ECPGt_varchar:
-                   @$ = make2_str(@1, mm_strdup(".arr"));
+                   @$ = make2_str(@1, ".arr");
                    break;
                default:
                    mmerror(PARSE_ERROR, ET_ERROR, "invalid data type");
@@ -297,7 +302,7 @@ opt_options: Op connect_options
        if (strcmp(@1, "?") != 0)
            mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", @1);
 
-       @$ = make2_str(mm_strdup("?"), @2);
+       @$ = make2_str("?", @2);
    }
    | /* EMPTY */
    ;
@@ -321,30 +326,34 @@ connect_options: ColId opt_opt_value
 opt_opt_value: /* EMPTY */
    | '=' Iconst
    {
-       @$ = make2_str(mm_strdup("="), @2);
+       @$ = make2_str("=", @2);
    }
    | '=' ecpg_ident
    {
-       @$ = make2_str(mm_strdup("="), @2);
+       @$ = make2_str("=", @2);
    }
    | '=' civar
    {
-       @$ = make2_str(mm_strdup("="), @2);
+       @$ = make2_str("=", @2);
    }
    ;
 
 prepared_name: name
    {
-       if (@1[0] == '\"' && @1[strlen(@1) - 1] == '\"')    /* already quoted? */
+       size_t      slen = strlen(@1);
+
+       if (@1[0] == '\"' && @1[slen - 1] == '\"')  /* already quoted? */
            @$ = @1;
        else                    /* not quoted => convert to lowercase */
        {
-           size_t      i;
-
-           for (i = 0; i < strlen(@1); i++)
-               @1[i] = tolower((unsigned char) @1[i]);
-
-           @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\""));
+           char       *str = loc_alloc(slen + 3);
+
+           str[0] = '\"';
+           for (size_t i = 0; i < slen; i++)
+               str[i + 1] = tolower((unsigned char) @1[i]);
+           str[slen + 1] = '\"';
+           str[slen + 2] = '\0';
+           @$ = str;
        }
    }
    | char_variable
@@ -355,7 +364,7 @@ prepared_name: name
  */
 ECPGDeclareStmt: DECLARE prepared_name STATEMENT
    {
-       struct declared_list *ptr = NULL;
+       struct declared_list *ptr;
 
        /* Check whether the declared name has been defined or not */
        for (ptr = g_declared_list; ptr != NULL; ptr = ptr->next)
@@ -368,12 +377,11 @@ ECPGDeclareStmt: DECLARE prepared_name STATEMENT
        }
 
        /* Add a new declared name into the g_declared_list */
-       ptr = NULL;
        ptr = (struct declared_list *) mm_alloc(sizeof(struct declared_list));
        if (ptr)
        {
            /* initial definition */
-           ptr->name = @2;
+           ptr->name = mm_strdup(@2);
            if (connection)
                ptr->connection = mm_strdup(connection);
            else
@@ -383,7 +391,7 @@ ECPGDeclareStmt: DECLARE prepared_name STATEMENT
            g_declared_list = ptr;
        }
 
-       @$ = cat_str(3, mm_strdup("/* declare "), mm_strdup(@2), mm_strdup(" as an SQL identifier */"));
+       @$ = cat_str(3, "/* declare ", @2, " as an SQL identifier */");
    }
    ;
 
@@ -395,7 +403,7 @@ ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared_
    {
        struct cursor *ptr,
                   *this;
-       char       *cursor_marker = @2[0] == ':' ? mm_strdup("$0") : mm_strdup(@2);
+       const char *cursor_marker = @2[0] == ':' ? "$0" : @2;
        int         (*strcmp_fn) (const char *, const char *) = ((@2[0] == ':' || @2[0] == '"') ? strcmp : pg_strcasecmp);
        struct variable *thisquery = (struct variable *) mm_alloc(sizeof(struct variable));
        char       *comment;
@@ -422,10 +430,10 @@ ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared_
 
        /* initial definition */
        this->next = cur;
-       this->name = @2;
+       this->name = mm_strdup(@2);
        this->function = (current_function ? mm_strdup(current_function) : NULL);
        this->connection = connection ? mm_strdup(connection) : NULL;
-       this->command = cat_str(6, mm_strdup("declare"), cursor_marker, @3, mm_strdup("cursor"), @5, mm_strdup("for $1"));
+       this->command = mm_strdup(cat_str(6, "declare", cursor_marker, @3, "cursor", @5, "for $1"));
        this->argsresult = NULL;
        this->argsresult_oos = NULL;
 
@@ -448,7 +456,7 @@ ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared_
 
        cur = this;
 
-       comment = cat_str(3, mm_strdup("/*"), mm_strdup(this->command), mm_strdup("*/"));
+       comment = cat_str(3, "/*", this->command, "*/");
 
        @$ = cat_str(2, adjust_outofscope_cursor_vars(this),
                     comment);
@@ -541,45 +549,44 @@ type_declaration: S_TYPEDEF
 
        fprintf(base_yyout, "typedef %s %s %s %s;\n", $3.type_str, *@4 ? "*" : "", @5, $6.str);
        output_line_number();
-       @$ = EMPTY;
+       @$ = "";
    }
    ;
 
 var_declaration:
    storage_declaration var_type
    {
-       actual_type[struct_level].type_storage = @1;
+       actual_type[struct_level].type_storage = mm_strdup(@1);
        actual_type[struct_level].type_enum = $2.type_enum;
-       actual_type[struct_level].type_str = $2.type_str;
-       actual_type[struct_level].type_dimension = $2.type_dimension;
-       actual_type[struct_level].type_index = $2.type_index;
-       actual_type[struct_level].type_sizeof = $2.type_sizeof;
+       actual_type[struct_level].type_str = mm_strdup($2.type_str);
+       actual_type[struct_level].type_dimension = mm_strdup($2.type_dimension);
+       actual_type[struct_level].type_index = mm_strdup($2.type_index);
+       actual_type[struct_level].type_sizeof =
+           $2.type_sizeof ? mm_strdup($2.type_sizeof) : NULL;
 
        actual_startline[struct_level] = hashline_number();
    }
    variable_list ';'
    {
-       @$ = cat_str(5, actual_startline[struct_level], @1, $2.type_str, @4, mm_strdup(";\n"));
+       @$ = cat_str(5, actual_startline[struct_level], @1, $2.type_str, @4, ";\n");
    }
    | var_type
    {
-       actual_type[struct_level].type_storage = EMPTY;
+       actual_type[struct_level].type_storage = mm_strdup("");
        actual_type[struct_level].type_enum = $1.type_enum;
-       actual_type[struct_level].type_str = $1.type_str;
-       actual_type[struct_level].type_dimension = $1.type_dimension;
-       actual_type[struct_level].type_index = $1.type_index;
-       actual_type[struct_level].type_sizeof = $1.type_sizeof;
+       actual_type[struct_level].type_str = mm_strdup($1.type_str);
+       actual_type[struct_level].type_dimension = mm_strdup($1.type_dimension);
+       actual_type[struct_level].type_index = mm_strdup($1.type_index);
+       actual_type[struct_level].type_sizeof =
+           $1.type_sizeof ? mm_strdup($1.type_sizeof) : NULL;
 
        actual_startline[struct_level] = hashline_number();
    }
    variable_list ';'
    {
-       @$ = cat_str(4, actual_startline[struct_level], $1.type_str, @3, mm_strdup(";\n"));
+       @$ = cat_str(4, actual_startline[struct_level], $1.type_str, @3, ";\n");
    }
    | struct_union_type_with_symbol ';'
-   {
-       @$ = cat2_str(@1, mm_strdup(";"));
-   }
    ;
 
 opt_bit_field: ':' Iconst
@@ -604,16 +611,16 @@ storage_modifier: S_CONST
 var_type: simple_type
    {
        $$.type_enum = $1;
-       $$.type_str = mm_strdup(ecpg_type_name($1));
-       $$.type_dimension = mm_strdup("-1");
-       $$.type_index = mm_strdup("-1");
+       $$.type_str = loc_strdup(ecpg_type_name($1));
+       $$.type_dimension = "-1";
+       $$.type_index = "-1";
        $$.type_sizeof = NULL;
    }
    | struct_union_type
    {
-       $$.type_str = @1;
-       $$.type_dimension = mm_strdup("-1");
-       $$.type_index = mm_strdup("-1");
+       $$.type_str = loc_strdup(@1);
+       $$.type_dimension = "-1";
+       $$.type_index = "-1";
 
        if (strncmp(@1, "struct", sizeof("struct") - 1) == 0)
        {
@@ -628,26 +635,26 @@ var_type: simple_type
    }
    | enum_type
    {
-       $$.type_str = @1;
+       $$.type_str = loc_strdup(@1);
        $$.type_enum = ECPGt_int;
-       $$.type_dimension = mm_strdup("-1");
-       $$.type_index = mm_strdup("-1");
+       $$.type_dimension = "-1";
+       $$.type_index = "-1";
        $$.type_sizeof = NULL;
    }
    | NUMERIC '(' precision opt_scale ')'
    {
        $$.type_enum = ECPGt_numeric;
-       $$.type_str = mm_strdup("numeric");
-       $$.type_dimension = mm_strdup("-1");
-       $$.type_index = mm_strdup("-1");
+       $$.type_str = "numeric";
+       $$.type_dimension = "-1";
+       $$.type_index = "-1";
        $$.type_sizeof = NULL;
    }
    | DECIMAL_P '(' precision opt_scale ')'
    {
        $$.type_enum = ECPGt_decimal;
-       $$.type_str = mm_strdup("decimal");
-       $$.type_dimension = mm_strdup("-1");
-       $$.type_index = mm_strdup("-1");
+       $$.type_str = "decimal";
+       $$.type_dimension = "-1";
+       $$.type_index = "-1";
        $$.type_sizeof = NULL;
    }
    | IDENT '(' precision opt_scale ')'
@@ -660,63 +667,63 @@ var_type: simple_type
        if (strcmp(@1, "numeric") == 0)
        {
            $$.type_enum = ECPGt_numeric;
-           $$.type_str = mm_strdup("numeric");
+           $$.type_str = "numeric";
        }
        else if (strcmp(@1, "decimal") == 0)
        {
            $$.type_enum = ECPGt_decimal;
-           $$.type_str = mm_strdup("decimal");
+           $$.type_str = "decimal";
        }
        else
        {
            mmerror(PARSE_ERROR, ET_ERROR, "only data types numeric and decimal have precision/scale argument");
            $$.type_enum = ECPGt_numeric;
-           $$.type_str = mm_strdup("numeric");
+           $$.type_str = "numeric";
        }
 
-       $$.type_dimension = mm_strdup("-1");
-       $$.type_index = mm_strdup("-1");
+       $$.type_dimension = "-1";
+       $$.type_index = "-1";
        $$.type_sizeof = NULL;
    }
    | VARCHAR
    {
        $$.type_enum = ECPGt_varchar;
-       $$.type_str = EMPTY;    /* mm_strdup("varchar"); */
-       $$.type_dimension = mm_strdup("-1");
-       $$.type_index = mm_strdup("-1");
+       $$.type_str = "";   /* "varchar"; */
+       $$.type_dimension = "-1";
+       $$.type_index = "-1";
        $$.type_sizeof = NULL;
    }
    | FLOAT_P
    {
        /* Note: DOUBLE is handled in simple_type */
        $$.type_enum = ECPGt_float;
-       $$.type_str = mm_strdup("float");
-       $$.type_dimension = mm_strdup("-1");
-       $$.type_index = mm_strdup("-1");
+       $$.type_str = "float";
+       $$.type_dimension = "-1";
+       $$.type_index = "-1";
        $$.type_sizeof = NULL;
    }
    | NUMERIC
    {
        $$.type_enum = ECPGt_numeric;
-       $$.type_str = mm_strdup("numeric");
-       $$.type_dimension = mm_strdup("-1");
-       $$.type_index = mm_strdup("-1");
+       $$.type_str = "numeric";
+       $$.type_dimension = "-1";
+       $$.type_index = "-1";
        $$.type_sizeof = NULL;
    }
    | DECIMAL_P
    {
        $$.type_enum = ECPGt_decimal;
-       $$.type_str = mm_strdup("decimal");
-       $$.type_dimension = mm_strdup("-1");
-       $$.type_index = mm_strdup("-1");
+       $$.type_str = "decimal";
+       $$.type_dimension = "-1";
+       $$.type_index = "-1";
        $$.type_sizeof = NULL;
    }
    | TIMESTAMP
    {
        $$.type_enum = ECPGt_timestamp;
-       $$.type_str = mm_strdup("timestamp");
-       $$.type_dimension = mm_strdup("-1");
-       $$.type_index = mm_strdup("-1");
+       $$.type_str = "timestamp";
+       $$.type_dimension = "-1";
+       $$.type_index = "-1";
        $$.type_sizeof = NULL;
    }
    | STRING_P
@@ -725,9 +732,9 @@ var_type: simple_type
        {
            /* In Informix mode, "string" is automatically a typedef */
            $$.type_enum = ECPGt_string;
-           $$.type_str = mm_strdup("char");
-           $$.type_dimension = mm_strdup("-1");
-           $$.type_index = mm_strdup("-1");
+           $$.type_str = "char";
+           $$.type_dimension = "-1";
+           $$.type_index = "-1";
            $$.type_sizeof = NULL;
        }
        else
@@ -735,14 +742,14 @@ var_type: simple_type
            /* Otherwise, legal only if user typedef'ed it */
            struct typedefs *this = get_typedef("string", false);
 
-           $$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? EMPTY : mm_strdup(this->name);
+           $$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? mm_strdup("") : mm_strdup(this->name);
            $$.type_enum = this->type->type_enum;
            $$.type_dimension = this->type->type_dimension;
            $$.type_index = this->type->type_index;
            if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0)
                $$.type_sizeof = this->type->type_sizeof;
            else
-               $$.type_sizeof = cat_str(3, mm_strdup("sizeof("), mm_strdup(this->name), mm_strdup(")"));
+               $$.type_sizeof = cat_str(3, "sizeof(", this->name, ")");
 
            struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
        }
@@ -750,9 +757,9 @@ var_type: simple_type
    | INTERVAL ecpg_interval
    {
        $$.type_enum = ECPGt_interval;
-       $$.type_str = mm_strdup("interval");
-       $$.type_dimension = mm_strdup("-1");
-       $$.type_index = mm_strdup("-1");
+       $$.type_str = "interval";
+       $$.type_dimension = "-1";
+       $$.type_index = "-1";
        $$.type_sizeof = NULL;
    }
    | IDENT ecpg_interval
@@ -772,89 +779,89 @@ var_type: simple_type
        if (strcmp(@1, "varchar") == 0)
        {
            $$.type_enum = ECPGt_varchar;
-           $$.type_str = EMPTY;    /* mm_strdup("varchar"); */
-           $$.type_dimension = mm_strdup("-1");
-           $$.type_index = mm_strdup("-1");
+           $$.type_str = "";   /* "varchar"; */
+           $$.type_dimension = "-1";
+           $$.type_index = "-1";
            $$.type_sizeof = NULL;
        }
        else if (strcmp(@1, "bytea") == 0)
        {
            $$.type_enum = ECPGt_bytea;
-           $$.type_str = EMPTY;
-           $$.type_dimension = mm_strdup("-1");
-           $$.type_index = mm_strdup("-1");
+           $$.type_str = "";
+           $$.type_dimension = "-1";
+           $$.type_index = "-1";
            $$.type_sizeof = NULL;
        }
        else if (strcmp(@1, "float") == 0)
        {
            $$.type_enum = ECPGt_float;
-           $$.type_str = mm_strdup("float");
-           $$.type_dimension = mm_strdup("-1");
-           $$.type_index = mm_strdup("-1");
+           $$.type_str = "float";
+           $$.type_dimension = "-1";
+           $$.type_index = "-1";
            $$.type_sizeof = NULL;
        }
        else if (strcmp(@1, "double") == 0)
        {
            $$.type_enum = ECPGt_double;
-           $$.type_str = mm_strdup("double");
-           $$.type_dimension = mm_strdup("-1");
-           $$.type_index = mm_strdup("-1");
+           $$.type_str = "double";
+           $$.type_dimension = "-1";
+           $$.type_index = "-1";
            $$.type_sizeof = NULL;
        }
        else if (strcmp(@1, "numeric") == 0)
        {
            $$.type_enum = ECPGt_numeric;
-           $$.type_str = mm_strdup("numeric");
-           $$.type_dimension = mm_strdup("-1");
-           $$.type_index = mm_strdup("-1");
+           $$.type_str = "numeric";
+           $$.type_dimension = "-1";
+           $$.type_index = "-1";
            $$.type_sizeof = NULL;
        }
        else if (strcmp(@1, "decimal") == 0)
        {
            $$.type_enum = ECPGt_decimal;
-           $$.type_str = mm_strdup("decimal");
-           $$.type_dimension = mm_strdup("-1");
-           $$.type_index = mm_strdup("-1");
+           $$.type_str = "decimal";
+           $$.type_dimension = "-1";
+           $$.type_index = "-1";
            $$.type_sizeof = NULL;
        }
        else if (strcmp(@1, "date") == 0)
        {
            $$.type_enum = ECPGt_date;
-           $$.type_str = mm_strdup("date");
-           $$.type_dimension = mm_strdup("-1");
-           $$.type_index = mm_strdup("-1");
+           $$.type_str = "date";
+           $$.type_dimension = "-1";
+           $$.type_index = "-1";
            $$.type_sizeof = NULL;
        }
        else if (strcmp(@1, "timestamp") == 0)
        {
            $$.type_enum = ECPGt_timestamp;
-           $$.type_str = mm_strdup("timestamp");
-           $$.type_dimension = mm_strdup("-1");
-           $$.type_index = mm_strdup("-1");
+           $$.type_str = "timestamp";
+           $$.type_dimension = "-1";
+           $$.type_index = "-1";
            $$.type_sizeof = NULL;
        }
        else if (strcmp(@1, "interval") == 0)
        {
            $$.type_enum = ECPGt_interval;
-           $$.type_str = mm_strdup("interval");
-           $$.type_dimension = mm_strdup("-1");
-           $$.type_index = mm_strdup("-1");
+           $$.type_str = "interval";
+           $$.type_dimension = "-1";
+           $$.type_index = "-1";
            $$.type_sizeof = NULL;
        }
        else if (strcmp(@1, "datetime") == 0)
        {
            $$.type_enum = ECPGt_timestamp;
-           $$.type_str = mm_strdup("timestamp");
-           $$.type_dimension = mm_strdup("-1");
-           $$.type_index = mm_strdup("-1");
+           $$.type_str = "timestamp";
+           $$.type_dimension = "-1";
+           $$.type_index = "-1";
            $$.type_sizeof = NULL;
        }
        else if ((strcmp(@1, "string") == 0) && INFORMIX_MODE)
        {
            $$.type_enum = ECPGt_string;
-           $$.type_str = mm_strdup("char");
-           $$.type_dimension = mm_strdup("-1");
-           $$.type_index = mm_strdup("-1");
+           $$.type_str = "char";
+           $$.type_dimension = "-1";
+           $$.type_index = "-1";
            $$.type_sizeof = NULL;
        }
        else
@@ -862,14 +869,14 @@ var_type: simple_type
            /* Otherwise, it must be a user-defined typedef name */
            struct typedefs *this = get_typedef(@1, false);
 
-           $$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? EMPTY : mm_strdup(this->name);
+           $$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? mm_strdup("") : mm_strdup(this->name);
            $$.type_enum = this->type->type_enum;
            $$.type_dimension = this->type->type_dimension;
            $$.type_index = this->type->type_index;
            if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0)
                $$.type_sizeof = this->type->type_sizeof;
            else
-               $$.type_sizeof = cat_str(3, mm_strdup("sizeof("), mm_strdup(this->name), mm_strdup(")"));
+               $$.type_sizeof = cat_str(3, "sizeof(", this->name, ")");
 
            struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
        }
@@ -888,21 +895,20 @@ var_type: simple_type
            /* No */
 
            this = get_typedef(name, false);
-           $$.type_str = mm_strdup(this->name);
+           $$.type_str = this->name;
            $$.type_enum = this->type->type_enum;
            $$.type_dimension = this->type->type_dimension;
            $$.type_index = this->type->type_index;
            $$.type_sizeof = this->type->type_sizeof;
            struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
-           free(name);
        }
        else
        {
            $$.type_str = name;
            $$.type_enum = ECPGt_long;
-           $$.type_dimension = mm_strdup("-1");
-           $$.type_index = mm_strdup("-1");
-           $$.type_sizeof = mm_strdup("");
+           $$.type_dimension = "-1";
+           $$.type_index = "-1";
+           $$.type_sizeof = "";
            struct_member_list[struct_level] = NULL;
        }
    }
@@ -932,7 +938,7 @@ struct_union_type_with_symbol: s_struct_union_symbol
        ECPGfree_struct_member(struct_member_list[struct_level]);
        struct_member_list[struct_level] = NULL;
        struct_level--;
-       if (strncmp($1.su, "struct", sizeof("struct") - 1) == 0)
+       if (strcmp($1.su, "struct") == 0)
            su_type.type_enum = ECPGt_struct;
        else
            su_type.type_enum = ECPGt_union;
@@ -967,7 +973,7 @@ struct_union_type_with_symbol: s_struct_union_symbol
        this->struct_member_list = struct_member_list[struct_level];
 
        types = this;
-       @$ = cat_str(4, su_type.type_str, mm_strdup("{"), @4, mm_strdup("}"));
+       @$ = cat_str(4, su_type.type_str, "{", @4, "}");
    }
    ;
 
@@ -983,19 +989,21 @@ struct_union_type: struct_union_type_with_symbol
        ECPGfree_struct_member(struct_member_list[struct_level]);
        struct_member_list[struct_level] = NULL;
        struct_level--;
-       @$ = cat_str(4, @1, mm_strdup("{"), @4, mm_strdup("}"));
+       @$ = cat_str(4, @1, "{", @4, "}");
    }
    ;
 
 s_struct_union_symbol: SQL_STRUCT symbol
    {
-       $$.su = mm_strdup("struct");
+       $$.su = "struct";
        $$.symbol = @2;
-       ECPGstruct_sizeof = cat_str(3, mm_strdup("sizeof("), cat2_str(mm_strdup($$.su), mm_strdup($$.symbol)), mm_strdup(")"));
+       ECPGstruct_sizeof = mm_strdup(cat_str(3, "sizeof(",
+                                             cat2_str($$.su, $$.symbol),
+                                             ")"));
    }
    | UNION symbol
    {
-       $$.su = mm_strdup("union");
+       $$.su = "union";
        $$.symbol = @2;
    }
    ;
@@ -1004,11 +1012,11 @@ s_struct_union: SQL_STRUCT
    {
        ECPGstruct_sizeof = mm_strdup("");  /* This must not be NULL to
                                             * distinguish from simple types. */
-       @$ = mm_strdup("struct");
+       @$ = "struct";
    }
    | UNION
    {
-       @$ = mm_strdup("union");
+       @$ = "union";
    }
    ;
 
@@ -1047,23 +1055,27 @@ variable_list: variable
    | variable_list ',' variable
    {
        if (actual_type[struct_level].type_enum == ECPGt_varchar || actual_type[struct_level].type_enum == ECPGt_bytea)
-           @$ = cat_str(4, @1, mm_strdup(";"), mm_strdup(actual_type[struct_level].type_storage), @3);
+           @$ = cat_str(4, @1, ";", actual_type[struct_level].type_storage, @3);
        else
-           @$ = cat_str(3, @1, mm_strdup(","), @3);
+           @$ = cat_str(3, @1, ",", @3);
    }
    ;
 
 variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initializer
    {
        struct ECPGtype *type;
-       char       *dimension = $3.index1;  /* dimension of array */
-       char       *length = $3.index2; /* length of string */
+       const char *dimension = $3.index1;  /* dimension of array */
+       const char *length = $3.index2; /* length of string */
        char       *dim_str;
-       char       *vcn;
+       char        vcn[32];
        int        *varlen_type_counter;
        char       *struct_name;
 
-       adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension, actual_type[struct_level].type_index, strlen(@1), false);
+       adjust_array(actual_type[struct_level].type_enum,
+                    &dimension, &length,
+                    actual_type[struct_level].type_dimension,
+                    actual_type[struct_level].type_index,
+                    strlen(@1), false);
        switch (actual_type[struct_level].type_enum)
        {
            case ECPGt_struct:
@@ -1073,7 +1085,7 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initialize
                else
                    type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum, actual_type[struct_level].type_str, actual_type[struct_level].type_sizeof), dimension);
 
-               @$ = cat_str(5, @1, mm_strdup(@2), $3.str, @4, @5);
+               @$ = cat_str(5, @1, @2, $3.str, @4, @5);
                break;
 
            case ECPGt_varchar:
@@ -1094,9 +1106,9 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initialize
                    type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, *varlen_type_counter), dimension);
 
                if (strcmp(dimension, "0") == 0 || abs(atoi(dimension)) == 1)
-                   dim_str = mm_strdup("");
+                   dim_str = "";
                else
-                   dim_str = cat_str(3, mm_strdup("["), mm_strdup(dimension), mm_strdup("]"));
+                   dim_str = cat_str(3, "[", dimension, "]");
 
                /*
                 * cannot check for atoi <= 0 because a defined constant will
@@ -1109,12 +1121,11 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initialize
                 * make sure varchar struct name is unique by adding a unique
                 * counter to its definition
                 */
-               vcn = (char *) mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
-               sprintf(vcn, "%d", *varlen_type_counter);
+               snprintf(vcn, sizeof(vcn), "%d", *varlen_type_counter);
                if (strcmp(dimension, "0") == 0)
-                   @$ = cat_str(7, make2_str(mm_strdup(struct_name), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length), mm_strdup("]; } *"), mm_strdup(@2), @4, @5);
+                   @$ = cat_str(7, make2_str(struct_name, vcn), " { int len; char arr[", length, "]; } *", @2, @4, @5);
                else
-                   @$ = cat_str(8, make2_str(mm_strdup(struct_name), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length), mm_strdup("]; } "), mm_strdup(@2), dim_str, @4, @5);
+                   @$ = cat_str(8, make2_str(struct_name, vcn), " { int len; char arr[", length, "]; } ", @2, dim_str, @4, @5);
                (*varlen_type_counter)++;
                break;
 
@@ -1132,25 +1143,26 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initialize
                         * if we have an initializer but no string size set,
                         * let's use the initializer's length
                         */
-                       free(length);
-                       length = mm_alloc(i + sizeof("sizeof()"));
-                       sprintf(length, "sizeof(%s)", @5 + 2);
+                       char   *buf = loc_alloc(32);
+
+                       snprintf(buf, 32, "sizeof(%s)", @5 + 2);
+                       length = buf;
                    }
                    type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0);
                }
                else
                    type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0), dimension);
 
-               @$ = cat_str(5, @1, mm_strdup(@2), $3.str, @4, @5);
+               @$ = cat_str(5, @1, @2, $3.str, @4, @5);
                break;
 
            default:
                if (atoi(dimension) < 0)
-                   type = ECPGmake_simple_type(actual_type[struct_level].type_enum, mm_strdup("1"), 0);
+                   type = ECPGmake_simple_type(actual_type[struct_level].type_enum, "1", 0);
                else
-                   type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, mm_strdup("1"), 0), dimension);
+                   type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, "1", 0), dimension);
 
-               @$ = cat_str(5, @1, mm_strdup(@2), $3.str, @4, @5);
+               @$ = cat_str(5, @1, @2, $3.str, @4, @5);
                break;
        }
 
@@ -1172,7 +1184,7 @@ opt_pointer: /* EMPTY */
    | '*'
    | '*' '*'
    {
-       @$ = mm_strdup("**");
+       @$ = "**";
    }
    ;
 
@@ -1182,7 +1194,7 @@ opt_pointer: /* EMPTY */
 ECPGDeclare: DECLARE STATEMENT ecpg_ident
    {
        /* this is only supported for compatibility */
-       @$ = cat_str(3, mm_strdup("/* declare statement"), @3, mm_strdup("*/"));
+       @$ = cat_str(3, "/* declare statement", @3, "*/");
    }
    ;
 /*
@@ -1197,25 +1209,25 @@ ECPGDisconnect: SQL_DISCONNECT dis_name
 dis_name: connection_object
    | CURRENT_P
    {
-       @$ = mm_strdup("\"CURRENT\"");
+       @$ = "\"CURRENT\"";
    }
    | ALL
    {
-       @$ = mm_strdup("\"ALL\"");
+       @$ = "\"ALL\"";
    }
    | /* EMPTY */
    {
-       @$ = mm_strdup("\"CURRENT\"");
+       @$ = "\"CURRENT\"";
    }
    ;
 
 connection_object: name
    {
-       @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\""));
+       @$ = make3_str("\"", @1, "\"");
    }
    | DEFAULT
    {
-       @$ = mm_strdup("\"DEFAULT\"");
+       @$ = "\"DEFAULT\"";
    }
    | char_variable
    ;
@@ -1223,7 +1235,7 @@ connection_object: name
 execstring: char_variable
    | CSTRING
    {
-       @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\""));
+       @$ = make3_str("\"", @1, "\"");
    }
    ;
 
@@ -1237,7 +1249,7 @@ ECPGFree: SQL_FREE cursor_name
    }
    | SQL_FREE ALL
    {
-       @$ = mm_strdup("all");
+       @$ = "all";
    }
    ;
 
@@ -1258,7 +1270,7 @@ opt_ecpg_using: /* EMPTY */
 
 ecpg_using: USING using_list
    {
-       @$ = EMPTY;
+       @$ = "";
    }
    | using_descriptor
    ;
@@ -1266,31 +1278,31 @@ ecpg_using: USING using_list
 using_descriptor: USING SQL_P SQL_DESCRIPTOR quoted_ident_stringvar
    {
        add_variable_to_head(&argsinsert, descriptor_variable(@4, 0), &no_indicator);
-       @$ = EMPTY;
+       @$ = "";
    }
    | USING SQL_DESCRIPTOR name
    {
        add_variable_to_head(&argsinsert, sqlda_variable(@3), &no_indicator);
-       @$ = EMPTY;
+       @$ = "";
    }
    ;
 
 into_descriptor: INTO SQL_P SQL_DESCRIPTOR quoted_ident_stringvar
    {
        add_variable_to_head(&argsresult, descriptor_variable(@4, 1), &no_indicator);
-       @$ = EMPTY;
+       @$ = "";
    }
    | INTO SQL_DESCRIPTOR name
    {
        add_variable_to_head(&argsresult, sqlda_variable(@3), &no_indicator);
-       @$ = EMPTY;
+       @$ = "";
    }
    ;
 
 into_sqlda: INTO name
    {
        add_variable_to_head(&argsresult, sqlda_variable(@2), &no_indicator);
-       @$ = EMPTY;
+       @$ = "";
    }
    ;
 
@@ -1299,18 +1311,18 @@ using_list: UsingValue | UsingValue ',' using_list
 
 UsingValue: UsingConst
    {
-       char       *length = mm_alloc(32);
+       char        length[32];
 
-       sprintf(length, "%zu", strlen(@1));
+       snprintf(length, sizeof(length), "%zu", strlen(@1));
        add_variable_to_head(&argsinsert, new_variable(@1, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator);
    }
    | civar
    {
-       @$ = EMPTY;
+       @$ = "";
    }
    | civarind
    {
-       @$ = EMPTY;
+       @$ = "";
    }
    ;
 
@@ -1430,9 +1442,9 @@ ECPGSetDescHeaderItem: desc_header_item '=' IntConstVar
 
 IntConstVar: Iconst
    {
-       char       *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
+       char        length[32];
 
-       sprintf(length, "%zu", strlen(@1));
+       snprintf(length, sizeof(length), "%zu", strlen(@1));
        new_variable(@1, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
    }
    | cvariable
@@ -1484,37 +1496,39 @@ ECPGSetDescItem: descriptor_item '=' AllConstVar
 
 AllConstVar: ecpg_fconst
    {
-       char       *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
+       char        length[32];
 
-       sprintf(length, "%zu", strlen(@1));
+       snprintf(length, sizeof(length), "%zu", strlen(@1));
        new_variable(@1, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
    }
    | IntConstVar
    | '-' ecpg_fconst
    {
-       char       *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
-       char       *var = cat2_str(mm_strdup("-"), @2);
+       char        length[32];
+       char       *var = cat2_str("-", @2);
 
-       sprintf(length, "%zu", strlen(var));
+       snprintf(length, sizeof(length), "%zu", strlen(var));
        new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
        @$ = var;
    }
    | '-' Iconst
    {
-       char       *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
-       char       *var = cat2_str(mm_strdup("-"), @2);
+       char        length[32];
+       char       *var = cat2_str("-", @2);
 
-       sprintf(length, "%zu", strlen(var));
+       snprintf(length, sizeof(length), "%zu", strlen(var));
        new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
        @$ = var;
    }
    | ecpg_sconst
    {
-       char       *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
-       char       *var = @1 + 1;
+       char        length[32];
+       char       *var;
 
+       /* Strip single quotes from ecpg_sconst */
+       var = loc_strdup(@1 + 1);
        var[strlen(var) - 1] = '\0';
-       sprintf(length, "%zu", strlen(var));
+       snprintf(length, sizeof(length), "%zu", strlen(var));
        new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
        @$ = var;
    }
@@ -1587,9 +1601,9 @@ ECPGTypedef: TYPE_P
        add_typedef(@3, $6.index1, $6.index2, $5.type_enum, $5.type_dimension, $5.type_index, initializer, *@7 ? 1 : 0);
 
        if (auto_create_c == false)
-           @$ = cat_str(7, mm_strdup("/* exec sql type"), mm_strdup(@3), mm_strdup("is"), mm_strdup($5.type_str), mm_strdup($6.str), @7, mm_strdup("*/"));
+           @$ = cat_str(7, "/* exec sql type", @3, "is", $5.type_str, $6.str, @7, "*/");
        else
-           @$ = cat_str(6, mm_strdup("typedef "), mm_strdup($5.type_str), *@7 ? mm_strdup("*") : mm_strdup(""), mm_strdup(@3), mm_strdup($6.str), mm_strdup(";"));
+           @$ = cat_str(6, "typedef ", $5.type_str, *@7 ? "*" : "", @3, $6.str, ";");
    }
    ;
 
@@ -1609,8 +1623,8 @@ ECPGVar: SQL_VAR
    ColLabel    IS var_type opt_array_bounds opt_reference
    {
        struct variable *p = find_variable(@3);
-       char       *dimension = $6.index1;
-       char       *length = $6.index2;
+       const char *dimension = $6.index1;
+       const char *length = $6.index2;
        struct ECPGtype *type;
 
        if          (($5.type_enum == ECPGt_struct ||
@@ -1619,7 +1633,8 @@ ECPGVar: SQL_VAR
            mmerror(PARSE_ERROR, ET_ERROR, "initializer not allowed in EXEC SQL VAR command");
        else
        {
-           adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *@7 ? 1 : 0, false);
+           adjust_array($5.type_enum, &dimension, &length,
+                        $5.type_dimension, $5.type_index, *@7 ? 1 : 0, false);
 
            switch ($5.type_enum)
            {
@@ -1653,9 +1668,9 @@ ECPGVar: SQL_VAR
                        mmerror(PARSE_ERROR, ET_ERROR, "multidimensional arrays for simple data types are not supported");
 
                    if (atoi(dimension) < 0)
-                       type = ECPGmake_simple_type($5.type_enum, mm_strdup("1"), 0);
+                       type = ECPGmake_simple_type($5.type_enum, "1", 0);
                    else
-                       type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, mm_strdup("1"), 0), dimension);
+                       type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, "1", 0), dimension);
                    break;
            }
 
@@ -1663,7 +1678,7 @@ ECPGVar: SQL_VAR
            p->type = type;
        }
 
-                   @$ = cat_str(7, mm_strdup("/* exec sql var"), mm_strdup(@3), mm_strdup("is"), mm_strdup($5.type_str), mm_strdup($6.str), @7, mm_strdup("*/"));
+                   @$ = cat_str(7, "/* exec sql var", @3, "is", $5.type_str, $6.str, @7, "*/");
    }
    ;
 
@@ -1673,83 +1688,83 @@ ECPGVar: SQL_VAR
  */
 ECPGWhenever: SQL_WHENEVER SQL_SQLERROR action
    {
-       when_error.code = $<action>3.code;
-       when_error.command = $<action>3.command;
-       @$ = cat_str(3, mm_strdup("/* exec sql whenever sqlerror "), $3.str, mm_strdup("; */"));
+       when_error.code = $3.code;
+       when_error.command = $3.command ? mm_strdup($3.command) : NULL;
+       @$ = cat_str(3, "/* exec sql whenever sqlerror ", $3.str, "; */");
    }
    | SQL_WHENEVER NOT SQL_FOUND action
    {
-       when_nf.code = $<action>4.code;
-       when_nf.command = $<action>4.command;
-       @$ = cat_str(3, mm_strdup("/* exec sql whenever not found "), $4.str, mm_strdup("; */"));
+       when_nf.code = $4.code;
+       when_nf.command = $4.command ? mm_strdup($4.command) : NULL;
+       @$ = cat_str(3, "/* exec sql whenever not found ", $4.str, "; */");
    }
    | SQL_WHENEVER SQL_SQLWARNING action
    {
-       when_warn.code = $<action>3.code;
-       when_warn.command = $<action>3.command;
-       @$ = cat_str(3, mm_strdup("/* exec sql whenever sql_warning "), $3.str, mm_strdup("; */"));
+       when_warn.code = $3.code;
+       when_warn.command = $3.command ? mm_strdup($3.command) : NULL;
+       @$ = cat_str(3, "/* exec sql whenever sql_warning ", $3.str, "; */");
    }
    ;
 
 action: CONTINUE_P
    {
-       $<action>$.code = W_NOTHING;
-       $<action>$.command = NULL;
-       $<action>$.str = mm_strdup("continue");
+       $$.code = W_NOTHING;
+       $$.command = NULL;
+       $$.str = "continue";
    }
    | SQL_SQLPRINT
    {
-       $<action>$.code = W_SQLPRINT;
-       $<action>$.command = NULL;
-       $<action>$.str = mm_strdup("sqlprint");
+       $$.code = W_SQLPRINT;
+       $$.command = NULL;
+       $$.str = "sqlprint";
    }
    | SQL_STOP
    {
-       $<action>$.code = W_STOP;
-       $<action>$.command = NULL;
-       $<action>$.str = mm_strdup("stop");
+       $$.code = W_STOP;
+       $$.command = NULL;
+       $$.str = "stop";
    }
    | SQL_GOTO name
    {
-       $<action>$.code = W_GOTO;
-       $<action>$.command = mm_strdup(@2);
-       $<action>$.str = cat2_str(mm_strdup("goto "), @2);
+       $$.code = W_GOTO;
+       $$.command = loc_strdup(@2);
+       $$.str = cat2_str("goto ", @2);
    }
    | SQL_GO TO name
    {
-       $<action>$.code = W_GOTO;
-       $<action>$.command = mm_strdup(@3);
-       $<action>$.str = cat2_str(mm_strdup("goto "), @3);
+       $$.code = W_GOTO;
+       $$.command = loc_strdup(@3);
+       $$.str = cat2_str("goto ", @3);
    }
    | DO name '(' c_args ')'
    {
-       $<action>$.code = W_DO;
-       $<action>$.command = cat_str(4, @2, mm_strdup("("), @4, mm_strdup(")"));
-       $<action>$.str = cat2_str(mm_strdup("do"), mm_strdup($<action>$.command));
+       $$.code = W_DO;
+       $$.command = cat_str(4, @2, "(", @4, ")");
+       $$.str = cat2_str("do", $$.command);
    }
    | DO SQL_BREAK
    {
-       $<action>$.code = W_BREAK;
-       $<action>$.command = NULL;
-       $<action>$.str = mm_strdup("break");
+       $$.code = W_BREAK;
+       $$.command = NULL;
+       $$.str = "break";
    }
    | DO CONTINUE_P
    {
-       $<action>$.code = W_CONTINUE;
-       $<action>$.command = NULL;
-       $<action>$.str = mm_strdup("continue");
+       $$.code = W_CONTINUE;
+       $$.command = NULL;
+       $$.str = "continue";
    }
    | CALL name '(' c_args ')'
    {
-       $<action>$.code = W_DO;
-       $<action>$.command = cat_str(4, @2, mm_strdup("("), @4, mm_strdup(")"));
-       $<action>$.str = cat2_str(mm_strdup("call"), mm_strdup($<action>$.command));
+       $$.code = W_DO;
+       $$.command = cat_str(4, @2, "(", @4, ")");
+       $$.str = cat2_str("call", $$.command);
    }
    | CALL name
    {
-       $<action>$.code = W_DO;
-       $<action>$.command = cat2_str(@2, mm_strdup("()"));
-       $<action>$.str = cat2_str(mm_strdup("call"), mm_strdup($<action>$.command));
+       $$.code = W_DO;
+       $$.command = cat2_str(@2, "()");
+       $$.str = cat2_str("call", $$.command);
    }
    ;
 
@@ -1913,7 +1928,7 @@ ecpgstart: SQL_START
    {
        reset_variables();
        pacounter = 1;
-       @$ = EMPTY;
+       @$ = "";
    }
    ;
 
@@ -1982,7 +1997,7 @@ cvariable: CVARIABLE
         * As long as multidimensional arrays are not implemented we have to
         * check for those here
         */
-       char       *ptr = @1;
+       const char *ptr = @1;
        int         brace_open = 0,
                    brace = false;
 
@@ -2013,18 +2028,12 @@ cvariable: CVARIABLE
    ;
 
 ecpg_param: PARAM
-   {
-       @$ = make_name();
-   }
    ;
 
 ecpg_bconst: BCONST
    ;
 
 ecpg_fconst: FCONST
-   {
-       @$ = make_name();
-   }
    ;
 
 ecpg_sconst: SCONST
@@ -2036,17 +2045,17 @@ ecpg_xconst: XCONST
 ecpg_ident: IDENT
    | CSTRING
    {
-       @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\""));
+       @$ = make3_str("\"", @1, "\"");
    }
    ;
 
 quoted_ident_stringvar: name
    {
-       @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\""));
+       @$ = make3_str("\"", @1, "\"");
    }
    | char_variable
    {
-       @$ = make3_str(mm_strdup("("), @1, mm_strdup(")"));
+       @$ = make3_str("(", @1, ")");
    }
    ;
 
@@ -2057,7 +2066,7 @@ quoted_ident_stringvar: name
 c_stuff_item: c_anything
    | '(' ')'
    {
-       @$ = mm_strdup("()");
+       @$ = "()";
    }
    | '(' c_stuff ')'
    ;
@@ -2094,7 +2103,7 @@ c_anything: ecpg_ident
    | '-'
    | '/'
    | '%'
-   | NULL_P                        { @$ = mm_strdup("NULL"); }
+   | NULL_P                        { @$ = "NULL"; }
    | S_ADD
    | S_AND
    | S_ANYTHING
@@ -2155,11 +2164,11 @@ DeallocateStmt: DEALLOCATE prepared_name
    }
    | DEALLOCATE ALL
    {
-       @$ = mm_strdup("all");
+       @$ = "all";
    }
    | DEALLOCATE PREPARE ALL
    {
-       @$ = mm_strdup("all");
+       @$ = "all";
    }
    ;
 
@@ -2177,7 +2186,7 @@ Iresult: Iconst
        if (pg_strcasecmp(@1, "sizeof") != 0)
            mmerror(PARSE_ERROR, ET_ERROR, "operator not allowed in variable definition");
        else
-           @$ = cat_str(4, @1, mm_strdup("("), $3.type_str, mm_strdup(")"));
+           @$ = cat_str(4, @1, "(", $3.type_str, ")");
    }
    ;
 
@@ -2190,7 +2199,7 @@ execute_rest: /* EMPTY */
 ecpg_into: INTO into_list
    {
        /* always suppress this from the constructed string */
-       @$ = EMPTY;
+       @$ = "";
    }
    | into_descriptor
    ;
index 8d2b6e7cb81226bd8e58ae7937564f034c720f2c..a18904f88bd38c48ddd2fdb708c7d6243432af09 100644 (file)
@@ -12,7 +12,6 @@ output_line_number(void)
    char       *line = hashline_number();
 
    fprintf(base_yyout, "%s", line);
-   free(line);
 }
 
 void
@@ -100,7 +99,7 @@ hashline_number(void)
        )
    {
        /* "* 2" here is for escaping '\' and '"' below */
-       char       *line = mm_alloc(strlen("\n#line %d \"%s\"\n") + sizeof(int) * CHAR_BIT * 10 / 3 + strlen(input_filename) * 2);
+       char       *line = loc_alloc(strlen("\n#line %d \"%s\"\n") + sizeof(int) * CHAR_BIT * 10 / 3 + strlen(input_filename) * 2);
        char       *src,
                   *dest;
 
@@ -119,7 +118,7 @@ hashline_number(void)
        return line;
    }
 
-   return EMPTY;
+   return "";
 }
 
 static char *ecpg_statement_type_name[] = {
index ca0dead26d0c5f478803e5f80004d416e673fdde..373c93fc04ae355b3f84d24abd15a746bd59a80a 100644 (file)
@@ -204,7 +204,7 @@ filtered_base_yylex(void)
 
                /* Combine 3 tokens into 1 */
                base_yylval.str = psprintf("%s UESCAPE %s", base_yylval.str, escstr);
-               base_yylloc = mm_strdup(base_yylval.str);
+               base_yylloc = loc_strdup(base_yylval.str);
 
                /* Clear have_lookahead, thereby consuming all three tokens */
                have_lookahead = false;
@@ -254,11 +254,11 @@ base_yylex_location(void)
        case UIDENT:
        case IP:
            /* Duplicate the <str> value */
-           base_yylloc = mm_strdup(base_yylval.str);
+           base_yylloc = loc_strdup(base_yylval.str);
            break;
        default:
            /* Else just use the input, i.e., yytext */
-           base_yylloc = mm_strdup(base_yytext);
+           base_yylloc = loc_strdup(base_yytext);
            /* Apply an ASCII-only downcasing */
            for (unsigned char *ptr = (unsigned char *) base_yylloc; *ptr; ptr++)
            {
index 29329ccd89194f7549aefecceecd4416c6a44e4f..a60b0381fbb39541cf8a07f788b93e59c1864e60 100644 (file)
 /* defines */
 
 #define STRUCT_DEPTH 128
-#define EMPTY mm_strdup("")
 
 /*
  * "Location tracking" support --- see ecpg.header for more comments.
  */
-typedef char *YYLTYPE;
+typedef const char *YYLTYPE;
 
 #define YYLTYPE_IS_DECLARED 1
 
@@ -82,22 +81,25 @@ extern int  base_yylex(void);
 extern void base_yyerror(const char *error);
 extern void *mm_alloc(size_t size);
 extern char *mm_strdup(const char *string);
-extern char *cat2_str(char *str1, char *str2);
+extern void *loc_alloc(size_t size);
+extern char *loc_strdup(const char *string);
+extern void reclaim_local_storage(void);
+extern char *cat2_str(const char *str1, const char *str2);
 extern char *cat_str(int count,...);
-extern char *make2_str(char *str1, char *str2);
-extern char *make3_str(char *str1, char *str2, char *str3);
+extern char *make2_str(const char *str1, const char *str2);
+extern char *make3_str(const char *str1, const char *str2, const char *str3);
 extern void mmerror(int error_code, enum errortype type, const char *error,...) pg_attribute_printf(3, 4);
 extern void mmfatal(int error_code, const char *error,...) pg_attribute_printf(2, 3) pg_attribute_noreturn();
-extern void output_get_descr_header(char *desc_name);
-extern void output_get_descr(char *desc_name, char *index);
-extern void output_set_descr_header(char *desc_name);
-extern void output_set_descr(char *desc_name, char *index);
-extern void push_assignment(char *var, enum ECPGdtype value);
-extern struct variable *find_variable(char *name);
+extern void output_get_descr_header(const char *desc_name);
+extern void output_get_descr(const char *desc_name, const char *index);
+extern void output_set_descr_header(const char *desc_name);
+extern void output_set_descr(const char *desc_name, const char *index);
+extern void push_assignment(const char *var, enum ECPGdtype value);
+extern struct variable *find_variable(const char *name);
 extern void whenever_action(int mode);
-extern void add_descriptor(char *name, char *connection);
-extern void drop_descriptor(char *name, char *connection);
-extern struct descriptor *lookup_descriptor(char *name, char *connection);
+extern void add_descriptor(const char *name, const char *connection);
+extern void drop_descriptor(const char *name, const char *connection);
+extern struct descriptor *lookup_descriptor(const char *name, const char *connection);
 extern struct variable *descriptor_variable(const char *name, int input);
 extern struct variable *sqlda_variable(const char *name);
 extern void add_variable_to_head(struct arguments **list,
@@ -109,9 +111,9 @@ extern void add_variable_to_tail(struct arguments **list,
 extern void remove_variable_from_list(struct arguments **list, struct variable *var);
 extern void dump_variables(struct arguments *list, int mode);
 extern struct typedefs *get_typedef(const char *name, bool noerror);
-extern void adjust_array(enum ECPGttype type_enum, char **dimension,
-                        char **length, char *type_dimension,
-                        char *type_index, int pointer_len,
+extern void adjust_array(enum ECPGttype type_enum, const char **dimension,
+                        const char **length, const char *type_dimension,
+                        const char *type_index, int pointer_len,
                         bool type_definition);
 extern void reset_variables(void);
 extern void check_indicator(struct ECPGtype *var);
index 5610a8dc76bffda703471746600358ad3818e389..7f52521dbf12aee7ce38123962136ff09f67ae74 100644 (file)
@@ -69,13 +69,13 @@ ECPGmake_struct_member(const char *name, struct ECPGtype *type, struct ECPGstruc
 }
 
 struct ECPGtype *
-ECPGmake_simple_type(enum ECPGttype type, char *size, int counter)
+ECPGmake_simple_type(enum ECPGttype type, const char *size, int counter)
 {
    struct ECPGtype *ne = (struct ECPGtype *) mm_alloc(sizeof(struct ECPGtype));
 
    ne->type = type;
    ne->type_name = NULL;
-   ne->size = size;
+   ne->size = mm_strdup(size);
    ne->u.element = NULL;
    ne->struct_sizeof = NULL;
    ne->counter = counter;      /* only needed for varchar and bytea */
@@ -84,7 +84,7 @@ ECPGmake_simple_type(enum ECPGttype type, char *size, int counter)
 }
 
 struct ECPGtype *
-ECPGmake_array_type(struct ECPGtype *type, char *size)
+ECPGmake_array_type(struct ECPGtype *type, const char *size)
 {
    struct ECPGtype *ne = ECPGmake_simple_type(ECPGt_array, size, 0);
 
@@ -96,7 +96,7 @@ ECPGmake_array_type(struct ECPGtype *type, char *size)
 struct ECPGtype *
 ECPGmake_struct_type(struct ECPGstruct_member *rm, enum ECPGttype type, char *type_name, char *struct_sizeof)
 {
-   struct ECPGtype *ne = ECPGmake_simple_type(type, mm_strdup("1"), 0);
+   struct ECPGtype *ne = ECPGmake_simple_type(type, "1", 0);
 
    ne->type_name = mm_strdup(type_name);
    ne->u.members = ECPGstruct_member_dup(rm);
index ce2124361fd0a72f029c2f939ef3fdbd8faaa9fc..90126551d19d8afa8f08314a5e60ec181b1fe722 100644 (file)
@@ -35,8 +35,8 @@ struct ECPGtype
 /* Everything is malloced. */
 void       ECPGmake_struct_member(const char *name, struct ECPGtype *type,
                                   struct ECPGstruct_member **start);
-struct ECPGtype *ECPGmake_simple_type(enum ECPGttype type, char *size, int counter);
-struct ECPGtype *ECPGmake_array_type(struct ECPGtype *type, char *size);
+struct ECPGtype *ECPGmake_simple_type(enum ECPGttype type, const char *size, int counter);
+struct ECPGtype *ECPGmake_array_type(struct ECPGtype *type, const char *size);
 struct ECPGtype *ECPGmake_struct_type(struct ECPGstruct_member *rm,
                                      enum ECPGttype type, char *type_name,
                                      char *struct_sizeof);
@@ -93,28 +93,28 @@ struct when
 
 struct index
 {
-   char       *index1;
-   char       *index2;
-   char       *str;
+   const char *index1;
+   const char *index2;
+   const char *str;
 };
 
 struct su_symbol
 {
-   char       *su;
-   char       *symbol;
+   const char *su;
+   const char *symbol;
 };
 
 struct prep
 {
-   char       *name;
-   char       *stmt;
-   char       *type;
+   const char *name;
+   const char *stmt;
+   const char *type;
 };
 
 struct exec
 {
-   char       *name;
-   char       *type;
+   const char *name;
+   const char *type;
 };
 
 struct this_type
@@ -221,14 +221,14 @@ enum errortype
 
 struct fetch_desc
 {
-   char       *str;
-   char       *name;
+   const char *str;
+   const char *name;
 };
 
 struct describe
 {
    int         input;
-   char       *stmt_name;
+   const char *stmt_name;
 };
 
 #endif                         /* _ECPG_PREPROC_TYPE_H */
index cb1eca7f3cb1c097147e94c41c9b437cea9d28d8..f177df32488ce7af7a70af9215f444a27f3192ae 100644 (file)
@@ -104,33 +104,117 @@ mm_strdup(const char *string)
    return new;
 }
 
+
 /*
- * String concatenation
+ * "Local" memory management support
+ *
+ * These functions manage memory that is only needed for a short time
+ * (processing of one input statement) within the ecpg grammar.
+ * Data allocated with these is not meant to be freed separately;
+ * rather it's freed by calling reclaim_local_storage() at the end
+ * of each statement cycle.
  */
 
+typedef struct loc_chunk
+{
+   struct loc_chunk *next;     /* list link */
+   unsigned int chunk_used;    /* index of first unused byte in data[] */
+   unsigned int chunk_avail;   /* # bytes still available in data[] */
+   char        data[FLEXIBLE_ARRAY_MEMBER];    /* actual storage */
+} loc_chunk;
+
+#define LOC_CHUNK_OVERHEAD MAXALIGN(offsetof(loc_chunk, data))
+#define LOC_CHUNK_MIN_SIZE 8192
+
+/* Head of list of loc_chunks */
+static loc_chunk *loc_chunks = NULL;
+
 /*
- * Concatenate 2 strings, inserting a space between them unless either is empty
+ * Allocate local space of the requested size.
  *
- * The input strings are freed.
+ * Exits on OOM.
+ */
+void *
+loc_alloc(size_t size)
+{
+   void       *result;
+   loc_chunk  *cur_chunk = loc_chunks;
+
+   /* Ensure all allocations are adequately aligned */
+   size = MAXALIGN(size);
+
+   /* Need a new chunk? */
+   if (cur_chunk == NULL || size > cur_chunk->chunk_avail)
+   {
+       size_t      chunk_size = Max(size, LOC_CHUNK_MIN_SIZE);
+
+       cur_chunk = mm_alloc(chunk_size + LOC_CHUNK_OVERHEAD);
+       /* Depending on alignment rules, we could waste a bit here */
+       cur_chunk->chunk_used = LOC_CHUNK_OVERHEAD - offsetof(loc_chunk, data);
+       cur_chunk->chunk_avail = chunk_size;
+       /* New chunk becomes the head of the list */
+       cur_chunk->next = loc_chunks;
+       loc_chunks = cur_chunk;
+   }
+
+   result = cur_chunk->data + cur_chunk->chunk_used;
+   cur_chunk->chunk_used += size;
+   cur_chunk->chunk_avail -= size;
+   return result;
+}
+
+/*
+ * Copy given string into local storage
+ */
+char *
+loc_strdup(const char *string)
+{
+   char       *result = loc_alloc(strlen(string) + 1);
+
+   strcpy(result, string);
+   return result;
+}
+
+/*
+ * Reclaim local storage when appropriate
+ */
+void
+reclaim_local_storage(void)
+{
+   loc_chunk  *cur_chunk,
+              *next_chunk;
+
+   for (cur_chunk = loc_chunks; cur_chunk; cur_chunk = next_chunk)
+   {
+       next_chunk = cur_chunk->next;
+       free(cur_chunk);
+   }
+   loc_chunks = NULL;
+}
+
+
+/*
+ * String concatenation support routines.  These return "local" (transient)
+ * storage.
+ */
+
+/*
+ * Concatenate 2 strings, inserting a space between them unless either is empty
  */
 char *
-cat2_str(char *str1, char *str2)
+cat2_str(const char *str1, const char *str2)
 {
-   char       *res_str = (char *) mm_alloc(strlen(str1) + strlen(str2) + 2);
+   char       *res_str = (char *) loc_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;
 }
 
 /*
  * Concatenate N strings, inserting spaces between them unless they are empty
- *
- * The input strings are freed.
  */
 char *
 cat_str(int count,...)
@@ -154,36 +238,27 @@ cat_str(int count,...)
 
 /*
  * Concatenate 2 strings, with no space between
- *
- * The input strings are freed.
  */
 char *
-make2_str(char *str1, char *str2)
+make2_str(const char *str1, const char *str2)
 {
-   char       *res_str = (char *) mm_alloc(strlen(str1) + strlen(str2) + 1);
+   char       *res_str = (char *) loc_alloc(strlen(str1) + strlen(str2) + 1);
 
    strcpy(res_str, str1);
    strcat(res_str, str2);
-   free(str1);
-   free(str2);
    return res_str;
 }
 
 /*
  * Concatenate 3 strings, with no space between
- *
- * The input strings are freed.
  */
 char *
-make3_str(char *str1, char *str2, char *str3)
+make3_str(const char *str1, const char *str2, const char *str3)
 {
-   char       *res_str = (char *) mm_alloc(strlen(str1) + strlen(str2) + strlen(str3) + 1);
+   char       *res_str = (char *) loc_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;
 }
index b23ed5edf460f2fe5379e3e1051c31ca5e2bbb6d..6b87d5ff3d9edae8e36e6a6985a6834bda1b20d5 100644 (file)
@@ -22,7 +22,7 @@ new_variable(const char *name, struct ECPGtype *type, int brace_level)
 }
 
 static struct variable *
-find_struct_member(char *name, char *str, struct ECPGstruct_member *members, int brace_level)
+find_struct_member(const char *name, char *str, struct ECPGstruct_member *members, int brace_level)
 {
    char       *next = strpbrk(++str, ".-["),
               *end,
@@ -123,7 +123,7 @@ find_struct_member(char *name, char *str, struct ECPGstruct_member *members, int
 }
 
 static struct variable *
-find_struct(char *name, char *next, char *end)
+find_struct(const char *name, char *next, char *end)
 {
    struct variable *p;
    char        c = *next;
@@ -174,7 +174,7 @@ find_struct(char *name, char *next, char *end)
 }
 
 static struct variable *
-find_simple(char *name)
+find_simple(const char *name)
 {
    struct variable *p;
 
@@ -190,7 +190,7 @@ find_simple(char *name)
 /* Note that this function will end the program in case of an unknown */
 /* variable */
 struct variable *
-find_variable(char *name)
+find_variable(const char *name)
 {
    char       *next,
               *end;
@@ -513,7 +513,10 @@ get_typedef(const char *name, bool noerror)
 }
 
 void
-adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *type_dimension, char *type_index, int pointer_len, bool type_definition)
+adjust_array(enum ECPGttype type_enum,
+            const char **dimension, const char **length,
+            const char *type_dimension, const char *type_index,
+            int pointer_len, bool type_definition)
 {
    if (atoi(type_index) >= 0)
    {
@@ -556,7 +559,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty
            if (pointer_len)
            {
                *length = *dimension;
-               *dimension = mm_strdup("0");
+               *dimension = "0";
            }
 
            if (atoi(*length) >= 0)
@@ -567,13 +570,13 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty
        case ECPGt_bytea:
            /* pointer has to get dimension 0 */
            if (pointer_len)
-               *dimension = mm_strdup("0");
+               *dimension = "0";
 
            /* one index is the string length */
            if (atoi(*length) < 0)
            {
                *length = *dimension;
-               *dimension = mm_strdup("-1");
+               *dimension = "-1";
            }
 
            break;
@@ -583,13 +586,13 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty
            /* char ** */
            if (pointer_len == 2)
            {
-               *length = *dimension = mm_strdup("0");
+               *length = *dimension = "0";
                break;
            }
 
            /* pointer has to get length 0 */
            if (pointer_len == 1)
-               *length = mm_strdup("0");
+               *length = "0";
 
            /* one index is the string length */
            if (atoi(*length) < 0)
@@ -604,13 +607,13 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty
                     * do not change this for typedefs since it will be
                     * changed later on when the variable is defined
                     */
-                   *length = mm_strdup("1");
+                   *length = "1";
                else if (strcmp(*dimension, "0") == 0)
-                   *length = mm_strdup("-1");
+                   *length = "-1";
                else
                    *length = *dimension;
 
-               *dimension = mm_strdup("-1");
+               *dimension = "-1";
            }
            break;
        default:
@@ -618,7 +621,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty
            if (pointer_len)
            {
                *length = *dimension;
-               *dimension = mm_strdup("0");
+               *dimension = "0";
            }
 
            if (atoi(*length) >= 0)
index a65e1c07c5d33478aa5ab1a979f62eb7e9b23faa..57de1acff3a5596e33b41716a063318ee8eb052c 100644 (file)
@@ -3602,6 +3602,7 @@ libpq_source
 line_t
 lineno_t
 list_sort_comparator
+loc_chunk
 local_relopt
 local_relopts
 local_source