@@ -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 );
@@ -197,9 +200,8 @@ CheckIndexCompatible(Oid oldId,
197
200
* Compute the operator classes, collations, and exclusion operators for
198
201
* the new index, so we can test whether it's compatible with the existing
199
202
* one. Note that ComputeIndexAttrs might fail here, but that's OK:
200
- * DefineIndex would have called this function with the same arguments
201
- * later on, and it would have failed then anyway. Our attributeList
202
- * contains only key attributes, thus we're filling ii_NumIndexAttrs and
203
+ * DefineIndex would have failed later. Our attributeList contains only
204
+ * key attributes, thus we're filling ii_NumIndexAttrs and
203
205
* ii_NumIndexKeyAttrs with same value.
204
206
*/
205
207
indexInfo = makeIndexInfo (numberOfAttributes ,numberOfAttributes ,
@@ -213,7 +215,7 @@ CheckIndexCompatible(Oid oldId,
213
215
coloptions ,attributeList ,
214
216
exclusionOpNames ,relationId ,
215
217
accessMethodName ,accessMethodId ,
216
- amcanorder ,isconstraint );
218
+ amcanorder ,isconstraint , InvalidOid , 0 , NULL );
217
219
218
220
219
221
/* Get the soon-obsolete pg_index tuple. */
@@ -406,6 +408,19 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
406
408
* DefineIndex
407
409
*Creates a new index.
408
410
*
411
+ * This function manages the current userid according to the needs of pg_dump.
412
+ * Recreating old-database catalog entries in new-database is fine, regardless
413
+ * of which users would have permission to recreate those entries now. That's
414
+ * just preservation of state. Running opaque expressions, like calling a
415
+ * function named in a catalog entry or evaluating a pg_node_tree in a catalog
416
+ * entry, as anyone other than the object owner, is not fine. To adhere to
417
+ * those principles and to remain fail-safe, use the table owner userid for
418
+ * most ACL checks. Use the original userid for ACL checks reached without
419
+ * traversing opaque expressions. (pg_dump can predict such ACL checks from
420
+ * catalogs.) Overall, this is a mess. Future DDL development should
421
+ * consider offering one DDL command for catalog setup and a separate DDL
422
+ * command for steps that run opaque expressions.
423
+ *
409
424
* 'relationId': the OID of the heap relation on which the index is to be
410
425
*created
411
426
* 'stmt': IndexStmt describing the properties of the new index.
@@ -822,7 +837,8 @@ DefineIndex(Oid relationId,
822
837
coloptions ,allIndexParams ,
823
838
stmt -> excludeOpNames ,relationId ,
824
839
accessMethodName ,accessMethodId ,
825
- amcanorder ,stmt -> isconstraint );
840
+ amcanorder ,stmt -> isconstraint ,root_save_userid ,
841
+ root_save_sec_context ,& root_save_nestlevel );
826
842
827
843
/*
828
844
* Extra checks when creating a PRIMARY KEY index.
@@ -1098,11 +1114,8 @@ DefineIndex(Oid relationId,
1098
1114
1099
1115
/*
1100
1116
* Roll back any GUC changes executed by index functions, and keep
1101
- * subsequent changes local to this command. It's barely possible that
1102
- * some index function changed a behavior-affecting GUC, e.g. xmloption,
1103
- * that affects subsequent steps. This improves bug-compatibility with
1104
- * older PostgreSQL versions. They did the AtEOXact_GUC() here for the
1105
- * purpose of clearing the above default_tablespace change.
1117
+ * subsequent changes local to this command. This is essential if some
1118
+ * index function changed a behavior-affecting GUC, e.g. search_path.
1106
1119
*/
1107
1120
AtEOXact_GUC (false,root_save_nestlevel );
1108
1121
root_save_nestlevel = NewGUCNestLevel ();
@@ -1638,6 +1651,10 @@ CheckPredicate(Expr *predicate)
1638
1651
* Compute per-index-column information, including indexed column numbers
1639
1652
* or index expressions, opclasses, and indoptions. Note, all output vectors
1640
1653
* should be allocated for all columns, including "including" ones.
1654
+ *
1655
+ * If the caller switched to the table owner, ddl_userid is the role for ACL
1656
+ * checks reached without traversing opaque expressions. Otherwise, it's
1657
+ * InvalidOid, and other ddl_* arguments are undefined.
1641
1658
*/
1642
1659
static void
1643
1660
ComputeIndexAttrs (IndexInfo * indexInfo ,
@@ -1651,12 +1668,17 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1651
1668
const char * accessMethodName ,
1652
1669
Oid accessMethodId ,
1653
1670
bool amcanorder ,
1654
- bool isconstraint )
1671
+ bool isconstraint ,
1672
+ Oid ddl_userid ,
1673
+ int ddl_sec_context ,
1674
+ int * ddl_save_nestlevel )
1655
1675
{
1656
1676
ListCell * nextExclOp ;
1657
1677
ListCell * lc ;
1658
1678
int attn ;
1659
1679
int nkeycols = indexInfo -> ii_NumIndexKeyAttrs ;
1680
+ Oid save_userid ;
1681
+ int save_sec_context ;
1660
1682
1661
1683
/* Allocate space for exclusion operator info, if needed */
1662
1684
if (exclusionOpNames )
@@ -1670,6 +1692,9 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1670
1692
else
1671
1693
nextExclOp = NULL ;
1672
1694
1695
+ if (OidIsValid (ddl_userid ))
1696
+ GetUserIdAndSecContext (& save_userid ,& save_sec_context );
1697
+
1673
1698
/*
1674
1699
* process attributeList
1675
1700
*/
@@ -1800,10 +1825,24 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1800
1825
}
1801
1826
1802
1827
/*
1803
- * Apply collation override if any
1828
+ * Apply collation override if any. Use of ddl_userid is necessary
1829
+ * due to ACL checks therein, and it's safe because collations don't
1830
+ * contain opaque expressions (or non-opaque expressions).
1804
1831
*/
1805
1832
if (attribute -> collation )
1833
+ {
1834
+ if (OidIsValid (ddl_userid ))
1835
+ {
1836
+ AtEOXact_GUC (false,* ddl_save_nestlevel );
1837
+ SetUserIdAndSecContext (ddl_userid ,ddl_sec_context );
1838
+ }
1806
1839
attcollation = get_collation_oid (attribute -> collation , false);
1840
+ if (OidIsValid (ddl_userid ))
1841
+ {
1842
+ SetUserIdAndSecContext (save_userid ,save_sec_context );
1843
+ * ddl_save_nestlevel = NewGUCNestLevel ();
1844
+ }
1845
+ }
1807
1846
1808
1847
/*
1809
1848
* Check we have a collation iff it's a collatable type. The only
@@ -1831,12 +1870,25 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1831
1870
collationOidP [attn ]= attcollation ;
1832
1871
1833
1872
/*
1834
- * Identify the opclass to use.
1873
+ * Identify the opclass to use. Use of ddl_userid is necessary due to
1874
+ * ACL checks therein. This is safe despite opclasses containing
1875
+ * opaque expressions (specifically, functions), because only
1876
+ * superusers can define opclasses.
1835
1877
*/
1878
+ if (OidIsValid (ddl_userid ))
1879
+ {
1880
+ AtEOXact_GUC (false,* ddl_save_nestlevel );
1881
+ SetUserIdAndSecContext (ddl_userid ,ddl_sec_context );
1882
+ }
1836
1883
classOidP [attn ]= ResolveOpClass (attribute -> opclass ,
1837
1884
atttype ,
1838
1885
accessMethodName ,
1839
1886
accessMethodId );
1887
+ if (OidIsValid (ddl_userid ))
1888
+ {
1889
+ SetUserIdAndSecContext (save_userid ,save_sec_context );
1890
+ * ddl_save_nestlevel = NewGUCNestLevel ();
1891
+ }
1840
1892
1841
1893
/*
1842
1894
* Identify the exclusion operator, if any.
@@ -1850,9 +1902,23 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
1850
1902
1851
1903
/*
1852
1904
* Find the operator --- it must accept the column datatype
1853
- * without runtime coercion (but binary compatibility is OK)
1905
+ * without runtime coercion (but binary compatibility is OK).
1906
+ * Operators contain opaque expressions (specifically, functions).
1907
+ * compatible_oper_opid() boils down to oper() and
1908
+ * IsBinaryCoercible(). PostgreSQL would have security problems
1909
+ * elsewhere if oper() started calling opaque expressions.
1854
1910
*/
1911
+ if (OidIsValid (ddl_userid ))
1912
+ {
1913
+ AtEOXact_GUC (false,* ddl_save_nestlevel );
1914
+ SetUserIdAndSecContext (ddl_userid ,ddl_sec_context );
1915
+ }
1855
1916
opid = compatible_oper_opid (opname ,atttype ,atttype , false);
1917
+ if (OidIsValid (ddl_userid ))
1918
+ {
1919
+ SetUserIdAndSecContext (save_userid ,save_sec_context );
1920
+ * ddl_save_nestlevel = NewGUCNestLevel ();
1921
+ }
1856
1922
1857
1923
/*
1858
1924
* Only allow commutative operators to be used in exclusion