aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/ecpg/lib/ecpglib.c
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1999-02-20 07:01:08 +0000
committerMarc G. Fournier <scrappy@hub.org>1999-02-20 07:01:08 +0000
commitbf6636baa69cd343c12b27df87f23809c1ce04c1 (patch)
treeae14fe2336482a9223bd334a337edfce2c7875a4 /src/interfaces/ecpg/lib/ecpglib.c
parent3eb22085b578bc112a824efae2402545ce93d991 (diff)
downloadpostgresql-bf6636baa69cd343c12b27df87f23809c1ce04c1.tar.gz
postgresql-bf6636baa69cd343c12b27df87f23809c1ce04c1.zip
From: Michael Meskes <Michael_Meskes@topmail.de>
See Changes file...
Diffstat (limited to 'src/interfaces/ecpg/lib/ecpglib.c')
-rw-r--r--src/interfaces/ecpg/lib/ecpglib.c214
1 files changed, 210 insertions, 4 deletions
diff --git a/src/interfaces/ecpg/lib/ecpglib.c b/src/interfaces/ecpg/lib/ecpglib.c
index 62769941a7c..01fe37298bb 100644
--- a/src/interfaces/ecpg/lib/ecpglib.c
+++ b/src/interfaces/ecpg/lib/ecpglib.c
@@ -75,12 +75,19 @@ struct variable
struct statement
{
- int lineno;
+ int lineno;
char *command;
struct variable *inlist;
struct variable *outlist;
};
+struct prepared_statement
+{
+ char *name;
+ struct statement *stmt;
+ struct prepared_statement *next;
+} *prep_stmts = NULL;
+
static int simple_debug = 0;
static FILE *debugstream = NULL;
static int committed = true;
@@ -196,6 +203,41 @@ quote_postgres(char *arg, int lineno)
return res;
}
+/* This function returns a newly malloced string that has the \
+ in the strings inside the argument quoted with another \.
+ */
+static
+char *
+quote_strings(char *arg, int lineno)
+{
+ char *res = (char *) ecpg_alloc(2 * strlen(arg) + 1, lineno);
+ int i,
+ ri;
+ bool string = false;
+
+ if (!res)
+ return (res);
+
+ for (i = 0, ri = 0; arg[i]; i++, ri++)
+ {
+ switch (arg[i])
+ {
+ case '\'':
+ string = string ? false : true;
+ break;
+ case '\\':
+ res[ri++] = '\\';
+ default:
+ ;
+ }
+
+ res[ri] = arg[i];
+ }
+ res[ri] = '\0';
+
+ return res;
+}
+
/* create a list of variables */
static bool
create_statement(int lineno, struct statement ** stmt, char *query, va_list ap)
@@ -236,6 +278,14 @@ 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 (var->value == NULL)
+ {
+ ECPGlog("create_statement: invalid statement name\n");
+ register_error(ECPG_INVALID_STMT, "Invalid statement name in line %d", lineno);
+ free(var);
+ return false;
+ }
for (ptr = *list; ptr && ptr->next; ptr = ptr->next);
@@ -251,6 +301,19 @@ create_statement(int lineno, struct statement ** stmt, char *query, va_list ap)
return (true);
}
+static char *
+next_insert(char *text)
+{
+ char *ptr = text;
+ bool string = false;
+
+ for (; ptr[1] != '\0' && (ptr[0] != ';' || ptr[1] != ';' || string); ptr++)
+ if (ptr[0] == '\'')
+ string = string ? false : true;
+
+ return (ptr[1] == '\0') ? NULL : ptr;
+}
+
static bool
ECPGexecute(struct statement * stmt)
{
@@ -379,7 +442,30 @@ ECPGexecute(struct statement * stmt)
tobeinserted = mallocedval;
}
break;
+ case ECPGt_char_variable:
+ {
+ /* set slen to string length if type is char * */
+ int slen = (var->varcharsize == 0) ? strlen((char *) var->value) : var->varcharsize;
+ char *tmp;
+ if (!(newcopy = ecpg_alloc(slen + 1, stmt->lineno)))
+ return false;
+
+ strncpy(newcopy, (char *) var->value, slen);
+ newcopy[slen] = '\0';
+ if (!(mallocedval = (char *) ecpg_alloc(2 * strlen(newcopy) + 1, stmt->lineno)))
+ return false;
+
+ tmp = quote_strings(newcopy, stmt->lineno);
+ if (!tmp)
+ return false;
+
+ strcat(mallocedval, tmp);
+ free(newcopy);
+
+ tobeinserted = mallocedval;
+ }
+ break;
case ECPGt_varchar:
{
struct ECPGgeneric_varchar *variable =
@@ -428,7 +514,7 @@ ECPGexecute(struct statement * stmt)
return false;
strcpy(newcopy, copiedquery);
- if ((p = strstr(newcopy, ";;")) == NULL)
+ if ((p = next_insert(newcopy)) == NULL)
{
/*
@@ -449,7 +535,7 @@ ECPGexecute(struct statement * stmt)
strcat(newcopy,
copiedquery
+ (p - newcopy)
- + 2 /* Length of ;; */ );
+ + sizeof(";;") - 1 /* don't count the '\0' */);
}
/*
@@ -470,7 +556,7 @@ ECPGexecute(struct statement * stmt)
}
/* Check if there are unmatched things left. */
- if (strstr(copiedquery, ";;") != NULL)
+ if (next_insert(copiedquery) != NULL)
{
register_error(ECPG_TOO_FEW_ARGUMENTS, "Too few arguments line %d.", stmt->lineno);
return false;
@@ -898,7 +984,21 @@ ECPGtrans(int lineno, const char *transaction)
PQclear(res);
}
if (strcmp(transaction, "commit") == 0 || strcmp(transaction, "rollback") == 0)
+ {
+ struct prepared_statement *this;
+
committed = 1;
+
+ /* deallocate all prepared statements */
+ for (this = prep_stmts; this != NULL; this = this->next)
+ {
+ bool b = ECPGdeallocate(lineno, this->name);
+
+ if (!b)
+ return false;
+ }
+ }
+
return TRUE;
}
@@ -1033,3 +1133,109 @@ sqlprint(void)
sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml] = '\0';
printf("sql error %s\n", sqlca.sqlerrm.sqlerrmc);
}
+
+static void
+replace_variables(char *text)
+{
+ char *ptr = text;
+ bool string = false;
+
+ for (; *ptr != '\0'; ptr++)
+ {
+ if (*ptr == '\'')
+ string = string ? false : true;
+
+ if (!string && *ptr == ':')
+ {
+ ptr[0] = ptr[1] = ';';
+ for (ptr += 2; *ptr && *ptr != ' '; ptr++)
+ *ptr = ' ';
+ }
+ }
+}
+
+/* handle the EXEC SQL PREPARE statement */
+bool
+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)
+ {
+ bool b = ECPGdeallocate(lineno, name);
+
+ if (!b)
+ return false;
+ }
+
+ this = (struct prepared_statement *) ecpg_alloc(sizeof(struct prepared_statement), lineno);
+ if (!this)
+ return false;
+
+ stmt = (struct statement *) ecpg_alloc(sizeof(struct statement), lineno);
+ if (!stmt)
+ {
+ free(this);
+ return false;
+ }
+
+ /* create statement */
+ stmt->lineno = lineno;
+ stmt->command = ecpg_strdup(variable, lineno);
+ stmt->inlist = stmt->outlist = NULL;
+
+ /* if we have C variables in our statment replace them with ';;' */
+ replace_variables(stmt->command);
+
+ /* add prepared statement to our list */
+ this->name = ecpg_strdup(name, lineno);
+ this->stmt = stmt;
+
+ if (prep_stmts == NULL)
+ this->next = NULL;
+ else
+ this->next = prep_stmts;
+
+ prep_stmts = this;
+ return true;
+}
+
+/* handle the EXEC SQL DEALLOCATE PREPARE statement */
+bool
+ECPGdeallocate(int lineno, char *name)
+{
+ struct prepared_statement *this, *prev;
+
+ /* check if we really have prepared this statement */
+ for (this = prep_stmts, prev = NULL; this != NULL && strcmp(this->name, name) != 0; prev = this, this = this->next);
+ if (this)
+ {
+ /* okay, free all the resources */
+ free(this->name);
+ free(this->stmt->command);
+ free(this->stmt);
+ if (prev != NULL)
+ prev->next = this->next;
+ else
+ prep_stmts = this->next;
+
+ return true;
+ }
+ ECPGlog("deallocate_prepare: invalid statement name %s\n", name);
+ register_error(ECPG_INVALID_STMT, "Invalid statement name %s in line %d", name, lineno);
+ return false;
+}
+
+/* return the prepared statement */
+char *
+ECPGprepared_statement(char *name)
+{
+ struct prepared_statement *this;
+
+ for (this = prep_stmts; this != NULL && strcmp(this->name, name) != 0; this = this->next);
+ return (this) ? this->stmt->command : NULL;
+}
+