Applied patch by ITAGAKI Takahiro <itagaki.takahiro@oss.ntt.co.jp> to get prepare...
authorMichael Meskes <meskes@postgresql.org>
Wed, 26 Sep 2007 10:57:01 +0000 (10:57 +0000)
committerMichael Meskes <meskes@postgresql.org>
Wed, 26 Sep 2007 10:57:01 +0000 (10:57 +0000)
20 files changed:
src/interfaces/ecpg/ChangeLog
src/interfaces/ecpg/ecpglib/connect.c
src/interfaces/ecpg/ecpglib/execute.c
src/interfaces/ecpg/ecpglib/extern.h
src/interfaces/ecpg/ecpglib/prepare.c
src/interfaces/ecpg/include/ecpglib.h
src/interfaces/ecpg/preproc/output.c
src/interfaces/ecpg/preproc/preproc.y
src/interfaces/ecpg/test/ecpg_schedule
src/interfaces/ecpg/test/ecpg_schedule_tcp
src/interfaces/ecpg/test/expected/sql-desc.c
src/interfaces/ecpg/test/expected/sql-dyntest.c
src/interfaces/ecpg/test/expected/sql-execute.c
src/interfaces/ecpg/test/expected/sql-oldexec.c
src/interfaces/ecpg/test/expected/thread-prep.c [new file with mode: 0644]
src/interfaces/ecpg/test/expected/thread-prep.stderr [new file with mode: 0644]
src/interfaces/ecpg/test/expected/thread-prep.stdout [new file with mode: 0644]
src/interfaces/ecpg/test/expected/thread-prep_2.stdout [new file with mode: 0644]
src/interfaces/ecpg/test/thread/Makefile
src/interfaces/ecpg/test/thread/prep.pgc [new file with mode: 0644]

index b045dc8b58d6833fdfd1a63abd65c01de05edd12..fa4ea4ddce691730d9e431845891ca09c57a6616 100644 (file)
@@ -2237,5 +2237,10 @@ Wed, 29 Aug 2007 15:41:58 +0200
 Tue, 04 Sep 2007 11:13:55 +0200
 
        - Synced parser and keyword list.
+
+Mi 26. Sep 12:45:51 CEST 2007
+
+       - Applied patch by ITAGAKI Takahiro <itagaki.takahiro@oss.ntt.co.jp>
+         to get prepare thread-safe.
        - Set ecpg library version to 6.0.
        - Set ecpg version to 4.4.
index 421155bb9230576cb1d9cfaaa22d7b72c72beb30..40f5d7ead3426621eff950015856bc6b16bf8e44 100644 (file)
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/connect.c,v 1.42 2007/08/14 10:01:52 meskes Exp $ */
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/connect.c,v 1.43 2007/09/26 10:57:00 meskes Exp $ */
 
 #define POSTGRES_ECPG_INTERNAL
 #include "postgres_fe.h"
@@ -460,6 +460,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
                this->name = ECPGstrdup(realname, lineno);
 
        this->cache_head = NULL;
+       this->prep_stmts = NULL;
 
        if (all_connections == NULL)
                this->next = NULL;
index a1aad0b30a1c4d7c2f3213f2fb9fee78106ee278..c5ae1dadf32096afdfa45df6a58347b16be0dc34 100644 (file)
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.69 2007/09/21 10:59:27 meskes Exp $ */
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.70 2007/09/26 10:57:00 meskes Exp $ */
 
 /*
  * The aim is to get a simpler inteface to the database routines.
@@ -1515,7 +1515,7 @@ ECPGdo(const int lineno, const int compat, const int force_indicator, const char
        if (statement_type == ECPGst_execute)
        {
                /* if we have an EXECUTE command, only the name is send */
-               char *command = ECPGprepared(stmt->command, lineno);
+               char *command = ECPGprepared(stmt->command, con, lineno);
 
                if (command)
                {
index c9e230447f75a11ef89a063a91b77c4c9861f486..f69730740be383620145f630fada0017ef30f73c 100644 (file)
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/extern.h,v 1.26 2007/08/14 10:54:57 meskes Exp $ */
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/extern.h,v 1.27 2007/09/26 10:57:00 meskes Exp $ */
 
 #ifndef _ECPG_LIB_EXTERN_H
 #define _ECPG_LIB_EXTERN_H
@@ -91,6 +91,7 @@ struct connection
        bool            committed;
        int                     autocommit;
        struct ECPGtype_information_cache *cache_head;
+       struct prepared_statement *prep_stmts;
        struct connection *next;
 };
 
