mirror of
https://github.com/postgres/postgres.git
synced 2025-04-24 10:47:04 +03:00
177 lines
3.6 KiB
C
177 lines
3.6 KiB
C
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/prepare.c,v 1.8 2003/08/01 13:53:36 petere Exp $ */
|
|
|
|
#define POSTGRES_ECPG_INTERNAL
|
|
#include "postgres_fe.h"
|
|
|
|
#include <ctype.h>
|
|
|
|
#include "ecpgtype.h"
|
|
#include "ecpglib.h"
|
|
#include "ecpgerrno.h"
|
|
#include "extern.h"
|
|
#include "sqlca.h"
|
|
|
|
static struct prepared_statement
|
|
{
|
|
char *name;
|
|
struct statement *stmt;
|
|
struct prepared_statement *next;
|
|
} *prep_stmts = NULL;
|
|
|
|
static bool
|
|
isvarchar(unsigned char c)
|
|
{
|
|
if (isalnum(c))
|
|
return true;
|
|
|
|
if (c == '_' || c == '>' || c == '-' || c == '.')
|
|
return true;
|
|
|
|
if (c >= 128)
|
|
return true;
|
|
|
|
return (false);
|
|
}
|
|
|
|
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 = '?';
|
|
for (++ptr; *ptr && isvarchar(*ptr); ptr++)
|
|
*ptr = ' ';
|
|
}
|
|
}
|
|
}
|
|
|
|
/* handle the EXEC SQL PREPARE statement */
|
|
bool
|
|
ECPGprepare(int lineno, char *name, char *variable)
|
|
{
|
|
struct statement *stmt;
|
|
struct prepared_statement *this;
|
|
struct sqlca_t *sqlca = ECPGget_sqlca();
|
|
|
|
ECPGinit_sqlca(sqlca);
|
|
/* 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, ECPG_COMPAT_PGSQL, name);
|
|
|
|
if (!b)
|
|
return false;
|
|
}
|
|
|
|
this = (struct prepared_statement *) ECPGalloc(sizeof(struct prepared_statement), lineno);
|
|
if (!this)
|
|
return false;
|
|
|
|
stmt = (struct statement *) ECPGalloc(sizeof(struct statement), lineno);
|
|
if (!stmt)
|
|
{
|
|
ECPGfree(this);
|
|
return false;
|
|
}
|
|
|
|
/* create statement */
|
|
stmt->lineno = lineno;
|
|
stmt->connection = NULL;
|
|
stmt->command = ECPGstrdup(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 = ECPGstrdup(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, int c, char *name)
|
|
{
|
|
bool ret = ECPGdeallocate_one(lineno, name);
|
|
enum COMPAT_MODE compat = c;
|
|
|
|
if (INFORMIX_MODE(compat))
|
|
{
|
|
/* Just ignore all errors since we do not know the list of cursors we
|
|
* are allowed to free. We have to trust that the software. */
|
|
return true;
|
|
}
|
|
|
|
if (!ret)
|
|
ECPGraise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, name);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool
|
|
ECPGdeallocate_one(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 */
|
|
ECPGfree(this->name);
|
|
ECPGfree(this->stmt->command);
|
|
ECPGfree(this->stmt);
|
|
if (prev != NULL)
|
|
prev->next = this->next;
|
|
else
|
|
prep_stmts = this->next;
|
|
|
|
ECPGfree(this);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
ECPGdeallocate_all(int lineno)
|
|
{
|
|
/* deallocate all prepared statements */
|
|
while (prep_stmts != NULL)
|
|
{
|
|
bool b = ECPGdeallocate(lineno, ECPG_COMPAT_PGSQL, prep_stmts->name);
|
|
|
|
if (!b)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* 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;
|
|
}
|