Make SPI's execution of querystrings follow the rules agreed to for
command status at the interactive level. SPI_processed, etc are set in the same way as the returned command status would have been set if the same querystring were issued interactively. Per gripe from Michael Paesold 25-Sep-02.
This commit is contained in:
parent
ba0edcf451
commit
9ff695c944
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.74 2002/09/04 20:31:18 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.75 2002/10/14 23:49:20 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -88,7 +88,6 @@ SPI_connect(void)
|
||||
_SPI_connected++;
|
||||
|
||||
_SPI_current = &(_SPI_stack[_SPI_connected]);
|
||||
_SPI_current->qtlist = NULL;
|
||||
_SPI_current->processed = 0;
|
||||
_SPI_current->tuptable = NULL;
|
||||
|
||||
@ -258,7 +257,6 @@ SPI_prepare(char *src, int nargs, Oid *argtypes)
|
||||
_SPI_end_call(true);
|
||||
|
||||
return (void *) plan;
|
||||
|
||||
}
|
||||
|
||||
void *
|
||||
@ -716,9 +714,9 @@ SPI_cursor_open(char *name, void *plan, Datum *Values, char *Nulls)
|
||||
int k;
|
||||
|
||||
/* Ensure that the plan contains only one regular SELECT query */
|
||||
if (length(ptlist) != 1)
|
||||
if (length(ptlist) != 1 || length(qtlist) != 1)
|
||||
elog(ERROR, "cannot open multi-query plan as cursor");
|
||||
queryTree = (Query *) lfirst(qtlist);
|
||||
queryTree = (Query *) lfirst((List *) lfirst(qtlist));
|
||||
planTree = (Plan *) lfirst(ptlist);
|
||||
|
||||
if (queryTree->commandType != CMD_SELECT)
|
||||
@ -948,29 +946,22 @@ spi_printtup(HeapTuple tuple, TupleDesc tupdesc, DestReceiver *self)
|
||||
* Static functions
|
||||
*/
|
||||
|
||||
/*
|
||||
* Plan and optionally execute a querystring.
|
||||
*
|
||||
* If plan != NULL, just prepare plan tree, else execute immediately.
|
||||
*/
|
||||
static int
|
||||
_SPI_execute(char *src, int tcount, _SPI_plan *plan)
|
||||
{
|
||||
List *queryTree_list;
|
||||
List *planTree_list;
|
||||
List *queryTree_list_item;
|
||||
QueryDesc *qdesc;
|
||||
Query *queryTree;
|
||||
Plan *planTree;
|
||||
EState *state;
|
||||
StringInfoData stri;
|
||||
List *raw_parsetree_list;
|
||||
List *query_list_list;
|
||||
List *plan_list;
|
||||
List *list_item;
|
||||
int nargs = 0;
|
||||
Oid *argtypes = NULL;
|
||||
int res = 0;
|
||||
bool islastquery;
|
||||
|
||||
/* Increment CommandCounter to see changes made by now */
|
||||
CommandCounterIncrement();
|
||||
|
||||
SPI_processed = 0;
|
||||
SPI_lastoid = InvalidOid;
|
||||
SPI_tuptable = NULL;
|
||||
_SPI_current->tuptable = NULL;
|
||||
_SPI_current->qtlist = NULL;
|
||||
|
||||
if (plan)
|
||||
{
|
||||
@ -978,72 +969,149 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
|
||||
argtypes = plan->argtypes;
|
||||
}
|
||||
|
||||
queryTree_list = pg_parse_and_rewrite(src, argtypes, nargs);
|
||||
/* Increment CommandCounter to see changes made by now */
|
||||
CommandCounterIncrement();
|
||||
|
||||
_SPI_current->qtlist = queryTree_list;
|
||||
/* Reset state (only needed in case string is empty) */
|
||||
SPI_processed = 0;
|
||||
SPI_lastoid = InvalidOid;
|
||||
SPI_tuptable = NULL;
|
||||
_SPI_current->tuptable = NULL;
|
||||
|
||||
planTree_list = NIL;
|
||||
/*
|
||||
* Parse the request string into a list of raw parse trees.
|
||||
*/
|
||||
initStringInfo(&stri);
|
||||
appendStringInfo(&stri, "%s", src);
|
||||
|
||||
foreach(queryTree_list_item, queryTree_list)
|
||||
raw_parsetree_list = pg_parse_query(&stri, argtypes, nargs);
|
||||
|
||||
/*
|
||||
* Do parse analysis and rule rewrite for each raw parsetree.
|
||||
*
|
||||
* We save the querytrees from each raw parsetree as a separate
|
||||
* sublist. This allows _SPI_execute_plan() to know where the
|
||||
* boundaries between original queries fall.
|
||||
*/
|
||||
query_list_list = NIL;
|
||||
plan_list = NIL;
|
||||
|
||||
foreach(list_item, raw_parsetree_list)
|
||||
{
|
||||
queryTree = (Query *) lfirst(queryTree_list_item);
|
||||
islastquery = (lnext(queryTree_list_item) == NIL);
|
||||
Node *parsetree = (Node *) lfirst(list_item);
|
||||
CmdType origCmdType;
|
||||
bool foundOriginalQuery = false;
|
||||
List *query_list;
|
||||
List *query_list_item;
|
||||
|
||||
planTree = pg_plan_query(queryTree);
|
||||
planTree_list = lappend(planTree_list, planTree);
|
||||
|
||||
if (queryTree->commandType == CMD_UTILITY)
|
||||
switch (nodeTag(parsetree))
|
||||
{
|
||||
if (nodeTag(queryTree->utilityStmt) == T_CopyStmt)
|
||||
{
|
||||
CopyStmt *stmt = (CopyStmt *) (queryTree->utilityStmt);
|
||||
case T_InsertStmt:
|
||||
origCmdType = CMD_INSERT;
|
||||
break;
|
||||
case T_DeleteStmt:
|
||||
origCmdType = CMD_DELETE;
|
||||
break;
|
||||
case T_UpdateStmt:
|
||||
origCmdType = CMD_UPDATE;
|
||||
break;
|
||||
case T_SelectStmt:
|
||||
origCmdType = CMD_SELECT;
|
||||
break;
|
||||
default:
|
||||
/* Otherwise, never match commandType */
|
||||
origCmdType = CMD_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (stmt->filename == NULL)
|
||||
return SPI_ERROR_COPY;
|
||||
}
|
||||
else if (nodeTag(queryTree->utilityStmt) == T_ClosePortalStmt ||
|
||||
nodeTag(queryTree->utilityStmt) == T_FetchStmt)
|
||||
return SPI_ERROR_CURSOR;
|
||||
else if (nodeTag(queryTree->utilityStmt) == T_TransactionStmt)
|
||||
return SPI_ERROR_TRANSACTION;
|
||||
res = SPI_OK_UTILITY;
|
||||
if (plan == NULL)
|
||||
if (plan)
|
||||
plan->origCmdType = origCmdType;
|
||||
|
||||
query_list = pg_analyze_and_rewrite(parsetree);
|
||||
|
||||
query_list_list = lappend(query_list_list, query_list);
|
||||
|
||||
/* Reset state for each original parsetree */
|
||||
SPI_processed = 0;
|
||||
SPI_lastoid = InvalidOid;
|
||||
SPI_tuptable = NULL;
|
||||
_SPI_current->tuptable = NULL;
|
||||
|
||||
foreach(query_list_item, query_list)
|
||||
{
|
||||
Query *queryTree = (Query *) lfirst(query_list_item);
|
||||
Plan *planTree;
|
||||
bool canSetResult;
|
||||
QueryDesc *qdesc;
|
||||
EState *state;
|
||||
|
||||
planTree = pg_plan_query(queryTree);
|
||||
plan_list = lappend(plan_list, planTree);
|
||||
|
||||
/*
|
||||
* This query can set the SPI result if it is the original
|
||||
* query, or if it is an INSTEAD query of the same kind as the
|
||||
* original and we haven't yet seen the original query.
|
||||
*/
|
||||
if (queryTree->querySource == QSRC_ORIGINAL)
|
||||
{
|
||||
ProcessUtility(queryTree->utilityStmt, None, NULL);
|
||||
if (!islastquery)
|
||||
canSetResult = true;
|
||||
foundOriginalQuery = true;
|
||||
}
|
||||
else if (!foundOriginalQuery &&
|
||||
queryTree->commandType == origCmdType &&
|
||||
(queryTree->querySource == QSRC_INSTEAD_RULE ||
|
||||
queryTree->querySource == QSRC_QUAL_INSTEAD_RULE))
|
||||
canSetResult = true;
|
||||
else
|
||||
canSetResult = false;
|
||||
|
||||
if (queryTree->commandType == CMD_UTILITY)
|
||||
{
|
||||
if (IsA(queryTree->utilityStmt, CopyStmt))
|
||||
{
|
||||
CopyStmt *stmt = (CopyStmt *) queryTree->utilityStmt;
|
||||
|
||||
if (stmt->filename == NULL)
|
||||
return SPI_ERROR_COPY;
|
||||
}
|
||||
else if (IsA(queryTree->utilityStmt, ClosePortalStmt) ||
|
||||
IsA(queryTree->utilityStmt, FetchStmt))
|
||||
return SPI_ERROR_CURSOR;
|
||||
else if (IsA(queryTree->utilityStmt, TransactionStmt))
|
||||
return SPI_ERROR_TRANSACTION;
|
||||
res = SPI_OK_UTILITY;
|
||||
if (plan == NULL)
|
||||
{
|
||||
ProcessUtility(queryTree->utilityStmt, None, NULL);
|
||||
CommandCounterIncrement();
|
||||
else
|
||||
}
|
||||
}
|
||||
else if (plan == NULL)
|
||||
{
|
||||
qdesc = CreateQueryDesc(queryTree, planTree,
|
||||
canSetResult ? SPI : None, NULL);
|
||||
state = CreateExecutorState();
|
||||
res = _SPI_pquery(qdesc, state, canSetResult ? tcount : 0);
|
||||
if (res < 0)
|
||||
return res;
|
||||
CommandCounterIncrement();
|
||||
}
|
||||
else
|
||||
{
|
||||
qdesc = CreateQueryDesc(queryTree, planTree,
|
||||
canSetResult ? SPI : None, NULL);
|
||||
res = _SPI_pquery(qdesc, NULL, 0);
|
||||
if (res < 0)
|
||||
return res;
|
||||
}
|
||||
else if (islastquery)
|
||||
break;
|
||||
}
|
||||
else if (plan == NULL)
|
||||
{
|
||||
qdesc = CreateQueryDesc(queryTree, planTree,
|
||||
islastquery ? SPI : None, NULL);
|
||||
state = CreateExecutorState();
|
||||
res = _SPI_pquery(qdesc, state, islastquery ? tcount : 0);
|
||||
if (res < 0 || islastquery)
|
||||
return res;
|
||||
CommandCounterIncrement();
|
||||
}
|
||||
else
|
||||
{
|
||||
qdesc = CreateQueryDesc(queryTree, planTree,
|
||||
islastquery ? SPI : None, NULL);
|
||||
res = _SPI_pquery(qdesc, NULL, islastquery ? tcount : 0);
|
||||
if (res < 0)
|
||||
return res;
|
||||
if (islastquery)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (plan)
|
||||
{
|
||||
plan->qtlist = queryTree_list;
|
||||
plan->ptlist = planTree_list;
|
||||
plan->qtlist = query_list_list;
|
||||
plan->ptlist = plan_list;
|
||||
}
|
||||
|
||||
return res;
|
||||
@ -1052,72 +1120,100 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
|
||||
static int
|
||||
_SPI_execute_plan(_SPI_plan *plan, Datum *Values, char *Nulls, int tcount)
|
||||
{
|
||||
List *queryTree_list = plan->qtlist;
|
||||
List *planTree_list = plan->ptlist;
|
||||
List *queryTree_list_item;
|
||||
QueryDesc *qdesc;
|
||||
Query *queryTree;
|
||||
Plan *planTree;
|
||||
EState *state;
|
||||
List *query_list_list = plan->qtlist;
|
||||
List *plan_list = plan->ptlist;
|
||||
List *query_list_list_item;
|
||||
int nargs = plan->nargs;
|
||||
int res = 0;
|
||||
bool islastquery;
|
||||
int k;
|
||||
|
||||
/* Increment CommandCounter to see changes made by now */
|
||||
CommandCounterIncrement();
|
||||
|
||||
/* Reset state (only needed in case string is empty) */
|
||||
SPI_processed = 0;
|
||||
SPI_lastoid = InvalidOid;
|
||||
SPI_tuptable = NULL;
|
||||
_SPI_current->tuptable = NULL;
|
||||
_SPI_current->qtlist = NULL;
|
||||
|
||||
foreach(queryTree_list_item, queryTree_list)
|
||||
foreach(query_list_list_item, query_list_list)
|
||||
{
|
||||
queryTree = (Query *) lfirst(queryTree_list_item);
|
||||
planTree = lfirst(planTree_list);
|
||||
planTree_list = lnext(planTree_list);
|
||||
islastquery = (planTree_list == NIL); /* assume lists are same
|
||||
* len */
|
||||
List *query_list = lfirst(query_list_list_item);
|
||||
List *query_list_item;
|
||||
bool foundOriginalQuery = false;
|
||||
|
||||
if (queryTree->commandType == CMD_UTILITY)
|
||||
/* Reset state for each original parsetree */
|
||||
SPI_processed = 0;
|
||||
SPI_lastoid = InvalidOid;
|
||||
SPI_tuptable = NULL;
|
||||
_SPI_current->tuptable = NULL;
|
||||
|
||||
foreach(query_list_item, query_list)
|
||||
{
|
||||
ProcessUtility(queryTree->utilityStmt, None, NULL);
|
||||
if (!islastquery)
|
||||
CommandCounterIncrement();
|
||||
else
|
||||
return SPI_OK_UTILITY;
|
||||
}
|
||||
else
|
||||
{
|
||||
qdesc = CreateQueryDesc(queryTree, planTree,
|
||||
islastquery ? SPI : None, NULL);
|
||||
state = CreateExecutorState();
|
||||
if (nargs > 0)
|
||||
Query *queryTree = (Query *) lfirst(query_list_item);
|
||||
Plan *planTree;
|
||||
bool canSetResult;
|
||||
QueryDesc *qdesc;
|
||||
EState *state;
|
||||
|
||||
planTree = lfirst(plan_list);
|
||||
plan_list = lnext(plan_list);
|
||||
|
||||
/*
|
||||
* This query can set the SPI result if it is the original
|
||||
* query, or if it is an INSTEAD query of the same kind as the
|
||||
* original and we haven't yet seen the original query.
|
||||
*/
|
||||
if (queryTree->querySource == QSRC_ORIGINAL)
|
||||
{
|
||||
ParamListInfo paramLI;
|
||||
canSetResult = true;
|
||||
foundOriginalQuery = true;
|
||||
}
|
||||
else if (!foundOriginalQuery &&
|
||||
queryTree->commandType == plan->origCmdType &&
|
||||
(queryTree->querySource == QSRC_INSTEAD_RULE ||
|
||||
queryTree->querySource == QSRC_QUAL_INSTEAD_RULE))
|
||||
canSetResult = true;
|
||||
else
|
||||
canSetResult = false;
|
||||
|
||||
paramLI = (ParamListInfo) palloc((nargs + 1) *
|
||||
sizeof(ParamListInfoData));
|
||||
MemSet(paramLI, 0, (nargs + 1) * sizeof(ParamListInfoData));
|
||||
|
||||
state->es_param_list_info = paramLI;
|
||||
for (k = 0; k < plan->nargs; paramLI++, k++)
|
||||
{
|
||||
paramLI->kind = PARAM_NUM;
|
||||
paramLI->id = k + 1;
|
||||
paramLI->isnull = (Nulls && Nulls[k] == 'n');
|
||||
paramLI->value = Values[k];
|
||||
}
|
||||
paramLI->kind = PARAM_INVALID;
|
||||
if (queryTree->commandType == CMD_UTILITY)
|
||||
{
|
||||
res = SPI_OK_UTILITY;
|
||||
ProcessUtility(queryTree->utilityStmt, None, NULL);
|
||||
CommandCounterIncrement();
|
||||
}
|
||||
else
|
||||
state->es_param_list_info = NULL;
|
||||
res = _SPI_pquery(qdesc, state, islastquery ? tcount : 0);
|
||||
if (res < 0 || islastquery)
|
||||
return res;
|
||||
CommandCounterIncrement();
|
||||
{
|
||||
qdesc = CreateQueryDesc(queryTree, planTree,
|
||||
canSetResult ? SPI : None, NULL);
|
||||
state = CreateExecutorState();
|
||||
if (nargs > 0)
|
||||
{
|
||||
ParamListInfo paramLI;
|
||||
int k;
|
||||
|
||||
paramLI = (ParamListInfo)
|
||||
palloc((nargs + 1) * sizeof(ParamListInfoData));
|
||||
MemSet(paramLI, 0,
|
||||
(nargs + 1) * sizeof(ParamListInfoData));
|
||||
|
||||
state->es_param_list_info = paramLI;
|
||||
for (k = 0; k < plan->nargs; paramLI++, k++)
|
||||
{
|
||||
paramLI->kind = PARAM_NUM;
|
||||
paramLI->id = k + 1;
|
||||
paramLI->isnull = (Nulls && Nulls[k] == 'n');
|
||||
paramLI->value = Values[k];
|
||||
}
|
||||
paramLI->kind = PARAM_INVALID;
|
||||
}
|
||||
else
|
||||
state->es_param_list_info = NULL;
|
||||
res = _SPI_pquery(qdesc, state, canSetResult ? tcount : 0);
|
||||
if (res < 0)
|
||||
return res;
|
||||
CommandCounterIncrement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1169,7 +1265,7 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
||||
return SPI_ERROR_OPUNKNOWN;
|
||||
}
|
||||
|
||||
if (state == NULL) /* plan preparation */
|
||||
if (state == NULL) /* plan preparation, don't execute */
|
||||
return res;
|
||||
|
||||
#ifdef SPI_EXECUTOR_STATS
|
||||
@ -1340,12 +1436,10 @@ static int
|
||||
_SPI_end_call(bool procmem)
|
||||
{
|
||||
/*
|
||||
* We' returning to procedure where _SPI_curid == _SPI_connected - 1
|
||||
* We're returning to procedure where _SPI_curid == _SPI_connected - 1
|
||||
*/
|
||||
_SPI_curid--;
|
||||
|
||||
_SPI_current->qtlist = NULL;
|
||||
|
||||
if (procmem) /* switch to the procedure memory context */
|
||||
{
|
||||
_SPI_procmem();
|
||||
@ -1420,6 +1514,7 @@ _SPI_copy_plan(_SPI_plan *plan, int location)
|
||||
}
|
||||
else
|
||||
newplan->argtypes = NULL;
|
||||
newplan->origCmdType = plan->origCmdType;
|
||||
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.302 2002/10/14 22:14:35 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.303 2002/10/14 23:49:20 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* this is the "main" module of the postgres backend and
|
||||
@ -119,8 +119,6 @@ int XfuncMode = 0;
|
||||
static int InteractiveBackend(StringInfo inBuf);
|
||||
static int SocketBackend(StringInfo inBuf);
|
||||
static int ReadCommand(StringInfo inBuf);
|
||||
static List *pg_parse_query(StringInfo query_string, Oid *typev, int nargs);
|
||||
static List *pg_analyze_and_rewrite(Node *parsetree);
|
||||
static void start_xact_command(void);
|
||||
static void finish_xact_command(bool forceCommit);
|
||||
static void SigHupHandler(SIGNAL_ARGS);
|
||||
@ -367,7 +365,7 @@ pg_parse_and_rewrite(char *query_string, /* string to execute */
|
||||
* we've seen a COMMIT or ABORT command; when we are in abort state, other
|
||||
* commands are not processed any further than the raw parse stage.
|
||||
*/
|
||||
static List *
|
||||
List *
|
||||
pg_parse_query(StringInfo query_string, Oid *typev, int nargs)
|
||||
{
|
||||
List *raw_parsetree_list;
|
||||
@ -395,7 +393,7 @@ pg_parse_query(StringInfo query_string, Oid *typev, int nargs)
|
||||
*
|
||||
* NOTE: for reasons mentioned above, this must be separate from raw parsing.
|
||||
*/
|
||||
static List *
|
||||
List *
|
||||
pg_analyze_and_rewrite(Node *parsetree)
|
||||
{
|
||||
List *querytree_list;
|
||||
@ -1769,7 +1767,7 @@ PostgresMain(int argc, char *argv[], const char *username)
|
||||
if (!IsUnderPostmaster)
|
||||
{
|
||||
puts("\nPOSTGRES backend interactive interface ");
|
||||
puts("$Revision: 1.302 $ $Date: 2002/10/14 22:14:35 $\n");
|
||||
puts("$Revision: 1.303 $ $Date: 2002/10/14 23:49:20 $\n");
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1,9 +1,12 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* spi.c
|
||||
* spi_priv.h
|
||||
* Server Programming Interface private declarations
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/include/executor/spi_priv.h,v 1.12 2002/05/21 22:05:55 tgl Exp $
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: spi_priv.h,v 1.13 2002/10/14 23:49:20 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -12,9 +15,9 @@
|
||||
|
||||
#include "executor/spi.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
List *qtlist;
|
||||
uint32 processed; /* by Executor */
|
||||
SPITupleTable *tuptable;
|
||||
MemoryContext procCxt; /* procedure context */
|
||||
@ -24,13 +27,20 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* context containing _SPI_plan itself as well as subsidiary structures */
|
||||
MemoryContext plancxt;
|
||||
/* List of List of querytrees; one sublist per original parsetree */
|
||||
List *qtlist;
|
||||
/* List of plan trees --- length == # of querytrees, but flat list */
|
||||
List *ptlist;
|
||||
/* Argument types, if a prepared plan */
|
||||
int nargs;
|
||||
Oid *argtypes;
|
||||
/* Command type of last original parsetree */
|
||||
CmdType origCmdType;
|
||||
} _SPI_plan;
|
||||
|
||||
|
||||
#define _SPI_CPLAN_CURCXT 0
|
||||
#define _SPI_CPLAN_PROCXT 1
|
||||
#define _SPI_CPLAN_TOPCXT 2
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: tcopprot.h,v 1.49 2002/06/20 20:29:52 momjian Exp $
|
||||
* $Id: tcopprot.h,v 1.50 2002/10/14 23:49:20 tgl Exp $
|
||||
*
|
||||
* OLD COMMENTS
|
||||
* This file was created so that other c files could get the two
|
||||
@ -35,12 +35,15 @@ extern bool ShowPortNumber;
|
||||
|
||||
#ifndef BOOTSTRAP_INCLUDE
|
||||
|
||||
extern List *pg_parse_query(StringInfo query_string, Oid *typev, int nargs);
|
||||
extern List *pg_analyze_and_rewrite(Node *parsetree);
|
||||
extern List *pg_parse_and_rewrite(char *query_string,
|
||||
Oid *typev, int nargs);
|
||||
extern Plan *pg_plan_query(Query *querytree);
|
||||
extern void pg_exec_query_string(StringInfo query_string,
|
||||
CommandDest dest,
|
||||
MemoryContext parse_context);
|
||||
|
||||
#endif /* BOOTSTRAP_INCLUDE */
|
||||
|
||||
extern void die(SIGNAL_ARGS);
|
||||
|
Loading…
Reference in New Issue
Block a user