@@ -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.
@@ -899,7 +914,8 @@ DefineIndex(Oid relationId,
899
914
coloptions , allIndexParams ,
900
915
stmt -> excludeOpNames , relationId ,
901
916
accessMethodName , accessMethodId ,
902
- amcanorder , stmt -> isconstraint );
917
+ amcanorder , stmt -> isconstraint , root_save_userid ,
918
+ root_save_sec_context , & root_save_nestlevel );
903
919
904
920
/*
905
921
* Extra checks when creating a PRIMARY KEY index.
@@ -1179,11 +1195,8 @@ DefineIndex(Oid relationId,
1179
1195
1180
1196
/*
1181
1197
* Roll back any GUC changes executed by index functions, and keep
1182
- * subsequent changes local to this command. It's barely possible that
1183
- * some index function changed a behavior-affecting GUC, e.g. xmloption,
1184
- * that affects subsequent steps. This improves bug-compatibility with
1185
- * older PostgreSQL versions. They did the AtEOXact_GUC() here for the
1186
- * purpose of clearing the above default_tablespace change.
1198
+ * subsequent changes local to this command. This is essential if some
1199
+ * index function changed a behavior-affecting GUC, e.g. search_path.
1187
1200
*/
1188
1201
AtEOXact_GUC (false, root_save_nestlevel );
1189
1202
root_save_nestlevel = NewGUCNestLevel ();
@@ -1739,6 +1752,10 @@ CheckPredicate(Expr *predicate)
1739
1752
* Compute per-index-column information, including indexed column numbers
1740
1753
* or index expressions, opclasses and their options. Note, all output vectors
1741
1754
* should be allocated for all columns, including "including" ones.
1755
+ *
1756
+ * If the caller switched to the table owner, ddl_userid is the role for ACL
1757
+ * checks reached without traversing opaque expressions. Otherwise, it's
1758
+ * InvalidOid, and other ddl_* arguments are undefined.
1742
1759
*/
1743
1760
static void
1744
1761
ComputeIndexAttrs (IndexInfo * indexInfo ,
@@ -1752,12 +1769,17 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1752
1769
const char * accessMethodName ,
1753
1770
Oid accessMethodId ,
1754
1771
bool amcanorder ,
1755
- bool isconstraint )
1772
+ bool isconstraint ,
1773
+ Oid ddl_userid ,
1774
+ int ddl_sec_context ,
1775
+ int * ddl_save_nestlevel )
1756
1776
{
1757
1777
ListCell * nextExclOp ;
1758
1778
ListCell * lc ;
1759
1779
int attn ;
1760
1780
int nkeycols = indexInfo -> ii_NumIndexKeyAttrs ;
1781
+ Oid save_userid ;
1782
+ int save_sec_context ;
1761
1783
1762
1784
/* Allocate space for exclusion operator info, if needed */
1763
1785
if (exclusionOpNames )
@@ -1771,6 +1793,9 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1771
1793
else
1772
1794
nextExclOp = NULL ;
1773
1795
1796
+ if (OidIsValid (ddl_userid ))
1797
+ GetUserIdAndSecContext (& save_userid , & save_sec_context );
1798
+
1774
1799
/*
1775
1800
* process attributeList
1776
1801
*/
@@ -1901,10 +1926,24 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1901
1926
}
1902
1927
1903
1928
/*
1904
- * Apply collation override if any
1929
+ * Apply collation override if any. Use of ddl_userid is necessary
1930
+ * due to ACL checks therein, and it's safe because collations don't
1931
+ * contain opaque expressions (or non-opaque expressions).
1905
1932
*/
1906
1933
if (attribute -> collation )
1934
+ {
1935
+ if (OidIsValid (ddl_userid ))
1936
+ {
1937
+ AtEOXact_GUC (false, * ddl_save_nestlevel );
1938
+ SetUserIdAndSecContext (ddl_userid , ddl_sec_context );
1939
+ }
1907
1940
attcollation = get_collation_oid (attribute -> collation , false);
1941
+ if (OidIsValid (ddl_userid ))
1942
+ {
1943
+ SetUserIdAndSecContext (save_userid , save_sec_context );
1944
+ * ddl_save_nestlevel = NewGUCNestLevel ();
1945
+ }
1946
+ }
1908
1947
1909
1948
/*
1910
1949
* Check we have a collation iff it's a collatable type. The only
@@ -1932,12 +1971,25 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1932
1971
collationOidP [attn ] = attcollation ;
1933
1972
1934
1973
/*
1935
- * Identify the opclass to use.
1974
+ * Identify the opclass to use. Use of ddl_userid is necessary due to
1975
+ * ACL checks therein. This is safe despite opclasses containing
1976
+ * opaque expressions (specifically, functions), because only
1977
+ * superusers can define opclasses.
1936
1978
*/
1979
+ if (OidIsValid (ddl_userid ))
1980
+ {
1981
+ AtEOXact_GUC (false, * ddl_save_nestlevel );
1982
+ SetUserIdAndSecContext (ddl_userid , ddl_sec_context );
1983
+ }
1937
1984
classOidP [attn ] = ResolveOpClass (attribute -> opclass ,
1938
1985
atttype ,
1939
1986
accessMethodName ,
1940
1987
accessMethodId );
1988
+ if (OidIsValid (ddl_userid ))
1989
+ {
1990
+ SetUserIdAndSecContext (save_userid , save_sec_context );
1991
+ * ddl_save_nestlevel = NewGUCNestLevel ();
1992
+ }
1941
1993
1942
1994
/*
1943
1995
* Identify the exclusion operator, if any.
@@ -1951,9 +2003,23 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1951
2003
1952
2004
/*
1953
2005
* Find the operator --- it must accept the column datatype
1954
- * without runtime coercion (but binary compatibility is OK)
2006
+ * without runtime coercion (but binary compatibility is OK).
2007
+ * Operators contain opaque expressions (specifically, functions).
2008
+ * compatible_oper_opid() boils down to oper() and
2009
+ * IsBinaryCoercible(). PostgreSQL would have security problems
2010
+ * elsewhere if oper() started calling opaque expressions.
1955
2011
*/
2012
+ if (OidIsValid (ddl_userid ))
2013
+ {
2014
+ AtEOXact_GUC (false, * ddl_save_nestlevel );
2015
+ SetUserIdAndSecContext (ddl_userid , ddl_sec_context );
2016
+ }
1956
2017
opid = compatible_oper_opid (opname , atttype , atttype , false);
2018
+ if (OidIsValid (ddl_userid ))
2019
+ {
2020
+ SetUserIdAndSecContext (save_userid , save_sec_context );
2021
+ * ddl_save_nestlevel = NewGUCNestLevel ();
2022
+ }
1957
2023
1958
2024
/*
1959
2025
* Only allow commutative operators to be used in exclusion
0 commit comments