Commit 11f7b290 authored by Tom Lane's avatar Tom Lane

Allow ORDER BY, LIMIT in sub-selects. Fix most (not all) cases where

the grammar did not allow redundant parentheses around sub-selects.
Distinguish LIMIT ALL from LIMIT 0; make the latter behave as one would
expect.
parent 66436e66
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.1 2000/10/26 21:35:15 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.2 2000/11/05 00:15:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -188,17 +188,11 @@ recompute_limits(Limit *node)
econtext,
&isNull,
NULL));
/* Interpret NULL count as no count */
/* Interpret NULL count as no count (LIMIT ALL) */
if (isNull)
limitstate->noCount = true;
else
{
/* Currently, LIMIT 0 is specified as meaning no limit.
* I think this is pretty bogus, but ...
*/
if (limitstate->count <= 0)
limitstate->noCount = true;
}
else if (limitstate->count < 0)
limitstate->count = 0;
}
else
{
......
......@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.128 2000/10/31 10:22:10 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.129 2000/11/05 00:15:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1826,6 +1826,7 @@ _copySelectStmt(SelectStmt *from)
Node_Copy(from, newnode, distinctClause);
if (from->into)
newnode->into = pstrdup(from->into);
newnode->istemp = from->istemp;
Node_Copy(from, newnode, targetList);
Node_Copy(from, newnode, fromClause);
Node_Copy(from, newnode, whereClause);
......@@ -1835,10 +1836,13 @@ _copySelectStmt(SelectStmt *from)
if (from->portalname)
newnode->portalname = pstrdup(from->portalname);
newnode->binary = from->binary;
newnode->istemp = from->istemp;
Node_Copy(from, newnode, limitOffset);
Node_Copy(from, newnode, limitCount);
Node_Copy(from, newnode, forUpdate);
newnode->op = from->op;
newnode->all = from->all;
Node_Copy(from, newnode, larg);
Node_Copy(from, newnode, rarg);
return newnode;
}
......
......@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.78 2000/10/31 10:22:10 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.79 2000/11/05 00:15:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -686,6 +686,8 @@ _equalSelectStmt(SelectStmt *a, SelectStmt *b)
return false;
if (!equalstr(a->into, b->into))
return false;
if (a->istemp != b->istemp)
return false;
if (!equal(a->targetList, b->targetList))
return false;
if (!equal(a->fromClause, b->fromClause))
......@@ -702,14 +704,20 @@ _equalSelectStmt(SelectStmt *a, SelectStmt *b)
return false;
if (a->binary != b->binary)
return false;
if (a->istemp != b->istemp)
return false;
if (!equal(a->limitOffset, b->limitOffset))
return false;
if (!equal(a->limitCount, b->limitCount))
return false;
if (!equal(a->forUpdate, b->forUpdate))
return false;
if (a->op != b->op)
return false;
if (a->all != b->all)
return false;
if (!equal(a->larg, b->larg))
return false;
if (!equal(a->rarg, b->rarg))
return false;
return true;
}
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.93 2000/10/26 21:36:09 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.94 2000/11/05 00:15:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -809,25 +809,26 @@ union_planner(Query *parse,
if (IsA(parse->limitCount, Const))
{
Const *limitc = (Const *) parse->limitCount;
int count = (int) (limitc->constvalue);
int32 count = DatumGetInt32(limitc->constvalue);
/*
* The constant can legally be either 0 ("ALL") or a
* positive integer. If it is not ALL, we also need
* to consider the OFFSET part of LIMIT.
* A NULL-constant LIMIT represents "LIMIT ALL",
* which we treat the same as no limit (ie,
* expect to retrieve all the tuples).
*/
if (count > 0)
if (!limitc->constisnull && count > 0)
{
tuple_fraction = (double) count;
/* We must also consider the OFFSET, if present */
if (parse->limitOffset != NULL)
{
if (IsA(parse->limitOffset, Const))
{
int offset;
int32 offset;
limitc = (Const *) parse->limitOffset;
offset = (int) (limitc->constvalue);
if (offset > 0)
offset = DatumGetInt32(limitc->constvalue);
if (!limitc->constisnull && offset > 0)
tuple_fraction += (double) offset;
}
else
......@@ -850,14 +851,14 @@ union_planner(Query *parse,
}
/*
* Check for a retrieve-into-portal, ie DECLARE CURSOR.
* If no LIMIT, check for retrieve-into-portal, ie DECLARE CURSOR.
*
* We have no real idea how many tuples the user will ultimately
* FETCH from a cursor, but it seems a good bet that he
* doesn't want 'em all. Optimize for 10% retrieval (you
* gotta better number?)
*/
if (parse->isPortal)
else if (parse->isPortal)
tuple_fraction = 0.10;
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -3,7 +3,7 @@
* back to source text
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.67 2000/10/26 21:37:45 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.68 2000/11/05 00:15:53 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
......@@ -941,7 +941,11 @@ get_select_query_def(Query *query, deparse_context *context)
if (query->limitCount != NULL)
{
appendStringInfo(buf, " LIMIT ");
get_rule_expr(query->limitCount, context);
if (IsA(query->limitCount, Const) &&
((Const *) query->limitCount)->constisnull)
appendStringInfo(buf, "ALL");
else
get_rule_expr(query->limitCount, context);
}
}
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parsenodes.h,v 1.117 2000/10/18 16:16:10 momjian Exp $
* $Id: parsenodes.h,v 1.118 2000/11/05 00:15:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -782,7 +782,7 @@ typedef struct InsertStmt
/*
* An INSERT statement has *either* VALUES or SELECT, never both.
* If VALUES, a targetList is supplied (empty for DEFAULT VALUES).
* If SELECT, a complete SelectStmt (or SetOperation tree) is supplied.
* If SELECT, a complete SelectStmt (or set-operation tree) is supplied.
*/
List *targetList; /* the target list (of ResTarget) */
Node *selectStmt; /* the source SELECT */
......@@ -816,51 +816,71 @@ typedef struct UpdateStmt
/* ----------------------
* Select Statement
*
* A "simple" SELECT is represented in the output of gram.y by a single
* SelectStmt node. A SELECT construct containing set operators (UNION,
* INTERSECT, EXCEPT) is represented by a tree of SelectStmt nodes, in
* which the leaf nodes are component SELECTs and the internal nodes
* represent UNION, INTERSECT, or EXCEPT operators. Using the same node
* type for both leaf and internal nodes allows gram.y to stick ORDER BY,
* LIMIT, etc, clause values into a SELECT statement without worrying
* whether it is a simple or compound SELECT.
* ----------------------
*/
typedef enum SetOperation
{
SETOP_NONE = 0,
SETOP_UNION,
SETOP_INTERSECT,
SETOP_EXCEPT
} SetOperation;
typedef struct SelectStmt
{
NodeTag type;
/*
* These fields are used only in "leaf" SelectStmts.
*/
List *distinctClause; /* NULL, list of DISTINCT ON exprs, or
* lcons(NIL,NIL) for all (SELECT
* DISTINCT) */
char *into; /* name of table (for select into table) */
bool istemp; /* into is a temp table? */
List *targetList; /* the target list (of ResTarget) */
List *fromClause; /* the from clause */
Node *whereClause; /* qualifications */
List *fromClause; /* the FROM clause */
Node *whereClause; /* WHERE qualification */
List *groupClause; /* GROUP BY clauses */
Node *havingClause; /* having conditional-expression */
Node *havingClause; /* HAVING conditional-expression */
/*
* These fields are used in both "leaf" SelectStmts and upper-level
* SelectStmts. portalname/binary may only be set at the top level.
*/
List *sortClause; /* sort clause (a list of SortGroupBy's) */
char *portalname; /* the portal (cursor) to create */
bool binary; /* a binary (internal) portal? */
bool istemp; /* into is a temp table */
Node *limitOffset; /* # of result tuples to skip */
Node *limitCount; /* # of result tuples to return */
List *forUpdate; /* FOR UPDATE clause */
/*
* These fields are used only in upper-level SelectStmts.
*/
SetOperation op; /* type of set op */
bool all; /* ALL specified? */
struct SelectStmt *larg; /* left child */
struct SelectStmt *rarg; /* right child */
/* Eventually add fields for CORRESPONDING spec here */
} SelectStmt;
/* ----------------------
* Select Statement with Set Operations
*
* UNION/INTERSECT/EXCEPT operations are represented in the output of gram.y
* as a tree whose leaves are SelectStmts and internal nodes are
* SetOperationStmts. The statement-wide info (ORDER BY, etc clauses)
* is placed in the leftmost SelectStmt leaf.
* Set Operation node for post-analysis query trees
*
* After parse analysis, there is a top-level Query node containing the leaf
* SELECTs as subqueries in its range table. Its setOperations field is the
* SetOperationStmt tree with leaf SelectStmt nodes replaced by RangeTblRef
* nodes. The statement-wide options such as ORDER BY are attached to this
* top-level Query.
* After parse analysis, a SELECT with set operations is represented by a
* top-level Query node containing the leaf SELECTs as subqueries in its
* range table. Its setOperations field shows the tree of set operations,
* with leaf SelectStmt nodes replaced by RangeTblRef nodes, and internal
* nodes replaced by SetOperationStmt nodes.
* ----------------------
*/
typedef enum SetOperation
{
SETOP_UNION,
SETOP_INTERSECT,
SETOP_EXCEPT
} SetOperation;
typedef struct SetOperationStmt
{
NodeTag type;
......@@ -870,7 +890,7 @@ typedef struct SetOperationStmt
Node *rarg; /* right child */
/* Eventually add fields for CORRESPONDING spec here */
/* This field is filled in during parse analysis: */
/* Fields derived during parse analysis: */
List *colTypes; /* integer list of OIDs of output column types */
} SetOperationStmt;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment