1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* pquery.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* POSTGRES process query command code
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2002-06-20 22:29:54 +02:00
|
|
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2002-11-18 02:17:39 +01:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.56 2002/11/18 01:17:39 tgl Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1996-11-08 07:02:30 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "postgres.h"
|
|
|
|
|
2002-04-15 07:22:04 +02:00
|
|
|
#include "commands/portalcmds.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "executor/execdefs.h"
|
|
|
|
#include "executor/executor.h"
|
|
|
|
#include "tcop/pquery.h"
|
2000-07-17 05:05:41 +02:00
|
|
|
#include "utils/memutils.h"
|
1998-08-25 23:24:12 +02:00
|
|
|
#include "utils/ps_status.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2000-07-17 05:05:41 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* CreateQueryDesc
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
2001-10-25 07:50:21 +02:00
|
|
|
QueryDesc *
|
1997-09-08 23:56:23 +02:00
|
|
|
CreateQueryDesc(Query *parsetree,
|
|
|
|
Plan *plantree,
|
2002-02-27 20:36:13 +01:00
|
|
|
CommandDest dest,
|
|
|
|
const char *portalName)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
QueryDesc *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
qd->operation = parsetree->commandType; /* operation */
|
|
|
|
qd->parsetree = parsetree; /* parse tree */
|
|
|
|
qd->plantree = plantree; /* plan */
|
|
|
|
qd->dest = dest; /* output dest */
|
2002-09-04 22:31:48 +02:00
|
|
|
qd->portalName = portalName; /* name, if dest is a portal */
|
2002-02-27 20:36:13 +01:00
|
|
|
qd->tupDesc = NULL; /* until set by ExecutorStart */
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return qd;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* CreateExecutorState
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* Note: this may someday take parameters -cim 9/18/89
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
1998-02-26 05:46:47 +01:00
|
|
|
EState *
|
1996-11-10 04:06:38 +01:00
|
|
|
CreateExecutorState(void)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
EState *state;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* create a new executor state
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
state = makeNode(EState);
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* initialize the Executor State structure
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
state->es_direction = ForwardScanDirection;
|
|
|
|
state->es_range_table = NIL;
|
|
|
|
|
2000-11-12 01:37:02 +01:00
|
|
|
state->es_result_relations = NULL;
|
|
|
|
state->es_num_result_relations = 0;
|
1997-09-07 07:04:48 +02:00
|
|
|
state->es_result_relation_info = NULL;
|
2000-11-12 01:37:02 +01:00
|
|
|
|
|
|
|
state->es_junkFilter = NULL;
|
|
|
|
|
2000-08-22 06:06:22 +02:00
|
|
|
state->es_into_relation_descriptor = NULL;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
state->es_param_list_info = NULL;
|
1998-02-13 04:42:32 +01:00
|
|
|
state->es_param_exec_vals = NULL;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
state->es_tupleTable = NULL;
|
|
|
|
|
2000-08-22 06:06:22 +02:00
|
|
|
state->es_query_cxt = CurrentMemoryContext;
|
|
|
|
|
|
|
|
state->es_per_tuple_exprcontext = NULL;
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* return the executor state structure
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
return state;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
2000-06-28 05:33:33 +02:00
|
|
|
* PreparePortal
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
2000-06-28 05:33:33 +02:00
|
|
|
Portal
|
|
|
|
PreparePortal(char *portalName)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Portal portal;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* Check for already-in-use portal name.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-06-05 00:08:53 +02:00
|
|
|
portal = GetPortalByName(portalName);
|
|
|
|
if (PortalIsValid(portal))
|
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
/*
|
|
|
|
* XXX Should we raise an error rather than closing the old
|
|
|
|
* portal?
|
|
|
|
*/
|
2002-03-06 07:10:59 +01:00
|
|
|
elog(WARNING, "Closing pre-existing portal \"%s\"",
|
1997-09-07 07:04:48 +02:00
|
|
|
portalName);
|
2001-10-05 19:28:13 +02:00
|
|
|
PortalDrop(portal);
|
2000-06-05 00:08:53 +02:00
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* Create the new portal.
|
2000-06-05 00:08:53 +02:00
|
|
|
*/
|
2000-06-28 05:33:33 +02:00
|
|
|
portal = CreatePortal(portalName);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-06-28 05:33:33 +02:00
|
|
|
return portal;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-02-26 23:47:12 +01:00
|
|
|
/*
|
|
|
|
* ProcessQuery
|
|
|
|
* Execute a query
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2002-02-26 23:47:12 +01:00
|
|
|
* parsetree: the query tree
|
|
|
|
* plan: the plan tree for the query
|
|
|
|
* dest: where to send results
|
|
|
|
* completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
|
|
|
|
* in which to store a command completion status string.
|
|
|
|
*
|
|
|
|
* completionTag may be NULL if caller doesn't want a status string.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-06-28 05:33:33 +02:00
|
|
|
void
|
|
|
|
ProcessQuery(Query *parsetree,
|
|
|
|
Plan *plan,
|
2002-02-26 23:47:12 +01:00
|
|
|
CommandDest dest,
|
|
|
|
char *completionTag)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-06-28 05:33:33 +02:00
|
|
|
int operation = parsetree->commandType;
|
2002-02-27 20:36:13 +01:00
|
|
|
bool isRetrieveIntoPortal = false;
|
1997-09-08 04:41:22 +02:00
|
|
|
char *intoName = NULL;
|
2000-08-22 06:06:22 +02:00
|
|
|
Portal portal = NULL;
|
|
|
|
MemoryContext oldContext = NULL;
|
2000-06-28 05:33:33 +02:00
|
|
|
QueryDesc *queryDesc;
|
|
|
|
EState *state;
|
|
|
|
TupleDesc attinfo;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2002-02-27 20:36:13 +01:00
|
|
|
* Check for special-case destinations
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
if (operation == CMD_SELECT)
|
|
|
|
{
|
2000-06-28 05:33:33 +02:00
|
|
|
if (parsetree->isPortal)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
isRetrieveIntoPortal = true;
|
2002-02-27 20:36:13 +01:00
|
|
|
/* If binary portal, switch to alternate output format */
|
|
|
|
if (dest == Remote && parsetree->isBinary)
|
2000-06-28 05:33:33 +02:00
|
|
|
dest = RemoteInternal;
|
2002-11-18 02:17:39 +01:00
|
|
|
/* Check for invalid context (must be in transaction block) */
|
|
|
|
RequireTransactionChain((void *) parsetree, "DECLARE CURSOR");
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2000-06-28 05:33:33 +02:00
|
|
|
else if (parsetree->into != NULL)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2002-02-27 20:36:13 +01:00
|
|
|
/*
|
|
|
|
* SELECT INTO table (a/k/a CREATE AS ... SELECT).
|
|
|
|
*
|
|
|
|
* Override the normal communication destination; execMain.c
|
2002-09-04 22:31:48 +02:00
|
|
|
* special-cases this case. (Perhaps would be cleaner to have
|
|
|
|
* an additional destination type?)
|
2002-02-27 20:36:13 +01:00
|
|
|
*/
|
|
|
|
dest = None;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2000-06-28 05:33:33 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* If retrieving into a portal, set up the portal and copy the
|
|
|
|
* parsetree and plan into its memory context.
|
2000-06-28 05:33:33 +02:00
|
|
|
*/
|
|
|
|
if (isRetrieveIntoPortal)
|
|
|
|
{
|
2002-03-21 17:02:16 +01:00
|
|
|
intoName = parsetree->into->relname;
|
2000-06-28 05:33:33 +02:00
|
|
|
portal = PreparePortal(intoName);
|
2000-08-22 06:06:22 +02:00
|
|
|
oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
2000-06-28 05:33:33 +02:00
|
|
|
parsetree = copyObject(parsetree);
|
|
|
|
plan = copyObject(plan);
|
2002-09-04 22:31:48 +02:00
|
|
|
intoName = parsetree->into->relname; /* use copied name in
|
|
|
|
* QueryDesc */
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-08-22 06:06:22 +02:00
|
|
|
/*
|
|
|
|
* We stay in portal's memory context for now, so that query desc,
|
|
|
|
* EState, and plan startup info are also allocated in the portal
|
|
|
|
* context.
|
|
|
|
*/
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* Now we can create the QueryDesc object.
|
2000-06-28 05:33:33 +02:00
|
|
|
*/
|
2002-02-27 20:36:13 +01:00
|
|
|
queryDesc = CreateQueryDesc(parsetree, plan, dest, intoName);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* create a default executor state.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
state = CreateExecutorState();
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* call ExecStart to prepare the plan for execution
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
attinfo = ExecutorStart(queryDesc, state);
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* If retrieve into portal, stop now; we do not run the plan until a
|
|
|
|
* FETCH command is received.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
if (isRetrieveIntoPortal)
|
|
|
|
{
|
2000-06-28 05:33:33 +02:00
|
|
|
PortalSetQuery(portal,
|
|
|
|
queryDesc,
|
|
|
|
attinfo,
|
|
|
|
state,
|
|
|
|
PortalCleanup);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-08-22 06:06:22 +02:00
|
|
|
/* Now we can return to caller's memory context. */
|
|
|
|
MemoryContextSwitchTo(oldContext);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
/* Set completion tag. SQL calls this operation DECLARE CURSOR */
|
2002-02-26 23:47:12 +01:00
|
|
|
if (completionTag)
|
2002-05-18 17:44:48 +02:00
|
|
|
strcpy(completionTag, "DECLARE CURSOR");
|
2000-08-22 06:06:22 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* Now we get to the important call to ExecutorRun() where we actually
|
|
|
|
* run the plan..
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2002-02-27 20:36:13 +01:00
|
|
|
ExecutorRun(queryDesc, state, ForwardScanDirection, 0L);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2002-02-26 23:47:12 +01:00
|
|
|
* Build command completion status string, if caller wants one.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2002-02-26 23:47:12 +01:00
|
|
|
if (completionTag)
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
Oid lastOid;
|
2002-02-26 23:47:12 +01:00
|
|
|
|
|
|
|
switch (operation)
|
|
|
|
{
|
|
|
|
case CMD_SELECT:
|
|
|
|
strcpy(completionTag, "SELECT");
|
|
|
|
break;
|
|
|
|
case CMD_INSERT:
|
|
|
|
if (state->es_processed == 1)
|
|
|
|
lastOid = state->es_lastoid;
|
|
|
|
else
|
|
|
|
lastOid = InvalidOid;
|
|
|
|
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
|
|
|
"INSERT %u %u", lastOid, state->es_processed);
|
|
|
|
break;
|
|
|
|
case CMD_UPDATE:
|
|
|
|
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
|
|
|
"UPDATE %u", state->es_processed);
|
|
|
|
break;
|
|
|
|
case CMD_DELETE:
|
|
|
|
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
|
|
|
"DELETE %u", state->es_processed);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
strcpy(completionTag, "???");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2002-02-26 23:47:12 +01:00
|
|
|
* Now, we close down all the scans and free allocated resources.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2002-02-26 23:47:12 +01:00
|
|
|
ExecutorEnd(queryDesc, state);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|