@@ -79,7 +79,10 @@ static void ComputeIndexAttrs(IndexInfo *indexInfo,
79
79
Oid relId ,
80
80
const char * accessMethodName , Oid accessMethodId ,
81
81
bool amcanorder ,
82
- bool isconstraint );
82
+ bool isconstraint ,
83
+ Oid ddl_userid ,
84
+ int ddl_sec_context ,
85
+ int * ddl_save_nestlevel );
83
86
static char * ChooseIndexName (const char * tabname , Oid namespaceId ,
84
87
List * colnames , List * exclusionOpNames ,
85
88
bool primary , bool isconstraint );
@@ -198,9 +201,8 @@ CheckIndexCompatible(Oid oldId,
198
201
* Compute the operator classes, collations, and exclusion operators for
199
202
* the new index, so we can test whether it's compatible with the existing
200
203
* one. Note that ComputeIndexAttrs might fail here, but that's OK:
201
- * DefineIndex would have called this function with the same arguments
202
- * later on, and it would have failed then anyway. Our attributeList
203
- * contains only key attributes, thus we're filling ii_NumIndexAttrs and
204
+ * DefineIndex would have failed later. Our attributeList contains only
205
+ * key attributes, thus we're filling ii_NumIndexAttrs and
204
206
* ii_NumIndexKeyAttrs with same value.
205
207
*/
206
208
indexInfo = makeIndexInfo (numberOfAttributes , numberOfAttributes ,
@@ -214,7 +216,7 @@ CheckIndexCompatible(Oid oldId,
214
216
coloptions , attributeList ,
215
217
exclusionOpNames , relationId ,
216
218
accessMethodName , accessMethodId ,
217
- amcanorder , isconstraint );
219
+ amcanorder , isconstraint , InvalidOid , 0 , NULL );
218
220
219
221
220
222
/* Get the soon-obsolete pg_index tuple. */
@@ -455,6 +457,19 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
455
457
* DefineIndex
456
458
* Creates a new index.
457
459
*
460
+ * This function manages the current userid according to the needs of pg_dump.
461
+ * Recreating old-database catalog entries in new-database is fine, regardless
462
+ * of which users would have permission to recreate those entries now. That's
463
+ * just preservation of state. Running opaque expressions, like calling a
464
+ * function named in a catalog entry or evaluating a pg_node_tree in a catalog
465
+ * entry, as anyone other than the object owner, is not fine. To adhere to
466
+ * those principles and to remain fail-safe, use the table owner userid for
467
+ * most ACL checks. Use the original userid for ACL checks reached without
468
+ * traversing opaque expressions. (pg_dump can predict such ACL checks from
469
+ * catalogs.) Overall, this is a mess. Future DDL development should
470
+ * consider offering one DDL command for catalog setup and a separate DDL
471
+ * command for steps that run opaque expressions.
472
+ *
458
473
* 'relationId': the OID of the heap relation on which the index is to be
459
474
* created
460
475
* 'stmt': IndexStmt describing the properties of the new index.
@@ -871,7 +886,8 @@ DefineIndex(Oid relationId,
871
886
coloptions , allIndexParams ,
872
887
stmt -> excludeOpNames , relationId ,
873
888
accessMethodName , accessMethodId ,
874
- amcanorder , stmt -> isconstraint );
889
+ amcanorder , stmt -> isconstraint , root_save_userid ,
890
+ root_save_sec_context , & root_save_nestlevel );
875
891
876
892
/*
877
893
* Extra checks when creating a PRIMARY KEY index.
@@ -1147,11 +1163,8 @@ DefineIndex(Oid relationId,
1147
1163
1148
1164
/*
1149
1165
* Roll back any GUC changes executed by index functions, and keep
1150
- * subsequent changes local to this command. It's barely possible that
1151
- * some index function changed a behavior-affecting GUC, e.g. xmloption,
1152
- * that affects subsequent steps. This improves bug-compatibility with
1153
- * older PostgreSQL versions. They did the AtEOXact_GUC() here for the
1154
- * purpose of clearing the above default_tablespace change.
1166
+ * subsequent changes local to this command. This is essential if some
1167
+ * index function changed a behavior-affecting GUC, e.g. search_path.
1155
1168
*/
1156
1169
AtEOXact_GUC (false, root_save_nestlevel );
1157
1170
root_save_nestlevel = NewGUCNestLevel ();
@@ -1686,6 +1699,10 @@ CheckPredicate(Expr *predicate)
1686
1699
* Compute per-index-column information, including indexed column numbers
1687
1700
* or index expressions, opclasses and their options. Note, all output vectors
1688
1701
* should be allocated for all columns, including "including" ones.
1702
+ *
1703
+ * If the caller switched to the table owner, ddl_userid is the role for ACL
1704
+ * checks reached without traversing opaque expressions. Otherwise, it's
1705
+ * InvalidOid, and other ddl_* arguments are undefined.
1689
1706
*/
1690
1707
static void
1691
1708
ComputeIndexAttrs (IndexInfo * indexInfo ,
@@ -1699,12 +1716,17 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1699
1716
const char * accessMethodName ,
1700
1717
Oid accessMethodId ,
1701
1718
bool amcanorder ,
1702
- bool isconstraint )
1719
+ bool isconstraint ,
1720
+ Oid ddl_userid ,
1721
+ int ddl_sec_context ,
1722
+ int * ddl_save_nestlevel )
1703
1723
{
1704
1724
ListCell * nextExclOp ;
1705
1725
ListCell * lc ;
1706
1726
int attn ;
1707
1727
int nkeycols = indexInfo -> ii_NumIndexKeyAttrs ;
1728
+ Oid save_userid ;
1729
+ int save_sec_context ;
1708
1730
1709
1731
/* Allocate space for exclusion operator info, if needed */
1710
1732
if (exclusionOpNames )
@@ -1718,6 +1740,9 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1718
1740
else
1719
1741
nextExclOp = NULL ;
1720
1742
1743
+ if (OidIsValid (ddl_userid ))
1744
+ GetUserIdAndSecContext (& save_userid , & save_sec_context );
1745
+
1721
1746
/*
1722
1747
* process attributeList
1723
1748
*/
@@ -1848,10 +1873,24 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1848
1873
}
1849
1874
1850
1875
/*
1851
- * Apply collation override if any
1876
+ * Apply collation override if any. Use of ddl_userid is necessary
1877
+ * due to ACL checks therein, and it's safe because collations don't
1878
+ * contain opaque expressions (or non-opaque expressions).
1852
1879
*/
1853
1880
if (attribute -> collation )
1881
+ {
1882
+ if (OidIsValid (ddl_userid ))
1883
+ {
1884
+ AtEOXact_GUC (false, * ddl_save_nestlevel );
1885
+ SetUserIdAndSecContext (ddl_userid , ddl_sec_context );
1886
+ }
1854
1887
attcollation = get_collation_oid (attribute -> collation , false);
1888
+ if (OidIsValid (ddl_userid ))
1889
+ {
1890
+ SetUserIdAndSecContext (save_userid , save_sec_context );
1891
+ * ddl_save_nestlevel = NewGUCNestLevel ();
1892
+ }
1893
+ }
1855
1894
1856
1895
/*
1857
1896
* Check we have a collation iff it's a collatable type. The only
@@ -1879,12 +1918,25 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1879
1918
collationOidP [attn ] = attcollation ;
1880
1919
1881
1920
/*
1882
- * Identify the opclass to use.
1921
+ * Identify the opclass to use. Use of ddl_userid is necessary due to
1922
+ * ACL checks therein. This is safe despite opclasses containing
1923
+ * opaque expressions (specifically, functions), because only
1924
+ * superusers can define opclasses.
1883
1925
*/
1926
+ if (OidIsValid (ddl_userid ))
1927
+ {
1928
+ AtEOXact_GUC (false, * ddl_save_nestlevel );
1929
+ SetUserIdAndSecContext (ddl_userid , ddl_sec_context );
1930
+ }
1884
1931
classOidP [attn ] = ResolveOpClass (attribute -> opclass ,
1885
1932
atttype ,
1886
1933
accessMethodName ,
1887
1934
accessMethodId );
1935
+ if (OidIsValid (ddl_userid ))
1936
+ {
1937
+ SetUserIdAndSecContext (save_userid , save_sec_context );
1938
+ * ddl_save_nestlevel = NewGUCNestLevel ();
1939
+ }
1888
1940
1889
1941
/*
1890
1942
* Identify the exclusion operator, if any.
@@ -1898,9 +1950,23 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1898
1950
1899
1951
/*
1900
1952
* Find the operator --- it must accept the column datatype
1901
- * without runtime coercion (but binary compatibility is OK)
1953
+ * without runtime coercion (but binary compatibility is OK).
1954
+ * Operators contain opaque expressions (specifically, functions).
1955
+ * compatible_oper_opid() boils down to oper() and
1956
+ * IsBinaryCoercible(). PostgreSQL would have security problems
1957
+ * elsewhere if oper() started calling opaque expressions.
1902
1958
*/
1959
+ if (OidIsValid (ddl_userid ))
1960
+ {
1961
+ AtEOXact_GUC (false, * ddl_save_nestlevel );
1962
+ SetUserIdAndSecContext (ddl_userid , ddl_sec_context );
1963
+ }
1903
1964
opid = compatible_oper_opid (opname , atttype , atttype , false);
1965
+ if (OidIsValid (ddl_userid ))
1966
+ {
1967
+ SetUserIdAndSecContext (save_userid , save_sec_context );
1968
+ * ddl_save_nestlevel = NewGUCNestLevel ();
1969
+ }
1904
1970
1905
1971
/*
1906
1972
* Only allow commutative operators to be used in exclusion
0 commit comments