@@ -144,7 +145,7 @@ bool                ECPGstore_input(const int, const bool, const struct variable *, const char
 bool ECPGcheck_PQresult(PGresult *, int, PGconn *, enum COMPAT_MODE);
 void ECPGraise(int line, int code, const char *sqlstate, const char *str);
 void ECPGraise_backend(int line, PGresult *result, PGconn *conn, int compat);
-char *ECPGprepared(const char *, int);
+char *ECPGprepared(const char *, struct connection *, int);
 
 /* SQLSTATE values generated or processed by ecpglib (intentionally
  * not exported -- users should refer to the codes directly) */
index bad7b359b45dffe77aaa1fd0762f8ae3f0f38a78..6d884bfb0ae864909840d532b30643853d0c3c33 100644 (file)
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/prepare.c,v 1.19 2007/08/14 10:01:52 meskes Exp $ */
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/prepare.c,v 1.20 2007/09/26 10:57:00 meskes Exp $ */
 
 #define POSTGRES_ECPG_INTERNAL
 #include "postgres_fe.h"
 #include "extern.h"
 #include "sqlca.h"
 
-static struct prepared_statement
+struct prepared_statement
 {
-       char    *name;
-       bool    prepared;
-       struct statement *stmt;
-       struct prepared_statement *next;
-}      *prep_stmts = NULL;
+       char                                       *name;
+       bool                                            prepared;
+       struct statement                   *stmt;
+       struct prepared_statement  *next;
+};
 
 #define STMTID_SIZE 32
 
@@ -35,6 +35,11 @@ static int             stmtCacheNBuckets        = 2039;     /* # buckets - a pri
 static int             stmtCacheEntPerBucket    = 8;        /* # entries/bucket     */
 static stmtCacheEntry  stmtCacheEntries[16384] = {{0,{0},0,0,0}};
 
+static struct prepared_statement *find_prepared_statement(const char *name,
+       struct connection *con, struct prepared_statement **prev);
+static bool    deallocate_one(int lineno, enum COMPAT_MODE c, struct connection *con,
+       struct prepared_statement *prev, struct prepared_statement *this);
+
 static bool
 isvarchar(unsigned char c)
 {
@@ -105,23 +110,23 @@ replace_variables(char **text, int lineno, bool questionmarks)
 bool
 ECPGprepare(int lineno, const char *connection_name, const int questionmarks, const char *name, const char *variable)
 {
-       struct statement *stmt;
-       struct prepared_statement *this;
+       struct connection                  *con;
+       struct statement                   *stmt;
+       struct prepared_statement  *this,
+                                                          *prev;
        struct sqlca_t *sqlca = ECPGget_sqlca();
        PGresult   *query;
 
        ECPGinit_sqlca(sqlca);
 
-       /* check if we already have prepared this statement */
-       for (this = prep_stmts; this != NULL && strcmp(this->name, name) != 0; this = this->next);
-       if (this)
-       {
-               bool            b = ECPGdeallocate(lineno, ECPG_COMPAT_PGSQL, name);
+       con = ECPGget_connection(connection_name);
 
-               if (!b)
-                       return false;
-       }
+       /* check if we already have prepared this statement */
+       this = find_prepared_statement(name, con, &prev);
+       if (this && !deallocate_one(lineno, ECPG_COMPAT_PGSQL, con, prev, this))
+               return false;
 
+       /* allocate new statement */
        this = (struct prepared_statement *) ECPGalloc(sizeof(struct prepared_statement), lineno);
        if (!this)
                return false;
@@ -135,7 +140,7 @@ ECPGprepare(int lineno, const char *connection_name, const int questionmarks, co
 
        /* create statement */
        stmt->lineno = lineno;
-       stmt->connection = ECPGget_connection(connection_name);
+       stmt->connection = con;
        stmt->command = ECPGstrdup(variable, lineno);
        stmt->inlist = stmt->outlist = NULL;
 
@@ -160,90 +165,114 @@ ECPGprepare(int lineno, const char *connection_name, const int questionmarks, co
        PQclear(query);
        this->prepared = true;
 
-       if (prep_stmts == NULL)
+       if (con->prep_stmts == NULL)
                this->next = NULL;
        else
-               this->next = prep_stmts;
+               this->next = con->prep_stmts;
 
-       prep_stmts = this;
+       con->prep_stmts = this;
        return true;
 }
 
+static struct prepared_statement *find_prepared_statement(const char *name,
+       struct connection *con, struct prepared_statement **prev_)
+{
+       struct prepared_statement  *this,
+                                                          *prev;
+
+       for (this = con->prep_stmts, prev = NULL; this != NULL; prev = this, this = this->next)
+       {
+               if (strcmp(this->name, name) == 0)
+               {
+                       if (prev_)
+                               *prev_ = prev;
+                       return this;
+               }
+       }
+       return NULL;
+}
+
 static bool
-deallocate_one(int lineno, const char *name)
+deallocate_one(int lineno, enum COMPAT_MODE c, struct connection *con, struct prepared_statement *prev, struct prepared_statement *this)
 {
-       struct prepared_statement *this,
-                          *prev;
+       bool    r = false;
 
-       /* check if we really have prepared this statement */
-       for (this = prep_stmts, prev = NULL; this != NULL && strcmp(this->name, name) != 0; prev = this, this = this->next);
-       if (this)
+       ECPGlog("ECPGdeallocate line %d: NAME: %s\n", lineno, this->name);
+
+       /* first deallocate the statement in the backend */
+       if (this->prepared)
        {
-               /* first deallocate the statement in the backend */
-               if (this->prepared)
+               char *text;
+               PGresult *query;
+               
+               text = (char *) ECPGalloc(strlen("deallocate \"\" ") + strlen(this->name), this->stmt->lineno);
+               if (text)
                {
-                       char *text;
-                       PGresult *query;
-                       
-                       if (!(text = (char *) ECPGalloc(strlen("deallocate \"\" ") + strlen(this->name), this->stmt->lineno)))
-                               return false;
-                       else
+                       sprintf(text, "deallocate \"%s\"", this->name);
+                       query = PQexec(this->stmt->connection->connection, text);
+                       ECPGfree(text);
+                       if (ECPGcheck_PQresult(query, lineno, this->stmt->connection->connection, this->stmt->compat))
                        {
-                               sprintf(text, "deallocate \"%s\"", this->name);
-                               query = PQexec(this->stmt->connection->connection, text);
-                               ECPGfree(text);
-                               if (!ECPGcheck_PQresult(query, lineno, this->stmt->connection->connection, this->stmt->compat))
-                                       return false;
                                PQclear(query);
+                               r = true;
                        }
                }
-               
-               /* okay, free all the resources */
-               ECPGfree(this->stmt->command);
-               ECPGfree(this->stmt);
-               if (prev != NULL)
-                       prev->next = this->next;
-               else
-                       prep_stmts = this->next;
+       }
 
-               ECPGfree(this);
-               return true;
+       /*
+        * Just ignore all errors since we do not know the list of cursors we
+        * are allowed to free. We have to trust the software.
+        */
+       if (!r && !INFORMIX_MODE(c))
+       {
+               ECPGraise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, this->name);
+               return false;
        }
-       return false;
+       
+       /* okay, free all the resources */
+       ECPGfree(this->stmt->command);
+       ECPGfree(this->stmt);
+       if (prev != NULL)
+               prev->next = this->next;
+       else
+               con->prep_stmts = this->next;
+
+       ECPGfree(this);
+       return true;
 }
 
 /* handle the EXEC SQL DEALLOCATE PREPARE statement */
 bool
-ECPGdeallocate(int lineno, int c, const char *name)
+ECPGdeallocate(int lineno, int c, const char *connection_name, const char *name)
 {
-       bool            ret = deallocate_one(lineno, name);
-       enum COMPAT_MODE compat = c;
+       struct connection                  *con;
+       struct prepared_statement  *this,
+                                                          *prev;
 
-       ECPGlog("ECPGdeallocate line %d: NAME: %s\n", lineno, name);
-       if (INFORMIX_MODE(compat))
-       {
-               /*
-                * Just ignore all errors since we do not know the list of cursors we
-                * are allowed to free. We have to trust the software.
-                */
-               return true;
-       }
+       con = ECPGget_connection(connection_name);
 
-       if (!ret)
-               ECPGraise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, name);
+       this = find_prepared_statement(name, con, &prev);
+       if (this)
+               return deallocate_one(lineno, c, con, prev, this);
 
-       return ret;
+       /* prepared statement is not found */
+       if (INFORMIX_MODE(c))
+               return true;
+       ECPGraise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, name);
+       return false;
 }
 
 bool
