aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/ecpg/lib
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1998-02-10 16:44:17 +0000
committerMarc G. Fournier <scrappy@hub.org>1998-02-10 16:44:17 +0000
commit38201e21d0849a469e165085e4d12ac0969f5018 (patch)
treeb9e0e9db026ea6b3838f57025aebbca014f998f4 /src/interfaces/ecpg/lib
parenta8313f9671c621852dbdf16b6f47e19ceda489ea (diff)
downloadpostgresql-38201e21d0849a469e165085e4d12ac0969f5018.tar.gz
postgresql-38201e21d0849a469e165085e4d12ac0969f5018.zip
Erk, the whole directory structure changed on us here...
Diffstat (limited to 'src/interfaces/ecpg/lib')
-rw-r--r--src/interfaces/ecpg/lib/Makefile26
-rw-r--r--src/interfaces/ecpg/lib/Makefile.in25
-rw-r--r--src/interfaces/ecpg/lib/ecpglib.c648
-rw-r--r--src/interfaces/ecpg/lib/typename.c24
4 files changed, 723 insertions, 0 deletions
diff --git a/src/interfaces/ecpg/lib/Makefile b/src/interfaces/ecpg/lib/Makefile
new file mode 100644
index 00000000000..e3722e8aec1
--- /dev/null
+++ b/src/interfaces/ecpg/lib/Makefile
@@ -0,0 +1,26 @@
+# Generated automatically from Makefile.in by configure.
+SRCDIR= ../../..
+include $(SRCDIR)/Makefile.global
+
+PQ_INCLUDE=-I$(SRCDIR)/include -I$(SRCDIR)/interfaces/libpq
+
+all: lib
+
+lib: libecpg.a
+
+clean:
+ rm -f *.o *.a core a.out *~
+
+install: libecpg.a
+ install -m 644 libecpg.a $(LIBDIR)
+
+uninstall::
+ rm -f $(LIBDIR)/libecpg.a
+
+# Rules that do something
+libecpg.a : libecpg.a(ecpglib.o) libecpg.a(typename.o)
+
+ecpglib.o : ecpglib.c ../include/ecpglib.h ../include/ecpgtype.h
+ $(CC) -O2 -g -Wall -I../include $(PQ_INCLUDE) -c ecpglib.c
+typename.o : typename.c ../include/ecpgtype.h
+ $(CC) -g -O2 -Wall -I../include $(PQ_INCLUDE) -c typename.c
diff --git a/src/interfaces/ecpg/lib/Makefile.in b/src/interfaces/ecpg/lib/Makefile.in
new file mode 100644
index 00000000000..7ed351ab7a9
--- /dev/null
+++ b/src/interfaces/ecpg/lib/Makefile.in
@@ -0,0 +1,25 @@
+SRCDIR= ../../..
+include $(SRCDIR)/Makefile.global
+
+PQ_INCLUDE=-I$(SRCDIR)/include -I$(SRCDIR)/interfaces/libpq
+
+all: lib
+
+lib: libecpg.a
+
+clean:
+ rm -f *.o *.a core a.out *~
+
+install: libecpg.a
+ install -m 644 libecpg.a $(LIBDIR)
+
+uninstall::
+ rm -f $(LIBDIR)/libecpg.a
+
+# Rules that do something
+libecpg.a : libecpg.a(ecpglib.o) libecpg.a(typename.o)
+
+ecpglib.o : ecpglib.c ../include/ecpglib.h ../include/ecpgtype.h
+ $(CC) -O2 -g -Wall -I../include $(PQ_INCLUDE) -c ecpglib.c
+typename.o : typename.c ../include/ecpgtype.h
+ $(CC) -g -O2 -Wall -I../include $(PQ_INCLUDE) -c typename.c
diff --git a/src/interfaces/ecpg/lib/ecpglib.c b/src/interfaces/ecpg/lib/ecpglib.c
new file mode 100644
index 00000000000..80e9b0fd9c4
--- /dev/null
+++ b/src/interfaces/ecpg/lib/ecpglib.c
@@ -0,0 +1,648 @@
+/* Copyright comment */
+/*
+ * The aim is to get a simpler inteface to the database routines.
+ * All the tidieous messing around with tuples is supposed to be hidden
+ * by this function.
+ */
+/* Author: Linus Tolke
+ (actually most if the code is "borrowed" from the distribution and just
+ slightly modified)
+ */
+
+/* Taken over as part of PostgreSQL by Michael Meskes <meskes@debian.org>
+ on Feb. 5th, 1998 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <ecpgtype.h>
+#include <ecpglib.h>
+#include <sqlca.h>
+#include <libpq-fe.h>
+#include <libpq/pqcomm.h>
+
+static PGconn *simple_connection;
+static int simple_debug = 0;
+static FILE *debugstream = NULL;
+static int committed = true;
+
+static void
+register_error(int code, char *fmt,...)
+{
+ va_list args;
+
+ sqlca.sqlcode = code;
+ va_start(args, fmt);
+ vsprintf(sqlca.sqlerrm.sqlerrmc, fmt, args);
+ va_end(args);
+ sqlca.sqlerrm.sqlerrml = strlen(sqlca.sqlerrm.sqlerrmc);
+}
+
+/* This function returns a newly malloced string that has the ' and \
+ in the argument quoted with \.
+ */
+static
+char *
+quote_postgres(char *arg)
+{
+ char *res = (char *) malloc(2 * strlen(arg) + 1);
+ int i,
+ ri;
+
+ for (i = 0, ri = 0; arg[i]; i++, ri++)
+ {
+ switch (arg[i])
+ {
+ case '\'':
+ case '\\':
+ res[ri++] = '\\';
+ default:
+ ;
+ }
+
+ res[ri] = arg[i];
+ }
+ res[ri] = '\0';
+
+ return res;
+}
+
+
+bool
+ECPGdo(int lineno, char *query,...)
+{
+ va_list ap;
+ bool status = false;
+ char *copiedquery;
+ PGresult *results;
+ PGnotify *notify;
+ enum ECPGttype type;
+
+ va_start(ap, query);
+
+ sqlca.sqlcode = 0;
+ copiedquery = strdup(query);
+
+ type = va_arg(ap, enum ECPGttype);
+
+ /*
+ * Now, if the type is one of the fill in types then we take the argument
+ * and enter that in the string at the first %s position. Then if there
+ * are any more fill in types we fill in at the next and so on.
+ */
+ while (type != ECPGt_EOIT)
+ {
+ void *value = NULL;
+ short varcharsize;
+ short size;
+ short arrsize;
+
+ char *newcopy;
+ char *mallocedval = NULL;
+ char *tobeinserted = NULL;
+ char *p;
+ char buff[20];
+
+ /* Some special treatment is needed for records since we want their
+ contents to arrive in a comma-separated list on insert (I think). */
+
+ value = va_arg(ap, void *);
+ varcharsize = va_arg(ap, short);
+ size = va_arg(ap, short);
+ arrsize = va_arg(ap, short);
+
+ switch (type)
+ {
+ case ECPGt_char:
+ case ECPGt_short:
+ case ECPGt_int:
+ sprintf(buff, "%d", *(int *) value);
+ tobeinserted = buff;
+ break;
+
+ case ECPGt_unsigned_char:
+ case ECPGt_unsigned_short:
+ case ECPGt_unsigned_int:
+ sprintf(buff, "%d", *(unsigned int *) value);
+ tobeinserted = buff;
+ break;
+
+ case ECPGt_long:
+ sprintf(buff, "%ld", *(long *) value);
+ tobeinserted = buff;
+ break;
+
+ case ECPGt_unsigned_long:
+ sprintf(buff, "%ld", *(unsigned long *) value);
+ tobeinserted = buff;
+ break;
+
+ case ECPGt_float:
+ sprintf(buff, "%.14g", *(float *) value);
+ tobeinserted = buff;
+ break;
+
+ case ECPGt_double:
+ sprintf(buff, "%.14g", *(double *) value);
+ tobeinserted = buff;
+ break;
+
+ case ECPGt_bool:
+ sprintf(buff, "'%c'", (*(char *) value ? 't' : 'f'));
+ tobeinserted = buff;
+ break;
+
+ case ECPGt_varchar:
+ case ECPGt_varchar2:
+ {
+ struct ECPGgeneric_varchar *var =
+ (struct ECPGgeneric_varchar *) value;
+
+ newcopy = (char *) malloc(var->len + 1);
+ strncpy(newcopy, var->arr, var->len);
+ newcopy[var->len] = '\0';
+
+ mallocedval = (char *) malloc(2 * strlen(newcopy) + 3);
+ strcpy(mallocedval, "'");
+ strcat(mallocedval, quote_postgres(newcopy));
+ strcat(mallocedval, "'");
+
+ free(newcopy);
+
+ tobeinserted = mallocedval;
+ }
+ break;
+
+ default:
+ /* Not implemented yet */
+ register_error(-1, "Unsupported type %s on line %d.",
+ ECPGtype_name(type), lineno);
+ return false;
+ break;
+ }
+
+ /* Now tobeinserted points to an area that is to be inserted at
+ the first %s
+ */
+ newcopy = (char *) malloc(strlen(copiedquery)
+ + strlen(tobeinserted)
+ + 1);
+ strcpy(newcopy, copiedquery);
+ if ((p = strstr(newcopy, ";;")) == NULL)
+ {
+ /* We have an argument but we dont have the matched up string
+ in the string
+ */
+ register_error(-1, "Too many arguments line %d.", lineno);
+ return false;
+ }
+ else
+ {
+ strcpy(p, tobeinserted);
+ /* The strange thing in the second argument is the rest of the
+ string from the old string */
+ strcat(newcopy,
+ copiedquery
+ + (p - newcopy)
+ + 2 /* Length of ;; */ );
+ }
+
+ /* Now everything is safely copied to the newcopy. Lets free the
+ oldcopy and let the copiedquery get the value from the newcopy.
+ */
+ if (mallocedval != NULL)
+ {
+ free(mallocedval);
+ mallocedval = NULL;
+ }
+
+ free(copiedquery);
+ copiedquery = newcopy;
+
+ type = va_arg(ap, enum ECPGttype);
+ }
+
+ /* Check if there are unmatched things left. */
+ if (strstr(copiedquery, ";;") != NULL)
+ {
+ register_error(-1, "Too few arguments line %d.", lineno);
+ return false;
+ }
+
+ /* Now then request is built. */
+
+ if (committed)
+ {
+ if ((results = PQexec(simple_connection, "begin")) == NULL)
+ {
+ register_error(-1, "Error starting transaction line %d.", lineno);
+ return false;
+ }
+ PQclear(results);
+ committed = 0;
+ }
+
+ ECPGlog("ECPGdo line %d: QUERY: %s\n", lineno, copiedquery);
+ results = PQexec(simple_connection, copiedquery);
+ free(copiedquery);
+
+ if (results == NULL)
+ {
+ ECPGlog("ECPGdo line %d: error: %s", lineno,
+ PQerrorMessage(simple_connection));
+ register_error(-1, "Postgres error: %s line %d.",
+ PQerrorMessage(simple_connection), lineno);
+ }
+ else
+ switch (PQresultStatus(results))
+ {
+ int m,
+ n,
+ x;
+
+ case PGRES_TUPLES_OK:
+ /* XXX Cheap Hack. For now, we see only the last group
+ * of tuples. This is clearly not the right
+ * way to do things !!
+ */
+
+ m = PQnfields(results);
+ n = PQntuples(results);
+
+ if (n < 1)
+ {
+ ECPGlog("ECPGdo lineno %d: Incorrect number of matches: %d\n",
+ lineno, n);
+ register_error(1, "Data not found line %d.", lineno);
+ break;
+ }
+
+ if (n > 1)
+ {
+ ECPGlog("ECPGdo line %d: Incorrect number of matches: %d\n",
+ lineno, n);
+ register_error(-1, "To many matches line %d.", lineno);
+ break;
+ }
+
+ status = true;
+
+ for (x = 0; x < m && status; x++)
+ {
+ void *value = NULL;
+ short varcharsize;
+ short size;
+ short arrsize;
+
+ char *pval = PQgetvalue(results, 0, x);
+
+ /*long int * res_int;
+ char ** res_charstar;
+ char * res_char;
+ int res_len; */
+ char *scan_length;
+
+ ECPGlog("ECPGdo line %d: RESULT: %s\n", lineno, pval ? pval : "");
+
+ /* No the pval is a pointer to the value. */
+ /* We will have to decode the value */
+ type = va_arg(ap, enum ECPGttype);
+ value = va_arg(ap, void *);
+ varcharsize = va_arg(ap, short);
+ size = va_arg(ap, short);
+ arrsize = va_arg(ap, short);
+
+ switch (type)
+ {
+ long res;
+ unsigned long ures;
+ double dres;
+
+ case ECPGt_char:
+ case ECPGt_short:
+ case ECPGt_int:
+ case ECPGt_long:
+ if (pval)
+ {
+ res = strtol(pval, &scan_length, 10);
+ if (*scan_length != '\0') /* Garbage left */
+ {
+ register_error(-1, "Not correctly formatted int type: %s line %d.",
+ pval, lineno);
+ status = false;
+ res = 0L;
+ }
+ }
+ else
+ res = 0L;
+
+ /* Again?! Yes */
+ switch (type)
+ {
+ case ECPGt_char:
+ *(char *) value = (char) res;
+ break;
+ case ECPGt_short:
+ *(short *) value = (short) res;
+ break;
+ case ECPGt_int:
+ *(int *) value = (int) res;
+ break;
+ case ECPGt_long:
+ *(long *) value = res;
+ break;
+ default:
+ /* Cannot happen */
+ break;
+ }
+ break;
+
+ case ECPGt_unsigned_char:
+ case ECPGt_unsigned_short:
+ case ECPGt_unsigned_int:
+ case ECPGt_unsigned_long:
+ if (pval)
+ {
+ ures = strtoul(pval, &scan_length, 10);
+ if (*scan_length != '\0') /* Garbage left */
+ {
+ register_error(-1, "Not correctly formatted unsigned type: %s line %d.",
+ pval, lineno);
+ status = false;
+ ures = 0L;
+ }
+ }
+ else
+ ures = 0L;
+
+ /* Again?! Yes */
+ switch (type)
+ {
+ case ECPGt_unsigned_char:
+ *(unsigned char *) value = (unsigned char) ures;
+ break;
+ case ECPGt_unsigned_short:
+ *(unsigned short *) value = (unsigned short) ures;
+ break;
+ case ECPGt_unsigned_int:
+ *(unsigned int *) value = (unsigned int) ures;
+ break;
+ case ECPGt_unsigned_long:
+ *(unsigned long *) value = ures;
+ break;
+ default:
+ /* Cannot happen */
+ break;
+ }
+ break;
+
+
+ case ECPGt_float:
+ case ECPGt_double:
+ if (pval)
+ {
+ dres = strtod(pval, &scan_length);
+ if (*scan_length != '\0') /* Garbage left */
+ {
+ register_error(-1, "Not correctly formatted floating point type: %s line %d.",
+ pval, lineno);
+ status = false;
+ dres = 0.0;
+ }
+ }
+ else
+ dres = 0.0;
+
+ /* Again?! Yes */
+ switch (type)
+ {
+ case ECPGt_float:
+ *(float *) value = dres;
+ break;
+ case ECPGt_double:
+ *(double *) value = dres;
+ break;
+ default:
+ /* Cannot happen */
+ break;
+ }
+ break;
+
+ case ECPGt_bool:
+ if (pval)
+ {
+ if (pval[0] == 'f' && pval[1] == '\0')
+ {
+ *(char *) value = false;
+ break;
+ }
+ else if (pval[0] == 't' && pval[1] == '\0')
+ {
+ *(char *) value = true;
+ break;
+ }
+ }
+
+ register_error(-1, "Unable to convert %s to bool on line %d.",
+ (pval ? pval : "NULL"),
+ lineno);
+ return false;
+ break;
+
+ case ECPGt_varchar:
+ {
+ struct ECPGgeneric_varchar *var =
+ (struct ECPGgeneric_varchar *) value;
+
+ strncpy(var->arr, pval, varcharsize);
+ var->len = strlen(pval);
+ if (var->len > varcharsize)
+ var->len = varcharsize;
+ }
+ break;
+
+ case ECPGt_EORT:
+ ECPGlog("ECPGdo line %d: Too few arguments.\n", lineno);
+ register_error(-1, "Too few arguments line %d.", lineno);
+ status = false;
+ break;
+
+ default:
+ register_error(-1, "Unsupported type %s on line %d.",
+ ECPGtype_name(type), lineno);
+ return false;
+ break;
+ }
+ }
+
+ type = va_arg(ap, enum ECPGttype);
+
+ if (status && type != ECPGt_EORT)
+ {
+ register_error(-1, "Too many arguments line %d.", lineno);
+ return false;
+ }
+
+ PQclear(results);
+ break;
+ case PGRES_EMPTY_QUERY:
+ /* do nothing */
+ register_error(-1, "Empty query line %d.", lineno);
+ break;
+ case PGRES_COMMAND_OK:
+ status = true;
+ ECPGlog("ECPGdo line %d Ok: %s\n", lineno, PQcmdStatus(results));
+ break;
+ case PGRES_NONFATAL_ERROR:
+ case PGRES_FATAL_ERROR:
+ case PGRES_BAD_RESPONSE:
+ ECPGlog("ECPGdo line %d: Error: %s",
+ lineno, PQerrorMessage(simple_connection));
+ register_error(-1, "Error: %s line %d.",
+ PQerrorMessage(simple_connection), lineno);
+ break;
+ case PGRES_COPY_OUT:
+ ECPGlog("ECPGdo line %d: Got PGRES_COPY_OUT ... tossing.\n", lineno);
+ PQendcopy(results->conn);
+ break;
+ case PGRES_COPY_IN:
+ ECPGlog("ECPGdo line %d: Got PGRES_COPY_IN ... tossing.\n", lineno);
+ PQendcopy(results->conn);
+ break;
+ default:
+ ECPGlog("ECPGdo line %d: Got something else, postgres error.\n",
+ lineno);
+ register_error(-1, "Postgres error line %d.", lineno);
+ break;
+ }
+
+ /* check for asynchronous returns */
+ notify = PQnotifies(simple_connection);
+ if (notify)
+ {
+ ECPGlog("ECPGdo line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
+ lineno, notify->relname, notify->be_pid);
+ free(notify);
+ }
+
+ va_end(ap);
+ return status;
+}
+
+
+bool
+ECPGcommit(int lineno)
+{
+ PGresult *res;
+
+ ECPGlog("ECPGcommit line %d\n", lineno);
+ if ((res = PQexec(simple_connection, "end")) == NULL)
+ {
+ register_error(-1, "Error committing line %d.", lineno);
+ return (FALSE);
+ }
+ PQclear(res);
+ committed = 1;
+ return (TRUE);
+}
+
+bool
+ECPGrollback(int lineno)
+{
+ PGresult *res;
+
+ ECPGlog("ECPGrollback line %d\n", lineno);
+ if ((res = PQexec(simple_connection, "abort")) == NULL)
+ {
+ register_error(-1, "Error rolling back line %d.", lineno);
+ return (FALSE);
+ }
+ PQclear(res);
+ committed = 1;
+ return (TRUE);
+}
+
+
+
+bool
+ECPGsetdb(PGconn *newcon)
+{
+ ECPGfinish();
+ simple_connection = newcon;
+ return true;
+}
+
+bool
+ECPGconnect(const char *dbname)
+{
+ char *name = strdup(dbname);
+
+ ECPGlog("ECPGconnect: opening database %s\n", name);
+
+ sqlca.sqlcode = 0;
+
+ ECPGsetdb(PQsetdb(NULL, NULL, NULL, NULL, name));
+
+ free(name);
+ name = NULL;
+
+ if (PQstatus(simple_connection) == CONNECTION_BAD)
+ {
+ ECPGfinish();
+ ECPGlog("ECPGconnect: could not open database %s\n", dbname);
+ register_error(-1, "ECPGconnect: could not open database %s.", dbname);
+ return false;
+ }
+ return true;
+}
+
+
+bool
+ECPGstatus()
+{
+ return PQstatus(simple_connection) != CONNECTION_BAD;
+}
+
+
+bool
+ECPGfinish()
+{
+ if (simple_connection != NULL)
+ {
+ ECPGlog("ECPGfinish: finishing.\n");
+ PQfinish(simple_connection);
+ }
+ else
+ ECPGlog("ECPGfinish: called an extra time.\n");
+ return true;
+}
+
+void
+ECPGdebug(int n, FILE *dbgs)
+{
+ simple_debug = n;
+ debugstream = dbgs;
+ ECPGlog("ECPGdebug: set to %d\n", simple_debug);
+}
+
+void
+ECPGlog(const char *format,...)
+{
+ va_list ap;
+
+ if (simple_debug)
+ {
+ char *f = (char *) malloc(strlen(format) + 100);
+
+ sprintf(f, "[%d]: %s", getpid(), format);
+
+ va_start(ap, format);
+ vfprintf(debugstream, f, ap);
+ va_end(ap);
+
+ free(f);
+ }
+}
diff --git a/src/interfaces/ecpg/lib/typename.c b/src/interfaces/ecpg/lib/typename.c
new file mode 100644
index 00000000000..55756037b30
--- /dev/null
+++ b/src/interfaces/ecpg/lib/typename.c
@@ -0,0 +1,24 @@
+#include <ecpgtype.h>
+/*
+ * This function is used to generate the correct type names.
+ */
+const char *
+ECPGtype_name(enum ECPGttype typ)
+{
+ switch (typ)
+ {
+ case ECPGt_char: return "char";
+ case ECPGt_unsigned_char: return "unsigned char";
+ case ECPGt_short: return "short";
+ case ECPGt_unsigned_short: return "unsigned short";
+ case ECPGt_int: return "int";
+ case ECPGt_unsigned_int: return "unsigned int";
+ case ECPGt_long: return "long";
+ case ECPGt_unsigned_long: return "unsigned long";
+ case ECPGt_float: return "float";
+ case ECPGt_double: return "double";
+ case ECPGt_bool: return "bool";
+ default:
+ abort();
+ }
+}