1
0
mirror of https://github.com/postgres/postgres.git synced 2025-10-27 00:12:01 +03:00

Revert "Add DECLARE STATEMENT support to ECPG."

This reverts commit bd7c95f0c1,
along with assorted follow-on fixes.  There are some questions
about the definition and implementation of that statement, and
we don't have time to resolve them before v13 release.  Rather
than ship the feature and then have backwards-compatibility
concerns constraining any redesign, let's remove it for now
and try again later.

Discussion: https://postgr.es/m/TY2PR01MB2443EC8286995378AEB7D9F8F5B10@TY2PR01MB2443.jpnprd01.prod.outlook.com
This commit is contained in:
Tom Lane
2019-09-20 12:47:21 -04:00
parent d1b0007639
commit 96b6c82c9d
45 changed files with 172 additions and 2360 deletions

View File

@@ -23,7 +23,7 @@ override CPPFLAGS := -I../include -I$(top_srcdir)/src/interfaces/ecpg/include \
override CFLAGS += $(PTHREAD_CFLAGS)
OBJS= execute.o typename.o descriptor.o sqlda.o data.o error.o prepare.o \
memory.o connect.o misc.o cursor.o $(WIN32RES)
memory.o connect.o misc.o $(WIN32RES)
SHLIB_LINK_INTERNAL = -L../pgtypeslib -lpgtypes $(libpq_pgport_shlib)
SHLIB_LINK = $(filter -lintl -lm, $(LIBS)) $(PTHREAD_LIBS)

View File

@@ -340,8 +340,6 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
return false;
}
memset(this, 0, sizeof(struct connection));
if (dbname != NULL)
{
/* get the detail information from dbname */
@@ -707,7 +705,6 @@ ECPGdisconnect(int lineno, const char *connection_name)
struct connection *f = con;
con = con->next;
ecpg_release_declared_statement(f->name);
ecpg_finish(f);
}
}
@@ -723,10 +720,7 @@ ECPGdisconnect(int lineno, const char *connection_name)
return false;
}
else
{
ecpg_release_declared_statement(connection_name);
ecpg_finish(con);
}
}
#ifdef ENABLE_THREAD_SAFETY

View File

