📄 ecpglib.c
字号:
/* 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 <ctype.h>#include <libpq-fe.h>#include <libpq/pqcomm.h>#include <ecpgtype.h>#include <ecpglib.h>#include <sqlca.h>/* variables visible to the programs */static struct sqlca sqlca_init ={ {'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '}, sizeof(struct sqlca), 0, {0, {0}}, {'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}};struct sqlca sqlca ={ {'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '}, sizeof(struct sqlca), 0, {0, {0}}, {'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}};static struct connection{ char *name; PGconn *connection; bool committed; int autocommit; struct connection *next;} *all_connections = NULL, *actual_connection = NULL;struct variable{ enum ECPGttype type; void *value; void *pointer; long varcharsize; long arrsize; long offset; enum ECPGttype ind_type; void *ind_value; long ind_varcharsize; long ind_arrsize; long ind_offset; struct variable *next;};struct statement{ int lineno; char *command; struct connection *connection; struct variable *inlist; struct variable *outlist;};struct prepared_statement{ char *name; struct statement *stmt; struct prepared_statement *next;} *prep_stmts = NULL;struct auto_mem{ void *pointer; struct auto_mem *next;} *auto_allocs = NULL;static int simple_debug = 0;static FILE *debugstream = NULL;static voidregister_error(long code, char *fmt,...){ va_list args; struct auto_mem *am; sqlca.sqlcode = code; va_start(args, fmt); vsprintf(sqlca.sqlerrm.sqlerrmc, fmt, args); va_end(args); sqlca.sqlerrm.sqlerrml = strlen(sqlca.sqlerrm.sqlerrmc); /* free all memory we have allocated for the user */ for (am = auto_allocs; am;) { struct auto_mem *act = am; am = am->next; free(act->pointer); free(act); } auto_allocs = NULL;}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 voidECPGfinish(struct connection * act){ if (act != NULL) { ECPGlog("ECPGfinish: finishing %s.\n", act->name); PQfinish(act->connection); /* remove act from the list */ if (act == all_connections) all_connections = act->next; else { struct connection *con; for (con = all_connections; con->next && con->next != act; con = con->next); if (con->next) con->next = act->next; } if (actual_connection == act) actual_connection = all_connections; free(act->name); free(act); } else ECPGlog("ECPGfinish: called an extra time.\n");}static char *ecpg_alloc(long size, int lineno){ char *new = (char *) calloc(1L, size); if (!new) { ECPGlog("out of memory\n"); register_error(ECPG_OUT_OF_MEMORY, "Out of memory in line %d", lineno); return NULL; } memset(new, '\0', size); return (new);}static char *ecpg_strdup(const char *string, int lineno){ char *new = strdup(string); if (!new) { ECPGlog("out of memory\n"); register_error(ECPG_OUT_OF_MEMORY, "Out of memory in line %d", lineno); return NULL; } return (new);}static voidadd_mem(void *ptr, int lineno){ struct auto_mem *am = (struct auto_mem *) ecpg_alloc(sizeof(struct auto_mem), lineno); am->next = auto_allocs; auto_allocs = am;}/* This function returns a newly malloced string that has the ' and \ in the argument quoted with \. */staticchar *quote_postgres(char *arg, int lineno){ char *res = (char *) ecpg_alloc(2 * strlen(arg) + 1, lineno); int i, ri; if (!res) return (res); 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;}/* * 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 boolcreate_statement(int lineno, struct connection * connection, struct statement ** stmt, char *query, va_list ap){ struct variable **list = &((*stmt)->inlist); enum ECPGttype type; if (!(*stmt = (struct statement *) ecpg_alloc(sizeof(struct statement), lineno))) return false; (*stmt)->command = query; (*stmt)->connection = connection; (*stmt)->lineno = lineno; list = &((*stmt)->inlist); type = va_arg(ap, enum ECPGttype); while (type != ECPGt_EORT) { if (type == ECPGt_EOIT) list = &((*stmt)->outlist); else { struct variable *var, *ptr; if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno))) return false; var->type = type; var->pointer = va_arg(ap, void *); /* if variable is NULL, the statement hasn't been prepared */ if (var->pointer == NULL) { ECPGlog("create_statement: invalid statement name\n"); register_error(ECPG_INVALID_STMT, "Invalid statement name in line %d.", lineno); free(var); return false; } var->varcharsize = va_arg(ap, long); var->arrsize = va_arg(ap, long); var->offset = va_arg(ap, long); if (var->arrsize == 0 || var->varcharsize == 0) var->value = *((void **) (var->pointer)); else var->value = var->pointer; var->ind_type = va_arg(ap, enum ECPGttype); var->ind_value = va_arg(ap, void *); var->ind_varcharsize = va_arg(ap, long); var->ind_arrsize = va_arg(ap, long); var->ind_offset = va_arg(ap, long); var->next = NULL; for (ptr = *list; ptr && ptr->next; ptr = ptr->next); if (ptr == NULL) *list = var; else ptr->next = var; } type = va_arg(ap, enum ECPGttype); } return (true);}static voidfree_variable(struct variable * var){ struct variable *var_next; if (var == (struct variable *) NULL) return; var_next = var->next; free(var); while (var_next) { var = var_next; var_next = var->next; free(var); }}static voidfree_statement(struct statement * stmt){ if (stmt == (struct statement *) NULL) return; free_variable(stmt->inlist); free_variable(stmt->outlist); free(stmt);}static char *next_insert(char *text){ char *ptr = text; bool string = false; for (; *ptr != '\0' && (*ptr != '?' || string); ptr++) if (*ptr == '\'') string = string ? false : true; return (*ptr == '\0') ? NULL : ptr;}static boolECPGexecute(struct statement * stmt){ bool status = false; char *copiedquery; PGresult *results; PGnotify *notify; struct variable *var; memcpy((char *) &sqlca, (char *) &sqlca_init, sizeof(sqlca)); copiedquery = ecpg_strdup(stmt->command, stmt->lineno); /* * 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. */ var = stmt->inlist; while (var) { 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). */ buff[0] = '\0'; /* check for null value and set input buffer accordingly */ switch (var->ind_type) { case ECPGt_short: case ECPGt_unsigned_short: if (*(short *) var->ind_value < 0) strcpy(buff, "null"); break; case ECPGt_int: case ECPGt_unsigned_int: if (*(int *) var->ind_value < 0) strcpy(buff, "null"); break; case ECPGt_long: case ECPGt_unsigned_long: if (*(long *) var->ind_value < 0L) strcpy(buff, "null"); break; default: break; } if (*buff == '\0') { switch (var->type) { case ECPGt_short: sprintf(buff, "%d", *(short *) var->value); tobeinserted = buff; break; case ECPGt_int: sprintf(buff, "%d", *(int *) var->value); tobeinserted = buff; break; case ECPGt_unsigned_short: sprintf(buff, "%d", *(unsigned short *) var->value); tobeinserted = buff; break; case ECPGt_unsigned_int: sprintf(buff, "%d", *(unsigned int *) var->value); tobeinserted = buff; break; case ECPGt_long: sprintf(buff, "%ld", *(long *) var->value); tobeinserted = buff; break; case ECPGt_unsigned_long: sprintf(buff, "%ld", *(unsigned long *) var->value); tobeinserted = buff; break; case ECPGt_float: sprintf(buff, "%.14g", *(float *) var->value); tobeinserted = buff; break; case ECPGt_double: sprintf(buff, "%.14g", *(double *) var->value);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -