summaryrefslogtreecommitdiff
path: root/src/interfaces/ecpg/lib/ecpglib.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/ecpg/lib/ecpglib.c')
-rw-r--r--src/interfaces/ecpg/lib/ecpglib.c133
1 files changed, 97 insertions, 36 deletions
diff --git a/src/interfaces/ecpg/lib/ecpglib.c b/src/interfaces/ecpg/lib/ecpglib.c
index 2a7745f2a67..e686edd512d 100644
--- a/src/interfaces/ecpg/lib/ecpglib.c
+++ b/src/interfaces/ecpg/lib/ecpglib.c
@@ -17,6 +17,7 @@
#include <unistd.h>
#include <stdarg.h>
#include <string.h>
+#include <ctype.h>
#include <libpq-fe.h>
#include <libpq/pqcomm.h>
@@ -78,6 +79,7 @@ struct statement
{
int lineno;
char *command;
+ struct connection *connection;
struct variable *inlist;
struct variable *outlist;
};
@@ -104,6 +106,21 @@ register_error(long code, char *fmt,...)
sqlca.sqlerrm.sqlerrml = strlen(sqlca.sqlerrm.sqlerrmc);
}
+static struct connection *
+get_connection(const char *connection_name)
+{
+ struct connection *con = all_connections;;
+
+ if (connection_name == NULL || strcmp(connection_name, "CURRENT") == 0)
+ return actual_connection;
+
+ for (; con && strcmp(connection_name, con->name) != 0; con = con->next);
+ if (con)
+ return con;
+ else
+ return NULL;
+}
+
static void
ECPGfinish(struct connection * act)
{
@@ -145,7 +162,6 @@ ecpg_alloc(long size, int lineno)
if (!new)
{
- ECPGfinish(actual_connection);
ECPGlog("out of memory\n");
register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
return NULL;
@@ -162,7 +178,6 @@ ecpg_strdup(const char *string, int lineno)
if (!new)
{
- ECPGfinish(actual_connection);
ECPGlog("out of memory\n");
register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
return NULL;
@@ -238,9 +253,26 @@ quote_strings(char *arg, int lineno)
return res;
}
-/* create a list of variables */
+/*
+ * create a list of variables
+ * The variables are listed with input variables preceeding outputvariables
+ * The end of each group is marked by an end marker.
+ * per variable we list:
+ * type - as defined in ecpgtype.h
+ * value - where to store the data
+ * varcharsize - length of string in case we have a stringvariable, else 0
+ * arraysize - 0 for pointer (we don't know the size of the array),
+ * 1 for simple variable, size for arrays
+ * offset - offset between ith and (i+1)th entry in an array,
+ * normally that means sizeof(type)
+ * ind_type - type of indicator variable
+ * ind_value - pointer to indicator variable
+ * ind_varcharsize - empty
+ * ind_arraysize - arraysize of indicator array
+ * ind_offset - indicator offset
+ */
static bool
-create_statement(int lineno, struct statement ** stmt, char *query, va_list ap)
+create_statement(int lineno, struct connection *connection, struct statement ** stmt, char *query, va_list ap)
{
struct variable **list = &((*stmt)->inlist);
enum ECPGttype type;
@@ -249,6 +281,7 @@ create_statement(int lineno, struct statement ** stmt, char *query, va_list ap)
return false;
(*stmt)->command = query;
+ (*stmt)->connection = connection;
(*stmt)->lineno = lineno;
list = &((*stmt)->inlist);
@@ -278,7 +311,8 @@ create_statement(int lineno, struct statement ** stmt, char *query, va_list ap)
var->ind_arrsize = va_arg(ap, long);
var->ind_offset = va_arg(ap, long);
var->next = NULL;
-
+
+ /* if variable is NULL, the statement hasn't been prepared */
if (var->value == NULL)
{
ECPGlog("create_statement: invalid statement name\n");
@@ -564,27 +598,27 @@ ECPGexecute(struct statement * stmt)
/* Now the request is built. */
- if (actual_connection->committed && !no_auto_trans)
+ if (stmt->connection->committed && !no_auto_trans)
{
- if ((results = PQexec(actual_connection->connection, "begin transaction")) == NULL)
+ if ((results = PQexec(stmt->connection->connection, "begin transaction")) == NULL)
{
register_error(ECPG_TRANS, "Error starting transaction line %d.", stmt->lineno);
return false;
}
PQclear(results);
- actual_connection->committed = false;
+ stmt->connection->committed = false;
}
- ECPGlog("ECPGexecute line %d: QUERY: %s\n", stmt->lineno, copiedquery);
- results = PQexec(actual_connection->connection, copiedquery);
+ ECPGlog("ECPGexecute line %d: QUERY: %s on connection %s\n", stmt->lineno, copiedquery, stmt->connection->name);
+ results = PQexec(stmt->connection->connection, copiedquery);
free(copiedquery);
if (results == NULL)
{
ECPGlog("ECPGexecute line %d: error: %s", stmt->lineno,
- PQerrorMessage(actual_connection->connection));
+ PQerrorMessage(stmt->connection->connection));
register_error(ECPG_PGSQL, "Postgres error: %s line %d.",
- PQerrorMessage(actual_connection->connection), stmt->lineno);
+ PQerrorMessage(stmt->connection->connection), stmt->lineno);
}
else
{
@@ -642,6 +676,7 @@ ECPGexecute(struct statement * stmt)
status = false;
break;
}
+
for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
{
pval = PQgetvalue(results, act_tuple, act_field);
@@ -909,18 +944,18 @@ ECPGexecute(struct statement * stmt)
case PGRES_FATAL_ERROR:
case PGRES_BAD_RESPONSE:
ECPGlog("ECPGexecute line %d: Error: %s",
- stmt->lineno, PQerrorMessage(actual_connection->connection));
+ stmt->lineno, PQerrorMessage(stmt->connection->connection));
register_error(ECPG_PGSQL, "Error: %s line %d.",
- PQerrorMessage(actual_connection->connection), stmt->lineno);
+ PQerrorMessage(stmt->connection->connection), stmt->lineno);
status = false;
break;
case PGRES_COPY_OUT:
ECPGlog("ECPGexecute line %d: Got PGRES_COPY_OUT ... tossing.\n", stmt->lineno);
- PQendcopy(actual_connection->connection);
+ PQendcopy(stmt->connection->connection);
break;
case PGRES_COPY_IN:
ECPGlog("ECPGexecute line %d: Got PGRES_COPY_IN ... tossing.\n", stmt->lineno);
- PQendcopy(actual_connection->connection);
+ PQendcopy(stmt->connection->connection);
break;
default:
ECPGlog("ECPGexecute line %d: Got something else, postgres error.\n",
@@ -932,7 +967,7 @@ ECPGexecute(struct statement * stmt)
}
/* check for asynchronous returns */
- notify = PQnotifies(actual_connection->connection);
+ notify = PQnotifies(stmt->connection->connection);
if (notify)
{
ECPGlog("ECPGexecute line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
@@ -944,20 +979,27 @@ ECPGexecute(struct statement * stmt)
}
bool
-ECPGdo(int lineno, char *query,...)
+ECPGdo(int lineno, const char *connection_name, char *query,...)
{
va_list args;
struct statement *stmt;
+ struct connection *con = get_connection(connection_name);
+ if (con == NULL)
+ {
+ register_error(ECPG_NO_CONN, "No such connection %s in line %d", connection_name, lineno);
+ return (false);
+ }
+
va_start(args, query);
- if (create_statement(lineno, &stmt, query, args) == false)
+ if (create_statement(lineno, con, &stmt, query, args) == false)
return (false);
va_end(args);
/* are we connected? */
- if (actual_connection == NULL || actual_connection->connection == NULL)
+ if (con == NULL || con->connection == NULL)
{
- ECPGlog("ECPGdo: not connected\n");
+ ECPGlog("ECPGdo: not connected to %s\n", con->name);
register_error(ECPG_NOT_CONN, "Not connected in line %d", lineno);
return false;
}
@@ -967,16 +1009,23 @@ ECPGdo(int lineno, char *query,...)
bool
-ECPGtrans(int lineno, const char *transaction)
+ECPGtrans(int lineno, const char *connection_name, const char *transaction)
{
PGresult *res;
+ struct connection *con = get_connection(connection_name);
+
+ if (con == NULL)
+ {
+ register_error(ECPG_NO_CONN, "No such connection %s in line %d", connection_name, lineno);
+ return (false);
+ }
- ECPGlog("ECPGtrans line %d action = %s\n", lineno, transaction);
+ ECPGlog("ECPGtrans line %d action = %s connection = %s\n", lineno, transaction, con->name);
/* if we have no connection we just simulate the command */
- if (actual_connection && actual_connection->connection)
+ if (con && con->connection)
{
- if ((res = PQexec(actual_connection->connection, transaction)) == NULL)
+ if ((res = PQexec(con->connection, transaction)) == NULL)
{
register_error(ECPG_TRANS, "Error in transaction processing line %d.", lineno);
return FALSE;
@@ -987,7 +1036,7 @@ ECPGtrans(int lineno, const char *transaction)
{
struct prepared_statement *this;
- actual_connection->committed = true;
+ con->committed = true;
/* deallocate all prepared statements */
for (this = prep_stmts; this != NULL; this = this->next)
@@ -1005,11 +1054,8 @@ ECPGtrans(int lineno, const char *transaction)
bool
ECPGsetconn(int lineno, const char *connection_name)
{
- struct connection *con = all_connections;
-
- ECPGlog("ECPGsetconn: setting actual connection to %s\n", connection_name);
+ struct connection *con = get_connection(connection_name);
- for (; con && strcmp(connection_name, con->name) != 0; con = con->next);
if (con)
{
actual_connection = con;
@@ -1070,9 +1116,7 @@ ECPGdisconnect(int lineno, const char *connection_name)
{
struct connection *con;
- if (strcmp(connection_name, "CURRENT") == 0)
- ECPGfinish(actual_connection);
- else if (strcmp(connection_name, "ALL") == 0)
+ if (strcmp(connection_name, "ALL") == 0)
{
for (con = all_connections; con;)
{
@@ -1084,7 +1128,8 @@ ECPGdisconnect(int lineno, const char *connection_name)
}
else
{
- for (con = all_connections; con && strcmp(con->name, connection_name) != 0; con = con->next);
+ con = get_connection(connection_name);
+
if (con == NULL)
{
ECPGlog("disconnect: not connected to connection %s\n", connection_name);
@@ -1136,6 +1181,21 @@ sqlprint(void)
printf("sql error %s\n", sqlca.sqlerrm.sqlerrmc);
}
+static bool
+isvarchar(unsigned char c)
+{
+ if (isalnum(c))
+ return true;
+
+ if (c == '_' || c == '>' || c == '-' || c == '.')
+ return true;
+
+ if (c >= 128)
+ return true;
+
+ return(false);
+}
+
static void
replace_variables(char *text)
{
@@ -1150,7 +1210,7 @@ replace_variables(char *text)
if (!string && *ptr == ':')
{
ptr[0] = ptr[1] = ';';
- for (ptr += 2; *ptr && *ptr != ' '; ptr++)
+ for (ptr += 2; *ptr && isvarchar(*ptr); ptr++)
*ptr = ' ';
}
}
@@ -1162,7 +1222,7 @@ ECPGprepare(int lineno, char *name, char *variable)
{
struct statement *stmt;
struct prepared_statement *this;
-
+
/* check if we already have prepared this statement */
for (this = prep_stmts; this != NULL && strcmp(this->name, name) != 0; this = this->next);
if (this)
@@ -1186,6 +1246,7 @@ ECPGprepare(int lineno, char *name, char *variable)
/* create statement */
stmt->lineno = lineno;
+ stmt->connection = NULL;
stmt->command = ecpg_strdup(variable, lineno);
stmt->inlist = stmt->outlist = NULL;