@@ -1,261 +0,0 @@
/* src/interfaces/ecpg/ecpglib/cursor.c */
#define POSTGRES_ECPG_INTERNAL
#include "postgres_fe.h"
#include <ctype.h>
#include <locale.h>
#include <string.h>
#include "ecpgtype.h"
#include "ecpglib.h"
#include "ecpgerrno.h"
#include "ecpglib_extern.h"
#include "sqlca.h"
static void add_cursor(const int, const char *, const char *);
static void remove_cursor(const char *, struct connection *);
static bool find_cursor(const char *, const struct connection *);
/*
* Function: Handle the EXEC SQL OPEN cursor statement:
* Input:
* cursor_name --- cursor name
* prepared_name --- prepared name
* others --- keep same as the parameters in ECPGdo() function
*/
bool
ECPGopen(const char *cursor_name, const char *prepared_name,
const int lineno, const int compat, const int force_indicator,
const char *connection_name, const bool questionmarks,
const int st, const char *query,...)
{
va_list args;
bool status;
const char *real_connection_name = NULL;
if (!query)
{
ecpg_raise(lineno, ECPG_EMPTY, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, NULL);
return false;
}
/*
* If the declared name is referred by the PREPARE statement then the
* prepared_name is same as declared name
*/
real_connection_name = ecpg_get_con_name_by_declared_name(prepared_name);
if (real_connection_name)
{
/* Add the cursor name into the declared node */
ecpg_update_declare_statement(prepared_name, cursor_name, lineno);
}
else
{
/*
* If can't get the connection name by declared name then using
* connection name coming from the parameter connection_name
*/
real_connection_name = connection_name;
}
/* Add the cursor into the connection */
add_cursor(lineno, cursor_name, real_connection_name);
va_start(args, query);
status = ecpg_do(lineno, compat, force_indicator, real_connection_name, questionmarks, st, query, args);
va_end(args);
return status;
}
/*
* Function: Handle the EXEC SQL FETCH/MOVE CURSOR statements:
* Input:
* cursor_name --- cursor name
* others --- keep same as the parameters in ECPGdo() function
*/
bool
ECPGfetch(const char *cursor_name,
const int lineno, const int compat, const int force_indicator,
const char *connection_name, const bool questionmarks,
const int st, const char *query,...)
{
va_list args;
bool status;
const char *real_connection_name = NULL;
if (!query)
{
ecpg_raise(lineno, ECPG_EMPTY, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, NULL);
return (false);
}
real_connection_name = ecpg_get_con_name_by_cursor_name(cursor_name);
if (real_connection_name == NULL)
{
/*
* If can't get the connection name by cursor name then using
* connection name coming from the parameter connection_name
*/
real_connection_name = connection_name;
}
va_start(args, query);
status = ecpg_do(lineno, compat, force_indicator, real_connection_name, questionmarks, st, query, args);
va_end(args);
return status;
}
/*
* Function: Handle the EXEC SQL CLOSE CURSOR statements:
* Input:
* cursor_name --- cursor name
* others --- keep same as the parameters in ECPGdo() function
*/
bool
ECPGclose(const char *cursor_name,
const int lineno, const int compat, const int force_indicator,
const char *connection_name, const bool questionmarks,
const int st, const char *query,...)
{
va_list args;
bool status;
const char *real_connection_name = NULL;
struct connection *con = NULL;
if (!query)
{
ecpg_raise(lineno, ECPG_EMPTY, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, NULL);
return false;
}
real_connection_name = ecpg_get_con_name_by_cursor_name(cursor_name);
if (real_connection_name == NULL)
{
/*
* If can't get the connection name by cursor name then using
* connection name coming from the parameter connection_name
*/
real_connection_name = connection_name;
}
con = ecpg_get_connection(real_connection_name);
/* send the query to backend */
va_start(args, query);
status = ecpg_do(lineno, compat, force_indicator, real_connection_name, questionmarks, st, query, args);
va_end(args);
/* if it fails, raise an error */
if (!status)
{
ecpg_raise(lineno, ECPG_INVALID_CURSOR, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, NULL);
return false;
}
/* check the existence of the cursor in the connection */
if (find_cursor(cursor_name, con) == true)
remove_cursor(cursor_name, con);
return status;
}
/*
* Function: Add a cursor into the connection
* The duplication of cursor_name is checked at ecpg.trailer,
* so we don't check here.
*/
static void
add_cursor(const int lineno, const char *cursor_name, const char *connection_name)
{
struct connection *con;
struct cursor_statement *new = NULL;
if (!cursor_name)
{
ecpg_raise(lineno, ECPG_INVALID_CURSOR, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, NULL);
return;
}
con = ecpg_get_connection(connection_name);
if (!con)
{
ecpg_raise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
connection_name ? connection_name : ecpg_gettext("NULL"));
return;
}
/* allocate a node to store the new cursor */
new = (struct cursor_statement *) ecpg_alloc(sizeof(struct cursor_statement), lineno);
if (new)
{
new->name = ecpg_strdup(cursor_name, lineno);
new->next = con->cursor_stmts;
con->cursor_stmts = new;
}
}
/*
* Function: Remove the cursor from the connection
*/
static void
remove_cursor(const char *cursor_name, struct connection *connection)
{
struct cursor_statement *cur = NULL;
struct cursor_statement *prev = NULL;
if (!connection || !cursor_name)
return;
cur = connection->cursor_stmts;
while (cur)
{
if (strcmp(cur->name, cursor_name) == 0)
{
if (!prev)
connection->cursor_stmts = cur->next;
else
prev->next = cur->next;
ecpg_free(cur->name);
ecpg_free(cur);
break;
}
prev = cur;
cur = cur->next;
}
}
/*
* Function: check the existence of the cursor in the connection
* Return: true ---Found
* false --- Not found
*/
static bool
find_cursor(const char *cursor_name, const struct connection *connection)
{
struct cursor_statement *cur = NULL;
if (!connection || !cursor_name)
return false;
for (cur = connection->cursor_stmts; cur != NULL; cur = cur->next)
{
if (strcmp(cur->name, cursor_name) == 0)
return true;
}
return false;
}

View File

