mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Track nesting depth correctly when drilling down into RECORD Vars.
expandRecordVariable() failed to adjust the parse nesting structure correctly when recursing to inspect an outer-level Var. This could result in assertion failures or core dumps in corner cases. Likewise, get_name_for_var_field() failed to adjust the deparse namespace stack correctly when recursing to inspect an outer-level Var. In this case the likely result was a "bogus varno" error while deparsing a view. Per bug #18077 from Jingzhou Fu. Back-patch to all supported branches. Richard Guo, with some adjustments by me Discussion: https://postgr.es/m/18077-b9db97c6e0ab45d8@postgresql.org
This commit is contained in:
		@@ -1499,7 +1499,8 @@ ExpandRowReference(ParseState *pstate, Node *expr,
 | 
			
		||||
 * drill down to find the ultimate defining expression and attempt to infer
 | 
			
		||||
 * the tupdesc from it.  We ereport if we can't determine the tupdesc.
 | 
			
		||||
 *
 | 
			
		||||
 * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
 | 
			
		||||
 * levelsup is an extra offset to interpret the Var's varlevelsup correctly
 | 
			
		||||
 * when recursing.  Outside callers should pass zero.
 | 
			
		||||
 */
 | 
			
		||||
TupleDesc
 | 
			
		||||
expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
 | 
			
		||||
@@ -1587,10 +1588,17 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
 | 
			
		||||
					/*
 | 
			
		||||
					 * Recurse into the sub-select to see what its Var refers
 | 
			
		||||
					 * to.  We have to build an additional level of ParseState
 | 
			
		||||
					 * to keep in step with varlevelsup in the subselect.
 | 
			
		||||
					 * to keep in step with varlevelsup in the subselect;
 | 
			
		||||
					 * furthermore, the subquery RTE might be from an outer
 | 
			
		||||
					 * query level, in which case the ParseState for the
 | 
			
		||||
					 * subselect must have that outer level as parent.
 | 
			
		||||
					 */
 | 
			
		||||
					ParseState	mypstate = {0};
 | 
			
		||||
					Index		levelsup;
 | 
			
		||||
 | 
			
		||||
					/* this loop must work, since GetRTEByRangeTablePosn did */
 | 
			
		||||
					for (levelsup = 0; levelsup < netlevelsup; levelsup++)
 | 
			
		||||
						pstate = pstate->parentParseState;
 | 
			
		||||
					mypstate.parentParseState = pstate;
 | 
			
		||||
					mypstate.p_rtable = rte->subquery->rtable;
 | 
			
		||||
					/* don't bother filling the rest of the fake pstate */
 | 
			
		||||
@@ -1641,12 +1649,11 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
 | 
			
		||||
					 * Recurse into the CTE to see what its Var refers to. We
 | 
			
		||||
					 * have to build an additional level of ParseState to keep
 | 
			
		||||
					 * in step with varlevelsup in the CTE; furthermore it
 | 
			
		||||
					 * could be an outer CTE.
 | 
			
		||||
					 * could be an outer CTE (compare SUBQUERY case above).
 | 
			
		||||
					 */
 | 
			
		||||
					ParseState	mypstate;
 | 
			
		||||
					ParseState	mypstate = {0};
 | 
			
		||||
					Index		levelsup;
 | 
			
		||||
 | 
			
		||||
					MemSet(&mypstate, 0, sizeof(mypstate));
 | 
			
		||||
					/* this loop must work, since GetCTEForRTE did */
 | 
			
		||||
					for (levelsup = 0;
 | 
			
		||||
						 levelsup < rte->ctelevelsup + netlevelsup;
 | 
			
		||||
 
 | 
			
		||||
@@ -7820,22 +7820,28 @@ get_name_for_var_field(Var *var, int fieldno,
 | 
			
		||||
						 * Recurse into the sub-select to see what its Var
 | 
			
		||||
						 * refers to. We have to build an additional level of
 | 
			
		||||
						 * namespace to keep in step with varlevelsup in the
 | 
			
		||||
						 * subselect.
 | 
			
		||||
						 * subselect; furthermore, the subquery RTE might be
 | 
			
		||||
						 * from an outer query level, in which case the
 | 
			
		||||
						 * namespace for the subselect must have that outer
 | 
			
		||||
						 * level as parent namespace.
 | 
			
		||||
						 */
 | 
			
		||||
						List	   *save_nslist = context->namespaces;
 | 
			
		||||
						List	   *parent_namespaces;
 | 
			
		||||
						deparse_namespace mydpns;
 | 
			
		||||
						const char *result;
 | 
			
		||||
 | 
			
		||||
						set_deparse_for_query(&mydpns, rte->subquery,
 | 
			
		||||
											  context->namespaces);
 | 
			
		||||
						parent_namespaces = list_copy_tail(context->namespaces,
 | 
			
		||||
														   netlevelsup);
 | 
			
		||||
 | 
			
		||||
						context->namespaces = lcons(&mydpns,
 | 
			
		||||
													context->namespaces);
 | 
			
		||||
						set_deparse_for_query(&mydpns, rte->subquery,
 | 
			
		||||
											  parent_namespaces);
 | 
			
		||||
 | 
			
		||||
						context->namespaces = lcons(&mydpns, parent_namespaces);
 | 
			
		||||
 | 
			
		||||
						result = get_name_for_var_field((Var *) expr, fieldno,
 | 
			
		||||
														0, context);
 | 
			
		||||
 | 
			
		||||
						context->namespaces =
 | 
			
		||||
							list_delete_first(context->namespaces);
 | 
			
		||||
						context->namespaces = save_nslist;
 | 
			
		||||
 | 
			
		||||
						return result;
 | 
			
		||||
					}
 | 
			
		||||
@@ -7927,7 +7933,7 @@ get_name_for_var_field(Var *var, int fieldno,
 | 
			
		||||
														attnum);
 | 
			
		||||
 | 
			
		||||
					if (ste == NULL || ste->resjunk)
 | 
			
		||||
						elog(ERROR, "subquery %s does not have attribute %d",
 | 
			
		||||
						elog(ERROR, "CTE %s does not have attribute %d",
 | 
			
		||||
							 rte->eref->aliasname, attnum);
 | 
			
		||||
					expr = (Node *) ste->expr;
 | 
			
		||||
					if (IsA(expr, Var))
 | 
			
		||||
@@ -7935,21 +7941,22 @@ get_name_for_var_field(Var *var, int fieldno,
 | 
			
		||||
						/*
 | 
			
		||||
						 * Recurse into the CTE to see what its Var refers to.
 | 
			
		||||
						 * We have to build an additional level of namespace
 | 
			
		||||
						 * to keep in step with varlevelsup in the CTE.
 | 
			
		||||
						 * Furthermore it could be an outer CTE, so we may
 | 
			
		||||
						 * have to delete some levels of namespace.
 | 
			
		||||
						 * to keep in step with varlevelsup in the CTE;
 | 
			
		||||
						 * furthermore it could be an outer CTE (compare
 | 
			
		||||
						 * SUBQUERY case above).
 | 
			
		||||
						 */
 | 
			
		||||
						List	   *save_nslist = context->namespaces;
 | 
			
		||||
						List	   *new_nslist;
 | 
			
		||||
						List	   *parent_namespaces;
 | 
			
		||||
						deparse_namespace mydpns;
 | 
			
		||||
						const char *result;
 | 
			
		||||
 | 
			
		||||
						set_deparse_for_query(&mydpns, ctequery,
 | 
			
		||||
											  context->namespaces);
 | 
			
		||||
						parent_namespaces = list_copy_tail(context->namespaces,
 | 
			
		||||
														   ctelevelsup);
 | 
			
		||||
 | 
			
		||||
						new_nslist = list_copy_tail(context->namespaces,
 | 
			
		||||
													ctelevelsup);
 | 
			
		||||
						context->namespaces = lcons(&mydpns, new_nslist);
 | 
			
		||||
						set_deparse_for_query(&mydpns, ctequery,
 | 
			
		||||
											  parent_namespaces);
 | 
			
		||||
 | 
			
		||||
						context->namespaces = lcons(&mydpns, parent_namespaces);
 | 
			
		||||
 | 
			
		||||
						result = get_name_for_var_field((Var *) expr, fieldno,
 | 
			
		||||
														0, context);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user