-ECPGdeallocate_all(int lineno, int compat)
+ECPGdeallocate_all(int lineno, int compat, const char *connection_name)
 {
+       struct connection                  *con;
+
+       con = ECPGget_connection(connection_name);
+
        /* deallocate all prepared statements */
-       while (prep_stmts != NULL)
+       while (con->prep_stmts)
        {
-               bool            b = ECPGdeallocate(lineno, compat, prep_stmts->name);
-
-               if (!b)
+               if (!deallocate_one(lineno, compat, con, NULL, con->prep_stmts))
                        return false;
        }
 
@@ -251,22 +280,18 @@ ECPGdeallocate_all(int lineno, int compat)
 }
 
 char *
-ECPGprepared(const char *name, int lineno)
+ECPGprepared(const char *name, struct connection *con, int lineno)
 {
-       struct prepared_statement *this;
-
-       for (this = prep_stmts; this != NULL && ((strcmp(this->name, name) != 0) || this->prepared == false); this = this->next);
-       return (this) ? this->stmt->command : NULL;
+       struct prepared_statement  *this;
+       this = find_prepared_statement(name, con, NULL);
+       return this ? this->stmt->command : NULL;
 }
 
 /* return the prepared statement */
 char *
-ECPGprepared_statement(const char *name, int lineno)
+ECPGprepared_statement(const char *connection_name, const char *name, int lineno)
 {
-       struct prepared_statement *this;
-
-       for (this = prep_stmts; this != NULL && strcmp(this->name, name) != 0; this = this->next);
-       return (this) ? this->stmt->command : NULL;
+       return ECPGprepared(name, ECPGget_connection(connection_name), lineno);
 }
 
 /*
@@ -426,14 +451,14 @@ ECPGauto_prepare(int lineno, const char *connection_name, const int questionmark
        entNo = SearchStmtCache(query);
 
        /* if not found - add the statement to the cache    */
