1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* analyze.c--
|
1997-09-07 07:04:48 +02:00
|
|
|
* transform the parse tree into a query tree
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
1997-11-26 02:14:33 +01:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.51 1997/11/26 01:11:03 momjian Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1997-11-25 23:07:18 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
1997-04-02 06:01:03 +02:00
|
|
|
|
1997-11-26 02:14:33 +01:00
|
|
|
#include "postgres.h"
|
1997-11-25 23:07:18 +01:00
|
|
|
#include "access/heapam.h"
|
|
|
|
#include "nodes/makefuncs.h"
|
|
|
|
#include "nodes/memnodes.h"
|
|
|
|
#include "nodes/pg_list.h"
|
|
|
|
#include "parser/analyze.h"
|
|
|
|
#include "parser/parse_agg.h"
|
1997-11-26 02:14:33 +01:00
|
|
|
#include "parser/parse_clause.h"
|
1997-11-25 23:07:18 +01:00
|
|
|
#include "parser/parse_node.h"
|
|
|
|
#include "parser/parse_relation.h"
|
|
|
|
#include "parser/parse_target.h"
|
|
|
|
#include "utils/builtins.h"
|
|
|
|
#include "utils/mcxt.h"
|
1996-11-26 04:20:35 +01:00
|
|
|
|
1997-09-08 23:56:23 +02:00
|
|
|
static Query *transformStmt(ParseState *pstate, Node *stmt);
|
|
|
|
static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
|
|
|
|
static Query *transformInsertStmt(ParseState *pstate, AppendStmt *stmt);
|
|
|
|
static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt);
|
|
|
|
static Query *transformExtendStmt(ParseState *pstate, ExtendStmt *stmt);
|
|
|
|
static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt);
|
|
|
|
static Query *transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt);
|
|
|
|
static Query *transformUpdateStmt(ParseState *pstate, ReplaceStmt *stmt);
|
|
|
|
static Query *transformCursorStmt(ParseState *pstate, CursorStmt *stmt);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1996-10-30 03:02:41 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
|
|
|
* parse_analyze -
|
1997-09-07 07:04:48 +02:00
|
|
|
* analyze a list of parse trees and transform them if necessary.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* Returns a list of transformed parse trees. Optimizable statements are
|
|
|
|
* all transformed to Query while the rest stays the same.
|
|
|
|
*
|
|
|
|
* CALLER is responsible for freeing the QueryTreeList* returned
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
QueryTreeList *
|
1997-09-08 23:56:23 +02:00
|
|
|
parse_analyze(List *pl)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
QueryTreeList *result;
|
|
|
|
ParseState *pstate;
|
|
|
|
int i = 0;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
result = malloc(sizeof(QueryTreeList));
|
|
|
|
result->len = length(pl);
|
|
|
|
result->qtrees = (Query **) malloc(result->len * sizeof(Query *));
|
|
|
|
|
|
|
|
while (pl != NIL)
|
|
|
|
{
|
1997-11-25 23:07:18 +01:00
|
|
|
pstate = make_parsestate();
|
1997-09-07 07:04:48 +02:00
|
|
|
result->qtrees[i++] = transformStmt(pstate, lfirst(pl));
|
|
|
|
pl = lnext(pl);
|
|
|
|
if (pstate->p_target_relation != NULL)
|
|
|
|
heap_close(pstate->p_target_relation);
|
|
|
|
free(pstate);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transformStmt -
|
1997-09-07 07:04:48 +02:00
|
|
|
* transform a Parse tree. If it is an optimizable statement, turn it
|
|
|
|
* into a Query tree.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Query *
|
1997-09-08 23:56:23 +02:00
|
|
|
transformStmt(ParseState *pstate, Node *parseTree)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Query *result = NULL;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
switch (nodeTag(parseTree))
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
/*------------------------
|
|
|
|
* Non-optimizable statements
|
|
|
|
*------------------------
|
|
|
|
*/
|
|
|
|
case T_IndexStmt:
|
|
|
|
result = transformIndexStmt(pstate, (IndexStmt *) parseTree);
|
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_ExtendStmt:
|
|
|
|
result = transformExtendStmt(pstate, (ExtendStmt *) parseTree);
|
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_RuleStmt:
|
|
|
|
result = transformRuleStmt(pstate, (RuleStmt *) parseTree);
|
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_ViewStmt:
|
|
|
|
{
|
|
|
|
ViewStmt *n = (ViewStmt *) parseTree;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
n->query = (Query *) transformStmt(pstate, (Node *) n->query);
|
|
|
|
result = makeNode(Query);
|
|
|
|
result->commandType = CMD_UTILITY;
|
|
|
|
result->utilityStmt = (Node *) n;
|
|
|
|
}
|
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_VacuumStmt:
|
|
|
|
{
|
|
|
|
MemoryContext oldcontext;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
/*
|
|
|
|
* make sure that this Query is allocated in TopMemory
|
|
|
|
* context because vacuum spans transactions and we don't
|
|
|
|
* want to lose the vacuum Query due to end-of-transaction
|
|
|
|
* free'ing
|
|
|
|
*/
|
|
|
|
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
|
|
|
|
result = makeNode(Query);
|
|
|
|
result->commandType = CMD_UTILITY;
|
|
|
|
result->utilityStmt = (Node *) parseTree;
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
}
|
|
|
|
case T_ExplainStmt:
|
|
|
|
{
|
|
|
|
ExplainStmt *n = (ExplainStmt *) parseTree;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
result = makeNode(Query);
|
|
|
|
result->commandType = CMD_UTILITY;
|
|
|
|
n->query = transformStmt(pstate, (Node *) n->query);
|
|
|
|
result->utilityStmt = (Node *) parseTree;
|
|
|
|
}
|
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
/*------------------------
|
|
|
|
* Optimizable statements
|
|
|
|
*------------------------
|
|
|
|
*/
|
|
|
|
case T_AppendStmt:
|
|
|
|
result = transformInsertStmt(pstate, (AppendStmt *) parseTree);
|
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_DeleteStmt:
|
|
|
|
result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);
|
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_ReplaceStmt:
|
|
|
|
result = transformUpdateStmt(pstate, (ReplaceStmt *) parseTree);
|
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_CursorStmt:
|
|
|
|
result = transformCursorStmt(pstate, (CursorStmt *) parseTree);
|
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_RetrieveStmt:
|
|
|
|
result = transformSelectStmt(pstate, (RetrieveStmt *) parseTree);
|
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
default:
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
/*
|
|
|
|
* other statments don't require any transformation-- just
|
|
|
|
* return the original parsetree
|
|
|
|
*/
|
|
|
|
result = makeNode(Query);
|
|
|
|
result->commandType = CMD_UTILITY;
|
|
|
|
result->utilityStmt = (Node *) parseTree;
|
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
return result;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transformDeleteStmt -
|
1997-09-07 07:04:48 +02:00
|
|
|
* transforms a Delete Statement
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Query *
|
1997-09-08 23:56:23 +02:00
|
|
|
transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Query *qry = makeNode(Query);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
qry->commandType = CMD_DELETE;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* set up a range table */
|
|
|
|
makeRangeTable(pstate, stmt->relname, NULL);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
qry->uniqueFlag = NULL;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* fix where clause */
|
|
|
|
qry->qual = transformWhereClause(pstate, stmt->whereClause);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
qry->rtable = pstate->p_rtable;
|
|
|
|
qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
|
|
|
|
|
|
|
|
/* make sure we don't have aggregates in the where clause */
|
|
|
|
if (pstate->p_numAgg > 0)
|
|
|
|
parseCheckAggregates(pstate, qry);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return (Query *) qry;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transformInsertStmt -
|
1997-09-07 07:04:48 +02:00
|
|
|
* transform an Insert Statement
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Query *
|
1997-09-08 23:56:23 +02:00
|
|
|
transformInsertStmt(ParseState *pstate, AppendStmt *stmt)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Query *qry = makeNode(Query); /* make a new query tree */
|
1997-10-12 09:09:20 +02:00
|
|
|
List *icolumns;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
qry->commandType = CMD_INSERT;
|
|
|
|
pstate->p_is_insert = true;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* set up a range table */
|
|
|
|
makeRangeTable(pstate, stmt->relname, stmt->fromClause);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
qry->uniqueFlag = NULL;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* fix the target list */
|
1997-10-12 09:09:20 +02:00
|
|
|
icolumns = pstate->p_insert_columns = makeTargetNames(pstate, stmt->cols);
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
qry->targetList = transformTargetList(pstate, stmt->targetList);
|
1997-10-12 09:09:20 +02:00
|
|
|
|
|
|
|
/* DEFAULT handling */
|
|
|
|
if (length(qry->targetList) < pstate->p_target_relation->rd_att->natts &&
|
|
|
|
pstate->p_target_relation->rd_att->constr &&
|
|
|
|
pstate->p_target_relation->rd_att->constr->num_defval > 0)
|
|
|
|
{
|
|
|
|
AttributeTupleForm *att = pstate->p_target_relation->rd_att->attrs;
|
|
|
|
AttrDefault *defval = pstate->p_target_relation->rd_att->constr->defval;
|
|
|
|
int ndef = pstate->p_target_relation->rd_att->constr->num_defval;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if stmt->cols == NIL then makeTargetNames returns list of all
|
|
|
|
* attrs: have to shorter icolumns list...
|
|
|
|
*/
|
|
|
|
if (stmt->cols == NIL)
|
|
|
|
{
|
|
|
|
List *extrl;
|
|
|
|
int i = length(qry->targetList);
|
|
|
|
|
|
|
|
foreach (extrl, icolumns)
|
|
|
|
{
|
|
|
|
if (--i <= 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
freeList (lnext(extrl));
|
|
|
|
lnext(extrl) = NIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (ndef-- > 0)
|
|
|
|
{
|
|
|
|
List *tl;
|
|
|
|
Ident *id;
|
|
|
|
TargetEntry *te;
|
|
|
|
|
|
|
|
foreach (tl, icolumns)
|
|
|
|
{
|
|
|
|
id = (Ident *) lfirst(tl);
|
|
|
|
if (!namestrcmp(&(att[defval[ndef].adnum - 1]->attname), id->name))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (tl != NIL) /* something given for this attr */
|
|
|
|
continue;
|
|
|
|
/*
|
|
|
|
* Nothing given for this attr with DEFAULT expr, so
|
|
|
|
* add new TargetEntry to qry->targetList.
|
|
|
|
* Note, that we set resno to defval[ndef].adnum:
|
|
|
|
* it's what transformTargetList()->make_targetlist_expr()
|
|
|
|
* does for INSERT ... SELECT. But for INSERT ... VALUES
|
|
|
|
* pstate->p_last_resno is used. It doesn't matter for
|
|
|
|
* "normal" using (planner creates proper target list
|
|
|
|
* in preptlist.c), but may break RULEs in some way.
|
|
|
|
* It seems better to create proper target list here...
|
|
|
|
*/
|
|
|
|
te = makeNode(TargetEntry);
|
|
|
|
te->resdom = makeResdom(defval[ndef].adnum,
|
|
|
|
att[defval[ndef].adnum - 1]->atttypid,
|
|
|
|
att[defval[ndef].adnum - 1]->attlen,
|
|
|
|
pstrdup(nameout(&(att[defval[ndef].adnum - 1]->attname))),
|
|
|
|
0, 0, 0);
|
|
|
|
te->fjoin = NULL;
|
|
|
|
te->expr = (Node *) stringToNode(defval[ndef].adbin);
|
|
|
|
qry->targetList = lappend (qry->targetList, te);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* fix where clause */
|
|
|
|
qry->qual = transformWhereClause(pstate, stmt->whereClause);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* now the range table will not change */
|
|
|
|
qry->rtable = pstate->p_rtable;
|
|
|
|
qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (pstate->p_numAgg > 0)
|
|
|
|
finalizeAggregates(pstate, qry);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return (Query *) qry;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transformIndexStmt -
|
1997-09-07 07:04:48 +02:00
|
|
|
* transforms the qualification of the index statement
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Query *
|
1997-09-08 23:56:23 +02:00
|
|
|
transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Query *q;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
q = makeNode(Query);
|
|
|
|
q->commandType = CMD_UTILITY;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* take care of the where clause */
|
|
|
|
stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
|
|
|
|
stmt->rangetable = pstate->p_rtable;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
q->utilityStmt = (Node *) stmt;
|
|
|
|
|
|
|
|
return q;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transformExtendStmt -
|
1997-09-07 07:04:48 +02:00
|
|
|
* transform the qualifications of the Extend Index Statement
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Query *
|
1997-09-08 23:56:23 +02:00
|
|
|
transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Query *q;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
q = makeNode(Query);
|
|
|
|
q->commandType = CMD_UTILITY;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* take care of the where clause */
|
|
|
|
stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
|
|
|
|
stmt->rangetable = pstate->p_rtable;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
q->utilityStmt = (Node *) stmt;
|
|
|
|
return q;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transformRuleStmt -
|
1997-09-07 07:04:48 +02:00
|
|
|
* transform a Create Rule Statement. The actions is a list of parse
|
|
|
|
* trees which is transformed into a list of query trees.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Query *
|
1997-09-08 23:56:23 +02:00
|
|
|
transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Query *q;
|
|
|
|
List *actions;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
q = makeNode(Query);
|
|
|
|
q->commandType = CMD_UTILITY;
|
|
|
|
|
|
|
|
actions = stmt->actions;
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* transform each statment, like parse_analyze()
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
while (actions != NIL)
|
|
|
|
{
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
|
|
|
* NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
|
|
|
|
* equal to 2.
|
|
|
|
*/
|
|
|
|
addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
|
1997-11-21 00:24:03 +01:00
|
|
|
FALSE, FALSE);
|
1997-09-07 07:04:48 +02:00
|
|
|
addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
|
1997-11-21 00:24:03 +01:00
|
|
|
FALSE, FALSE);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
pstate->p_last_resno = 1;
|
|
|
|
pstate->p_is_rule = true; /* for expand all */
|
|
|
|
pstate->p_numAgg = 0;
|
|
|
|
pstate->p_aggs = NULL;
|
|
|
|
|
|
|
|
lfirst(actions) = transformStmt(pstate, lfirst(actions));
|
|
|
|
actions = lnext(actions);
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* take care of the where clause */
|
|
|
|
stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
q->utilityStmt = (Node *) stmt;
|
|
|
|
return q;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transformSelectStmt -
|
1997-09-07 07:04:48 +02:00
|
|
|
* transforms a Select Statement
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Query *
|
1997-09-08 23:56:23 +02:00
|
|
|
transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Query *qry = makeNode(Query);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
qry->commandType = CMD_SELECT;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* set up a range table */
|
|
|
|
makeRangeTable(pstate, NULL, stmt->fromClause);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
qry->uniqueFlag = stmt->unique;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
qry->into = stmt->into;
|
|
|
|
qry->isPortal = FALSE;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* fix the target list */
|
|
|
|
qry->targetList = transformTargetList(pstate, stmt->targetList);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* fix where clause */
|
|
|
|
qry->qual = transformWhereClause(pstate, stmt->whereClause);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* check subselect clause */
|
|
|
|
if (stmt->selectClause)
|
|
|
|
elog(NOTICE, "UNION not yet supported; using first SELECT only", NULL);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* check subselect clause */
|
|
|
|
if (stmt->havingClause)
|
|
|
|
elog(NOTICE, "HAVING not yet supported; ignore clause", NULL);
|
1997-09-01 07:56:34 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* fix order clause */
|
|
|
|
qry->sortClause = transformSortClause(pstate,
|
|
|
|
stmt->sortClause,
|
|
|
|
qry->targetList,
|
|
|
|
qry->uniqueFlag);
|
1997-09-01 07:56:34 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* fix group by clause */
|
|
|
|
qry->groupClause = transformGroupClause(pstate,
|
|
|
|
stmt->groupClause,
|
|
|
|
qry->targetList);
|
|
|
|
qry->rtable = pstate->p_rtable;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (pstate->p_numAgg > 0)
|
|
|
|
finalizeAggregates(pstate, qry);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return (Query *) qry;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transformUpdateStmt -
|
1997-09-07 07:04:48 +02:00
|
|
|
* transforms an update statement
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Query *
|
1997-09-08 23:56:23 +02:00
|
|
|
transformUpdateStmt(ParseState *pstate, ReplaceStmt *stmt)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Query *qry = makeNode(Query);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
qry->commandType = CMD_UPDATE;
|
|
|
|
pstate->p_is_update = true;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
|
|
|
* the FROM clause is non-standard SQL syntax. We used to be able to
|
|
|
|
* do this with REPLACE in POSTQUEL so we keep the feature.
|
|
|
|
*/
|
|
|
|
makeRangeTable(pstate, stmt->relname, stmt->fromClause);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* fix the target list */
|
|
|
|
qry->targetList = transformTargetList(pstate, stmt->targetList);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* fix where clause */
|
|
|
|
qry->qual = transformWhereClause(pstate, stmt->whereClause);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
qry->rtable = pstate->p_rtable;
|
|
|
|
qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* make sure we don't have aggregates in the where clause */
|
|
|
|
if (pstate->p_numAgg > 0)
|
|
|
|
parseCheckAggregates(pstate, qry);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return (Query *) qry;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transformCursorStmt -
|
1997-09-07 07:04:48 +02:00
|
|
|
* transform a Create Cursor Statement
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Query *
|
1997-09-08 23:56:23 +02:00
|
|
|
transformCursorStmt(ParseState *pstate, CursorStmt *stmt)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Query *qry = makeNode(Query);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
|
|
|
* in the old days, a cursor statement is a 'retrieve into portal'; If
|
|
|
|
* you change the following, make sure you also go through the code in
|
|
|
|
* various places that tests the kind of operation.
|
|
|
|
*/
|
|
|
|
qry->commandType = CMD_SELECT;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* set up a range table */
|
|
|
|
makeRangeTable(pstate, NULL, stmt->fromClause);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
qry->uniqueFlag = stmt->unique;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
qry->into = stmt->portalname;
|
|
|
|
qry->isPortal = TRUE;
|
|
|
|
qry->isBinary = stmt->binary; /* internal portal */
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* fix the target list */
|
|
|
|
qry->targetList = transformTargetList(pstate, stmt->targetList);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* fix where clause */
|
|
|
|
qry->qual = transformWhereClause(pstate, stmt->whereClause);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* fix order clause */
|
|
|
|
qry->sortClause = transformSortClause(pstate,
|
|
|
|
stmt->sortClause,
|
|
|
|
qry->targetList,
|
|
|
|
qry->uniqueFlag);
|
|
|
|
/* fix group by clause */
|
|
|
|
qry->groupClause = transformGroupClause(pstate,
|
|
|
|
stmt->groupClause,
|
|
|
|
qry->targetList);
|
1996-08-06 18:27:59 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
qry->rtable = pstate->p_rtable;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (pstate->p_numAgg > 0)
|
|
|
|
finalizeAggregates(pstate, qry);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return (Query *) qry;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|