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 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -188,17 +188,11 @@ recompute_limits(Limit *node)
econtext, econtext,
&isNull, &isNull,
NULL)); NULL));
/* Interpret NULL count as no count */ /* Interpret NULL count as no count (LIMIT ALL) */
if (isNull) if (isNull)
limitstate->noCount = true; limitstate->noCount = true;
else else if (limitstate->count < 0)
{ limitstate->count = 0;
/* Currently, LIMIT 0 is specified as meaning no limit.
* I think this is pretty bogus, but ...
*/
if (limitstate->count <= 0)
limitstate->noCount = true;
}
} }
else else
{ {
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -1826,6 +1826,7 @@ _copySelectStmt(SelectStmt *from)
Node_Copy(from, newnode, distinctClause); Node_Copy(from, newnode, distinctClause);
if (from->into) if (from->into)
newnode->into = pstrdup(from->into); newnode->into = pstrdup(from->into);
newnode->istemp = from->istemp;
Node_Copy(from, newnode, targetList); Node_Copy(from, newnode, targetList);
Node_Copy(from, newnode, fromClause); Node_Copy(from, newnode, fromClause);
Node_Copy(from, newnode, whereClause); Node_Copy(from, newnode, whereClause);
...@@ -1835,10 +1836,13 @@ _copySelectStmt(SelectStmt *from) ...@@ -1835,10 +1836,13 @@ _copySelectStmt(SelectStmt *from)
if (from->portalname) if (from->portalname)
newnode->portalname = pstrdup(from->portalname); newnode->portalname = pstrdup(from->portalname);
newnode->binary = from->binary; newnode->binary = from->binary;
newnode->istemp = from->istemp;
Node_Copy(from, newnode, limitOffset); Node_Copy(from, newnode, limitOffset);
Node_Copy(from, newnode, limitCount); Node_Copy(from, newnode, limitCount);
Node_Copy(from, newnode, forUpdate); 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; return newnode;
} }
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -686,6 +686,8 @@ _equalSelectStmt(SelectStmt *a, SelectStmt *b)
return false; return false;
if (!equalstr(a->into, b->into)) if (!equalstr(a->into, b->into))
return false; return false;
if (a->istemp != b->istemp)
return false;
if (!equal(a->targetList, b->targetList)) if (!equal(a->targetList, b->targetList))
return false; return false;
if (!equal(a->fromClause, b->fromClause)) if (!equal(a->fromClause, b->fromClause))
...@@ -702,14 +704,20 @@ _equalSelectStmt(SelectStmt *a, SelectStmt *b) ...@@ -702,14 +704,20 @@ _equalSelectStmt(SelectStmt *a, SelectStmt *b)
return false; return false;
if (a->binary != b->binary) if (a->binary != b->binary)
return false; return false;
if (a->istemp != b->istemp)
return false;
if (!equal(a->limitOffset, b->limitOffset)) if (!equal(a->limitOffset, b->limitOffset))
return false; return false;
if (!equal(a->limitCount, b->limitCount)) if (!equal(a->limitCount, b->limitCount))
return false; return false;
if (!equal(a->forUpdate, b->forUpdate)) if (!equal(a->forUpdate, b->forUpdate))
return false; 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; return true;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -809,25 +809,26 @@ union_planner(Query *parse,
if (IsA(parse->limitCount, Const)) if (IsA(parse->limitCount, Const))
{ {
Const *limitc = (Const *) parse->limitCount; 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 * A NULL-constant LIMIT represents "LIMIT ALL",
* positive integer. If it is not ALL, we also need * which we treat the same as no limit (ie,
* to consider the OFFSET part of LIMIT. * expect to retrieve all the tuples).
*/ */
if (count > 0) if (!limitc->constisnull && count > 0)
{ {
tuple_fraction = (double) count; tuple_fraction = (double) count;
/* We must also consider the OFFSET, if present */
if (parse->limitOffset != NULL) if (parse->limitOffset != NULL)
{ {
if (IsA(parse->limitOffset, Const)) if (IsA(parse->limitOffset, Const))
{ {
int offset; int32 offset;
limitc = (Const *) parse->limitOffset; limitc = (Const *) parse->limitOffset;
offset = (int) (limitc->constvalue); offset = DatumGetInt32(limitc->constvalue);
if (offset > 0) if (!limitc->constisnull && offset > 0)
tuple_fraction += (double) offset; tuple_fraction += (double) offset;
} }
else else
...@@ -850,14 +851,14 @@ union_planner(Query *parse, ...@@ -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 * We have no real idea how many tuples the user will ultimately
* FETCH from a cursor, but it seems a good bet that he * FETCH from a cursor, but it seems a good bet that he
* doesn't want 'em all. Optimize for 10% retrieval (you * doesn't want 'em all. Optimize for 10% retrieval (you
* gotta better number?) * gotta better number?)
*/ */
if (parse->isPortal) else if (parse->isPortal)
tuple_fraction = 0.10; tuple_fraction = 0.10;
} }
......
This diff is collapsed.
This diff is collapsed.
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* back to source text * back to source text
* *
* IDENTIFICATION * 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. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -941,7 +941,11 @@ get_select_query_def(Query *query, deparse_context *context) ...@@ -941,7 +941,11 @@ get_select_query_def(Query *query, deparse_context *context)
if (query->limitCount != NULL) if (query->limitCount != NULL)
{ {
appendStringInfo(buf, " LIMIT "); 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 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 ...@@ -782,7 +782,7 @@ typedef struct InsertStmt
/* /*
* An INSERT statement has *either* VALUES or SELECT, never both. * An INSERT statement has *either* VALUES or SELECT, never both.
* If VALUES, a targetList is supplied (empty for DEFAULT VALUES). * 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) */ List *targetList; /* the target list (of ResTarget) */
Node *selectStmt; /* the source SELECT */ Node *selectStmt; /* the source SELECT */
...@@ -816,51 +816,71 @@ typedef struct UpdateStmt ...@@ -816,51 +816,71 @@ typedef struct UpdateStmt
/* ---------------------- /* ----------------------
* Select Statement * 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 typedef struct SelectStmt
{ {
NodeTag type; NodeTag type;
/*
* These fields are used only in "leaf" SelectStmts.
*/
List *distinctClause; /* NULL, list of DISTINCT ON exprs, or List *distinctClause; /* NULL, list of DISTINCT ON exprs, or
* lcons(NIL,NIL) for all (SELECT * lcons(NIL,NIL) for all (SELECT
* DISTINCT) */ * DISTINCT) */
char *into; /* name of table (for select into table) */ char *into; /* name of table (for select into table) */
bool istemp; /* into is a temp table? */
List *targetList; /* the target list (of ResTarget) */ List *targetList; /* the target list (of ResTarget) */
List *fromClause; /* the from clause */ List *fromClause; /* the FROM clause */
Node *whereClause; /* qualifications */ Node *whereClause; /* WHERE qualification */
List *groupClause; /* GROUP BY clauses */ 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) */ List *sortClause; /* sort clause (a list of SortGroupBy's) */
char *portalname; /* the portal (cursor) to create */ char *portalname; /* the portal (cursor) to create */
bool binary; /* a binary (internal) portal? */ bool binary; /* a binary (internal) portal? */
bool istemp; /* into is a temp table */
Node *limitOffset; /* # of result tuples to skip */ Node *limitOffset; /* # of result tuples to skip */
Node *limitCount; /* # of result tuples to return */ Node *limitCount; /* # of result tuples to return */
List *forUpdate; /* FOR UPDATE clause */ 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; } SelectStmt;
/* ---------------------- /* ----------------------
* Select Statement with Set Operations * Set Operation node for post-analysis query trees
*
* 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.
* *
* After parse analysis, there is a top-level Query node containing the leaf * After parse analysis, a SELECT with set operations is represented by a
* SELECTs as subqueries in its range table. Its setOperations field is the * top-level Query node containing the leaf SELECTs as subqueries in its
* SetOperationStmt tree with leaf SelectStmt nodes replaced by RangeTblRef * range table. Its setOperations field shows the tree of set operations,
* nodes. The statement-wide options such as ORDER BY are attached to this * with leaf SelectStmt nodes replaced by RangeTblRef nodes, and internal
* top-level Query. * nodes replaced by SetOperationStmt nodes.
* ---------------------- * ----------------------
*/ */
typedef enum SetOperation
{
SETOP_UNION,
SETOP_INTERSECT,
SETOP_EXCEPT
} SetOperation;
typedef struct SetOperationStmt typedef struct SetOperationStmt
{ {
NodeTag type; NodeTag type;
...@@ -870,7 +890,7 @@ typedef struct SetOperationStmt ...@@ -870,7 +890,7 @@ typedef struct SetOperationStmt
Node *rarg; /* right child */ Node *rarg; /* right child */
/* Eventually add fields for CORRESPONDING spec here */ /* 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 */ List *colTypes; /* integer list of OIDs of output column types */
} SetOperationStmt; } 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