INSERT.returning_one.patch
text/x-diff
Filename: INSERT.returning_one.patch
Type: text/x-diff
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| src/backend/nodes/copyfuncs.c | 2 | 0 |
| src/backend/optimizer/plan/planner.c | 2 | 1 |
| src/backend/rewrite/rewriteHandler.c | 64 | 13 |
| src/include/nodes/parsenodes.h | 2 | 0 |
| src/include/nodes/plannodes.h | 2 | 0 |
--- src/backend/optimizer/plan/planner.c.orig 2012-06-19 14:59:21.264574275 -0400
+++ src/backend/optimizer/plan/planner.c 2012-06-19 15:10:54.776590758 -0400
@@ -226,7 +226,8 @@ standard_planner(Query *parse, int curso
result->commandType = parse->commandType;
result->queryId = parse->queryId;
- result->hasReturning = (parse->returningList != NIL);
+ result->returning_one = parse->returning_one;
+ result->hasReturning = ( (parse->returningList != NIL) || parse->returning_one );
result->hasModifyingCTE = parse->hasModifyingCTE;
result->canSetTag = parse->canSetTag;
result->transientPlan = glob->transientPlan;
--- src/backend/rewrite/rewriteHandler.c.orig 2012-06-19 14:59:21.324574277 -0400
+++ src/backend/rewrite/rewriteHandler.c 2012-06-19 15:14:44.080596207 -0400
@@ -1734,6 +1734,8 @@ CopyAndAddInvertedQual(Query *parsetree,
* (must be initialized to FALSE)
* *qual_product - filled with modified original query if any qualified
* INSTEAD rule is found (must be initialized to NULL)
+ * *limit_rows_ptr - hint that this rule will return rows :
+ * any value in range [ 1 , 23 ] indicates yes
* Return value:
* list of rule actions adjusted for use with this query
*
@@ -1753,11 +1755,16 @@ fireRules(Query *parsetree,
List *locks,
bool *instead_flag,
bool *returning_flag,
- Query **qual_product)
+ Query **qual_product
+ ,int64 *limit_rows_ptr
+ )
{
List *results = NIL;
ListCell *l;
+ if (limit_rows_ptr)
+ *limit_rows_ptr = -1;
+
foreach(l, locks)
{
RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
@@ -1810,6 +1817,22 @@ fireRules(Query *parsetree,
{
Query *rule_action = lfirst(r);
+ /* check for rule which is a SELECT with LIMIT clause -
+ ** if so, inform caller of the value (if const) or type of the limit
+ */
+ if ( (limit_rows_ptr)
+ && (rule_action->commandType == CMD_SELECT)
+ && (rule_action->limitCount)
+ )
+ {
+ if (nodeTag(rule_action->limitCount) == T_Const) {
+ *limit_rows_ptr = DatumGetInt64(((Const *)(rule_action->limitCount))->constvalue);
+ }
+ else if (nodeTag(rule_action->limitCount) == T_FuncExpr) {
+ *limit_rows_ptr = ((int64)((FuncExpr *)(rule_action->limitCount))->funcresulttype);
+ }
+ }
+
if (rule_action->commandType == CMD_NOTHING)
continue;
@@ -1850,6 +1873,7 @@ RewriteQuery(Query *parsetree, List *rew
* clauses. (We have to do this first because the WITH clauses may get
* copied into rule actions below.)
*/
+ parsetree->returning_one = false;
foreach(lc1, parsetree->cteList)
{
CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc1);
@@ -1922,7 +1946,10 @@ RewriteQuery(Query *parsetree, List *rew
RangeTblEntry *rt_entry;
Relation rt_entry_relation;
List *locks;
+ int64 limit_rows; /* has either the const value or the datatype of a limit value */
+ /* which is a hint that this action will return specified number of rows */
+ limit_rows = -1;
result_relation = parsetree->resultRelation;
Assert(result_relation != 0);
rt_entry = rt_fetch(result_relation, parsetree->rtable);
@@ -2002,7 +2029,9 @@ RewriteQuery(Query *parsetree, List *rew
locks,
&instead,
&returning,
- &qual_product);
+ &qual_product
+ ,&limit_rows
+ );
/*
* If we got any product queries, recursively rewrite them --- but
@@ -2044,14 +2073,28 @@ RewriteQuery(Query *parsetree, List *rew
/*
* If there is an INSTEAD, and the original query has a RETURNING, we
- * have to have found a RETURNING in the rule(s), else fail. (Because
- * DefineQueryRewrite only allows RETURNING in unconditional INSTEAD
- * rules, there's no need to worry whether the substituted RETURNING
- * will actually be executed --- it must be.)
- */
- if ((instead || qual_product != NULL) &&
- parsetree->returningList &&
- !returning)
+ * have to have found in the rule(s) :
+ * EITHER a RETURNING
+ * OR a hint that this action will return specified number of rows
+ * else fail.
+ * (Because DefineQueryRewrite only allows RETURNING in unconditional
+ * INSTEAD rules, there's no need to worry whether the substituted
+ * RETURNING will actually be executed --- it must be.)
+ */
+ if ( (instead || qual_product != NULL)
+ && (parsetree->returningList)
+ && (!returning)
+ )
+ {
+ /* a value of limit_rows in the range 1 - 23 is a good hint
+ ** that query will return specified number of rows
+ */
+ if ( (limit_rows >= 1)
+ && (limit_rows <= 23)
+ )
+ {
+ parsetree->returning_one = true;
+ } else
{
switch (event)
{
@@ -2082,6 +2125,7 @@ RewriteQuery(Query *parsetree, List *rew
break;
}
}
+ }
heap_close(rt_entry_relation, NoLock);
}
@@ -2165,6 +2209,7 @@ QueryRewrite(Query *parsetree)
bool foundOriginalQuery;
Query *lastInstead;
+ parsetree->returning_one = false;
/*
* This function is only applied to top-level original queries
*/
@@ -2184,6 +2229,7 @@ QueryRewrite(Query *parsetree)
* Apply all the RIR rules on each query
*
* This is also a handy place to mark each query with the original queryId
+ * and with returning_one
*/
results = NIL;
foreach(l, querylist)
@@ -2193,6 +2239,7 @@ QueryRewrite(Query *parsetree)
query = fireRIRrules(query, NIL, false);
query->queryId = input_query_id;
+ query->returning_one = parsetree->returning_one;
results = lappend(results, query);
}
@@ -2233,9 +2280,13 @@ QueryRewrite(Query *parsetree)
else
{
Assert(!query->canSetTag);
- if (query->commandType == origCmdType &&
- (query->querySource == QSRC_INSTEAD_RULE ||
- query->querySource == QSRC_QUAL_INSTEAD_RULE))
+ if ( ( (query->commandType == origCmdType)
+ || query->returning_one
+ )
+ && ( (query->querySource == QSRC_INSTEAD_RULE)
+ || (query->querySource == QSRC_QUAL_INSTEAD_RULE)
+ )
+ )
lastInstead = query;
}
}
--- src/backend/nodes/copyfuncs.c.orig 2012-06-19 14:59:21.256574276 -0400
+++ src/backend/nodes/copyfuncs.c 2012-06-19 15:10:54.776590758 -0400
@@ -93,6 +93,7 @@ _copyPlannedStmt(const PlannedStmt *from
COPY_NODE_FIELD(relationOids);
COPY_NODE_FIELD(invalItems);
COPY_SCALAR_FIELD(nParamExec);
+ COPY_SCALAR_FIELD(returning_one);
return newnode;
}
@@ -2434,6 +2435,7 @@ _copyQuery(const Query *from)
COPY_NODE_FIELD(rowMarks);
COPY_NODE_FIELD(setOperations);
COPY_NODE_FIELD(constraintDeps);
+ COPY_SCALAR_FIELD(returning_one);
return newnode;
}
--- src/include/nodes/plannodes.h.orig 2012-06-19 14:59:21.496574281 -0400
+++ src/include/nodes/plannodes.h 2012-06-19 15:10:54.812590759 -0400
@@ -43,6 +43,8 @@ typedef struct PlannedStmt
bool hasModifyingCTE; /* has insert|update|delete in WITH? */
+ bool returning_one; /* inform portal that any intermediate result is to be returned -
+ when a RETURNING was rewritten */
bool canSetTag; /* do I set the command result tag? */
bool transientPlan; /* redo plan when TransactionXmin changes? */
--- src/include/nodes/parsenodes.h.orig 2012-06-19 14:59:21.492574281 -0400
+++ src/include/nodes/parsenodes.h 2012-06-19 15:10:54.816590759 -0400
@@ -105,6 +105,8 @@ typedef struct Query
uint32 queryId; /* query identifier (can be set by plugins) */
+ bool returning_one; /* inform portal that any intermediate result is to be returned -
+ when a RETURNING was rewritten */
bool canSetTag; /* do I set the command result tag? */
Node *utilityStmt; /* non-null if this is DECLARE CURSOR or a