From d49b20fbe68fdc66795fe9588ebd510d52a5b9eb Mon Sep 17 00:00:00 2001 From: Michael Meskes Date: Wed, 26 Sep 2007 10:57:01 +0000 Subject: [PATCH] Applied patch by ITAGAKI Takahiro to get prepare thread-safe. --- src/interfaces/ecpg/ChangeLog | 5 + src/interfaces/ecpg/ecpglib/connect.c | 3 +- src/interfaces/ecpg/ecpglib/execute.c | 4 +- src/interfaces/ecpg/ecpglib/extern.h | 5 +- src/interfaces/ecpg/ecpglib/prepare.c | 202 ++++++++------ src/interfaces/ecpg/include/ecpglib.h | 8 +- src/interfaces/ecpg/preproc/output.c | 7 +- src/interfaces/ecpg/preproc/preproc.y | 29 +- src/interfaces/ecpg/test/ecpg_schedule | 1 + src/interfaces/ecpg/test/ecpg_schedule_tcp | 1 + src/interfaces/ecpg/test/expected/sql-desc.c | 8 +- .../ecpg/test/expected/sql-dyntest.c | 2 +- .../ecpg/test/expected/sql-execute.c | 6 +- .../ecpg/test/expected/sql-oldexec.c | 4 +- .../ecpg/test/expected/thread-prep.c | 256 ++++++++++++++++++ .../ecpg/test/expected/thread-prep.stderr | 0 .../ecpg/test/expected/thread-prep.stdout | 1 + .../ecpg/test/expected/thread-prep_2.stdout | 0 src/interfaces/ecpg/test/thread/Makefile | 3 +- src/interfaces/ecpg/test/thread/prep.pgc | 95 +++++++ 20 files changed, 516 insertions(+), 124 deletions(-) create mode 100644 src/interfaces/ecpg/test/expected/thread-prep.c create mode 100644 src/interfaces/ecpg/test/expected/thread-prep.stderr create mode 100644 src/interfaces/ecpg/test/expected/thread-prep.stdout create mode 100644 src/interfaces/ecpg/test/expected/thread-prep_2.stdout create mode 100644 src/interfaces/ecpg/test/thread/prep.pgc diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog index b045dc8b58..fa4ea4ddce 100644 --- a/src/interfaces/ecpg/ChangeLog +++ b/src/interfaces/ecpg/ChangeLog @@ -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 + to get prepare thread-safe. - Set ecpg library version to 6.0. - Set ecpg version to 4.4. diff --git a/src/interfaces/ecpg/ecpglib/connect.c b/src/interfaces/ecpg/ecpglib/connect.c index 421155bb92..40f5d7ead3 100644 --- a/src/interfaces/ecpg/ecpglib/connect.c +++ b/src/interfaces/ecpg/ecpglib/connect.c @@ -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; diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c index a1aad0b30a..c5ae1dadf3 100644 --- a/src/interfaces/ecpg/ecpglib/execute.c +++ b/src/interfaces/ecpg/ecpglib/execute.c @@ -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) { diff --git a/src/interfaces/ecpg/ecpglib/extern.h b/src/interfaces/ecpg/ecpglib/extern.h index c9e230447f..f69730740b 100644 --- a/src/interfaces/ecpg/ecpglib/extern.h +++ b/src/interfaces/ecpg/ecpglib/extern.h @@ -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) */ diff --git a/src/interfaces/ecpg/ecpglib/prepare.c b/src/interfaces/ecpg/ecpglib/prepare.c index bad7b359b4..6d884bfb0a 100644 --- a/src/interfaces/ecpg/ecpglib/prepare.c +++ b/src/interfaces/ecpg/ecpglib/prepare.c @@ -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" @@ -11,13 +11,13 @@ #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); + con = ECPGget_connection(connection_name); + /* 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); - - if (!b) - return false; - } + 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 bool -deallocate_one(int lineno, const char *name) +static struct prepared_statement *find_prepared_statement(const char *name, + struct connection *con, struct prepared_statement **prev_) { - struct prepared_statement *this, - *prev; + struct prepared_statement *this, + *prev; - /* 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) + for (this = con->prep_stmts, prev = NULL; this != NULL; prev = this, this = this->next) { - /* first deallocate the statement in the backend */ - if (this->prepared) + if (strcmp(this->name, name) == 0) { - char *text; - PGresult *query; - - if (!(text = (char *) ECPGalloc(strlen("deallocate \"\" ") + strlen(this->name), this->stmt->lineno))) - return false; - else + if (prev_) + *prev_ = prev; + return this; + } + } + return NULL; +} + +static bool +deallocate_one(int lineno, enum COMPAT_MODE c, struct connection *con, struct prepared_statement *prev, struct prepared_statement *this) +{ + bool r = false; + + ECPGlog("ECPGdeallocate line %d: NAME: %s\n", lineno, this->name); + + /* 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) + { + 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; } - return false; + + /* + * 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; + } + + /* 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. - */ + con = ECPGget_connection(connection_name); + + this = find_prepared_statement(name, con, &prev); + if (this) + return deallocate_one(lineno, c, con, prev, this); + + /* prepared statement is not found */ + if (INFORMIX_MODE(c)) return true; - } - - if (!ret) - ECPGraise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, name); - - return ret; + 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) { - /* deallocate all prepared statements */ - while (prep_stmts != NULL) - { - bool b = ECPGdeallocate(lineno, compat, prep_stmts->name); + struct connection *con; - if (!b) + con = ECPGget_connection(connection_name); + + /* deallocate all prepared statements */ + while (con->prep_stmts) + { + 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); } - diff --git a/src/interfaces/ecpg/include/ecpglib.h b/src/interfaces/ecpg/include/ecpglib.h index 80e5452a13..7a24618c83 100644 --- a/src/interfaces/ecpg/include/ecpglib.h +++ b/src/interfaces/ecpg/include/ecpglib.h @@ -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); diff --git a/src/interfaces/ecpg/preproc/output.c b/src/interfaces/ecpg/preproc/output.c index 26be27ba72..2a4a638004 100644 --- a/src/interfaces/ecpg/preproc/output.c +++ b/src/interfaces/ecpg/preproc/output.c @@ -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); diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y index 9166bb3e83..cd0d94ff97 100644 --- a/src/interfaces/ecpg/preproc/preproc.y +++ b/src/interfaces/ecpg/preproc/preproc.y @@ -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); } ; diff --git a/src/interfaces/ecpg/test/ecpg_schedule b/src/interfaces/ecpg/test/ecpg_schedule index 4df5d088de..432a458cde 100644 --- a/src/interfaces/ecpg/test/ecpg_schedule +++ b/src/interfaces/ecpg/test/ecpg_schedule @@ -41,3 +41,4 @@ test: sql/insupd test: sql/parser test: thread/thread test: thread/thread_implicit +test: thread/prep diff --git a/src/interfaces/ecpg/test/ecpg_schedule_tcp b/src/interfaces/ecpg/test/ecpg_schedule_tcp index 03703a0d06..64fbca2117 100644 --- a/src/interfaces/ecpg/test/ecpg_schedule_tcp +++ b/src/interfaces/ecpg/test/ecpg_schedule_tcp @@ -41,5 +41,6 @@ test: sql/insupd test: sql/parser test: thread/thread test: thread/thread_implicit +test: thread/prep test: connect/test1 diff --git a/src/interfaces/ecpg/test/expected/sql-desc.c b/src/interfaces/ecpg/test/expected/sql-desc.c index 2e93f90f40..c32cda15c2 100644 --- a/src/interfaces/ecpg/test/expected/sql-desc.c +++ b/src/interfaces/ecpg/test/expected/sql-desc.c @@ -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();} diff --git a/src/interfaces/ecpg/test/expected/sql-dyntest.c b/src/interfaces/ecpg/test/expected/sql-dyntest.c index 739141afe3..206fa2058d 100644 --- a/src/interfaces/ecpg/test/expected/sql-dyntest.c +++ b/src/interfaces/ecpg/test/expected/sql-dyntest.c @@ -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" diff --git a/src/interfaces/ecpg/test/expected/sql-execute.c b/src/interfaces/ecpg/test/expected/sql-execute.c index fad63e8326..7aa926ffa6 100644 --- a/src/interfaces/ecpg/test/expected/sql-execute.c +++ b/src/interfaces/ecpg/test/expected/sql-execute.c @@ -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); diff --git a/src/interfaces/ecpg/test/expected/sql-oldexec.c b/src/interfaces/ecpg/test/expected/sql-oldexec.c index 60e10a1fe1..21a84593bd 100644 --- a/src/interfaces/ecpg/test/expected/sql-oldexec.c +++ b/src/interfaces/ecpg/test/expected/sql-oldexec.c @@ -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 index 0000000000..cc3129b6c9 --- /dev/null +++ b/src/interfaces/ecpg/test/expected/thread-prep.c @@ -0,0 +1,256 @@ +/* Processed by ecpg (regression mode) */ +/* These include files are added by the preprocessor */ +#include +#include +#include +#include +/* End of automatic include section */ +#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y)) + +#line 1 "prep.pgc" +#include +#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 +#include +#else +#include +#endif +#include + +#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 index 0000000000..e69de29bb2 diff --git a/src/interfaces/ecpg/test/expected/thread-prep.stdout b/src/interfaces/ecpg/test/expected/thread-prep.stdout new file mode 100644 index 0000000000..75fe16bb36 --- /dev/null +++ b/src/interfaces/ecpg/test/expected/thread-prep.stdout @@ -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 index 0000000000..e69de29bb2 diff --git a/src/interfaces/ecpg/test/thread/Makefile b/src/interfaces/ecpg/test/thread/Makefile index 672622a32b..8695a254ac 100644 --- a/src/interfaces/ecpg/test/thread/Makefile +++ b/src/interfaces/ecpg/test/thread/Makefile @@ -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 index 0000000000..1213975b16 --- /dev/null +++ b/src/interfaces/ecpg/test/thread/prep.pgc @@ -0,0 +1,95 @@ +#include +#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 +#include +#else +#include +#endif +#include + +#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 +