- 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
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
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 *);
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)
# 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
#include <unistd.h>
#include <stdarg.h>
#include <string.h>
+#include <ctype.h>
#include <libpq-fe.h>
#include <libpq/pqcomm.h>
{
int lineno;
char *command;
+ struct connection *connection;
struct variable *inlist;
struct variable *outlist;
};
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)
{
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;
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;
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;
return false;
(*stmt)->command = query;
+ (*stmt)->connection = connection;
(*stmt)->lineno = lineno;
list = &((*stmt)->inlist);
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");
/* 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
{
status = false;
break;
}
+
for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
{
pval = PQgetvalue(results, act_tuple, act_field);
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",
}
/* 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",
}
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;
}
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;
{
struct prepared_statement *this;
- actual_connection->committed = true;
+ con->committed = true;
/* deallocate all prepared statements */
for (this = prep_stmts; this != NULL; this = this->next)
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;
{
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;)
{
}
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);
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)
{
if (!string && *ptr == ':')
{
ptr[0] = ptr[1] = ';';
- for (ptr += 2; *ptr && *ptr != ' '; ptr++)
+ for (ptr += 2; *ptr && isvarchar(*ptr); ptr++)
*ptr = ' ';
}
}
{
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)
/* create statement */
stmt->lineno = lineno;
+ stmt->connection = NULL;
stmt->command = ecpg_strdup(variable, lineno);
stmt->inlist = stmt->outlist = NULL;
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) \
{"signed", S_SIGNED},
{"static", S_STATIC},
{"struct", S_STRUCT},
+ {"union", S_UNION},
{"unsigned", S_UNSIGNED},
{"varchar", S_VARCHAR},
};
struct arguments *l1, *l2;
free(ptr->command);
+ free(ptr->connection);
free(ptr->name);
for (l1 = ptr->argsinsert; l1; l1 = l2)
{
*/
static ScanKeyword ScanKeywords[] = {
/* name value */
+ {"at", SQL_AT},
{"bool", SQL_BOOL},
{"break", SQL_BREAK},
{"call", SQL_CALL},
extern int braces_open,
no_auto_trans, struct_level;
-extern char *yytext;
+extern char *yytext, errortext[128];
extern int yylineno,
yyleng;
extern FILE *yyin,
xqstop {quote}
xqdouble {quote}{quote}
xqinside [^\\']*
-xqembedded "\\'"
xqliteral [\\](.|\n)
xqcat {quote}{space}*\n{space}*{quote}
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;
* 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];
{
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++)
fputs("ECPGt_EORT);", yyout);
whenever_action(mode);
free(stmt);
+ if (connection != NULL)
+ free(connection);
}
static struct typedefs *
}
/* 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
/* 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
%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
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); }
}
| 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);
}
| 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);
free($1);
}
| ECPGDeallocate {
+ if (connection)
+ yyerror("no at option for connect statement.\n");
+
fputs($1, yyout);
whenever_action(0);
free($1);
free($1);
}
| ECPGDisconnect {
+ if (connection)
+ yyerror("no at option for disconnect statement.\n");
+
fprintf(yyout, "ECPGdisconnect(__LINE__, \"%s\");", $1);
whenever_action(0);
free($1);
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);
}
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);
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);
/* 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;
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"); }
| 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"); }
/* 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;
$$ = 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; }
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);
$$.type_index = -1;
$$.type_dimension = -1;
}
- | SQL_STRUCT
+ | sql_struct_or_union
{
struct_member_list[struct_level++] = NULL;
if (struct_level >= STRUCT_DEPTH)
} '{' 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;
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 */
| 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(); }
return ("ECPGt_char_variable");
break;
default:
- abort();
+ sprintf(errortext, "illegal variable type %d\n", typ);
+ yyerror(errortext);
}
}
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. */
free(typ->u.members);
}
else
- abort();
+ {
+ sprintf(errortext, "illegal variable type %d\n", typ);
+ yyerror(errortext);
+ }
}
else if (typ->typ == ECPGt_struct)
{
free(typ->u.members);
}
else
- abort();
+ {
+ sprintf(errortext, "illegal variable type %d\n", typ);
+ yyerror(errortext);
+ }
}
free(typ);
}
{
char *name;
char *command;
+ char *connection;
struct arguments *argsinsert;
struct arguments *argsresult;
struct cursor *next;
/usr/local/pgsql/bin/ecpg $?
clean:
- /bin/rm test1 test2 perftest *.c log
+ -/bin/rm test1 test2 perftest *.c log
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);
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");
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);
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 ()
{
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;
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);
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);
printf(", age = %d", personal.birth.age);
if (!ind_married)
printf(", married %s", married);
+ if (!ind_children.smallinteger)
+ printf(", children = %d", children.integer);
putchar('\n');
}
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);
printf(", age = %d", personal.birth.age);
if (!ind_married)
printf(", married %s", married);
+ if (!ind_children.smallinteger)
+ printf(", children = %d", children.integer);
putchar('\n');
}