@@ -861,7 +861,6 @@ ECPGdescribe(int line, int compat, bool input, const char *connection_name, cons
struct prepared_statement *prep;
PGresult *res;
va_list args;
const char *real_connection_name = NULL;
/* DESCRIBE INPUT is not yet supported */
if (input)
@@ -870,21 +869,11 @@ ECPGdescribe(int line, int compat, bool input, const char *connection_name, cons
return ret;
}
real_connection_name = ecpg_get_con_name_by_declared_name(stmt_name);
if (real_connection_name == NULL)
{
/*
* If can't get the connection name by declared name then using
* connection name coming from the parameter connection_name
*/
real_connection_name = connection_name;
}
con = ecpg_get_connection(real_connection_name);
con = ecpg_get_connection(connection_name);
if (!con)
{
ecpg_raise(line, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
real_connection_name ? real_connection_name : ecpg_gettext("NULL"));
connection_name ? connection_name : ecpg_gettext("NULL"));
return ret;
}
prep = ecpg_find_prepared_statement(stmt_name, con, NULL);

View File

@@ -88,15 +88,6 @@ struct statement
PGresult *results;
};
/* structure to store declared statements */
struct declared_statement
{
char *name; /* declared name */
char *connection_name;
char *cursor_name;
struct declared_statement *next;
};
/* structure to store prepared statements for a connection */
struct prepared_statement
{
@@ -106,12 +97,6 @@ struct prepared_statement
struct prepared_statement *next;
};
struct cursor_statement
{
char *name; /* cursor name */
struct cursor_statement *next;
};
/* structure to store connections */
struct connection
{
@@ -120,7 +105,6 @@ struct connection
bool autocommit;
struct ECPGtype_information_cache *cache_head;
struct prepared_statement *prep_stmts;
struct cursor_statement *cursor_stmts;
struct connection *next;
};
@@ -202,11 +186,6 @@ struct descriptor *ecpg_find_desc(int line, const char *name);
struct prepared_statement *ecpg_find_prepared_statement(const char *,
struct connection *, struct prepared_statement **);
void ecpg_update_declare_statement(const char *, const char *, const int);
char *ecpg_get_con_name_by_declared_name(const char *);
const char *ecpg_get_con_name_by_cursor_name(const char *);
void ecpg_release_declared_statement(const char *);
bool ecpg_store_result(const PGresult *results, int act_field,
const struct statement *stmt, struct variable *var);
bool ecpg_store_input(const int, const bool, const struct variable *, char **, bool);

View File

