@@ -3567,6 +3567,295 @@ NamesFromList(List *names)
35673567 return result ;
35683568}
35693569
3570+ /* -----
3571+ * IdentifyVariable - try to find a variable from a list of identifiers
3572+ *
3573+ * Returns the OID of the variable found, or InvalidOid.
3574+ *
3575+ * "names" is a list of up to four identifiers; possible meanings are:
3576+ * - variable (searched on the search_path)
3577+ * - schema.variable
3578+ * - variable.attribute (searched on the search_path)
3579+ * - schema.variable.attribute
3580+ * - database.schema.variable
3581+ * - database.schema.variable.attribute
3582+ *
3583+ * If there is more than one way to identify a variable, "not_unique" will be
3584+ * set to true.
3585+ *
3586+ * Unless "noerror" is true, an error is raised if there are more than four
3587+ * identifiers in the list, or if the named database is not the current one.
3588+ * This is useful if we want to identify a shadowed variable.
3589+ *
3590+ * If an attribute is identified, it is stored in "attrname", otherwise the
3591+ * parameter is set to NULL.
3592+ *
3593+ * The identified session variable will be locked with an AccessShareLock.
3594+ * -----
3595+ */
3596+ Oid
3597+ IdentifyVariable (List * names , char * * attrname , bool * not_unique , bool noerror )
3598+ {
3599+ Oid varid = InvalidOid ;
3600+ Oid old_varid = InvalidOid ;
3601+ uint64 inval_count ;
3602+ bool retry = false;
3603+
3604+ /*
3605+ * DDL operations can change the results of a name lookup. Since all such
3606+ * operations will generate invalidation messages, we keep track of
3607+ * whether any such messages show up while we're performing the operation,
3608+ * and retry until either (1) no more invalidation messages show up or (2)
3609+ * the answer doesn't change.
3610+ */
3611+ for (;;)
3612+ {
3613+ Node * field1 = NULL ;
3614+ Node * field2 = NULL ;
3615+ Node * field3 = NULL ;
3616+ Node * field4 = NULL ;
3617+ char * a = NULL ;
3618+ char * b = NULL ;
3619+ char * c = NULL ;
3620+ char * d = NULL ;
3621+ Oid varoid_without_attr = InvalidOid ;
3622+ Oid varoid_with_attr = InvalidOid ;
3623+
3624+ * not_unique = false;
3625+ * attrname = NULL ;
3626+ varid = InvalidOid ;
3627+
3628+ inval_count = SharedInvalidMessageCounter ;
3629+
3630+ switch (list_length (names ))
3631+ {
3632+ case 1 :
3633+ field1 = linitial (names );
3634+
3635+ Assert (IsA (field1 , String ));
3636+
3637+ varid = LookupVariable (NULL , strVal (field1 ), true);
3638+ break ;
3639+
3640+ case 2 :
3641+ field1 = linitial (names );
3642+ field2 = lsecond (names );
3643+
3644+ Assert (IsA (field1 , String ));
3645+ a = strVal (field1 );
3646+
3647+ if (IsA (field2 , String ))
3648+ {
3649+ /* when both fields are of string type */
3650+ b = strVal (field2 );
3651+
3652+ /*
3653+ * a.b can mean "schema"."variable" or
3654+ * "variable"."attribute". Check both variants, and
3655+ * returns InvalidOid with not_unique flag, when both
3656+ * interpretations are possible.
3657+ */
3658+ varoid_without_attr = LookupVariable (a , b , true);
3659+ varoid_with_attr = LookupVariable (NULL , a , true);
3660+ }
3661+ else
3662+ {
3663+ /* the last field of list can be star too */
3664+ Assert (IsA (field2 , A_Star ));
3665+
3666+ /*
3667+ * The syntax ident.* is used only by relation aliases,
3668+ * and then this identifier cannot be a reference to
3669+ * session variable.
3670+ */
3671+ return InvalidOid ;
3672+ }
3673+
3674+ if (OidIsValid (varoid_without_attr ) && OidIsValid (varoid_with_attr ))
3675+ {
3676+ * not_unique = true;
3677+ varid = varoid_without_attr ;
3678+ }
3679+ else if (OidIsValid (varoid_without_attr ))
3680+ {
3681+ varid = varoid_without_attr ;
3682+ }
3683+ else if (OidIsValid (varoid_with_attr ))
3684+ {
3685+ * attrname = b ;
3686+ varid = varoid_with_attr ;
3687+ }
3688+ break ;
3689+
3690+ case 3 :
3691+ {
3692+ bool field1_is_catalog = false;
3693+
3694+ field1 = linitial (names );
3695+ field2 = lsecond (names );
3696+ field3 = lthird (names );
3697+
3698+ Assert (IsA (field1 , String ));
3699+ Assert (IsA (field2 , String ));
3700+
3701+ a = strVal (field1 );
3702+ b = strVal (field2 );
3703+
3704+ if (IsA (field3 , String ))
3705+ {
3706+ c = strVal (field3 );
3707+
3708+ /*
3709+ * a.b.c can mean catalog.schema.variable or
3710+ * schema.variable.attribute.
3711+ *
3712+ * Check both variants, and set not_unique flag, when
3713+ * both interpretations are possible.
3714+ *
3715+ * When third node is star, only possible
3716+ * interpretation is schema.variable.*, but this
3717+ * pattern is not supported now.
3718+ */
3719+ varoid_with_attr = LookupVariable (a , b , true);
3720+
3721+ /*
3722+ * check pattern catalog.schema.variable only when
3723+ * there is possibility to success.
3724+ */
3725+ if (strcmp (a , get_database_name (MyDatabaseId )) == 0 )
3726+ {
3727+ field1_is_catalog = true;
3728+ varoid_without_attr = LookupVariable (b , c , true);
3729+ }
3730+ }
3731+ else
3732+ {
3733+ Assert (IsA (field3 , A_Star ));
3734+ return InvalidOid ;
3735+ }
3736+
3737+ if (OidIsValid (varoid_without_attr ) && OidIsValid (varoid_with_attr ))
3738+ {
3739+ * not_unique = true;
3740+ varid = varoid_without_attr ;
3741+ }
3742+ else if (OidIsValid (varoid_without_attr ))
3743+ {
3744+ varid = varoid_without_attr ;
3745+ }
3746+ else if (OidIsValid (varoid_with_attr ))
3747+ {
3748+ * attrname = c ;
3749+ varid = varoid_with_attr ;
3750+ }
3751+
3752+ /*
3753+ * When we didn't find variable, we can (when it is
3754+ * allowed) raise cross-database reference error.
3755+ */
3756+ if (!OidIsValid (varid ) && !noerror && !field1_is_catalog )
3757+ ereport (ERROR ,
3758+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
3759+ errmsg ("cross-database references are not implemented: %s" ,
3760+ NameListToString (names ))));
3761+ }
3762+ break ;
3763+
3764+ case 4 :
3765+ {
3766+ field1 = linitial (names );
3767+ field2 = lsecond (names );
3768+ field3 = lthird (names );
3769+ field4 = lfourth (names );
3770+
3771+ Assert (IsA (field1 , String ));
3772+ Assert (IsA (field2 , String ));
3773+ Assert (IsA (field3 , String ));
3774+
3775+ a = strVal (field1 );
3776+ b = strVal (field2 );
3777+ c = strVal (field3 );
3778+
3779+ /*
3780+ * In this case, "a" is used as catalog name - check it.
3781+ */
3782+ if (strcmp (a , get_database_name (MyDatabaseId )) != 0 )
3783+ {
3784+ if (!noerror )
3785+ ereport (ERROR ,
3786+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
3787+ errmsg ("cross-database references are not implemented: %s" ,
3788+ NameListToString (names ))));
3789+ }
3790+
3791+ if (IsA (field4 , String ))
3792+ {
3793+ d = strVal (field4 );
3794+ }
3795+ else
3796+ {
3797+ Assert (IsA (field4 , A_Star ));
3798+ return InvalidOid ;
3799+ }
3800+
3801+ * attrname = d ;
3802+ varid = LookupVariable (b , c , true);
3803+ }
3804+ break ;
3805+
3806+ default :
3807+ if (!noerror )
3808+ ereport (ERROR ,
3809+ (errcode (ERRCODE_SYNTAX_ERROR ),
3810+ errmsg ("improper qualified name (too many dotted names): %s" ,
3811+ NameListToString (names ))));
3812+ return InvalidOid ;
3813+ }
3814+
3815+ /*
3816+ * If, upon retry, we get back the same OID we did last time, then the
3817+ * invalidation messages we processed did not change the final answer.
3818+ * So we're done.
3819+ *
3820+ * If we got a different OID, we've locked the variable that used to
3821+ * have this name rather than the one that does now. So release the
3822+ * lock.
3823+ */
3824+ if (retry )
3825+ {
3826+ if (old_varid == varid )
3827+ break ;
3828+
3829+ if (OidIsValid (old_varid ))
3830+ UnlockDatabaseObject (VariableRelationId , old_varid , 0 , AccessShareLock );
3831+ }
3832+
3833+ /*
3834+ * Lock the variable. This will also accept any pending invalidation
3835+ * messages. If we got back InvalidOid, indicating not found, then
3836+ * there's nothing to lock, but we accept invalidation messages
3837+ * anyway, to flush any negative catcache entries that may be
3838+ * lingering.
3839+ */
3840+ if (!OidIsValid (varid ))
3841+ AcceptInvalidationMessages ();
3842+ else
3843+ LockDatabaseObject (VariableRelationId , varid , 0 , AccessShareLock );
3844+
3845+ /*
3846+ * If no invalidation message were processed, we're done!
3847+ */
3848+ if (inval_count == SharedInvalidMessageCounter )
3849+ break ;
3850+
3851+ retry = true;
3852+ old_varid = varid ;
3853+ varid = InvalidOid ;
3854+ }
3855+
3856+ return varid ;
3857+ }
3858+
35703859/*
35713860 * DeconstructQualifiedName
35723861 * Given a possibly-qualified name expressed as a list of String nodes,
0 commit comments