Applied patch by ITAGAKI Takahiro <itagaki.takahiro@oss.ntt.co.jp> to get prepare thread-safe.
This commit is contained in:
parent
689df1bc77
commit
d49b20fbe6
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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) */
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -41,3 +41,4 @@ test: sql/insupd
|
||||
test: sql/parser
|
||||
test: thread/thread
|
||||
test: thread/thread_implicit
|
||||
test: thread/prep
|
||||
|
@ -41,5 +41,6 @@ test: sql/insupd
|
||||
test: sql/parser
|
||||
test: thread/thread
|
||||
test: thread/thread_implicit
|
||||
test: thread/prep
|
||||
test: connect/test1
|
||||
|
||||
|
@ -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();}
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
256
src/interfaces/ecpg/test/expected/thread-prep.c
Normal file
256
src/interfaces/ecpg/test/expected/thread-prep.c
Normal file
@ -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
|
||||
|
1
src/interfaces/ecpg/test/expected/thread-prep.stdout
Normal file
1
src/interfaces/ecpg/test/expected/thread-prep.stdout
Normal file
@ -0,0 +1 @@
|
||||
No threading enabled.
|
@ -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)
|
||||
|
||||
|
95
src/interfaces/ecpg/test/thread/prep.pgc
Normal file
95
src/interfaces/ecpg/test/thread/prep.pgc
Normal file
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user