@ -51,37 +51,33 @@
# include "utils/rel.h"
# include "utils/rel.h"
# include "utils/syscache.h"
# include "utils/syscache.h"
/* Convenience macro for the most common makeNamespaceItem() case */
# define makeDefaultNSItem(rte, rti) \
makeNamespaceItem ( rte , rti , true , true , false , true )
static void extractRemainingColumns ( List * common_colnames ,
static void extractRemainingColumns ( List * common_colnames ,
List * src_colnames , List * src_colvars ,
List * src_colnames , List * src_colvars ,
List * * res_colnames , List * * res_colvars ) ;
ParseNamespaceColumn * src_nscolumns ,
List * * res_colnames , List * * res_colvars ,
ParseNamespaceColumn * res_nscolumns ) ;
static Node * transformJoinUsingClause ( ParseState * pstate ,
static Node * transformJoinUsingClause ( ParseState * pstate ,
RangeTblEntry * leftRTE , RangeTblEntry * rightRTE ,
RangeTblEntry * leftRTE , RangeTblEntry * rightRTE ,
List * leftVars , List * rightVars ) ;
List * leftVars , List * rightVars ) ;
static Node * transformJoinOnClause ( ParseState * pstate , JoinExpr * j ,
static Node * transformJoinOnClause ( ParseState * pstate , JoinExpr * j ,
List * namespace ) ;
List * namespace ) ;
static RangeTblEntry * getRTEForSpecialRelationTypes ( ParseState * pstate ,
static ParseNamespaceItem * transformTableEntry ( ParseState * pstate , RangeVar * r ) ;
RangeVar * rv ) ;
static ParseNamespaceItem * transformRangeSubselect ( ParseState * pstate ,
static RangeTblEntry * transformTableEntry ( ParseState * pstate , RangeVar * r ) ;
RangeSubselect * r ) ;
static RangeTblEntry * transformRangeSubselect ( ParseState * pstate ,
static ParseNamespaceItem * transformRangeFunction ( ParseState * pstate ,
RangeSubselect * r ) ;
RangeFunction * r ) ;
static RangeTblEntry * transformRangeFunction ( ParseState * pstate ,
static ParseNamespaceItem * transformRangeTableFunc ( ParseState * pstate ,
RangeFunction * r ) ;
RangeTableFunc * t ) ;
static RangeTblEntry * transformRangeTableFunc ( ParseState * pstate ,
RangeTableFunc * t ) ;
static TableSampleClause * transformRangeTableSample ( ParseState * pstate ,
static TableSampleClause * transformRangeTableSample ( ParseState * pstate ,
RangeTableSample * rts ) ;
RangeTableSample * rts ) ;
static ParseNamespaceItem * getNSItemForSpecialRelationTypes ( ParseState * pstate ,
RangeVar * rv ) ;
static Node * transformFromClauseItem ( ParseState * pstate , Node * n ,
static Node * transformFromClauseItem ( ParseState * pstate , Node * n ,
RangeTblEntry * * top_rte , int * top_rti ,
ParseNamespaceItem * * top_nsitem ,
List * * namespace ) ;
List * * namespace ) ;
static Node * buildMergedJoinVar ( ParseState * pstate , JoinType jointype ,
static Node * buildMergedJoinVar ( ParseState * pstate , JoinType jointype ,
Var * l_colvar , Var * r_colvar ) ;
Var * l_colvar , Var * r_colvar ) ;
static ParseNamespaceItem * makeNamespaceItem ( RangeTblEntry * rte , int rtindex ,
bool rel_visible , bool cols_visible ,
bool lateral_only , bool lateral_ok ) ;
static void setNamespaceColumnVisibility ( List * namespace , bool cols_visible ) ;
static void setNamespaceColumnVisibility ( List * namespace , bool cols_visible ) ;
static void setNamespaceLateralState ( List * namespace ,
static void setNamespaceLateralState ( List * namespace ,
bool lateral_only , bool lateral_ok ) ;
bool lateral_only , bool lateral_ok ) ;
@ -130,13 +126,11 @@ transformFromClause(ParseState *pstate, List *frmList)
foreach ( fl , frmList )
foreach ( fl , frmList )
{
{
Node * n = lfirst ( fl ) ;
Node * n = lfirst ( fl ) ;
RangeTblEntry * rte ;
ParseNamespaceItem * nsitem ;
int rtindex ;
List * namespace ;
List * namespace ;
n = transformFromClauseItem ( pstate , n ,
n = transformFromClauseItem ( pstate , n ,
& rte ,
& nsitem ,
& rtindex ,
& namespace ) ;
& namespace ) ;
checkNameSpaceConflicts ( pstate , pstate - > p_namespace , namespace ) ;
checkNameSpaceConflicts ( pstate , pstate - > p_namespace , namespace ) ;
@ -183,8 +177,7 @@ int
setTargetTable ( ParseState * pstate , RangeVar * relation ,
setTargetTable ( ParseState * pstate , RangeVar * relation ,
bool inh , bool alsoSource , AclMode requiredPerms )
bool inh , bool alsoSource , AclMode requiredPerms )
{
{
RangeTblEntry * rte ;
ParseNamespaceItem * nsitem ;
int rtindex ;
/*
/*
* ENRs hide tables of the same name , so we need to check for them first .
* ENRs hide tables of the same name , so we need to check for them first .
@ -212,19 +205,14 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
RowExclusiveLock ) ;
RowExclusiveLock ) ;
/*
/*
* Now build an RTE .
* Now build an RTE and a ParseNamespaceItem .
*/
*/
rte = addRangeTableEntryForRelation ( pstate , pstate - > p_target_relation ,
nsitem = addRangeTableEntryForRelation ( pstate , pstate - > p_target_relation ,
RowExclusiveLock ,
RowExclusiveLock ,
relation - > alias , inh , false ) ;
relation - > alias , inh , false ) ;
/* assume new rte is at end */
/* remember the RTE/nsitem as being the query target */
rtindex = list_length ( pstate - > p_rtable ) ;
pstate - > p_target_nsitem = nsitem ;
Assert ( rte = = rt_fetch ( rtindex , pstate - > p_rtable ) ) ;
/* remember the RTE as being the query target */
pstate - > p_target_rangetblentry = rte ;
pstate - > p_target_rtindex = rtindex ;
/*
/*
* Override addRangeTableEntry ' s default ACL_SELECT permissions check , and
* Override addRangeTableEntry ' s default ACL_SELECT permissions check , and
@ -235,28 +223,30 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
* analysis , we will add the ACL_SELECT bit back again ; see
* analysis , we will add the ACL_SELECT bit back again ; see
* markVarForSelectPriv and its callers .
* markVarForSelectPriv and its callers .
*/
*/
rte - > requiredPerms = requiredPerms ;
nsitem - > p_ rte- > requiredPerms = requiredPerms ;
/*
/*
* If UPDATE / DELETE , add table to joinlist and namespace .
* If UPDATE / DELETE , add table to joinlist and namespace .
*
* Note : some callers know that they can find the new ParseNamespaceItem
* at the end of the pstate - > p_namespace list . This is a bit ugly but not
* worth complicating this function ' s signature for .
*/
*/
if ( alsoSource )
if ( alsoSource )
addRTEt oQuery ( pstate , rte , true , true , true ) ;
addNSItemToQuery ( pstate , nsitem , true , true , true ) ;
return rtindex ;
return nsitem - > p_ rtindex;
}
}
/*
/*
* Extract all not - in - common columns from column lists of a source table
* Extract all not - in - common columns from column lists of a source table
*
* We hand back new lists in * res_colnames and * res_colvars . But
* res_nscolumns points to a caller - allocated array that we fill in
* the next few entries in .
*/
*/
static void
static void
extractRemainingColumns ( List * common_colnames ,
extractRemainingColumns ( List * common_colnames ,
List * src_colnames , List * src_colvars ,
List * src_colnames , List * src_colvars ,
List * * res_colnames , List * * res_colvars )
ParseNamespaceColumn * src_nscolumns ,
List * * res_colnames , List * * res_colvars ,
ParseNamespaceColumn * res_nscolumns )
{
{
List * new_colnames = NIL ;
List * new_colnames = NIL ;
List * new_colvars = NIL ;
List * new_colvars = NIL ;
@ -271,6 +261,14 @@ extractRemainingColumns(List *common_colnames,
bool match = false ;
bool match = false ;
ListCell * cnames ;
ListCell * cnames ;
/*
* Ignore any dropped columns in the src_nscolumns input . ( The list
* inputs won ' t contain entries for dropped columns . )
*/
while ( src_nscolumns - > p_varno = = 0 )
src_nscolumns + + ;
/* is current src column already accounted for in common_colnames? */
foreach ( cnames , common_colnames )
foreach ( cnames , common_colnames )
{
{
char * ccolname = strVal ( lfirst ( cnames ) ) ;
char * ccolname = strVal ( lfirst ( cnames ) ) ;
@ -284,9 +282,15 @@ extractRemainingColumns(List *common_colnames,
if ( ! match )
if ( ! match )
{
{
/* Nope, so emit it as next output column */
new_colnames = lappend ( new_colnames , lfirst ( lnames ) ) ;
new_colnames = lappend ( new_colnames , lfirst ( lnames ) ) ;
new_colvars = lappend ( new_colvars , lfirst ( lvars ) ) ;
new_colvars = lappend ( new_colvars , lfirst ( lvars ) ) ;
/* Copy the input relation's nscolumn data for this column */
* res_nscolumns = * src_nscolumns ;
res_nscolumns + + ;
}
}
src_nscolumns + + ;
}
}
* res_colnames = new_colnames ;
* res_colnames = new_colnames ;
@ -388,25 +392,20 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j, List *namespace)
/*
/*
* transformTableEntry - - - transform a RangeVar ( simple relation reference )
* transformTableEntry - - - transform a RangeVar ( simple relation reference )
*/
*/
static RangeTblEntry *
static ParseNamespaceItem *
transformTableEntry ( ParseState * pstate , RangeVar * r )
transformTableEntry ( ParseState * pstate , RangeVar * r )
{
{
RangeTblEntry * rte ;
/* addRangeTableEntry does all the work */
return addRangeTableEntry ( pstate , r , r - > alias , r - > inh , true ) ;
/* We need only build a range table entry */
rte = addRangeTableEntry ( pstate , r , r - > alias , r - > inh , true ) ;
return rte ;
}
}
/*
/*
* transformRangeSubselect - - - transform a sub - SELECT appearing in FROM
* transformRangeSubselect - - - transform a sub - SELECT appearing in FROM
*/
*/
static RangeTblEntry *
static ParseNamespaceItem *
transformRangeSubselect ( ParseState * pstate , RangeSubselect * r )
transformRangeSubselect ( ParseState * pstate , RangeSubselect * r )
{
{
Query * query ;
Query * query ;
RangeTblEntry * rte ;
/*
/*
* We require user to supply an alias for a subselect , per SQL92 . To relax
* We require user to supply an alias for a subselect , per SQL92 . To relax
@ -454,29 +453,26 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
elog ( ERROR , " unexpected non-SELECT command in subquery in FROM " ) ;
elog ( ERROR , " unexpected non-SELECT command in subquery in FROM " ) ;
/*
/*
* OK , build an RTE for the subquery .
* OK , build an RTE and nsitem for the subquery .
*/
*/
rte = addRangeTableEntryForSubquery ( pstate ,
return addRangeTableEntryForSubquery ( pstate ,
query ,
query ,
r - > alias ,
r - > alias ,
r - > lateral ,
r - > lateral ,
true ) ;
true ) ;
return rte ;
}
}
/*
/*
* transformRangeFunction - - - transform a function call appearing in FROM
* transformRangeFunction - - - transform a function call appearing in FROM
*/
*/
static RangeTblEntry *
static ParseNamespaceItem *
transformRangeFunction ( ParseState * pstate , RangeFunction * r )
transformRangeFunction ( ParseState * pstate , RangeFunction * r )
{
{
List * funcexprs = NIL ;
List * funcexprs = NIL ;
List * funcnames = NIL ;
List * funcnames = NIL ;
List * coldeflists = NIL ;
List * coldeflists = NIL ;
bool is_lateral ;
bool is_lateral ;
RangeTblEntry * rte ;
ListCell * lc ;
ListCell * lc ;
/*
/*
@ -677,13 +673,11 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
is_lateral = r - > lateral | | contain_vars_of_level ( ( Node * ) funcexprs , 0 ) ;
is_lateral = r - > lateral | | contain_vars_of_level ( ( Node * ) funcexprs , 0 ) ;
/*
/*
* OK , build an RTE for the function .
* OK , build an RTE and nsitem for the function .
*/
*/
rte = addRangeTableEntryForFunction ( pstate ,
return addRangeTableEntryForFunction ( pstate ,
funcnames , funcexprs , coldeflists ,
funcnames , funcexprs , coldeflists ,
r , is_lateral , true ) ;
r , is_lateral , true ) ;
return rte ;
}
}
/*
/*
@ -694,13 +688,12 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
* row - generating expression , the column - generating expressions , and the
* row - generating expression , the column - generating expressions , and the
* default value expressions .
* default value expressions .
*/
*/
static RangeTblEntry *
static ParseNamespaceItem *
transformRangeTableFunc ( ParseState * pstate , RangeTableFunc * rtf )
transformRangeTableFunc ( ParseState * pstate , RangeTableFunc * rtf )
{
{
TableFunc * tf = makeNode ( TableFunc ) ;
TableFunc * tf = makeNode ( TableFunc ) ;
const char * constructName ;
const char * constructName ;
Oid docType ;
Oid docType ;
RangeTblEntry * rte ;
bool is_lateral ;
bool is_lateral ;
ListCell * col ;
ListCell * col ;
char * * names ;
char * * names ;
@ -903,10 +896,8 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf)
*/
*/
is_lateral = rtf - > lateral | | contain_vars_of_level ( ( Node * ) tf , 0 ) ;
is_lateral = rtf - > lateral | | contain_vars_of_level ( ( Node * ) tf , 0 ) ;
rte = addRangeTableEntryForTableFunc ( pstate ,
return addRangeTableEntryForTableFunc ( pstate ,
tf , rtf - > alias , is_lateral , true ) ;
tf , rtf - > alias , is_lateral , true ) ;
return rte ;
}
}
/*
/*
@ -1013,17 +1004,17 @@ transformRangeTableSample(ParseState *pstate, RangeTableSample *rts)
}
}
/*
/*
* getRTE ForSpecialRelationTypes
* getNSItem ForSpecialRelationTypes
*
*
* If given RangeVar refers to a CTE or an EphemeralNamedRelation ,
* If given RangeVar refers to a CTE or an EphemeralNamedRelation ,
* build and return an appropriate RTE , otherwise return NULL
* build and return an appropriate ParseNamespaceItem , otherwise return NULL
*/
*/
static RangeTblEntry *
static ParseNamespaceItem *
getRTE ForSpecialRelationTypes ( ParseState * pstate , RangeVar * rv )
getNSItem ForSpecialRelationTypes ( ParseState * pstate , RangeVar * rv )
{
{
ParseNamespaceItem * nsitem ;
CommonTableExpr * cte ;
CommonTableExpr * cte ;
Index levelsup ;
Index levelsup ;
RangeTblEntry * rte ;
/*
/*
* if it is a qualified name , it can ' t be a CTE or tuplestore reference
* if it is a qualified name , it can ' t be a CTE or tuplestore reference
@ -1033,13 +1024,13 @@ getRTEForSpecialRelationTypes(ParseState *pstate, RangeVar *rv)
cte = scanNameSpaceForCTE ( pstate , rv - > relname , & levelsup ) ;
cte = scanNameSpaceForCTE ( pstate , rv - > relname , & levelsup ) ;
if ( cte )
if ( cte )
rte = addRangeTableEntryForCTE ( pstate , cte , levelsup , rv , true ) ;
nsitem = addRangeTableEntryForCTE ( pstate , cte , levelsup , rv , true ) ;
else if ( scanNameSpaceForENR ( pstate , rv - > relname ) )
else if ( scanNameSpaceForENR ( pstate , rv - > relname ) )
rte = addRangeTableEntryForENR ( pstate , rv , true ) ;
nsitem = addRangeTableEntryForENR ( pstate , rv , true ) ;
else
else
rte = NULL ;
nsitem = NULL ;
return rte ;
return nsitem ;
}
}
/*
/*
@ -1053,11 +1044,9 @@ getRTEForSpecialRelationTypes(ParseState *pstate, RangeVar *rv)
* The function return value is the node to add to the jointree ( a
* The function return value is the node to add to the jointree ( a
* RangeTblRef or JoinExpr ) . Additional output parameters are :
* RangeTblRef or JoinExpr ) . Additional output parameters are :
*
*
* * top_rte : receives the RTE corresponding to the jointree item .
* * top_nsitem : receives the ParseNamespaceItem directly corresponding to the
* ( We could extract this from the function return node , but it saves cycles
* jointree item . ( This is only used during internal recursion , not by
* to pass it back separately . )
* outside callers . )
*
* * top_rti : receives the rangetable index of top_rte . ( Ditto . )
*
*
* * namespace : receives a List of ParseNamespaceItems for the RTEs exposed
* * namespace : receives a List of ParseNamespaceItems for the RTEs exposed
* as table / column names by this item . ( The lateral_only flags in these items
* as table / column names by this item . ( The lateral_only flags in these items
@ -1065,7 +1054,7 @@ getRTEForSpecialRelationTypes(ParseState *pstate, RangeVar *rv)
*/
*/
static Node *
static Node *
transformFromClauseItem ( ParseState * pstate , Node * n ,
transformFromClauseItem ( ParseState * pstate , Node * n ,
RangeTblEntry * * top_rte , int * top_rti ,
ParseNamespaceItem * * top_nsitem ,
List * * namespace )
List * * namespace )
{
{
if ( IsA ( n , RangeVar ) )
if ( IsA ( n , RangeVar ) )
@ -1073,78 +1062,58 @@ transformFromClauseItem(ParseState *pstate, Node *n,
/* Plain relation reference, or perhaps a CTE reference */
/* Plain relation reference, or perhaps a CTE reference */
RangeVar * rv = ( RangeVar * ) n ;
RangeVar * rv = ( RangeVar * ) n ;
RangeTblRef * rtr ;
RangeTblRef * rtr ;
RangeTblEntry * rte ;
ParseNamespaceItem * nsitem ;
int rtindex ;
/* Check if it's a CTE or tuplestore reference */
/* Check if it's a CTE or tuplestore reference */
rte = getRTE ForSpecialRelationTypes( pstate , rv ) ;
nsitem = getNSItem ForSpecialRelationTypes( pstate , rv ) ;
/* if not found above, must be a table reference */
/* if not found above, must be a table reference */
if ( ! rte )
if ( ! nsitem )
rte = transformTableEntry ( pstate , rv ) ;
nsitem = transformTableEntry ( pstate , rv ) ;
/* assume new rte is at end */
* top_nsitem = nsitem ;
rtindex = list_length ( pstate - > p_rtable ) ;
* namespace = list_make1 ( nsitem ) ;
Assert ( rte = = rt_fetch ( rtindex , pstate - > p_rtable ) ) ;
* top_rte = rte ;
* top_rti = rtindex ;
* namespace = list_make1 ( makeDefaultNSItem ( rte , rtindex ) ) ;
rtr = makeNode ( RangeTblRef ) ;
rtr = makeNode ( RangeTblRef ) ;
rtr - > rtindex = rtindex ;
rtr - > rtindex = nsitem - > p_rtindex ;
return ( Node * ) rtr ;
return ( Node * ) rtr ;
}
}
else if ( IsA ( n , RangeSubselect ) )
else if ( IsA ( n , RangeSubselect ) )
{
{
/* sub-SELECT is like a plain relation */
/* sub-SELECT is like a plain relation */
RangeTblRef * rtr ;
RangeTblRef * rtr ;
RangeTblEntry * rte ;
ParseNamespaceItem * nsitem ;
int rtindex ;
nsitem = transformRangeSubselect ( pstate , ( RangeSubselect * ) n ) ;
rte = transformRangeSubselect ( pstate , ( RangeSubselect * ) n ) ;
* top_nsitem = nsitem ;
/* assume new rte is at end */
* namespace = list_make1 ( nsitem ) ;
rtindex = list_length ( pstate - > p_rtable ) ;
Assert ( rte = = rt_fetch ( rtindex , pstate - > p_rtable ) ) ;
* top_rte = rte ;
* top_rti = rtindex ;
* namespace = list_make1 ( makeDefaultNSItem ( rte , rtindex ) ) ;
rtr = makeNode ( RangeTblRef ) ;
rtr = makeNode ( RangeTblRef ) ;
rtr - > rtindex = rtindex ;
rtr - > rtindex = nsitem - > p_rtindex ;
return ( Node * ) rtr ;
return ( Node * ) rtr ;
}
}
else if ( IsA ( n , RangeFunction ) )
else if ( IsA ( n , RangeFunction ) )
{
{
/* function is like a plain relation */
/* function is like a plain relation */
RangeTblRef * rtr ;
RangeTblRef * rtr ;
RangeTblEntry * rte ;
ParseNamespaceItem * nsitem ;
int rtindex ;
nsitem = transformRangeFunction ( pstate , ( RangeFunction * ) n ) ;
rte = transformRangeFunction ( pstate , ( RangeFunction * ) n ) ;
* top_nsitem = nsitem ;
/* assume new rte is at end */
* namespace = list_make1 ( nsitem ) ;
rtindex = list_length ( pstate - > p_rtable ) ;
Assert ( rte = = rt_fetch ( rtindex , pstate - > p_rtable ) ) ;
* top_rte = rte ;
* top_rti = rtindex ;
* namespace = list_make1 ( makeDefaultNSItem ( rte , rtindex ) ) ;
rtr = makeNode ( RangeTblRef ) ;
rtr = makeNode ( RangeTblRef ) ;
rtr - > rtindex = rtindex ;
rtr - > rtindex = nsitem - > p_rtindex ;
return ( Node * ) rtr ;
return ( Node * ) rtr ;
}
}
else if ( IsA ( n , RangeTableFunc ) )
else if ( IsA ( n , RangeTableFunc ) )
{
{
/* table function is like a plain relation */
/* table function is like a plain relation */
RangeTblRef * rtr ;
RangeTblRef * rtr ;
RangeTblEntry * rte ;
ParseNamespaceItem * nsitem ;
int rtindex ;
nsitem = transformRangeTableFunc ( pstate , ( RangeTableFunc * ) n ) ;
rte = transformRangeTableFunc ( pstate , ( RangeTableFunc * ) n ) ;
* top_nsitem = nsitem ;
/* assume new rte is at end */
* namespace = list_make1 ( nsitem ) ;
rtindex = list_length ( pstate - > p_rtable ) ;
Assert ( rte = = rt_fetch ( rtindex , pstate - > p_rtable ) ) ;
* top_rte = rte ;
* top_rti = rtindex ;
* namespace = list_make1 ( makeDefaultNSItem ( rte , rtindex ) ) ;
rtr = makeNode ( RangeTblRef ) ;
rtr = makeNode ( RangeTblRef ) ;
rtr - > rtindex = rtindex ;
rtr - > rtindex = nsitem - > p_rtindex ;
return ( Node * ) rtr ;
return ( Node * ) rtr ;
}
}
else if ( IsA ( n , RangeTableSample ) )
else if ( IsA ( n , RangeTableSample ) )
@ -1152,19 +1121,17 @@ transformFromClauseItem(ParseState *pstate, Node *n,
/* TABLESAMPLE clause (wrapping some other valid FROM node) */
/* TABLESAMPLE clause (wrapping some other valid FROM node) */
RangeTableSample * rts = ( RangeTableSample * ) n ;
RangeTableSample * rts = ( RangeTableSample * ) n ;
Node * rel ;
Node * rel ;
RangeTblRef * rtr ;
RangeTblEntry * rte ;
RangeTblEntry * rte ;
/* Recursively transform the contained relation */
/* Recursively transform the contained relation */
rel = transformFromClauseItem ( pstate , rts - > relation ,
rel = transformFromClauseItem ( pstate , rts - > relation ,
top_rte , top_rti , namespace ) ;
top_nsitem , namespace ) ;
/* Currently, grammar could only return a RangeVar as contained rel */
rte = ( * top_nsitem ) - > p_rte ;
rtr = castNode ( RangeTblRef , rel ) ;
rte = rt_fetch ( rtr - > rtindex , pstate - > p_rtable ) ;
/* We only support this on plain relations and matviews */
/* We only support this on plain relations and matviews */
if ( rte - > relkind ! = RELKIND_RELATION & &
if ( rte - > rtekind ! = RTE_RELATION | |
rte - > relkind ! = RELKIND_MATVIEW & &
( rte - > relkind ! = RELKIND_RELATION & &
rte - > relkind ! = RELKIND_PARTITIONED_TABLE )
rte - > relkind ! = RELKIND_MATVIEW & &
rte - > relkind ! = RELKIND_PARTITIONED_TABLE ) )
ereport ( ERROR ,
ereport ( ERROR ,
( errcode ( ERRCODE_FEATURE_NOT_SUPPORTED ) ,
( errcode ( ERRCODE_FEATURE_NOT_SUPPORTED ) ,
errmsg ( " TABLESAMPLE clause can only be applied to tables and materialized views " ) ,
errmsg ( " TABLESAMPLE clause can only be applied to tables and materialized views " ) ,
@ -1172,16 +1139,15 @@ transformFromClauseItem(ParseState *pstate, Node *n,
/* Transform TABLESAMPLE details and attach to the RTE */
/* Transform TABLESAMPLE details and attach to the RTE */
rte - > tablesample = transformRangeTableSample ( pstate , rts ) ;
rte - > tablesample = transformRangeTableSample ( pstate , rts ) ;
return ( Node * ) rtr ;
return rel ;
}
}
else if ( IsA ( n , JoinExpr ) )
else if ( IsA ( n , JoinExpr ) )
{
{
/* A newfangled join expression */
/* A newfangled join expression */
JoinExpr * j = ( JoinExpr * ) n ;
JoinExpr * j = ( JoinExpr * ) n ;
RangeTblEntry * l_rte ;
ParseNamespaceItem * nsitem ;
RangeTblEntry * r_rte ;
ParseNamespaceItem * l_nsitem ;
int l_rtindex ;
ParseNamespaceItem * r_nsitem ;
int r_rtindex ;
List * l_namespace ,
List * l_namespace ,
* r_namespace ,
* r_namespace ,
* my_namespace ,
* my_namespace ,
@ -1191,9 +1157,10 @@ transformFromClauseItem(ParseState *pstate, Node *n,
* l_colvars ,
* l_colvars ,
* r_colvars ,
* r_colvars ,
* res_colvars ;
* res_colvars ;
ParseNamespaceColumn * res_nscolumns ;
int res_colindex ;
bool lateral_ok ;
bool lateral_ok ;
int sv_namespace_length ;
int sv_namespace_length ;
RangeTblEntry * rte ;
int k ;
int k ;
/*
/*
@ -1201,8 +1168,7 @@ transformFromClauseItem(ParseState *pstate, Node *n,
* it in this order for correct visibility of LATERAL references .
* it in this order for correct visibility of LATERAL references .
*/
*/
j - > larg = transformFromClauseItem ( pstate , j - > larg ,
j - > larg = transformFromClauseItem ( pstate , j - > larg ,
& l_rte ,
& l_nsitem ,
& l_rtindex ,
& l_namespace ) ;
& l_namespace ) ;
/*
/*
@ -1225,8 +1191,7 @@ transformFromClauseItem(ParseState *pstate, Node *n,
/* And now we can process the RHS */
/* And now we can process the RHS */
j - > rarg = transformFromClauseItem ( pstate , j - > rarg ,
j - > rarg = transformFromClauseItem ( pstate , j - > rarg ,
& r_rte ,
& r_nsitem ,
& r_rtindex ,
& r_namespace ) ;
& r_namespace ) ;
/* Remove the left-side RTEs from the namespace list again */
/* Remove the left-side RTEs from the namespace list again */
@ -1248,12 +1213,10 @@ transformFromClauseItem(ParseState *pstate, Node *n,
/*
/*
* Extract column name and var lists from both subtrees
* Extract column name and var lists from both subtrees
*
*
* Note : expandRTE returns new lists , safe for me to modify
* Note : expandNSItemVars returns new lists , safe for me to modify
*/
*/
expandRTE ( l_rte , l_rtindex , 0 , - 1 , false ,
l_colvars = expandNSItemVars ( l_nsitem , 0 , - 1 , & l_colnames ) ;
& l_colnames , & l_colvars ) ;
r_colvars = expandNSItemVars ( r_nsitem , 0 , - 1 , & r_colnames ) ;
expandRTE ( r_rte , r_rtindex , 0 , - 1 , false ,
& r_colnames , & r_colvars ) ;
/*
/*
* Natural join does not explicitly specify columns ; must generate
* Natural join does not explicitly specify columns ; must generate
@ -1302,6 +1265,12 @@ transformFromClauseItem(ParseState *pstate, Node *n,
res_colnames = NIL ;
res_colnames = NIL ;
res_colvars = NIL ;
res_colvars = NIL ;
/* this may be larger than needed, but it's not worth being exact */
res_nscolumns = ( ParseNamespaceColumn * )
palloc0 ( ( list_length ( l_colnames ) + list_length ( r_colnames ) ) *
sizeof ( ParseNamespaceColumn ) ) ;
res_colindex = 0 ;
if ( j - > usingClause )
if ( j - > usingClause )
{
{
/*
/*
@ -1325,6 +1294,8 @@ transformFromClauseItem(ParseState *pstate, Node *n,
int r_index = - 1 ;
int r_index = - 1 ;
Var * l_colvar ,
Var * l_colvar ,
* r_colvar ;
* r_colvar ;
Node * u_colvar ;
ParseNamespaceColumn * res_nscolumn ;
/* Check for USING(foo,foo) */
/* Check for USING(foo,foo) */
foreach ( col , res_colnames )
foreach ( col , res_colnames )
@ -1390,16 +1361,58 @@ transformFromClauseItem(ParseState *pstate, Node *n,
r_usingvars = lappend ( r_usingvars , r_colvar ) ;
r_usingvars = lappend ( r_usingvars , r_colvar ) ;
res_colnames = lappend ( res_colnames , lfirst ( ucol ) ) ;
res_colnames = lappend ( res_colnames , lfirst ( ucol ) ) ;
res_colvars = lappend ( res_colvars ,
u_colvar = buildMergedJoinVar ( pstate ,
buildMergedJoinVar ( pstate ,
j - > jointype ,
j - > jointype ,
l_colvar ,
l_colvar ,
r_colvar ) ;
r_colvar ) ) ;
res_colvars = lappend ( res_colvars , u_colvar ) ;
res_nscolumn = res_nscolumns + res_colindex ;
res_colindex + + ;
if ( u_colvar = = ( Node * ) l_colvar )
{
/* Merged column is equivalent to left input */
res_nscolumn - > p_varno = l_colvar - > varno ;
res_nscolumn - > p_varattno = l_colvar - > varattno ;
res_nscolumn - > p_vartype = l_colvar - > vartype ;
res_nscolumn - > p_vartypmod = l_colvar - > vartypmod ;
res_nscolumn - > p_varcollid = l_colvar - > varcollid ;
/* XXX these are not quite right, but doesn't matter yet */
res_nscolumn - > p_varnosyn = l_colvar - > varno ;
res_nscolumn - > p_varattnosyn = l_colvar - > varattno ;
}
else if ( u_colvar = = ( Node * ) r_colvar )
{
/* Merged column is equivalent to right input */
res_nscolumn - > p_varno = r_colvar - > varno ;
res_nscolumn - > p_varattno = r_colvar - > varattno ;
res_nscolumn - > p_vartype = r_colvar - > vartype ;
res_nscolumn - > p_vartypmod = r_colvar - > vartypmod ;
res_nscolumn - > p_varcollid = r_colvar - > varcollid ;
/* XXX these are not quite right, but doesn't matter yet */
res_nscolumn - > p_varnosyn = r_colvar - > varno ;
res_nscolumn - > p_varattnosyn = r_colvar - > varattno ;
}
else
{
/*
* Merged column is not semantically equivalent to either
* input , so it needs to be referenced as the join output
* column . We don ' t know the join ' s varno yet , so we ' ll
* replace these zeroes below .
*/
res_nscolumn - > p_varno = 0 ;
res_nscolumn - > p_varattno = res_colindex ;
res_nscolumn - > p_vartype = exprType ( u_colvar ) ;
res_nscolumn - > p_vartypmod = exprTypmod ( u_colvar ) ;
res_nscolumn - > p_varcollid = exprCollation ( u_colvar ) ;
res_nscolumn - > p_varnosyn = 0 ;
res_nscolumn - > p_varattnosyn = res_colindex ;
}
}
}
j - > quals = transformJoinUsingClause ( pstate ,
j - > quals = transformJoinUsingClause ( pstate ,
l_rte ,
l_nsitem - > p_ rte ,
r_rte ,
r_nsitem - > p_ rte ,
l_usingvars ,
l_usingvars ,
r_usingvars ) ;
r_usingvars ) ;
}
}
@ -1416,10 +1429,16 @@ transformFromClauseItem(ParseState *pstate, Node *n,
/* Add remaining columns from each side to the output columns */
/* Add remaining columns from each side to the output columns */
extractRemainingColumns ( res_colnames ,
extractRemainingColumns ( res_colnames ,
l_colnames , l_colvars ,
l_colnames , l_colvars ,
& l_colnames , & l_colvars ) ;
l_nsitem - > p_nscolumns ,
& l_colnames , & l_colvars ,
res_nscolumns + res_colindex ) ;
res_colindex + = list_length ( l_colvars ) ;
extractRemainingColumns ( res_colnames ,
extractRemainingColumns ( res_colnames ,
r_colnames , r_colvars ,
r_colnames , r_colvars ,
& r_colnames , & r_colvars ) ;
r_nsitem - > p_nscolumns ,
& r_colnames , & r_colvars ,
res_nscolumns + res_colindex ) ;
res_colindex + = list_length ( r_colvars ) ;
res_colnames = list_concat ( res_colnames , l_colnames ) ;
res_colnames = list_concat ( res_colnames , l_colnames ) ;
res_colvars = list_concat ( res_colvars , l_colvars ) ;
res_colvars = list_concat ( res_colvars , l_colvars ) ;
res_colnames = list_concat ( res_colnames , r_colnames ) ;
res_colnames = list_concat ( res_colnames , r_colnames ) ;
@ -1441,21 +1460,41 @@ transformFromClauseItem(ParseState *pstate, Node *n,
}
}
/*
/*
* Now build an RTE for the result of the join
* Now build an RTE and nsitem for the result of the join .
* res_nscolumns isn ' t totally done yet , but that ' s OK because
* addRangeTableEntryForJoin doesn ' t examine it , only store a pointer .
*/
*/
rte = addRangeTableEntryForJoin ( pstate ,
nsitem = addRangeTableEntryForJoin ( pstate ,
res_colnames ,
res_colnames ,
j - > jointype ,
res_nscolumns ,
res_colvars ,
j - > jointype ,
j - > alias ,
res_colvars ,
true ) ;
j - > alias ,
true ) ;
/* assume new rte is at end */
j - > rtindex = nsitem - > p_rtindex ;
j - > rtindex = list_length ( pstate - > p_rtable ) ;
Assert ( rte = = rt_fetch ( j - > rtindex , pstate - > p_rtable ) ) ;
* top_rte = rte ;
/*
* top_rti = j - > rtindex ;
* Now that we know the join RTE ' s rangetable index , we can fix up the
* res_nscolumns data in places where it should contain that .
*/
Assert ( res_colindex = = list_length ( nsitem - > p_rte - > eref - > colnames ) ) ;
for ( k = 0 ; k < res_colindex ; k + + )
{
ParseNamespaceColumn * nscol = res_nscolumns + k ;
/* fill in join RTI for merged columns */
if ( nscol - > p_varno = = 0 )
nscol - > p_varno = j - > rtindex ;
if ( nscol - > p_varnosyn = = 0 )
nscol - > p_varnosyn = j - > rtindex ;
/* if join has an alias, it syntactically hides all inputs */
if ( j - > alias )
{
nscol - > p_varnosyn = j - > rtindex ;
nscol - > p_varattnosyn = k + 1 ;
}
}
/* make a matching link to the JoinExpr for later use */
/* make a matching link to the JoinExpr for later use */
for ( k = list_length ( pstate - > p_joinexprs ) + 1 ; k < j - > rtindex ; k + + )
for ( k = list_length ( pstate - > p_joinexprs ) + 1 ; k < j - > rtindex ; k + + )
@ -1483,13 +1522,13 @@ transformFromClauseItem(ParseState *pstate, Node *n,
* The join RTE itself is always made visible for unqualified column
* The join RTE itself is always made visible for unqualified column
* names . It ' s visible as a relation name only if it has an alias .
* names . It ' s visible as a relation name only if it has an alias .
*/
*/
* namespace = lappend ( my_namespace ,
nsitem - > p_rel_visible = ( j - > alias ! = NULL ) ;
makeNamespaceItem ( rte ,
nsitem - > p_cols_visible = true ;
j - > rtindex ,
nsitem - > p_lateral_only = false ;
( j - > alias ! = NULL ) ,
nsitem - > p_lateral_ok = true ;
true ,
false ,
* top_nsitem = nsitem ;
true ) ) ;
* namespace = lappend ( my_namespace , nsitem ) ;
return ( Node * ) j ;
return ( Node * ) j ;
}
}
@ -1617,27 +1656,6 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
return res_node ;
return res_node ;
}
}
/*
* makeNamespaceItem -
* Convenience subroutine to construct a ParseNamespaceItem .
*/
static ParseNamespaceItem *
makeNamespaceItem ( RangeTblEntry * rte , int rtindex ,
bool rel_visible , bool cols_visible ,
bool lateral_only , bool lateral_ok )
{
ParseNamespaceItem * nsitem ;
nsitem = ( ParseNamespaceItem * ) palloc ( sizeof ( ParseNamespaceItem ) ) ;
nsitem - > p_rte = rte ;
nsitem - > p_rtindex = rtindex ;
nsitem - > p_rel_visible = rel_visible ;
nsitem - > p_cols_visible = cols_visible ;
nsitem - > p_lateral_only = lateral_only ;
nsitem - > p_lateral_ok = lateral_ok ;
return nsitem ;
}
/*
/*
* setNamespaceColumnVisibility -
* setNamespaceColumnVisibility -
* Convenience subroutine to update cols_visible flags in a namespace list .
* Convenience subroutine to update cols_visible flags in a namespace list .
@ -3163,8 +3181,8 @@ transformOnConflictArbiter(ParseState *pstate,
*/
*/
save_namespace = pstate - > p_namespace ;
save_namespace = pstate - > p_namespace ;
pstate - > p_namespace = NIL ;
pstate - > p_namespace = NIL ;
addRTEt oQuery ( pstate , pstate - > p_target_rangetblentry ,
addNSItemT oQuery ( pstate , pstate - > p_target_nsitem ,
false , false , true ) ;
false , false , true ) ;
if ( infer - > indexElems )
if ( infer - > indexElems )
* arbiterExpr = resolve_unique_index_expr ( pstate , infer ,
* arbiterExpr = resolve_unique_index_expr ( pstate , infer ,
@ -3189,7 +3207,7 @@ transformOnConflictArbiter(ParseState *pstate,
if ( infer - > conname )
if ( infer - > conname )
{
{
Oid relid = RelationGetRelid ( pstate - > p_target_relation ) ;
Oid relid = RelationGetRelid ( pstate - > p_target_relation ) ;
RangeTblEntry * rte = pstate - > p_target_rangetblentry ;
RangeTblEntry * rte = pstate - > p_target_nsitem - > p_rte ;
Bitmapset * conattnos ;
Bitmapset * conattnos ;
conattnos = get_relation_constraint_attnos ( relid , infer - > conname ,
conattnos = get_relation_constraint_attnos ( relid , infer - > conname ,