@@ -80,7 +80,10 @@ static void ComputeIndexAttrs(IndexInfo *indexInfo,
80
80
Oid relId ,
81
81
const char * accessMethodName , Oid accessMethodId ,
82
82
bool amcanorder ,
83
- bool isconstraint );
83
+ bool isconstraint ,
84
+ Oid ddl_userid ,
85
+ int ddl_sec_context ,
86
+ int * ddl_save_nestlevel );
84
87
static char * ChooseIndexName (const char * tabname , Oid namespaceId ,
85
88
List * colnames , List * exclusionOpNames ,
86
89
bool primary , bool isconstraint );
@@ -220,9 +223,8 @@ CheckIndexCompatible(Oid oldId,
220
223
* Compute the operator classes, collations, and exclusion operators for
221
224
* the new index, so we can test whether it's compatible with the existing
222
225
* one. Note that ComputeIndexAttrs might fail here, but that's OK:
223
- * DefineIndex would have called this function with the same arguments
224
- * later on, and it would have failed then anyway. Our attributeList
225
- * contains only key attributes, thus we're filling ii_NumIndexAttrs and
226
+ * DefineIndex would have failed later. Our attributeList contains only
227
+ * key attributes, thus we're filling ii_NumIndexAttrs and
226
228
* ii_NumIndexKeyAttrs with same value.
227
229
*/
228
230
indexInfo = makeIndexInfo (numberOfAttributes , numberOfAttributes ,
@@ -236,7 +238,7 @@ CheckIndexCompatible(Oid oldId,
236
238
coloptions , attributeList ,
237
239
exclusionOpNames , relationId ,
238
240
accessMethodName , accessMethodId ,
239
- amcanorder , isconstraint );
241
+ amcanorder , isconstraint , InvalidOid , 0 , NULL );
240
242
241
243
242
244
/* Get the soon-obsolete pg_index tuple. */
@@ -482,6 +484,19 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
482
484
* DefineIndex
483
485
* Creates a new index.
484
486
*
487
+ * This function manages the current userid according to the needs of pg_dump.
488
+ * Recreating old-database catalog entries in new-database is fine, regardless
489
+ * of which users would have permission to recreate those entries now. That's
490
+ * just preservation of state. Running opaque expressions, like calling a
491
+ * function named in a catalog entry or evaluating a pg_node_tree in a catalog
492
+ * entry, as anyone other than the object owner, is not fine. To adhere to
493
+ * those principles and to remain fail-safe, use the table owner userid for
494
+ * most ACL checks. Use the original userid for ACL checks reached without
495
+ * traversing opaque expressions. (pg_dump can predict such ACL checks from
496
+ * catalogs.) Overall, this is a mess. Future DDL development should
497
+ * consider offering one DDL command for catalog setup and a separate DDL
498
+ * command for steps that run opaque expressions.
499
+ *
485
500
* 'relationId': the OID of the heap relation on which the index is to be
486
501
* created
487
502
* 'stmt': IndexStmt describing the properties of the new index.
@@ -890,7 +905,8 @@ DefineIndex(Oid relationId,
890
905
coloptions , allIndexParams ,
891
906
stmt -> excludeOpNames , relationId ,
892
907
accessMethodName , accessMethodId ,
893
- amcanorder , stmt -> isconstraint );
908
+ amcanorder , stmt -> isconstraint , root_save_userid ,
909
+ root_save_sec_context , & root_save_nestlevel );
894
910
895
911
/*
896
912
* Extra checks when creating a PRIMARY KEY index.
@@ -1170,11 +1186,8 @@ DefineIndex(Oid relationId,
1170
1186
1171
1187
/*
1172
1188
* Roll back any GUC changes executed by index functions, and keep
1173
- * subsequent changes local to this command. It's barely possible that
1174
- * some index function changed a behavior-affecting GUC, e.g. xmloption,
1175
- * that affects subsequent steps. This improves bug-compatibility with
1176
- * older PostgreSQL versions. They did the AtEOXact_GUC() here for the
1177
- * purpose of clearing the above default_tablespace change.
1189
+ * subsequent changes local to this command. This is essential if some
1190
+ * index function changed a behavior-affecting GUC, e.g. search_path.
1178
1191
*/
1179
1192
AtEOXact_GUC (false, root_save_nestlevel );
1180
1193
root_save_nestlevel = NewGUCNestLevel ();
@@ -1730,6 +1743,10 @@ CheckPredicate(Expr *predicate)
1730
1743
* Compute per-index-column information, including indexed column numbers
1731
1744
* or index expressions, opclasses and their options. Note, all output vectors
1732
1745
* should be allocated for all columns, including "including" ones.
1746
+ *
1747
+ * If the caller switched to the table owner, ddl_userid is the role for ACL
1748
+ * checks reached without traversing opaque expressions. Otherwise, it's
1749
+ * InvalidOid, and other ddl_* arguments are undefined.
1733
1750
*/
1734
1751
static void
1735
1752
ComputeIndexAttrs (IndexInfo * indexInfo ,
@@ -1743,12 +1760,17 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1743
1760
const char * accessMethodName ,
1744
1761
Oid accessMethodId ,
1745
1762
bool amcanorder ,
1746
- bool isconstraint )
1763
+ bool isconstraint ,
1764
+ Oid ddl_userid ,
1765
+ int ddl_sec_context ,
1766
+ int * ddl_save_nestlevel )
1747
1767
{
1748
1768
ListCell * nextExclOp ;
1749
1769
ListCell * lc ;
1750
1770
int attn ;
1751
1771
int nkeycols = indexInfo -> ii_NumIndexKeyAttrs ;
1772
+ Oid save_userid ;
1773
+ int save_sec_context ;
1752
1774
1753
1775
/* Allocate space for exclusion operator info, if needed */
1754
1776
if (exclusionOpNames )
@@ -1762,6 +1784,9 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1762
1784
else
1763
1785
nextExclOp = NULL ;
1764
1786
1787
+ if (OidIsValid (ddl_userid ))
1788
+ GetUserIdAndSecContext (& save_userid , & save_sec_context );
1789
+
1765
1790
/*
1766
1791
* process attributeList
1767
1792
*/
@@ -1892,10 +1917,24 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1892
1917
}
1893
1918
1894
1919
/*
1895
- * Apply collation override if any
1920
+ * Apply collation override if any. Use of ddl_userid is necessary
1921
+ * due to ACL checks therein, and it's safe because collations don't
1922
+ * contain opaque expressions (or non-opaque expressions).
1896
1923
*/
1897
1924
if (attribute -> collation )
1925
+ {
1926
+ if (OidIsValid (ddl_userid ))
1927
+ {
1928
+ AtEOXact_GUC (false, * ddl_save_nestlevel );
1929
+ SetUserIdAndSecContext (ddl_userid , ddl_sec_context );
1930
+ }
1898
1931
attcollation = get_collation_oid (attribute -> collation , false);
1932
+ if (OidIsValid (ddl_userid ))
1933
+ {
1934
+ SetUserIdAndSecContext (save_userid , save_sec_context );
1935
+ * ddl_save_nestlevel = NewGUCNestLevel ();
1936
+ }
1937
+ }
1899
1938
1900
1939
/*
1901
1940
* Check we have a collation iff it's a collatable type. The only
@@ -1923,12 +1962,25 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1923
1962
collationOidP [attn ] = attcollation ;
1924
1963
1925
1964
/*
1926
- * Identify the opclass to use.
1965
+ * Identify the opclass to use. Use of ddl_userid is necessary due to
1966
+ * ACL checks therein. This is safe despite opclasses containing
1967
+ * opaque expressions (specifically, functions), because only
1968
+ * superusers can define opclasses.
1927
1969
*/
1970
+ if (OidIsValid (ddl_userid ))
1971
+ {
1972
+ AtEOXact_GUC (false, * ddl_save_nestlevel );
1973
+ SetUserIdAndSecContext (ddl_userid , ddl_sec_context );
1974
+ }
1928
1975
classOidP [attn ] = ResolveOpClass (attribute -> opclass ,
1929
1976
atttype ,
1930
1977
accessMethodName ,
1931
1978
accessMethodId );
1979
+ if (OidIsValid (ddl_userid ))
1980
+ {
1981
+ SetUserIdAndSecContext (save_userid , save_sec_context );
1982
+ * ddl_save_nestlevel = NewGUCNestLevel ();
1983
+ }
1932
1984
1933
1985
/*
1934
1986
* Identify the exclusion operator, if any.
@@ -1942,9 +1994,23 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1942
1994
1943
1995
/*
1944
1996
* Find the operator --- it must accept the column datatype
1945
- * without runtime coercion (but binary compatibility is OK)
1997
+ * without runtime coercion (but binary compatibility is OK).
1998
+ * Operators contain opaque expressions (specifically, functions).
1999
+ * compatible_oper_opid() boils down to oper() and
2000
+ * IsBinaryCoercible(). PostgreSQL would have security problems
2001
+ * elsewhere if oper() started calling opaque expressions.
1946
2002
*/
2003
+ if (OidIsValid (ddl_userid ))
2004
+ {
2005
+ AtEOXact_GUC (false, * ddl_save_nestlevel );
2006
+ SetUserIdAndSecContext (ddl_userid , ddl_sec_context );
2007
+ }
1947
2008
opid = compatible_oper_opid (opname , atttype , atttype , false);
2009
+ if (OidIsValid (ddl_userid ))
2010
+ {
2011
+ SetUserIdAndSecContext (save_userid , save_sec_context );
2012
+ * ddl_save_nestlevel = NewGUCNestLevel ();
2013
+ }
1948
2014
1949
2015
/*
1950
2016
* Only allow commutative operators to be used in exclusion
0 commit comments