-        if(entNo)
+       if(entNo)
        {
-               ECPGlog("ECPGauto_prepare line %d: stmt found in cache, entry %d\n", lineno, entNo);
+               ECPGlog("ECPGauto_prepare line %d: stmt found in cache, entry %d\n", lineno, entNo);
                *name = ECPGstrdup(stmtCacheEntries[entNo].stmtID, lineno); 
        }
        else
        {
-               ECPGlog("ECPGauto_prepare line %d: stmt not in cache; inserting\n", lineno);
+               ECPGlog("ECPGauto_prepare line %d: stmt not in cache; inserting\n", lineno);
 
                /* generate a statement ID */
                *name = (char *) ECPGalloc(STMTID_SIZE, lineno);
@@ -450,4 +475,3 @@ ECPGauto_prepare(int lineno, const char *connection_name, const int questionmark
 
        return(true);
 }
-
index 80e5452a13102ca7599af80f3d1c80d4c46f7dca..7a24618c8388c35442cad59f0f336be61e6021fd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * this is a small part of c.h since we don't want to leak all postgres
  * definitions into ecpg programs
- * $PostgreSQL: pgsql/src/interfaces/ecpg/include/ecpglib.h,v 1.71 2007/08/14 10:01:52 meskes Exp $
+ * $PostgreSQL: pgsql/src/interfaces/ecpg/include/ecpglib.h,v 1.72 2007/09/26 10:57:00 meskes Exp $
  */
 
 #ifndef _ECPGLIB_H
@@ -49,9 +49,9 @@ bool          ECPGtrans(int, const char *, const char *);
 bool           ECPGdisconnect(int, const char *);
 bool           ECPGprepare(int, const char *, const int, const char *, const char *);
 bool           ECPGauto_prepare(int, const char *, const int, char **, const char *);
-bool           ECPGdeallocate(int, int, const char *);
-bool           ECPGdeallocate_all(int, int);
-char      *ECPGprepared_statement(const char *, int);
+bool           ECPGdeallocate(int, int, const char *connection_name, const char *name);
+bool           ECPGdeallocate_all(int, int, const char *connection_name);
+char      *ECPGprepared_statement(const char *connection_name, const char *name, int);
 
 void           ECPGlog(const char *format,...);
 char      *ECPGerrmsg(void);
index 26be27ba72c22f813b6f75ebbd433fe735eadef5..2a4a6380044f1e774f9ab64539d0d4d253a59558 100644 (file)
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/output.c,v 1.21 2007/08/14 10:32:47 meskes Exp $ */
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/output.c,v 1.22 2007/09/26 10:57:00 meskes Exp $ */
 
 #include "postgres_fe.h"
 
@@ -153,14 +153,15 @@ output_prepare_statement(char *name, char *stmt)
 void
 output_deallocate_prepare_statement(char *name)
 {
+       const char* con = connection ? connection : "NULL";
        if (strcmp(name, "all"))
        {
-               fprintf(yyout, "{ ECPGdeallocate(__LINE__, %d, ", compat);
+               fprintf(yyout, "{ ECPGdeallocate(__LINE__, %d, %s, ", compat, con);
                output_escaped_str(name, true);
                fputs(");", yyout);
        }
        else
-               fprintf(yyout, "{ ECPGdeallocate_all(__LINE__, %d);", compat);
+               fprintf(yyout, "{ ECPGdeallocate_all(__LINE__, %d, %s);", compat, con);
 
        whenever_action(2);
        free(name);
index 9166bb3e83b36eaad079e59ebea28dde956d4ad4..cd0d94ff97b261fd3dbb1bb40a252947cc18d5ee 100644 (file)
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.351 2007/09/04 10:02:29 meskes Exp $ */
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.352 2007/09/26 10:57:00 meskes Exp $ */
 
 /* Copyright comment */
 %{
@@ -906,10 +906,11 @@ stmt:  AlterDatabaseStmt          { output_statement($1, 0, ECPGst_normal); }
                | ECPGExecuteImmediateStmt      { output_statement($1, 0, ECPGst_exec_immediate); }
                | ECPGFree
                {
+                       const char *con = connection ? connection : "NULL";
                        if (strcmp($1, "all"))
-                               fprintf(yyout, "{ ECPGdeallocate(__LINE__, %d, \"%s\");", compat, $1);
+                               fprintf(yyout, "{ ECPGdeallocate(__LINE__, %d, %s, \"%s\");", compat, con, $1);
                        else
-                               fprintf(yyout, "{ ECPGdeallocate_all(__LINE__, %d);", compat);
+                               fprintf(yyout, "{ ECPGdeallocate_all(__LINE__, %d, %s);", compat, con);
 
                        whenever_action(2);
                        free($1);
@@ -3349,7 +3350,7 @@ prep_type_clause: '(' type_list ')'       { $$ = cat_str(3, make_str("("), $2, make_st
 
 ExecuteStmt: EXECUTE prepared_name execute_param_clause execute_rest /* execute_rest is an ecpg addon */
                        {
-                               /* $$ = cat_str(3, make_str("ECPGprepared_statement("), $2, make_str(", __LINE__)"));*/
+                               /* $$ = cat_str(3, make_str("ECPGprepared_statement("), connection, $2, make_str("__LINE__)"));*/
                                $$ = $2;
                        }
                | CREATE OptTemp TABLE create_as_target AS
@@ -5185,6 +5186,7 @@ ECPGCursorStmt:  DECLARE name cursor_options CURSOR opt_hold FOR prepared_name
                {
                        struct cursor *ptr, *this;
                        struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
+                       const char *con = connection ? connection : "NULL";
 
                        for (ptr = cur; ptr != NULL; ptr = ptr->next)
                        {
@@ -5205,8 +5207,8 @@ ECPGCursorStmt:  DECLARE name cursor_options CURSOR opt_hold FOR prepared_name
                        thisquery->type = &ecpg_query;
                        thisquery->brace_level = 0;
                        thisquery->next = NULL;
-                       thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(, __LINE__)") + strlen($7));
-                       sprintf(thisquery->name, "ECPGprepared_statement(%s, __LINE__)", $7);
+                       thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(, , __LINE__)") + strlen(con) + strlen($7));
+                       sprintf(thisquery->name, "ECPGprepared_statement(%s, %s, __LINE__)", con, $7);
 
                        this->argsinsert = NULL;
                        add_variable_to_head(&(this->argsinsert), thisquery, &no_indicator);
@@ -5914,21 +5916,24 @@ UsingConst: AllConst
  */
 ECPGDescribe: SQL_DESCRIBE INPUT_P name using_descriptor
        {
+               const char *con = connection ? connection : "NULL";
                mmerror(PARSE_ERROR, ET_WARNING, "using unsupported describe statement.\n");
-               $$ = (char *) mm_alloc(sizeof("1, ECPGprepared_statement(\"\", __LINE__)") + strlen($3));
-               sprintf($$, "1, ECPGprepared_statement(\"%s\", __LINE__)", $3);
+               $$ = (char *) mm_alloc(sizeof("1, ECPGprepared_statement(, \"\", __LINE__)") + strlen(con) + strlen($3));
+               sprintf($$, "1, ECPGprepared_statement(%s, \"%s\", __LINE__)", con, $3);
        }
        | SQL_DESCRIBE opt_output name using_descriptor
        {
+               const char *con = connection ? connection : "NULL";
                mmerror(PARSE_ERROR, ET_WARNING, "using unsupported describe statement.\n");
-               $$ = (char *) mm_alloc(sizeof("0, ECPGprepared_statement(\"\", __LINE__)") + strlen($3));
-               sprintf($$, "0, ECPGprepared_statement(\"%s\", __LINE__)", $3);
+               $$ = (char *) mm_alloc(sizeof("0, ECPGprepared_statement(, \"\", __LINE__)") + strlen(con) + strlen($3));
+               sprintf($$, "0, ECPGprepared_statement(%s, \"%s\", __LINE__)", con, $3);
        }
        | SQL_DESCRIBE opt_output name into_descriptor
        {
+               const char *con = connection ? connection : "NULL";
                mmerror(PARSE_ERROR, ET_WARNING, "using unsupported describe statement.\n");
-               $$ = (char *) mm_alloc(sizeof("0, ECPGprepared_statement(\"\", __LINE__)") + strlen($3));
-               sprintf($$, "0, ECPGprepared_statement(\"%s\", __LINE__)", $3);
+               $$ = (char *) mm_alloc(sizeof("0, ECPGprepared_statement(, \"\", __LINE__)") + strlen(con) + strlen($3));
+               sprintf($$, "0, ECPGprepared_statement(%s, \"%s\", __LINE__)", con, $3);
        }
        ;
 
index 4df5d088deb6ff505c82a28ae8932c5f4bf2eb47..432a458cdef85230591d2daaa37de112a5d38feb 100644 (file)
@@ -41,3 +41,4 @@ test: sql/insupd
 test: sql/parser
 test: thread/thread
 test: thread/thread_implicit
+test: thread/prep
index 03703a0d06a0a19cbd96c28144e6dc7d9085580a..64fbca21179033fb2acd2f84afeb8e75c21c4bc0 100644 (file)
@@ -41,5 +41,6 @@ test: sql/insupd
 test: sql/parser
 test: thread/thread
 test: thread/thread_implicit
+test: thread/prep
 test: connect/test1
 
index 2e93f90f40613726aadd42c3236f5a20d63dc676..c32cda15c288e6550cfd7152a4b2bc1ea8815cf5 100644 (file)
@@ -197,7 +197,7 @@ if (sqlca.sqlcode < 0) sqlprint();}
 #line 45 "desc.pgc"
 
 
-       { ECPGdeallocate(__LINE__, 0, "Foo-1");
+       { ECPGdeallocate(__LINE__, 0, NULL, "Foo-1");
 #line 47 "desc.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
@@ -247,7 +247,7 @@ if (sqlca.sqlcode < 0) sqlprint();}
 #line 57 "desc.pgc"
 
        { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "declare c1  cursor  for $1", 
-       ECPGt_char_variable,(ECPGprepared_statement("foo2", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
+       ECPGt_char_variable,(ECPGprepared_statement(NULL, "foo2", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
        ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
        ECPGt_descriptor, "indesc", 0L, 0L, 0L, 
        ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
@@ -297,7 +297,7 @@ if (sqlca.sqlcode < 0) sqlprint();}
 #line 69 "desc.pgc"
 
        { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "declare c2  cursor  for $1", 
-       ECPGt_char_variable,(ECPGprepared_statement("foo3", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
+       ECPGt_char_variable,(ECPGprepared_statement(NULL, "foo3", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
        ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
        ECPGt_descriptor, "indesc", 0L, 0L, 0L, 
        ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
@@ -344,7 +344,7 @@ if (sqlca.sqlcode < 0) sqlprint();}
 if (sqlca.sqlcode < 0) sqlprint();}
 #line 80 "desc.pgc"
 
-       { ECPGdeallocate_all(__LINE__, 0);
+       { ECPGdeallocate_all(__LINE__, 0, NULL);
 #line 81 "desc.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
index 739141afe3922d4e25050c556d3a584e88600f30..206fa2058da05d5b4b92e9509219f9f1a9bf3a2e 100644 (file)
@@ -263,7 +263,7 @@ if (sqlca.sqlcode < 0) error (  );}
 
 
   { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "declare MYCURS  cursor  for $1", 
-       ECPGt_char_variable,(ECPGprepared_statement("myquery", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
+       ECPGt_char_variable,(ECPGprepared_statement(NULL, "myquery", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
        ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
 #line 60 "dyntest.pgc"
 
index fad63e832618c22db4b73ad532c6db374daa93d2..7aa926ffa674c3cf3601094e23049ddba33904c7 100644 (file)
@@ -142,7 +142,7 @@ if (sqlca.sqlcode < 0) sqlprint();}
 
 
        { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "declare CUR  cursor  for $1", 
-       ECPGt_char_variable,(ECPGprepared_statement("f", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
+       ECPGt_char_variable,(ECPGprepared_statement(NULL, "f", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
        ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
 #line 52 "execute.pgc"
 
@@ -187,7 +187,7 @@ if (sqlca.sqlcode < 0) sqlprint();}
 if (sqlca.sqlcode < 0) sqlprint();}
 #line 66 "execute.pgc"
 
-       { ECPGdeallocate(__LINE__, 0, "f");
+       { ECPGdeallocate(__LINE__, 0, NULL, "f");
 #line 67 "execute.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
@@ -207,7 +207,7 @@ if (sqlca.sqlcode < 0) sqlprint();}
 
 
        { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "declare CUR2  cursor  for $1", 
-       ECPGt_char_variable,(ECPGprepared_statement("f", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
+       ECPGt_char_variable,(ECPGprepared_statement(NULL, "f", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
        ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
        ECPGt_const,"1",(long)1,(long)1,strlen("1"), 
        ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
index 60e10a1fe15b779a1156645fb9d9c68704f9fd67..21a84593bd849362d0905f96105792514a07f15b 100644 (file)
@@ -142,7 +142,7 @@ if (sqlca.sqlcode < 0) sqlprint();}
 
 
        { ECPGdo(__LINE__, 0, 1, NULL, 1, ECPGst_normal, "declare CUR  cursor  for $1", 
-       ECPGt_char_variable,(ECPGprepared_statement("f", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
+       ECPGt_char_variable,(ECPGprepared_statement(NULL, "f", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
        ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
 #line 52 "oldexec.pgc"
 
@@ -201,7 +201,7 @@ if (sqlca.sqlcode < 0) sqlprint();}
 
 
        { ECPGdo(__LINE__, 0, 1, NULL, 1, ECPGst_normal, "declare CUR3  cursor  for $1", 
-       ECPGt_char_variable,(ECPGprepared_statement("f", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
+       ECPGt_char_variable,(ECPGprepared_statement(NULL, "f", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
        ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
        ECPGt_const,"1",(long)1,(long)1,strlen("1"), 
        ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
diff --git a/src/interfaces/ecpg/test/expected/thread-prep.c b/src/interfaces/ecpg/test/expected/thread-prep.c
new file mode 100644 (file)
index 0000000..cc3129b
--- /dev/null
@@ -0,0 +1,256 @@
+/* Processed by ecpg (regression mode) */
+/* These include files are added by the preprocessor */
+#include <ecpgtype.h>
+#include <ecpglib.h>
+#include <ecpgerrno.h>
+#include <sqlca.h>
+/* End of automatic include section */
+#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+#line 1 "prep.pgc"
+#include <stdlib.h>
+#include "ecpg_config.h"
+
+#ifndef ENABLE_THREAD_SAFETY
+int
+main(void)
+{
+        printf("No threading enabled.\n");
+       return 0;
+}
+#else
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <process.h>
+#else
+#include <pthread.h>
+#endif
+#include <stdio.h>
+
+#define THREADS                16
+#define REPEATS                50
+
+
+#line 1 "sqlca.h"
+#ifndef POSTGRES_SQLCA_H
+#define POSTGRES_SQLCA_H
+
+#ifndef PGDLLIMPORT
+#if  defined(WIN32) || defined(__CYGWIN__)
+#define PGDLLIMPORT __declspec (dllimport)
+#else
+#define PGDLLIMPORT
+#endif   /* __CYGWIN__ */
+#endif   /* PGDLLIMPORT */
+
+#define SQLERRMC_LEN   150
+
+#ifdef __cplusplus
+extern         "C"
+{
+#endif
+
+struct sqlca_t
+{
+       char            sqlcaid[8];
+       long            sqlabc;
+       long            sqlcode;
+       struct
+       {
+               int                     sqlerrml;
+               char            sqlerrmc[SQLERRMC_LEN];
+       }                       sqlerrm;
+       char            sqlerrp[8];
+       long            sqlerrd[6];
+       /* Element 0: empty                                             */
+       /* 1: OID of processed tuple if applicable                      */
+       /* 2: number of rows processed                          */
+       /* after an INSERT, UPDATE or                           */
+       /* DELETE statement                                     */
+       /* 3: empty                                             */
+       /* 4: empty                                             */
+       /* 5: empty                                             */
+       char            sqlwarn[8];
+       /* Element 0: set to 'W' if at least one other is 'W'   */
+       /* 1: if 'W' at least one character string              */
+       /* value was truncated when it was                      */
+       /* stored into a host variable.                         */
+
+       /*
+        * 2: if 'W' a (hopefully) non-fatal notice occurred
+        */     /* 3: empty */
+       /* 4: empty                                             */
+       /* 5: empty                                             */
+       /* 6: empty                                             */
+       /* 7: empty                                             */
+
+       char            sqlstate[5];
+};
+
+struct sqlca_t *ECPGget_sqlca(void);
+
+#ifndef POSTGRES_ECPG_INTERNAL
+#define sqlca (*ECPGget_sqlca())
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#line 24 "prep.pgc"
+
+
+#line 1 "regression.h"
+
+
+
+
+
+
+#line 25 "prep.pgc"
+
+
+/* exec sql whenever sqlerror  sqlprint ; */
+#line 27 "prep.pgc"
+
+/* exec sql whenever not found  sqlprint ; */
+#line 28 "prep.pgc"
+
+
+#ifdef WIN32
+static unsigned STDCALL fn(void* arg)
+#else
+void* fn(void* arg)
+#endif
+{
+       int i;
+
+       /* exec sql begin declare section */
+         
+        
+          
+       
+#line 39 "prep.pgc"
+ int  value    ;
+#line 40 "prep.pgc"
+ char  name [ 100 ]    ;
+#line 41 "prep.pgc"
+ char  query [ 256 ]   = "INSERT INTO T VALUES ( ? )" ;
+/* exec sql end declare section */
+#line 42 "prep.pgc"
+
+
+       value = (int)arg;
+       sprintf(name, "Connection: %d", value);
+
+       { ECPGconnect(__LINE__, 0, "regress1" , NULL, NULL , name, 0); 
+#line 47 "prep.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 47 "prep.pgc"
+
+       { ECPGsetcommit(__LINE__, "on", NULL);
+#line 48 "prep.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 48 "prep.pgc"
+
+       for (i = 1; i <= REPEATS; ++i)
+       {
+               { ECPGprepare(__LINE__, NULL, 0, "i", query);
+#line 51 "prep.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 51 "prep.pgc"
+
+               { ECPGdo(__LINE__, 0, 1, NULL, 0, 1, "i", 
+       ECPGt_int,&(value),(long)1,(long)1,sizeof(int), 
+       ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+#line 52 "prep.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 52 "prep.pgc"
+
+       }
+       { ECPGdeallocate(__LINE__, 0, NULL, "i");
+#line 54 "prep.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 54 "prep.pgc"
+
+       { ECPGdisconnect(__LINE__, name);
+#line 55 "prep.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 55 "prep.pgc"
+
+
+       return 0;
+}
+
+int main (int argc, char** argv)
+{
+       int i;
+#ifdef WIN32
+       HANDLE threads[THREADS];
+#else
+       pthread_t threads[THREADS];
+#endif
+
+       { ECPGconnect(__LINE__, 0, "regress1" , NULL, NULL , NULL, 0); 
+#line 69 "prep.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 69 "prep.pgc"
+
+       { ECPGsetcommit(__LINE__, "on", NULL);
+#line 70 "prep.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 70 "prep.pgc"
+
+       { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table if exists T ", ECPGt_EOIT, ECPGt_EORT);
+#line 71 "prep.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 71 "prep.pgc"
+
+       { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create  table T ( i int   )    ", ECPGt_EOIT, ECPGt_EORT);
+#line 72 "prep.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 72 "prep.pgc"
+
+       { ECPGdisconnect(__LINE__, "CURRENT");
+#line 73 "prep.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 73 "prep.pgc"
+
+
+#ifdef WIN32
+       for (i = 0; i < THREADS; ++i)
+       {
+               unsigned id;
+               threads[i] = (HANDLE)_beginthreadex(NULL, 0, fn, (void*)i, 0, &id);
+       }
+
+       WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE);
+       for (i = 0; i < THREADS; ++i)
+               CloseHandle(threads[i]);
+#else
+       for (i = 0; i < THREADS; ++i)
+               pthread_create(&threads[i], NULL, fn, (void*)i);
+       for (i = 0; i < THREADS; ++i)
+               pthread_join(threads[i], NULL);
+#endif
+
+       return 0;
+}
+#endif
+
diff --git a/src/interfaces/ecpg/test/expected/thread-prep.stderr b/src/interfaces/ecpg/test/expected/thread-prep.stderr
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/interfaces/ecpg/test/expected/thread-prep.stdout b/src/interfaces/ecpg/test/expected/thread-prep.stdout
new file mode 100644 (file)
index 0000000..75fe16b
--- /dev/null
@@ -0,0 +1 @@
+No threading enabled.
diff --git a/src/interfaces/ecpg/test/expected/thread-prep_2.stdout b/src/interfaces/ecpg/test/expected/thread-prep_2.stdout
new file mode 100644 (file)
index 0000000..e69de29
index 672622a32b164efdac36d5e95b483c48a13f17e5..8695a254ac1ee58517ecdbc5b54462198c791101 100644 (file)
@@ -5,7 +5,8 @@ include $(top_srcdir)/$(subdir)/../Makefile.regress
 
 
 TESTS = thread_implicit thread_implicit.c \
-        thread thread.c
+        thread thread.c \
+       prep prep.c
 
 all: $(TESTS)
 
diff --git a/src/interfaces/ecpg/test/thread/prep.pgc b/src/interfaces/ecpg/test/thread/prep.pgc
new file mode 100644 (file)
index 0000000..1213975
--- /dev/null
@@ -0,0 +1,95 @@
+#include <stdlib.h>
+#include "ecpg_config.h"
+
+#ifndef ENABLE_THREAD_SAFETY
+int
+main(void)
+{
+        printf("No threading enabled.\n");
+       return 0;
+}
+#else
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <process.h>
+#else
+#include <pthread.h>
+#endif
+#include <stdio.h>
+
+#define THREADS                16
+#define REPEATS                50
+
+exec sql include sqlca;
+exec sql include ../regression;
+
+exec sql whenever sqlerror sqlprint;
+exec sql whenever not found sqlprint;
+
+#ifdef WIN32
+static unsigned STDCALL fn(void* arg)
+#else
+void* fn(void* arg)
+#endif
+{
+       int i;
+
+       EXEC SQL BEGIN DECLARE SECTION;
+       int  value;
+       char name[100];
+       char query[256] = "INSERT INTO T VALUES ( ? )";
+       EXEC SQL END DECLARE SECTION;
+
+       value = (int)arg;
+       sprintf(name, "Connection: %d", value);
+
+       EXEC SQL CONNECT TO REGRESSDB1 AS :name;
+       EXEC SQL SET AUTOCOMMIT TO ON;
+       for (i = 1; i <= REPEATS; ++i)
+       {
+               EXEC SQL PREPARE I FROM :query;
+               EXEC SQL EXECUTE I USING :value;
+       }
+       EXEC SQL DEALLOCATE I;
+       EXEC SQL DISCONNECT :name;
+
+       return 0;
+}
+
+int main (int argc, char** argv)
+{
+       int i;
+#ifdef WIN32
+       HANDLE threads[THREADS];
+#else
+       pthread_t threads[THREADS];
+#endif
+
+       EXEC SQL CONNECT TO REGRESSDB1;
+       EXEC SQL SET AUTOCOMMIT TO ON;
+       EXEC SQL DROP TABLE IF EXISTS T;
+       EXEC SQL CREATE TABLE T ( i int );
+       EXEC SQL DISCONNECT;
+
+#ifdef WIN32
+       for (i = 0; i < THREADS; ++i)
+       {
+               unsigned id;
+               threads[i] = (HANDLE)_beginthreadex(NULL, 0, fn, (void*)i, 0, &id);
+       }
+
+       WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE);
+       for (i = 0; i < THREADS; ++i)
+               CloseHandle(threads[i]);
+#else
+       for (i = 0; i < THREADS; ++i)
+               pthread_create(&threads[i], NULL, fn, (void*)i);
+       for (i = 0; i < THREADS; ++i)
+               pthread_join(threads[i], NULL);
+#endif
+
+       return 0;
+}
+#endif
+