@@ -200,13 +200,6 @@ ecpg_raise(int line, int code, const char *sqlstate, const char *str)
ecpg_gettext("could not connect to database \"%s\" on line %d"), str, line);
break;
case ECPG_INVALID_CURSOR:
snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
/*------
translator: this string will be truncated at 149 characters expanded. */
ecpg_gettext("cursor is invalid on line %d"), line);
break;
default:
snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
/*------

View File

@@ -2280,32 +2280,9 @@ ECPGdo(const int lineno, const int compat, const int force_indicator, const char
{
va_list args;
bool ret;
const char *real_connection_name = NULL;
real_connection_name = connection_name;
if (!query)
{
ecpg_raise(lineno, ECPG_EMPTY, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, NULL);
return false;
}
/* Handle the EXEC SQL EXECUTE... statement */
if (ECPGst_execute == st)
{
real_connection_name = ecpg_get_con_name_by_declared_name(query);
if (real_connection_name == NULL)
{
/*
* If can't get the connection name by declared name then using
* connection name coming from the parameter connection_name
*/
real_connection_name = connection_name;
}
}
va_start(args, query);
ret = ecpg_do(lineno, compat, force_indicator, real_connection_name,
ret = ecpg_do(lineno, compat, force_indicator, connection_name,
questionmarks, st, query, args);
va_end(args);

View File

@@ -29,7 +29,3 @@ ECPGget_PGconn 26
ECPGtransactionStatus 27
ECPGset_var 28
ECPGget_var 29
ECPGdeclare 30
ECPGopen 31
ECPGfetch 32
ECPGclose 33

View File

@@ -36,11 +36,10 @@ typedef struct
static int nextStmtID = 1;
static stmtCacheEntry *stmtCacheEntries = NULL;
static struct declared_statement *g_declared_list;
static bool deallocate_one(int lineno, enum COMPAT_MODE c, struct connection *con,
struct prepared_statement *prev, struct prepared_statement *this);
static struct declared_statement *ecpg_find_declared_statement(const char *);
static bool
isvarchar(unsigned char c)
{
@@ -61,19 +60,10 @@ ecpg_register_prepared_stmt(struct statement *stmt)
{
struct statement *prep_stmt;
struct prepared_statement *this;
struct connection *con = NULL;
struct connection *con = stmt->connection;
struct prepared_statement *prev = NULL;
char *real_connection_name;
int lineno = stmt->lineno;
real_connection_name = ecpg_get_con_name_by_declared_name(stmt->name);
if (real_connection_name == NULL)
real_connection_name = stmt->connection->name;
con = ecpg_get_connection(real_connection_name);
if (!ecpg_init(con, real_connection_name, stmt->lineno))
return false;
/* check if we already have prepared this statement */
this = ecpg_find_prepared_statement(stmt->name, con, &prev);
if (this && !deallocate_one(lineno, ECPG_COMPAT_PGSQL, con, prev, this))
@@ -183,7 +173,6 @@ prepare_common(int lineno, struct connection *con, const char *name, const char
ecpg_free(this);
return false;
}
memset(stmt, 0, sizeof(struct statement));
/* create statement */
stmt->lineno = lineno;
@@ -231,22 +220,11 @@ ECPGprepare(int lineno, const char *connection_name, const bool questionmarks,
struct connection *con;
struct prepared_statement *this,
*prev;
const char *real_connection_name = NULL;
(void) questionmarks; /* quiet the compiler */
real_connection_name = ecpg_get_con_name_by_declared_name(name);
if (real_connection_name == NULL)
{
/*
* If can't get the connection name by declared name then using
* connection name coming from the parameter connection_name
*/
real_connection_name = connection_name;
}
con = ecpg_get_connection(real_connection_name);
if (!ecpg_init(con, real_connection_name, lineno))
con = ecpg_get_connection(connection_name);
if (!ecpg_init(con, connection_name, lineno))
return false;
/* check if we already have prepared this statement */
@@ -339,20 +317,9 @@ ECPGdeallocate(int lineno, int c, const char *connection_name, const char *name)
struct connection *con;
struct prepared_statement *this,
*prev;
const char *real_connection_name = NULL;
real_connection_name = ecpg_get_con_name_by_declared_name(name);
if (real_connection_name == NULL)
{
/*
* If can't get the connection name by declared name then using
* connection name coming from the parameter connection_name
*/
real_connection_name = connection_name;
}
con = ecpg_get_connection(real_connection_name);
if (!ecpg_init(con, real_connection_name, lineno))
con = ecpg_get_connection(connection_name);
if (!ecpg_init(con, connection_name, lineno))
return false;
this = ecpg_find_prepared_statement(name, con, &prev);
@@ -400,21 +367,9 @@ ecpg_prepared(const char *name, struct connection *con)
char *
ECPGprepared_statement(const char *connection_name, const char *name, int lineno)
{
const char *real_connection_name = NULL;
(void) lineno; /* keep the compiler quiet */
real_connection_name = ecpg_get_con_name_by_declared_name(name);
if (real_connection_name == NULL)
{
/*
* If can't get the connection name by declared name then using
* connection name coming from the parameter connection_name
*/
real_connection_name = connection_name;
}
return ecpg_prepared(name, ecpg_get_connection(real_connection_name));
return ecpg_prepared(name, ecpg_get_connection(connection_name));
}
/*
@@ -645,210 +600,3 @@ ecpg_auto_prepare(int lineno, const char *connection_name, const int compat, cha
return true;
}
/*
* handle the EXEC SQL DECLARE STATEMENT
* Input: connection_name -- connection name
* name -- declared name
*/
bool
ECPGdeclare(int lineno, const char *connection_name, const char *name)
{
struct connection *con = NULL;
struct declared_statement *p = NULL;
if (name == NULL)
{
/* Should never go to here because ECPG pre-compiler will check it */
return false;
}
if (connection_name == NULL)
{
/*
* Going to here means not using AT clause in the DECLARE STATEMENT
* ECPG pre-processor allows this case. However, we don't allocate a
* node to store the declared name because the DECLARE STATEMENT
* without using AT clause will be ignored. The following statement
* such as PREPARE, EXECUTE are executed as usual on the current
* connection.
*/
return true;
}
con = ecpg_get_connection(connection_name);
if (!ecpg_init(con, connection_name, lineno))
return false;
if (ecpg_find_declared_statement(name))
{
/*
* Should not go to here because the pre-compiler has check the
* duplicate name
*/
return false;
}
/* allocate a declared_statement as a new node */
p = (struct declared_statement *) ecpg_alloc(sizeof(struct declared_statement), lineno);
if (!p)
return false;
memset(p, 0, sizeof(struct declared_statement));
ecpg_log("ECPGdeclare on line %d: declared name \"%s\" on connection: \"%s\"\n", lineno, name, connection_name);
p->name = ecpg_strdup(name, lineno);
p->connection_name = ecpg_strdup(connection_name, lineno);
/* Add the new node into the g_declared_list */
if (g_declared_list != NULL)
{
p->next = g_declared_list;
g_declared_list = p;
}
else
g_declared_list = p;
return true;
}
/*
* Find a declared node by declared name
* Input: name -- declared name
* Return: Found -- The pointer points to the declared node
* Not found -- NULL
*/
static struct declared_statement *
ecpg_find_declared_statement(const char *name)
{
struct declared_statement *p;
if (name == NULL)
return NULL;
p = g_declared_list;
while (p)
{
if (strcmp(p->name, name) == 0)
return p;
p = p->next;
}
return NULL;
}
/*
* Build the relationship between the declared name and cursor name
* Input: declared_name -- the name declared in the DECLARE STATEMENT
* cursor_name -- cursor name declared in the DECLARE/OPEN CURSOR statement
*/
void
ecpg_update_declare_statement(const char *declared_name, const char *cursor_name, const int lineno)
{
struct declared_statement *p = NULL;
if (!declared_name || !cursor_name)
return;
/* Find the declared node by declared name */
p = ecpg_find_declared_statement(declared_name);
if (p)
{
if (p->cursor_name)
ecpg_free(p->cursor_name);
p->cursor_name = ecpg_strdup(cursor_name, lineno);
}
}
/*
* Find and return the connection name referred by the declared name
* Input: declared_name -- the name declared in the DECLARE STATEMENT
* Return: Found -- The connection name
* Not found -- NULL
*/
char *
ecpg_get_con_name_by_declared_name(const char *declared_name)
{
struct declared_statement *p;
p = ecpg_find_declared_statement(declared_name);
if (p)
return p->connection_name;
return NULL;
}
/*
* Find the connection name by referring the declared statements
* cursors by using the provided cursor name
* Input: cursor_name -- the cursor name
* Return: Found -- The connection name
* Not found -- NULL
*/
const char *
ecpg_get_con_name_by_cursor_name(const char *cursor_name)
{
struct declared_statement *p;
if (cursor_name == NULL)
return NULL;
p = g_declared_list;
while (p)
{
/* Search the cursor name in the declared list */
if (p->cursor_name && (strcmp(p->cursor_name, cursor_name) == 0))
return p->connection_name;
p = p->next;
}
return NULL;
}
/*
* Release the declare node from the g_declared_list which refers the connection_name
* Input: connection_name -- connection name
*/
void
ecpg_release_declared_statement(const char *connection_name)
{
struct declared_statement *cur = NULL;
struct declared_statement *prev = NULL;
if (connection_name == NULL)
return;
cur = g_declared_list;
while (cur)
{
if (strcmp(cur->connection_name, connection_name) == 0)
{
/* If find then release the declared node from the list */
if (prev)
prev->next = cur->next;
else
g_declared_list = cur->next;
ecpg_log("ecpg_release_declared_statement: declared name \"%s\" is released\n", cur->name);
ecpg_free(cur->name);
ecpg_free(cur->connection_name);
ecpg_free(cur->cursor_name);
ecpg_free(cur);
/*
* One connection can be used by multiple declared name, so no
* break here
*/
}
else
prev = cur;
if (prev)
cur = prev->next;
else
cur = g_declared_list;
}
}