aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/interfaces/ecpg/ChangeLog14
-rw-r--r--src/interfaces/ecpg/TODO4
-rw-r--r--src/interfaces/ecpg/include/ecpglib.h4
-rw-r--r--src/interfaces/ecpg/include/ecpgtype.h4
-rw-r--r--src/interfaces/ecpg/lib/Makefile.in6
-rw-r--r--src/interfaces/ecpg/lib/ecpglib.c133
-rw-r--r--src/interfaces/ecpg/preproc/Makefile4
-rw-r--r--src/interfaces/ecpg/preproc/c_keywords.c1
-rw-r--r--src/interfaces/ecpg/preproc/ecpg.c1
-rw-r--r--src/interfaces/ecpg/preproc/ecpg_keywords.c1
-rw-r--r--src/interfaces/ecpg/preproc/extern.h2
-rw-r--r--src/interfaces/ecpg/preproc/pgc.l18
-rw-r--r--src/interfaces/ecpg/preproc/preproc.y72
-rw-r--r--src/interfaces/ecpg/preproc/type.c16
-rw-r--r--src/interfaces/ecpg/preproc/type.h1
-rw-r--r--src/interfaces/ecpg/test/Makefile2
-rw-r--r--src/interfaces/ecpg/test/test1.pgc32
-rw-r--r--src/interfaces/ecpg/test/test2.pgc23
18 files changed, 240 insertions, 98 deletions
diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog
index eac1b96e800..15248494346 100644
--- a/src/interfaces/ecpg/ChangeLog
+++ b/src/interfaces/ecpg/ChangeLog
@@ -463,3 +463,17 @@ Fri Feb 19 21:40:14 CET 1999
- Fixed bug in libecpg that caused it to start transactions only for
the first connection.
- Set library version to 2.7.1
+
+Son Feb 21 14:10:47 CET 1999
+
+ - Fixed variable detection in libecpg.
+
+Mon Feb 22 19:47:45 CET 1999
+
+ - Added 'at <db_connection>' option to all commands it is apllicable
+ to. Due to changing the API of some libecpg functions this
+ requires me to increase the major version number.
+ - Synced pgc.l with scan.l.
+ - Added support for unions.
+ - Set library version to 3.0.0
+ - Set ecpg version to 3.0.0
diff --git a/src/interfaces/ecpg/TODO b/src/interfaces/ecpg/TODO
index 82b8a5d8b85..0b4be6dd9f4 100644
--- a/src/interfaces/ecpg/TODO
+++ b/src/interfaces/ecpg/TODO
@@ -11,9 +11,9 @@ DESCRIPTOR statement will be ignored.
it would be nice to be able to use :var[:index] as cvariable
-'at DB connection' is missing for several commands (is this standard?)
+support for dynamic SQL with unknown number of variables with SQLDA structure
-support for unions
+allocate memory for pointers as C input variables
Missing statements:
- exec sql allocate
diff --git a/src/interfaces/ecpg/include/ecpglib.h b/src/interfaces/ecpg/include/ecpglib.h
index 4e1d6f9cde4..98153747f6f 100644
--- a/src/interfaces/ecpg/include/ecpglib.h
+++ b/src/interfaces/ecpg/include/ecpglib.h
@@ -8,8 +8,8 @@ extern "C"
void ECPGdebug(int, FILE *);
bool ECPGsetconn(int, const char *);
bool ECPGconnect(int, const char *, const char *, const char *, const char *);
- bool ECPGdo(int, char *,...);
- bool ECPGtrans(int, const char *);
+ bool ECPGdo(int, const char *, char *,...);
+ bool ECPGtrans(int, const char *, const char *);
bool ECPGdisconnect(int, const char *);
bool ECPGprepare(int, char *, char *);
bool ECPGdeallocate(int, char *);
diff --git a/src/interfaces/ecpg/include/ecpgtype.h b/src/interfaces/ecpg/include/ecpgtype.h
index e92220481da..8ca4d697c15 100644
--- a/src/interfaces/ecpg/include/ecpgtype.h
+++ b/src/interfaces/ecpg/include/ecpgtype.h
@@ -43,10 +43,10 @@ extern "C"
ECPGt_varchar, ECPGt_varchar2,
ECPGt_array,
ECPGt_struct,
+ ECPGt_char_variable,
ECPGt_EOIT, /* End of insert types. */
ECPGt_EORT, /* End of result types. */
- ECPGt_NO_INDICATOR, /* no indicator */
- ECPGt_char_variable
+ ECPGt_NO_INDICATOR /* no indicator */
};
#define IS_SIMPLE_TYPE(type) ((type) >= ECPGt_char && (type) <= ECPGt_varchar2)
diff --git a/src/interfaces/ecpg/lib/Makefile.in b/src/interfaces/ecpg/lib/Makefile.in
index 4872e8c0fd5..ef2373fa78e 100644
--- a/src/interfaces/ecpg/lib/Makefile.in
+++ b/src/interfaces/ecpg/lib/Makefile.in
@@ -6,13 +6,13 @@
# Copyright (c) 1994, Regents of the University of California
#
# IDENTIFICATION
-# $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile.in,v 1.42 1999/02/21 03:02:35 scrappy Exp $
+# $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile.in,v 1.43 1999/02/23 12:56:55 scrappy Exp $
#
#-------------------------------------------------------------------------
NAME= ecpg
-SO_MAJOR_VERSION= 2
-SO_MINOR_VERSION= 7.1
+SO_MAJOR_VERSION= 3
+SO_MINOR_VERSION= 0.0
SRCDIR= @top_srcdir@
include $(SRCDIR)/Makefile.global
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;
diff --git a/src/interfaces/ecpg/preproc/Makefile b/src/interfaces/ecpg/preproc/Makefile
index 87e788c83cc..66c8911c5a8 100644
--- a/src/interfaces/ecpg/preproc/Makefile
+++ b/src/interfaces/ecpg/preproc/Makefile
@@ -1,8 +1,8 @@
SRCDIR= ../../..
include $(SRCDIR)/Makefile.global
-MAJOR_VERSION=2
-MINOR_VERSION=5
+MAJOR_VERSION=3
+MINOR_VERSION=0
PATCHLEVEL=0
CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \
diff --git a/src/interfaces/ecpg/preproc/c_keywords.c b/src/interfaces/ecpg/preproc/c_keywords.c
index 5395b533d38..9a8b94bd256 100644
--- a/src/interfaces/ecpg/preproc/c_keywords.c
+++ b/src/interfaces/ecpg/preproc/c_keywords.c
@@ -36,6 +36,7 @@ static ScanKeyword ScanKeywords[] = {
{"signed", S_SIGNED},
{"static", S_STATIC},
{"struct", S_STRUCT},
+ {"union", S_UNION},
{"unsigned", S_UNSIGNED},
{"varchar", S_VARCHAR},
};
diff --git a/src/interfaces/ecpg/preproc/ecpg.c b/src/interfaces/ecpg/preproc/ecpg.c
index 2594718cd12..6b37442c836 100644
--- a/src/interfaces/ecpg/preproc/ecpg.c
+++ b/src/interfaces/ecpg/preproc/ecpg.c
@@ -165,6 +165,7 @@ main(int argc, char *const argv[])
struct arguments *l1, *l2;
free(ptr->command);
+ free(ptr->connection);
free(ptr->name);
for (l1 = ptr->argsinsert; l1; l1 = l2)
{
diff --git a/src/interfaces/ecpg/preproc/ecpg_keywords.c b/src/interfaces/ecpg/preproc/ecpg_keywords.c
index 52eea065b83..25c1f2b9813 100644
--- a/src/interfaces/ecpg/preproc/ecpg_keywords.c
+++ b/src/interfaces/ecpg/preproc/ecpg_keywords.c
@@ -20,6 +20,7 @@
*/
static ScanKeyword ScanKeywords[] = {
/* name value */
+ {"at", SQL_AT},
{"bool", SQL_BOOL},
{"break", SQL_BREAK},
{"call", SQL_CALL},
diff --git a/src/interfaces/ecpg/preproc/extern.h b/src/interfaces/ecpg/preproc/extern.h
index d5bc1fc9cab..94c76a507af 100644
--- a/src/interfaces/ecpg/preproc/extern.h
+++ b/src/interfaces/ecpg/preproc/extern.h
@@ -6,7 +6,7 @@
extern int braces_open,
no_auto_trans, struct_level;
-extern char *yytext;
+extern char *yytext, errortext[128];
extern int yylineno,
yyleng;
extern FILE *yyin,
diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l
index 5ddac659bbc..82369690763 100644
--- a/src/interfaces/ecpg/preproc/pgc.l
+++ b/src/interfaces/ecpg/preproc/pgc.l
@@ -105,7 +105,6 @@ xqstart {quote}
xqstop {quote}
xqdouble {quote}{quote}
xqinside [^\\']*
-xqembedded "\\'"
xqliteral [\\](.|\n)
xqcat {quote}{space}*\n{space}*{quote}
@@ -244,22 +243,9 @@ cppline {space}*#.*(\\{space}*\n)*\n*
return SCONST;
}
<xq>{xqdouble} |
-<xq>{xqinside} {
- if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
- yyerror("ERROR: quoted string parse buffer exceeded");
- memcpy(literal+llen, yytext, yyleng+1);
- llen += yyleng;
- }
-<xq>{xqembedded} {
- if ((llen+yyleng-1) > (MAX_PARSE_BUFFER - 1))
- yyerror("ERROR: quoted string parse buffer exceeded");
- memcpy(literal+llen, yytext, yyleng+1);
- *(literal+llen) = '\'';
- llen += yyleng;
- }
-
+<xq>{xqinside} |
<xq>{xqliteral} {
- if ((llen+yyleng-1) > (MAX_PARSE_BUFFER - 1))
+ if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
yyerror("ERROR: quoted string parse buffer exceeded");
memcpy(literal+llen, yytext, yyleng+1);
llen += yyleng;
diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y
index 7bb95d77e8c..ae5edf294d9 100644
--- a/src/interfaces/ecpg/preproc/preproc.y
+++ b/src/interfaces/ecpg/preproc/preproc.y
@@ -18,7 +18,8 @@
* Variables containing simple states.
*/
int struct_level = 0;
-static char errortext[128];
+char errortext[128];
+static char *connection = NULL;
static int QueryIsRule = 0, ForUpdateNotAllowed = 0;
static struct this_type actual_type[STRUCT_DEPTH];
static char *actual_storage[STRUCT_DEPTH];
@@ -489,7 +490,7 @@ output_statement(char * stmt, int mode)
{
int i, j=strlen(stmt);
- fputs("ECPGdo(__LINE__, \"", yyout);
+ fprintf(yyout, "ECPGdo(__LINE__, %s, \"", connection ? connection : "NULL");
/* do this char by char as we have to filter '\"' */
for (i = 0;i < j; i++)
@@ -504,6 +505,8 @@ output_statement(char * stmt, int mode)
fputs("ECPGt_EORT);", yyout);
whenever_action(mode);
free(stmt);
+ if (connection != NULL)
+ free(connection);
}
static struct typedefs *
@@ -612,7 +615,7 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
}
/* special embedded SQL token */
-%token SQL_BOOL SQL_BREAK
+%token SQL_AT SQL_BOOL SQL_BREAK
%token SQL_CALL SQL_CONNECT SQL_CONNECTION SQL_CONTINUE
%token SQL_DEALLOCATE SQL_DISCONNECT SQL_ENUM
%token SQL_FOUND SQL_FREE SQL_GO SQL_GOTO
@@ -625,8 +628,8 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
/* C token */
%token S_ANYTHING S_AUTO S_BOOL S_CHAR S_CONST S_DOUBLE S_ENUM S_EXTERN
%token S_FLOAT S_INT S
-%token S_LONG S_REGISTER S_SHORT S_SIGNED S_STATIC S_STRUCT
-%token S_UNSIGNED S_VARCHAR
+%token S_LONG S_REGISTER S_SHORT S_SIGNED S_STATIC S_STRUCT
+%token S_UNION S_UNSIGNED S_VARCHAR
/* I need this and don't know where it is defined inside the backend */
%token TYPECAST
@@ -785,8 +788,9 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
%type <str> ECPGSetConnection c_line cpp_line s_enum ECPGTypedef
%type <str> enum_type civariableonly ECPGCursorStmt ECPGDeallocate
%type <str> ECPGFree ECPGDeclare ECPGVar sql_variable_declarations
-%type <str> sql_declaration sql_variable_list sql_variable
+%type <str> sql_declaration sql_variable_list sql_variable opt_at
%type <str> struct_type s_struct declaration variable_declarations
+%type <str> s_struct_or_union sql_struct_or_union
%type <type_enum> simple_type varchar_type
@@ -803,13 +807,16 @@ prog: statements;
statements: /* empty */
| statements statement
-statement: ecpgstart stmt SQL_SEMI
+statement: ecpgstart opt_at stmt SQL_SEMI { connection = NULL; }
+ | ecpgstart stmt SQL_SEMI
| ECPGDeclaration
| c_thing { fprintf(yyout, "%s", $1); free($1); }
| cpp_line { fprintf(yyout, "%s", $1); free($1); }
| blockstart { fputs($1, yyout); free($1); }
| blockend { fputs($1, yyout); free($1); }
+opt_at: SQL_AT connection_target { connection = $2; }
+
stmt: AddAttrStmt { output_statement($1, 0); }
| AlterUserStmt { output_statement($1, 0); }
| ClosePortalStmt { output_statement($1, 0); }
@@ -853,7 +860,7 @@ stmt: AddAttrStmt { output_statement($1, 0); }
}
| RuleStmt { output_statement($1, 0); }
| TransactionStmt {
- fprintf(yyout, "ECPGtrans(__LINE__, \"%s\");", $1);
+ fprintf(yyout, "ECPGtrans(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1);
whenever_action(0);
free($1);
}
@@ -866,6 +873,9 @@ stmt: AddAttrStmt { output_statement($1, 0); }
| VariableShowStmt { output_statement($1, 0); }
| VariableResetStmt { output_statement($1, 0); }
| ECPGConnect {
+ if (connection)
+ yyerror("no at option for connect statement.\n");
+
fprintf(yyout, "no_auto_trans = %d;\n", no_auto_trans);
fprintf(yyout, "ECPGconnect(__LINE__, %s);", $1);
whenever_action(0);
@@ -876,6 +886,9 @@ stmt: AddAttrStmt { output_statement($1, 0); }
free($1);
}
| ECPGDeallocate {
+ if (connection)
+ yyerror("no at option for connect statement.\n");
+
fputs($1, yyout);
whenever_action(0);
free($1);
@@ -885,6 +898,9 @@ stmt: AddAttrStmt { output_statement($1, 0); }
free($1);
}
| ECPGDisconnect {
+ if (connection)
+ yyerror("no at option for disconnect statement.\n");
+
fprintf(yyout, "ECPGdisconnect(__LINE__, \"%s\");", $1);
whenever_action(0);
free($1);
@@ -893,7 +909,7 @@ stmt: AddAttrStmt { output_statement($1, 0); }
output_statement($1, 0);
}
| ECPGFree {
- fprintf(yyout, "ECPGdeallocate(__LINE__, \"%s\");", $1);
+ fprintf(yyout, "ECPGdeallocate(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1);
whenever_action(0);
free($1);
}
@@ -912,7 +928,7 @@ stmt: AddAttrStmt { output_statement($1, 0); }
yyerror(errortext);
}
- fprintf(yyout, "ECPGdo(__LINE__, \"%s\",", ptr->command);
+ fprintf(yyout, "ECPGdo(__LINE__, %s, \"%s\",", ptr->connection ? ptr->connection : "NULL", ptr->command);
/* dump variables to C file*/
dump_variables(ptr->argsinsert, 0);
dump_variables(argsinsert, 0);
@@ -923,25 +939,40 @@ stmt: AddAttrStmt { output_statement($1, 0); }
free($1);
}
| ECPGPrepare {
+ if (connection)
+ yyerror("no at option for set connection statement.\n");
+
fprintf(yyout, "ECPGprepare(__LINE__, %s);", $1);
whenever_action(0);
free($1);
}
| ECPGRelease { /* output already done */ }
| ECPGSetConnection {
+ if (connection)
+ yyerror("no at option for set connection statement.\n");
+
fprintf(yyout, "ECPGsetconn(__LINE__, %s);", $1);
whenever_action(0);
free($1);
}
| ECPGTypedef {
+ if (connection)
+ yyerror("no at option for typedef statement.\n");
+
fputs($1, yyout);
free($1);
}
| ECPGVar {
+ if (connection)
+ yyerror("no at option for var statement.\n");
+
fputs($1, yyout);
free($1);
}
| ECPGWhenever {
+ if (connection)
+ yyerror("no at option for whenever statement.\n");
+
fputs($1, yyout);
output_line_number();
free($1);
@@ -2727,6 +2758,7 @@ CursorStmt: DECLARE name opt_cursor CURSOR FOR SelectStmt cursor_clause
/* initial definition */
this->next = cur;
this->name = $2;
+ this->connection = connection;
this->command = cat2_str(cat5_str(make1_str("declare"), mm_strdup($2), $3, make1_str("cursor for"), $6), $7);
this->argsinsert = argsinsert;
this->argsresult = argsresult;
@@ -3103,6 +3135,7 @@ Generic: generic
generic: ident { $$ = $1; }
| TYPE_P { $$ = make1_str("type"); }
+ | SQL_AT { $$ = make1_str("at"); }
| SQL_BOOL { $$ = make1_str("bool"); }
| SQL_BREAK { $$ = make1_str("break"); }
| SQL_CALL { $$ = make1_str("call"); }
@@ -4306,6 +4339,7 @@ ColId: ident { $$ = $1; }
| VALID { $$ = make1_str("valid"); }
| VERSION { $$ = make1_str("version"); }
| ZONE { $$ = make1_str("zone"); }
+ | SQL_AT { $$ = make1_str("at"); }
| SQL_BOOL { $$ = make1_str("bool"); }
| SQL_BREAK { $$ = make1_str("break"); }
| SQL_CALL { $$ = make1_str("call"); }
@@ -4602,6 +4636,7 @@ ECPGCursorStmt: DECLARE name opt_cursor CURSOR FOR ident cursor_clause
/* initial definition */
this->next = cur;
this->name = $2;
+ this->connection = connection;
this->command = cat5_str(make1_str("declare"), mm_strdup($2), $3, make1_str("cursor for ;;"), $7);
this->argsresult = NULL;
@@ -4731,14 +4766,17 @@ struct_type: s_struct '{' variable_declarations '}'
$$ = cat4_str($1, make1_str("{"), $3, make1_str("}"));
}
-s_struct : S_STRUCT opt_symbol
+s_struct : s_struct_or_union opt_symbol
{
struct_member_list[struct_level++] = NULL;
if (struct_level >= STRUCT_DEPTH)
yyerror("Too many levels in nested structure definition");
- $$ = cat2_str(make1_str("struct"), $2);
+ $$ = cat2_str($1, $2);
}
+s_struct_or_union: S_STRUCT { $$ = make1_str("struct"); }
+ | S_UNION { $$ = make1_str("union"); }
+
opt_symbol: /* empty */ { $$ = make1_str(""); }
| symbol { $$ = $1; }
@@ -4940,7 +4978,7 @@ ECPGRelease: TransactionStmt SQL_RELEASE
if (strncmp($1, "begin", 5) == 0)
yyerror("RELEASE does not make sense when beginning a transaction");
- fprintf(yyout, "ECPGtrans(__LINE__, \"%s\");", $1);
+ fprintf(yyout, "ECPGtrans(__LINE__, %s, \"%s\");", connection, $1);
whenever_action(0);
fprintf(yyout, "ECPGdisconnect(\"\");");
whenever_action(0);
@@ -5151,7 +5189,7 @@ ctype: CHAR
$$.type_index = -1;
$$.type_dimension = -1;
}
- | SQL_STRUCT
+ | sql_struct_or_union
{
struct_member_list[struct_level++] = NULL;
if (struct_level >= STRUCT_DEPTH)
@@ -5159,7 +5197,7 @@ ctype: CHAR
} '{' sql_variable_declarations '}'
{
ECPGfree_struct_member(struct_member_list[struct_level--]);
- $$.type_str = cat3_str(make1_str("struct {"), $4, make1_str("}"));
+ $$.type_str = cat4_str($1, make1_str("{"), $4, make1_str("}"));
$$.type_enum = ECPGt_struct;
$$.type_index = -1;
$$.type_dimension = -1;
@@ -5175,6 +5213,9 @@ ctype: CHAR
struct_member_list[struct_level] = this->struct_member_list;
}
+sql_struct_or_union: SQL_STRUCT { $$ = make1_str("struct"); }
+ | UNION { $$ = make1_str("union"); }
+
opt_signed: SQL_SIGNED | /* empty */
sql_variable_declarations: /* empty */
@@ -5735,6 +5776,7 @@ c_anything: IDENT { $$ = $1; }
| S_SIGNED { $$ = make1_str("signed"); }
| S_STATIC { $$ = make1_str("static"); }
| S_STRUCT { $$ = make1_str("struct"); }
+ | S_UNION { $$ = make1_str("union"); }
| S_UNSIGNED { $$ = make1_str("unsigned"); }
| S_VARCHAR { $$ = make1_str("varchar"); }
| S_ANYTHING { $$ = make_name(); }
diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c
index dd3546b50ad..b5144d5d9a7 100644
--- a/src/interfaces/ecpg/preproc/type.c
+++ b/src/interfaces/ecpg/preproc/type.c
@@ -164,7 +164,8 @@ get_type(enum ECPGttype typ)
return ("ECPGt_char_variable");
break;
default:
- abort();
+ sprintf(errortext, "illegal variable type %d\n", typ);
+ yyerror(errortext);
}
}
@@ -357,7 +358,8 @@ ECPGfree_type(struct ECPGtype * typ)
if (IS_SIMPLE_TYPE(typ->u.element->typ))
free(typ->u.element);
else if (typ->u.element->typ == ECPGt_array)
- abort(); /* Array of array, */
+ /* Array of array, */
+ yyerror("internal error, found multi-dimensional array\n");
else if (typ->u.element->typ == ECPGt_struct)
{
/* Array of structs. */
@@ -365,7 +367,10 @@ ECPGfree_type(struct ECPGtype * typ)
free(typ->u.members);
}
else
- abort();
+ {
+ sprintf(errortext, "illegal variable type %d\n", typ);
+ yyerror(errortext);
+ }
}
else if (typ->typ == ECPGt_struct)
{
@@ -373,7 +378,10 @@ ECPGfree_type(struct ECPGtype * typ)
free(typ->u.members);
}
else
- abort();
+ {
+ sprintf(errortext, "illegal variable type %d\n", typ);
+ yyerror(errortext);
+ }
}
free(typ);
}
diff --git a/src/interfaces/ecpg/preproc/type.h b/src/interfaces/ecpg/preproc/type.h
index f9642d92766..59cf3be9009 100644
--- a/src/interfaces/ecpg/preproc/type.h
+++ b/src/interfaces/ecpg/preproc/type.h
@@ -101,6 +101,7 @@ struct cursor
{
char *name;
char *command;
+ char *connection;
struct arguments *argsinsert;
struct arguments *argsresult;
struct cursor *next;
diff --git a/src/interfaces/ecpg/test/Makefile b/src/interfaces/ecpg/test/Makefile
index 45d65fb44c6..2c4ba01ee0d 100644
--- a/src/interfaces/ecpg/test/Makefile
+++ b/src/interfaces/ecpg/test/Makefile
@@ -15,4 +15,4 @@ perftest.c:perftest.pgc
/usr/local/pgsql/bin/ecpg $?
clean:
- /bin/rm test1 test2 perftest *.c log
+ -/bin/rm test1 test2 perftest *.c log
diff --git a/src/interfaces/ecpg/test/test1.pgc b/src/interfaces/ecpg/test/test1.pgc
index ac2dbdc04e1..a1e13bb5175 100644
--- a/src/interfaces/ecpg/test/test1.pgc
+++ b/src/interfaces/ecpg/test/test1.pgc
@@ -4,7 +4,7 @@ exec sql whenever sqlerror sqlprint;
exec sql include sqlca;
-exec sql define AMOUNT 8;
+exec sql define AMOUNT 4;
exec sql type intarray is int[AMOUNT];
exec sql type string is char(6);
@@ -30,21 +30,31 @@ exec sql end declare section;
ECPGdebug(1, dbgs);
strcpy(msg, "connect");
- exec sql connect to mm;
+ exec sql connect to mm as main;
+
+ strcpy(msg, "connect");
+ exec sql connect to pm;
strcpy(msg, "create");
+ exec sql at main create table test(name char(6), amount int, letter char(1));
exec sql create table test(name char(6), amount int, letter char(1));
strcpy(msg, "commit");
+ exec sql at main commit;
exec sql commit;
+ strcpy(msg, "set connection");
+ exec sql set connection main;
+
strcpy(msg, "execute insert 1");
- sprintf(command, "insert into test(name, amount, letter) values ('foobar', 1, 'f')");
+ sprintf(command, "insert into test(name, amount, letter) values ('db: mm', 1, 'f')");
+ exec sql execute immediate :command;
+ sprintf(command, "insert into test(name, amount, letter) values ('db: mm', 2, 't')");
exec sql execute immediate :command;
strcpy(msg, "execute insert 2");
- sprintf(command, "insert into test(name, amount, letter) select name, amount+1, letter from test");
- exec sql execute immediate :command;
+ sprintf(command, "insert into test(name, amount, letter) values ('db: pm', 1, 'f')");
+ exec sql at pm execute immediate :command;
strcpy(msg, "execute insert 3");
sprintf(command, "insert into test(name, amount, letter) select name, amount+10, letter from test");
@@ -55,27 +65,35 @@ exec sql end declare section;
strcpy(msg, "execute insert 4");
sprintf(command, "insert into test(name, amount, letter) select name, amount+;;, letter from test");
exec sql prepare I from :command;
- exec sql execute I using :increment;
+ exec sql at pm execute I using :increment;
printf("Inserted %d tuples via prepared execute\n", sqlca.sqlerrd[2]);
strcpy(msg, "commit");
exec sql commit;
+ exec sql at pm commit;
strcpy(msg, "select");
exec sql select name, amount, letter into :name, :amount, :letter from test;
for (i=0, j=sqlca.sqlerrd[2]; i<j; i++)
printf("name[%d]=%6.6s\tamount[%d]=%d\tletter[%d]=%c\n", i, name[i], i, amount[i],i, letter[i][0]);
+
+ exec sql at pm select name, amount, letter into :name, :amount, :letter from test;
+
+ for (i=0, j=sqlca.sqlerrd[2]; i<j; i++)
+ printf("name[%d]=%6.6s\tamount[%d]=%d\tletter[%d]=%c\n", i, name[i], i, amount[i],i, letter[i][0]);
strcpy(msg, "drop");
exec sql drop table test;
+ exec sql at pm drop table test;
strcpy(msg, "commit");
exec sql commit;
+ exec sql at pm commit;
strcpy(msg, "disconnect");
- exec sql disconnect;
+ exec sql disconnect all;
if (dbgs != NULL)
fclose(dbgs);
diff --git a/src/interfaces/ecpg/test/test2.pgc b/src/interfaces/ecpg/test/test2.pgc
index ed06f179bc4..568add14634 100644
--- a/src/interfaces/ecpg/test/test2.pgc
+++ b/src/interfaces/ecpg/test/test2.pgc
@@ -5,6 +5,9 @@ exec sql include header_test;
exec sql type c is char reference;
typedef char* c;
+exec sql type ind is union { int integer; short smallinteger; };
+typedef union { int integer; short smallinteger; } ind;
+
int
main ()
{
@@ -18,15 +21,17 @@ exec sql begin declare section;
birthinfo ind_birth;
} ind_personal;
int ind_married;
+ ind children;
+ ind ind_children;
char married[9];
c testname="Petra";
- char *query="select name, born, age, married from meskes where name = :var1";
+ char *query="select name, born, age, married, children from meskes where name = :var1";
exec sql end declare section;
exec sql var ind_married is long;
exec sql declare cur cursor for
- select name, born, age, married from meskes;
+ select name, born, age, married, children from meskes;
char msg[128], command[128];
FILE *dbgs;
@@ -38,11 +43,11 @@ exec sql end declare section;
exec sql connect to unix:postgresql://localhost:5432/mm;
strcpy(msg, "create");
- exec sql create table meskes(name char(8), born integer, age smallint, married char(8));
+ exec sql create table meskes(name char(8), born integer, age smallint, married char(8), children integer);
strcpy(msg, "insert");
- exec sql insert into meskes(name, married) values ('Petra', '19900404');
- exec sql insert into meskes(name, born, age, married) values ('Michael', 19660117, 33, '19900404');
+ exec sql insert into meskes(name, married, children) values ('Petra', '19900404', 3);
+ exec sql insert into meskes(name, born, age, married, children) values ('Michael', 19660117, 33, '19900404', 3);
exec sql insert into meskes(name, born, age) values ('Carsten', 19910103, 8);
exec sql insert into meskes(name, born, age) values ('Marc', 19930907, 5);
exec sql insert into meskes(name, born, age) values ('Chris', 19970923, 1);
@@ -57,7 +62,7 @@ exec sql end declare section;
while (1) {
strcpy(msg, "fetch");
- exec sql fetch in cur into :personal:ind_personal, :married:ind_married;
+ exec sql fetch in cur into :personal:ind_personal, :married:ind_married, :children.integer:ind_children.smallinteger;
printf("%8.8s", personal.name.arr);
if (!ind_personal.ind_birth.born)
printf(", born %d", personal.birth.born);
@@ -65,6 +70,8 @@ exec sql end declare section;
printf(", age = %d", personal.birth.age);
if (!ind_married)
printf(", married %s", married);
+ if (!ind_children.smallinteger)
+ printf(", children = %d", children.integer);
putchar('\n');
}
@@ -82,7 +89,7 @@ exec sql end declare section;
while (1) {
strcpy(msg, "fetch");
- exec sql fetch in prep into :personal:ind_personal, :married:ind_married;
+ exec sql fetch in prep into :personal:ind_personal, :married:ind_married, :children.integer:ind_children.smallinteger;
printf("%8.8s", personal.name.arr);
if (!ind_personal.ind_birth.born)
printf(", born %d", personal.birth.born);
@@ -90,6 +97,8 @@ exec sql end declare section;
printf(", age = %d", personal.birth.age);
if (!ind_married)
printf(", married %s", married);
+ if (!ind_children.smallinteger)
+ printf(", children = %d", children.integer);
putchar('\n');
}