Commit 35ba9de2 authored by Michael Meskes's avatar Michael Meskes

*** empty log message ***

parent 988d53e5
......@@ -809,5 +809,10 @@ Tue Feb 15 17:39:19 CET 2000
Wed Feb 16 11:57:02 CET 2000
- Fixed library to be able to input complete arrays.
Wed Feb 16 17:04:41 CET 2000
- Apply patch by Christof Petig <christof.petig@wtal.de> that adds
descriptors.
- Set library version to 3.1.0.
- Set ecpg version to 2.7.0.
descriptor statements have the following shortcomings
- up to now the only reasonable statement is
FETCH ... INTO SQL DESCRIPTOR <name>
no input variables allowed!
Reason: to fully support dynamic SQL the frontend/backend communication
should change to recognize input parameters.
Since this is not likely to happen in the near future and you
can cover the same functionality with the existing infrastructure
I'll leave the work to someone else.
- string buffer overflow does not always generate warnings
(beware: terminating 0 may be missing because strncpy is used)
:var=data sets sqlwarn accordingly (but not indicator)
- char variables pointing to NULL are not allocated on demand
- string truncation does not show up in indicator
......@@ -18,8 +18,6 @@ cvariable for an array var
How can one insert arrays from c variables?
support for dynamic SQL with unknown number of variables with DESCRIPTORS
What happens to the output variable during read if there was an
indicator-error?
......
......@@ -10,11 +10,13 @@ install::
$(INSTALL) $(INSTLOPTS) ecpglib.h $(HEADERDIR)
$(INSTALL) $(INSTLOPTS) ecpgtype.h $(HEADERDIR)
$(INSTALL) $(INSTLOPTS) sqlca.h $(HEADERDIR)
$(INSTALL) $(INSTLOPTS) sql3types.h $(HEADERDIR)
uninstall::
rm -f $(HEADERDIR)/ecpgerrno.h
rm -f $(HEADERDIR)/ecpglib.h
rm -f $(HEADERDIR)/ecpgtype.h
rm -f $(HEADERDIR)/sqlca.h
rm -f $(HEADERDIR)/sql3types.h
dep depend:
......@@ -29,6 +29,10 @@
#define ECPG_INVALID_STMT -230
/* dynamic SQL related */
#define ECPG_UNKNOWN_DESCRIPTOR -240
#define ECPG_INVALID_DESCRIPTOR_INDEX -241
/* finally the backend error messages, they start at 400 */
#define ECPG_PGSQL -400
#define ECPG_TRANS -401
......
#include <postgres.h>
#include <libpq-fe.h>
#ifdef __cplusplus
extern "C"
......@@ -49,6 +50,17 @@ extern "C"
#define SQLCODE sqlca.sqlcode
/* dynamic SQL */
unsigned int ECPGDynamicType(Oid type);
unsigned int ECPGDynamicType_DDT(Oid type);
PGresult * ECPGresultByDescriptor(int line,const char *name);
bool ECPGdo_descriptor(int line,const char *connection,
const char *descriptor,const char *query);
bool ECPGdeallocate_desc(int line,const char *name);
bool ECPGallocate_desc(int line,const char *name);
void ECPGraise(int line,int code);
#ifdef __cplusplus
}
......
/* SQL3 dynamic type codes
*
* Copyright (c) 2000, Christof Petig <christof.petig@wtal.de>
*
* $Header: /cvsroot/pgsql/src/interfaces/ecpg/include/sql3types.h,v 1.1 2000/02/16 16:18:03 meskes Exp $
*/
/* chapter 13.1 table 2: Codes used for SQL data types in Dynamic SQL */
enum { SQL3_CHARACTER=1,
SQL3_NUMERIC,
SQL3_DECIMAL,
SQL3_INTEGER,
SQL3_SMALLINT,
SQL3_FLOAT,
SQL3_REAL,
SQL3_DOUBLE_PRECISION,
SQL3_DATE_TIME_TIMESTAMP,
SQL3_INTERVAL, //10
SQL3_CHARACTER_VARYING=12,
SQL3_ENUMERATED,
SQL3_BIT,
SQL3_BIT_VARYING,
SQL3_BOOLEAN,
SQL3_abstract
// the rest is xLOB stuff
};
/* chapter 13.1 table 3: Codes associated with datetime data types in Dynamic SQL */
enum { SQL3_DDT_DATE=1,
SQL3_DDT_TIME,
SQL3_DDT_TIMESTAMP,
SQL3_DDT_TIME_WITH_TIME_ZONE,
SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE,
SQL3_DDT_ILLEGAL /* not a datetime data type (not part of standard) */
};
......@@ -6,7 +6,7 @@
# Copyright (c) 1994, Regents of the University of California
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile.in,v 1.57 2000/02/16 11:52:24 meskes Exp $
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile.in,v 1.58 2000/02/16 16:18:05 meskes Exp $
#
#-------------------------------------------------------------------------
......@@ -36,7 +36,7 @@ include $(SRCDIR)/Makefile.shlib
install: install-lib $(install-shlib-dep)
# Handmade dependencies in case make depend not done
ecpglib.o : ecpglib.c ../include/ecpglib.h ../include/ecpgtype.h
ecpglib.o : ecpglib.c ../include/ecpglib.h ../include/ecpgtype.h dynamic.c
typename.o : typename.c ../include/ecpgtype.h
......
/* dynamic SQL support routines
*
* Copyright (c) 2000, Christof Petig <christof.petig@wtal.de>
*
* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/dynamic.c,v 1.1 2000/02/16 16:18:12 meskes Exp $
*/
/* I borrowed the include files from ecpglib.c, maybe we don't need all of them */
#if 0
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <locale.h>
#include <libpq-fe.h>
#include <libpq/pqcomm.h>
#include <ecpgtype.h>
#include <ecpglib.h>
#include <sqlca.h>
#endif
#include <sql3types.h>
static struct descriptor
{ char *name;
PGresult *result;
struct descriptor *next;
} *all_descriptors=NULL;
PGconn *ECPG_internal_get_connection(char *name);
unsigned int ECPGDynamicType(Oid type)
{ switch(type)
{ case 16: return SQL3_BOOLEAN; /* bool */
case 21: return SQL3_SMALLINT; /* int2 */
case 23: return SQL3_INTEGER; /* int4 */
case 25: return SQL3_CHARACTER; /* text */
case 700: return SQL3_REAL; /* float4 */
case 701: return SQL3_DOUBLE_PRECISION; /* float8 */
case 1042: return SQL3_CHARACTER; /* bpchar */
case 1043: return SQL3_CHARACTER_VARYING; /* varchar */
case 1082: return SQL3_DATE_TIME_TIMESTAMP; /* date */
case 1083: return SQL3_DATE_TIME_TIMESTAMP; /* time */
case 1184: return SQL3_DATE_TIME_TIMESTAMP; /* datetime */
case 1296: return SQL3_DATE_TIME_TIMESTAMP; /* timestamp */
case 1700: return SQL3_NUMERIC; /* numeric */
default:
return -type;
}
}
unsigned int ECPGDynamicType_DDT(Oid type)
{ switch(type)
{
case 1082: return SQL3_DDT_DATE; /* date */
case 1083: return SQL3_DDT_TIME; /* time */
case 1184: return SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE; /* datetime */
case 1296: return SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE; /* timestamp */
default:
return SQL3_DDT_ILLEGAL;
}
}
// like ECPGexecute
static bool execute_descriptor(int lineno,const char *query
,struct connection *con,PGresult **resultptr)
{
bool status = false;
PGresult *results;
PGnotify *notify;
/* Now the request is built. */
if (con->committed && !con->autocommit)
{
if ((results = PQexec(con->connection, "begin transaction")) == NULL)
{
register_error(ECPG_TRANS, "Error in transaction processing line %d.", lineno);
return false;
}
PQclear(results);
con->committed = false;
}
ECPGlog("execute_descriptor line %d: QUERY: %s on connection %s\n", lineno, query, con->name);
results = PQexec(con->connection, query);
if (results == NULL)
{
ECPGlog("ECPGexecute line %d: error: %s", lineno,
PQerrorMessage(con->connection));
register_error(ECPG_PGSQL, "Postgres error: %s line %d.",
PQerrorMessage(con->connection), lineno);
}
else
{ *resultptr=results;
switch (PQresultStatus(results))
{ int ntuples;
case PGRES_TUPLES_OK:
status = true;
sqlca.sqlerrd[2] = ntuples = PQntuples(results);
if (ntuples < 1)
{
ECPGlog("execute_descriptor line %d: Incorrect number of matches: %d\n",
lineno, ntuples);
register_error(ECPG_NOT_FOUND, "No data found line %d.", lineno);
status = false;
break;
}
break;
#if 1 /* strictly these are not needed (yet) */
case PGRES_EMPTY_QUERY:
/* do nothing */
register_error(ECPG_EMPTY, "Empty query line %d.", lineno);
break;
case PGRES_COMMAND_OK:
status = true;
sqlca.sqlerrd[1] = atol(PQoidStatus(results));
sqlca.sqlerrd[2] = atol(PQcmdTuples(results));
ECPGlog("ECPGexecute line %d Ok: %s\n", lineno, PQcmdStatus(results));
break;
case PGRES_COPY_OUT:
ECPGlog("ECPGexecute line %d: Got PGRES_COPY_OUT ... tossing.\n", lineno);
PQendcopy(con->connection);
break;
case PGRES_COPY_IN:
ECPGlog("ECPGexecute line %d: Got PGRES_COPY_IN ... tossing.\n", lineno);
PQendcopy(con->connection);
break;
#else
case PGRES_EMPTY_QUERY:
case PGRES_COMMAND_OK:
case PGRES_COPY_OUT:
case PGRES_COPY_IN:
break;
#endif
case PGRES_NONFATAL_ERROR:
case PGRES_FATAL_ERROR:
case PGRES_BAD_RESPONSE:
ECPGlog("ECPGexecute line %d: Error: %s",
lineno, PQerrorMessage(con->connection));
register_error(ECPG_PGSQL, "Postgres error: %s line %d.",
PQerrorMessage(con->connection), lineno);
status = false;
break;
default:
ECPGlog("ECPGexecute line %d: Got something else, postgres error.\n",
lineno);
register_error(ECPG_PGSQL, "Postgres error: %s line %d.",
PQerrorMessage(con->connection), lineno);
status = false;
break;
}
}
/* check for asynchronous returns */
notify = PQnotifies(con->connection);
if (notify)
{
ECPGlog("ECPGexecute line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
lineno, notify->relname, notify->be_pid);
free(notify);
}
return status;
}
/* like ECPGdo */
static bool do_descriptor2(int lineno,const char *connection_name,
PGresult **resultptr, const char *query)
{
struct connection *con = get_connection(connection_name);
bool status=true;
char *locale = setlocale(LC_NUMERIC, NULL);
/* Make sure we do NOT honor the locale for numeric input/output */
/* since the database wants teh standard decimal point */
setlocale(LC_NUMERIC, "C");
if (!ecpg_init(con, connection_name, lineno))
{ setlocale(LC_NUMERIC, locale);
return(false);
}
/* are we connected? */
if (con == NULL || con->connection == NULL)
{
ECPGlog("ECPGdo: not connected to %s\n", con->name);
register_error(ECPG_NOT_CONN, "Not connected in line %d.", lineno);
setlocale(LC_NUMERIC, locale);
return false;
}
status = execute_descriptor(lineno,query,con,resultptr);
/* and reset locale value so our application is not affected */
setlocale(LC_NUMERIC, locale);
return (status);
}
bool ECPGdo_descriptor(int line,const char *connection,
const char *descriptor,const char *query)
{
struct descriptor *i;
for (i=all_descriptors;i!=NULL;i=i->next)
{ if (!strcmp(descriptor,i->name))
{
bool status;
/* free previous result */
if (i->result) PQclear(i->result);
i->result=NULL;
status=do_descriptor2(line,connection,&i->result,query);
if (!i->result) PQmakeEmptyPGresult(NULL, 0);
return (status);
}
}
ECPGraise(line,ECPG_UNKNOWN_DESCRIPTOR);
return false;
}
PGresult *ECPGresultByDescriptor(int line,const char *name)
{
struct descriptor *i;
for (i=all_descriptors;i!=NULL;i=i->next)
{ if (!strcmp(name,i->name)) return i->result;
}
ECPGraise(line,ECPG_UNKNOWN_DESCRIPTOR);
return 0;
}
bool ECPGdeallocate_desc(int line,const char *name)
{
struct descriptor *i;
struct descriptor **lastptr=&all_descriptors;
for (i=all_descriptors;i;lastptr=&i->next,i=i->next)
{ if (!strcmp(name,i->name))
{ *lastptr=i->next;
free(i->name);
PQclear(i->result);
free(i);
return true;
}
}
ECPGraise(line,ECPG_UNKNOWN_DESCRIPTOR);
return false;
}
bool ECPGallocate_desc(int line,const char *name)
{
struct descriptor *new=(struct descriptor *)malloc(sizeof(struct descriptor));
new->next=all_descriptors;
new->name=malloc(strlen(name)+1);
new->result=PQmakeEmptyPGresult(NULL, 0);
strcpy(new->name,name);
all_descriptors=new;
return true;
}
void ECPGraise(int line,int code)
{ sqlca.sqlcode=code;
switch (code)
{ case ECPG_NOT_FOUND:
snprintf(sqlca.sqlerrm.sqlerrmc,sizeof(sqlca.sqlerrm.sqlerrmc),
"No data found line %d.",line);
break;
case ECPG_MISSING_INDICATOR:
snprintf(sqlca.sqlerrm.sqlerrmc,sizeof(sqlca.sqlerrm.sqlerrmc),
"NULL value without indicator, line %d.",line);
break;
case ECPG_UNKNOWN_DESCRIPTOR:
snprintf(sqlca.sqlerrm.sqlerrmc,sizeof(sqlca.sqlerrm.sqlerrmc),
"descriptor not found, line %d.",line);
break;
case ECPG_INVALID_DESCRIPTOR_INDEX:
snprintf(sqlca.sqlerrm.sqlerrmc,sizeof(sqlca.sqlerrm.sqlerrmc),
"descriptor index out of range, line %d.",line);
break;
default:
snprintf(sqlca.sqlerrm.sqlerrmc,sizeof(sqlca.sqlerrm.sqlerrmc),
"SQL error #%d, line %d.",code,line);
break;
}
}
......@@ -20,7 +20,6 @@
#include <ctype.h>
#include <locale.h>
#include <libpq-fe.h>
#include <libpq/pqcomm.h>
#include <ecpgtype.h>
#include <ecpglib.h>
......@@ -753,7 +752,7 @@ ECPGexecute(struct statement * stmt)
{
char *pval;
char *scan_length;
char *array_query;
char *array_query;
if (var == NULL)
{
......@@ -1127,36 +1126,44 @@ ECPGexecute(struct statement * stmt)
bool
ECPGdo(int lineno, const char *connection_name, char *query,...)
{
va_list args;
struct statement *stmt;
struct connection *con = get_connection(connection_name);
bool status;
char *locale = setlocale(LC_NUMERIC, NULL);
va_list args;
struct statement *stmt;
struct connection *con = get_connection(connection_name);
bool status=true;
char *locale = setlocale(LC_NUMERIC, NULL);
/* Make sure we do NOT honor the locale for numeric input/output */
/* since the database wants teh standard decimal point */
setlocale(LC_NUMERIC, "C");
if (!ecpg_init(con, connection_name, lineno))
{
setlocale(LC_NUMERIC, locale);
return(false);
}
va_start(args, query);
if (create_statement(lineno, con, &stmt, query, args) == false)
{
setlocale(LC_NUMERIC, locale);
return (false);
}
va_end(args);
/* are we connected? */
if (con == NULL || con->connection == NULL)
{
free_statement(stmt);
ECPGlog("ECPGdo: not connected to %s\n", con->name);
register_error(ECPG_NOT_CONN, "Not connected in line %d.", lineno);
setlocale(LC_NUMERIC, locale);
return false;
}
status = ECPGexecute(stmt);
free_statement(stmt);
/* and reser value so our application is not affected */
/* and reset locale value so our application is not affected */
setlocale(LC_NUMERIC, locale);
return (status);
}
......@@ -1508,3 +1515,5 @@ ECPGprepared_statement(char *name)
for (this = prep_stmts; this != NULL && strcmp(this->name, name) != 0; this = this->next);
return (this) ? this->stmt->command : NULL;
}
#include "dynamic.c"
......@@ -19,6 +19,7 @@
*/
static ScanKeyword ScanKeywords[] = {
/* name value */
{"allocate", SQL_ALLOCATE},
{"at", SQL_AT},
{"autocommit", SQL_AUTOCOMMIT},
{"bool", SQL_BOOL},
......@@ -28,10 +29,12 @@ static ScanKeyword ScanKeywords[] = {
{"connection", SQL_CONNECTION},
{"continue", SQL_CONTINUE},
{"deallocate", SQL_DEALLOCATE},
{"descriptor", SQL_DESCRIPTOR},
{"disconnect", SQL_DISCONNECT},
{"enum", SQL_ENUM},
{"found", SQL_FOUND},
{"free", SQL_FREE},
{"get", SQL_GET},
{"go", SQL_GO},
{"goto", SQL_GOTO},
{"identified", SQL_IDENTIFIED},
......@@ -46,12 +49,14 @@ static ScanKeyword ScanKeywords[] = {
{"section", SQL_SECTION},
{"short", SQL_SHORT},
{"signed", SQL_SIGNED},
{"sql",SQL_SQL}, // strange thing, used for into sql descriptor MYDESC;
{"sqlerror", SQL_SQLERROR},
{"sqlprint", SQL_SQLPRINT},
{"sqlwarning", SQL_SQLWARNING},
{"stop", SQL_STOP},
{"struct", SQL_STRUCT},
{"unsigned", SQL_UNSIGNED},
{"value", SQL_VALUE},
{"var", SQL_VAR},
{"whenever", SQL_WHENEVER},
};
......
......@@ -29,6 +29,7 @@ extern struct arguments *argsinsert;
extern struct arguments *argsresult;
extern struct when when_error, when_nf, when_warn;
extern struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH];
extern struct descriptor *descriptors;
/* functions */
......
This diff is collapsed.
......@@ -139,4 +139,18 @@ struct arguments
struct arguments *next;
};
struct descriptor
{
char *name;
char *connection;
struct descriptor *next;
};
struct assignment
{
char *variable;
char *value;
struct assignment *next;
};
enum errortype {ET_WARN, ET_ERROR, ET_FATAL};
all: stp.so test1 test2 test3 test4 test5 perftest
all: stp.so test1 test2 test3 test4 test5 perftest dyntest
#LDFLAGS=-g -I /usr/local/pgsql/include -L/usr/local/pgsql/lib -lecpg -lpq -lcrypt
#LDFLAGS=-g -I../include -I/usr/include/postgresql -L/usr/lib/postgresql -L../lib -lecpg -lpq -lcrypt
LDFLAGS=-g -I/usr/include/postgresql -lecpg -lpq -lcrypt
LDFLAGS=-g -I../include -I/usr/include/postgresql -L/usr/lib/postgresql -L../lib -lecpg -lpq -lcrypt
#LDFLAGS=-g -I/usr/include/postgresql -lecpg -lpq -lcrypt
#ECPG=/usr/local/pgsql/bin/ecpg
ECPG=../preproc/ecpg -I../include
......@@ -16,6 +16,7 @@ test3: test3.c
test4: test4.c
test5: test5.c
perftest: perftest.c
dyntest: dyntest.c
.pgc.c:
$(ECPG) $?
......
/* dynamic SQL test program
*
* Copyright (c) 2000, Christof Petig <christof.petig@wtal.de>
*
* $Header: /cvsroot/pgsql/src/interfaces/ecpg/test/Attic/dyntest.pgc,v 1.1 2000/02/16 16:18:29 meskes Exp $
*/
#include <stdio.h>
exec sql include sql3types;
exec sql include sqlca;
void error()
{ printf("#%d:%s\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
exit(1);
}
int main(int argc,char **argv)
{ exec sql begin declare section;
int COUNT;
int INTVAR;
int INDEX;
int INDICATOR;
int TYPE,LENGTH,OCTET_LENGTH,PRECISION,SCALE,NULLABLE,RETURNED_OCTET_LENGTH;
int DATETIME_INTERVAL_CODE;
char NAME[120];
char STRINGVAR[1024];
float FLOATVAR;
double DOUBLEVAR;
char QUERY[1024];
exec sql end declare section;
int done=0;
snprintf(QUERY,sizeof QUERY,"select * from %s",argc>1?argv[1]:"pg_tables");
exec sql whenever sqlerror do error();
exec sql allocate descriptor MYDESC;
exec sql connect to test;
exec sql prepare MYQUERY from :QUERY;
exec sql declare MYCURS cursor for MYQUERY;
exec sql open MYCURS;
while (1)
{ exec sql fetch in MYCURS into sql descriptor MYDESC;
if (sqlca.sqlcode) break;
exec sql get descriptor MYDESC :COUNT = count;
if (!done)
{ printf("Count %d\n",COUNT);
done=1;
}
for (INDEX=1;INDEX<=COUNT;++INDEX)
{ exec sql get descriptor MYDESC value :INDEX
:TYPE = type,
:LENGTH = length, :OCTET_LENGTH=octet_length,
:RETURNED_OCTET_LENGTH=returned_octet_length,
:PRECISION = precision, :SCALE=scale,
:NULLABLE=nullable, :NAME=name,
:INDICATOR=indicator;
printf("%2d %s %d(%d)(%d,%d) %d,%d %d = "
,INDEX,NAME,TYPE,LENGTH,PRECISION,SCALE
,OCTET_LENGTH,RETURNED_OCTET_LENGTH,NULLABLE);
if (INDICATOR==-1) printf("NULL\n");
else switch (TYPE)
{ case SQL3_BOOLEAN:
exec sql get descriptor MYDESC value :INDEX :INTVAR=data;
printf("%s\n",INTVAR?"true":"false");
break;
case SQL3_NUMERIC:
case SQL3_DECIMAL:
if (SCALE==0)
{ exec sql get descriptor MYDESC value :INDEX :INTVAR=data;
printf("%d\n",INTVAR);
}
else
{ exec sql get descriptor MYDESC value :INDEX :FLOATVAR=data;
printf("%.*f\n",SCALE,FLOATVAR);
}
break;
case SQL3_INTEGER:
case SQL3_SMALLINT:
exec sql get descriptor MYDESC value :INDEX :INTVAR=data;
printf("%d\n",INTVAR);
break;
case SQL3_FLOAT:
case SQL3_REAL:
exec sql get descriptor MYDESC value :INDEX :FLOATVAR=data;
printf("%.*f\n",PRECISION,FLOATVAR);
break;
case SQL3_DOUBLE_PRECISION:
exec sql get descriptor MYDESC value :INDEX :DOUBLEVAR=data;
printf("%.*f\n",PRECISION,DOUBLEVAR);
break;
case SQL3_DATE_TIME_TIMESTAMP:
exec sql get descriptor MYDESC value :INDEX
:DATETIME_INTERVAL_CODE=datetime_interval_code,
:STRINGVAR=data;
printf("%d \"%s\"\n",DATETIME_INTERVAL_CODE,STRINGVAR);
break;
case SQL3_INTERVAL:
exec sql get descriptor MYDESC value :INDEX :STRINGVAR=data;
printf("\"%s\"\n",STRINGVAR);
break;
case SQL3_CHARACTER:
case SQL3_CHARACTER_VARYING:
exec sql get descriptor MYDESC value :INDEX :STRINGVAR=data;
printf("\"%s\"\n",STRINGVAR);
break;
default:
exec sql get descriptor MYDESC value :INDEX :STRINGVAR=data;
printf("<\"%s\">\n",STRINGVAR);
break;
}
}
}
exec sql close MYCURS;
exec sql deallocate descriptor MYDESC;
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment