24
24
#include "catalog/pg_collation.h"
25
25
#include "catalog/pg_statistic_ext.h"
26
26
#include "catalog/pg_statistic_ext_data.h"
27
+ #include "miscadmin.h"
27
28
#include "nodes/nodeFuncs.h"
28
29
#include "optimizer/clauses.h"
29
30
#include "optimizer/optimizer.h"
@@ -760,7 +761,8 @@ choose_best_statistics(List *stats, Bitmapset *attnums, char requiredkind)
760
761
* attribute numbers from all compatible clauses (recursively).
761
762
*/
762
763
static bool
763
- statext_is_compatible_clause_internal (Node * clause , Index relid , Bitmapset * * attnums )
764
+ statext_is_compatible_clause_internal (PlannerInfo * root , Node * clause ,
765
+ Index relid , Bitmapset * * attnums )
764
766
{
765
767
/* Look inside any binary-compatible relabeling (as in examine_variable) */
766
768
if (IsA (clause , RelabelType ))
@@ -791,6 +793,7 @@ statext_is_compatible_clause_internal(Node *clause, Index relid, Bitmapset **att
791
793
/* (Var op Const) or (Const op Var) */
792
794
if (is_opclause (clause ))
793
795
{
796
+ RangeTblEntry * rte = root -> simple_rte_array [relid ];
794
797
OpExpr * expr = (OpExpr * ) clause ;
795
798
Var * var ;
796
799
bool varonleft = true;
@@ -833,9 +836,24 @@ statext_is_compatible_clause_internal(Node *clause, Index relid, Bitmapset **att
833
836
return false;
834
837
}
835
838
839
+ /*
840
+ * If there are any securityQuals on the RTE from security barrier
841
+ * views or RLS policies, then the user may not have access to all the
842
+ * table's data, and we must check that the operator is leak-proof.
843
+ *
844
+ * If the operator is leaky, then we must ignore this clause for the
845
+ * purposes of estimating with MCV lists, otherwise the operator might
846
+ * reveal values from the MCV list that the user doesn't have
847
+ * permission to see.
848
+ */
849
+ if (rte -> securityQuals != NIL &&
850
+ !get_func_leakproof (get_opcode (expr -> opno )))
851
+ return false;
852
+
836
853
var = (varonleft ) ? linitial (expr -> args ) : lsecond (expr -> args );
837
854
838
- return statext_is_compatible_clause_internal ((Node * ) var , relid , attnums );
855
+ return statext_is_compatible_clause_internal (root , (Node * ) var ,
856
+ relid , attnums );
839
857
}
840
858
841
859
/* AND/OR/NOT clause */
@@ -866,7 +884,8 @@ statext_is_compatible_clause_internal(Node *clause, Index relid, Bitmapset **att
866
884
* Had we found incompatible clause in the arguments, treat the
867
885
* whole clause as incompatible.
868
886
*/
869
- if (!statext_is_compatible_clause_internal ((Node * ) lfirst (lc ),
887
+ if (!statext_is_compatible_clause_internal (root ,
888
+ (Node * ) lfirst (lc ),
870
889
relid , attnums ))
871
890
return false;
872
891
}
@@ -886,7 +905,8 @@ statext_is_compatible_clause_internal(Node *clause, Index relid, Bitmapset **att
886
905
if (!IsA (nt -> arg , Var ))
887
906
return false;
888
907
889
- return statext_is_compatible_clause_internal ((Node * ) (nt -> arg ), relid , attnums );
908
+ return statext_is_compatible_clause_internal (root , (Node * ) (nt -> arg ),
909
+ relid , attnums );
890
910
}
891
911
892
912
return false;
@@ -909,9 +929,12 @@ statext_is_compatible_clause_internal(Node *clause, Index relid, Bitmapset **att
909
929
* complex cases, for example (Var op Var).
910
930
*/
911
931
static bool
912
- statext_is_compatible_clause (Node * clause , Index relid , Bitmapset * * attnums )
932
+ statext_is_compatible_clause (PlannerInfo * root , Node * clause , Index relid ,
933
+ Bitmapset * * attnums )
913
934
{
935
+ RangeTblEntry * rte = root -> simple_rte_array [relid ];
914
936
RestrictInfo * rinfo = (RestrictInfo * ) clause ;
937
+ Oid userid ;
915
938
916
939
if (!IsA (rinfo , RestrictInfo ))
917
940
return false;
@@ -924,8 +947,43 @@ statext_is_compatible_clause(Node *clause, Index relid, Bitmapset **attnums)
924
947
if (bms_membership (rinfo -> clause_relids ) != BMS_SINGLETON )
925
948
return false;
926
949
927
- return statext_is_compatible_clause_internal ((Node * ) rinfo -> clause ,
928
- relid , attnums );
950
+ /* Check the clause and determine what attributes it references. */
951
+ if (!statext_is_compatible_clause_internal (root , (Node * ) rinfo -> clause ,
952
+ relid , attnums ))
953
+ return false;
954
+
955
+ /*
956
+ * Check that the user has permission to read all these attributes. Use
957
+ * checkAsUser if it's set, in case we're accessing the table via a view.
958
+ */
959
+ userid = rte -> checkAsUser ? rte -> checkAsUser : GetUserId ();
960
+
961
+ if (pg_class_aclcheck (rte -> relid , userid , ACL_SELECT ) != ACLCHECK_OK )
962
+ {
963
+ /* Don't have table privilege, must check individual columns */
964
+ if (bms_is_member (InvalidAttrNumber , * attnums ))
965
+ {
966
+ /* Have a whole-row reference, must have access to all columns */
967
+ if (pg_attribute_aclcheck_all (rte -> relid , userid , ACL_SELECT ,
968
+ ACLMASK_ALL ) != ACLCHECK_OK )
969
+ return false;
970
+ }
971
+ else
972
+ {
973
+ /* Check the columns referenced by the clause */
974
+ int attnum = -1 ;
975
+
976
+ while ((attnum = bms_next_member (* attnums , attnum )) >= 0 )
977
+ {
978
+ if (pg_attribute_aclcheck (rte -> relid , attnum , userid ,
979
+ ACL_SELECT ) != ACLCHECK_OK )
980
+ return false;
981
+ }
982
+ }
983
+ }
984
+
985
+ /* If we reach here, the clause is OK */
986
+ return true;
929
987
}
930
988
931
989
/*
@@ -1027,7 +1085,7 @@ statext_mcv_clauselist_selectivity(PlannerInfo *root, List *clauses, int varReli
1027
1085
Bitmapset * attnums = NULL ;
1028
1086
1029
1087
if (!bms_is_member (listidx , * estimatedclauses ) &&
1030
- statext_is_compatible_clause (clause , rel -> relid , & attnums ))
1088
+ statext_is_compatible_clause (root , clause , rel -> relid , & attnums ))
1031
1089
{
1032
1090
list_attnums [listidx ] = attnums ;
1033
1091
clauses_attnums = bms_add_members (clauses_attnums , attnums );
0 commit comments