diff options
author | Marc G. Fournier <scrappy@hub.org> | 1999-02-20 07:01:08 +0000 |
---|---|---|
committer | Marc G. Fournier <scrappy@hub.org> | 1999-02-20 07:01:08 +0000 |
commit | bf6636baa69cd343c12b27df87f23809c1ce04c1 (patch) | |
tree | ae14fe2336482a9223bd334a337edfce2c7875a4 /src/interfaces/ecpg/lib/ecpglib.c | |
parent | 3eb22085b578bc112a824efae2402545ce93d991 (diff) | |
download | postgresql-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.c | 214 |
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; +} + |