static HTAB *createConnHash(void);
static void createNewConnection(const char *name, remoteConn *rconn);
static void deleteConnection(const char *name);
-static char **get_pkey_attnames(Relation rel, int16 *indnkeyatts);
+static char **get_pkey_attnames(Relation rel, int16 *numatts);
static char **get_text_array_contents(ArrayType *array, int *numitems);
static char *get_sql_insert(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals, char **tgt_pkattvals);
static char *get_sql_delete(Relation rel, int *pkattnums, int pknumatts, char **tgt_pkattvals);
Datum
dblink_get_pkey(PG_FUNCTION_ARGS)
{
- int16 indnkeyatts;
+ int16 numatts;
char **results;
FuncCallContext *funcctx;
int32 call_cntr;
rel = get_rel_from_relname(PG_GETARG_TEXT_P(0), AccessShareLock, ACL_SELECT);
/* get the array of attnums */
- results = get_pkey_attnames(rel, &indnkeyatts);
+ results = get_pkey_attnames(rel, &numatts);
relation_close(rel, AccessShareLock);
attinmeta = TupleDescGetAttInMetadata(tupdesc);
funcctx->attinmeta = attinmeta;
- if ((results != NULL) && (indnkeyatts > 0))
+ if ((results != NULL) && (numatts > 0))
{
- funcctx->max_calls = indnkeyatts;
+ funcctx->max_calls = numatts;
/* got results, keep track of them */
funcctx->user_fctx = results;
* get_pkey_attnames
*
* Get the primary key attnames for the given relation.
- * Return NULL, and set indnkeyatts = 0, if no primary key exists.
+ * Return NULL, and set numatts = 0, if no primary key exists.
*/
static char **
-get_pkey_attnames(Relation rel, int16 *indnkeyatts)
+get_pkey_attnames(Relation rel, int16 *numatts)
{
Relation indexRelation;
ScanKeyData skey;
char **result = NULL;
TupleDesc tupdesc;
- /* initialize indnkeyatts to 0 in case no primary key exists */
- *indnkeyatts = 0;
+ /* initialize numatts to 0 in case no primary key exists */
+ *numatts = 0;
tupdesc = rel->rd_att;
/* we're only interested if it is the primary key */
if (index->indisprimary)
{
- *indnkeyatts = index->indnkeyatts;
- if (*indnkeyatts > 0)
+ *numatts = index->indnatts;
+ if (*numatts > 0)
{
- result = (char **) palloc(*indnkeyatts * sizeof(char *));
+ result = (char **) palloc(*numatts * sizeof(char *));
- for (i = 0; i < *indnkeyatts; i++)
+ for (i = 0; i < *numatts; i++)
result[i] = SPI_fname(tupdesc, index->indkey.values[i]);
}
break;
/* we're only interested if it is the primary key and valid */
if (index->indisprimary && IndexIsValid(index))
{
- int indnkeyatts = index->indnkeyatts;
+ int numatts = index->indnatts;
- if (indnkeyatts > 0)
+ if (numatts > 0)
{
int i;
appendStringInfoCharMacro(payload, ',');
appendStringInfoCharMacro(payload, operation);
- for (i = 0; i < indnkeyatts; i++)
+ for (i = 0; i < numatts; i++)
{
int colno = index->indkey.values[i];
<literal>pg_class.relnatts</literal>)</entry>
</row>
- <row>
- <entry><structfield>indnkeyatts</structfield></entry>
- <entry><type>int2</type></entry>
- <entry></entry>
- <entry>The number of key columns in the index. "Key columns" are ordinary
- index columns in contrast with "included" columns.</entry>
- </row>
-
<row>
<entry><structfield>indisunique</structfield></entry>
<entry><type>bool</type></entry>
bool amclusterable;
/* does AM handle predicate locks? */
bool ampredlocks;
- /* does AM support columns included with clause INCLUDING? */
- bool amcaninclude;
/* type of data stored in index, or InvalidOid if variable */
Oid amkeytype;
using <firstterm>unique indexes</>, which are indexes that disallow
multiple entries with identical keys. An access method that supports this
feature sets <structfield>amcanunique</> true.
- (At present, only B-tree supports it.) Columns which are present in the
- <literal>INCLUDING</> clause are not used to enforce uniqueness.
+ (At present, only b-tree supports it.)
</para>
<para>
Indexes can also be used to enforce uniqueness of a column's value,
or the uniqueness of the combined values of more than one column.
<synopsis>
-CREATE UNIQUE INDEX <replaceable>name</replaceable> ON <replaceable>table</replaceable> (<replaceable>column</replaceable> <optional>, ...</optional>)
-<optional>INCLUDING (<replaceable>column</replaceable> <optional>, ...</optional>)</optional>;
+CREATE UNIQUE INDEX <replaceable>name</replaceable> ON <replaceable>table</replaceable> (<replaceable>column</replaceable> <optional>, ...</optional>);
</synopsis>
Currently, only B-tree indexes can be declared unique.
</para>
When an index is declared unique, multiple table rows with equal
indexed values are not allowed. Null values are not considered
equal. A multicolumn unique index will only reject cases where all
- indexed columns are equal in multiple rows. Columns included with clause
- <literal>INCLUDING</literal> aren't used to enforce constraints (UNIQUE,
- PRIMARY KEY, etc).
+ indexed columns are equal in multiple rows.
</para>
<para>
<synopsis>
CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> ] ON <replaceable class="parameter">table_name</replaceable> [ USING <replaceable class="parameter">method</replaceable> ]
( { <replaceable class="parameter">column_name</replaceable> | ( <replaceable class="parameter">expression</replaceable> ) } [ COLLATE <replaceable class="parameter">collation</replaceable> ] [ <replaceable class="parameter">opclass</replaceable> ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] )
- [ INCLUDING ( <replaceable class="parameter">column_name</replaceable> [, ...] ) ]
[ WITH ( <replaceable class="PARAMETER">storage_parameter</replaceable> = <replaceable class="PARAMETER">value</replaceable> [, ... ] ) ]
[ TABLESPACE <replaceable class="parameter">tablespace_name</replaceable> ]
[ WHERE <replaceable class="parameter">predicate</replaceable> ]
</listitem>
</varlistentry>
- <varlistentry>
- <term><literal>INCLUDING</literal></term>
- <listitem>
- <para>
- An optional <literal>INCLUDING</> clause allows a list of columns to be
- specified which will be included in the index, in the non-key portion of
- the index. Columns which are part of this clause cannot also exist in
- the key columns portion of the index, and vice versa. The
- <literal>INCLUDING</> columns exist solely to allow more queries to
- benefit from <firstterm>index-only scans</> by including certain
- columns in the index, the value of which would otherwise have to be
- obtained by reading
- the table's heap. Having these columns in the <literal>INCLUDING</>
- clause in some cases allows <productname>PostgreSQL</> to skip the heap
- read completely. This also allows <literal>UNIQUE</> indexes to be
- defined on one set of columns, which can include another set of column
- in the <literal>INCLUDING</> clause, on which the uniqueness is not
- enforced upon. It's the same with other constraints (PRIMARY KEY and
- EXCLUDE). This can also can be used for non-unique indexes as any
- columns which are not required for the searching or ordering of records
- can be included in the <literal>INCLUDING</> clause, which can slightly
- reduce the size of the index, due to storing included attributes only
- in leaf index pages. Currently, only the B-tree access method supports
- this feature. Expressions as included columns are not supported since
- they cannot be used in index-only scan.
- </para>
- </listitem>
- </varlistentry>
-
<varlistentry>
<term><replaceable class="parameter">name</replaceable></term>
<listitem>
<title>Examples</title>
<para>
- To create a unique B-tree index on the column <literal>title</literal> in
+ To create a B-tree index on the column <literal>title</literal> in
the table <literal>films</literal>:
<programlisting>
CREATE UNIQUE INDEX title_idx ON films (title);
</programlisting>
</para>
- <para>
- To create a unique B-tree index on the column <literal>title</literal>
- and included columns <literal>director</literal> and <literal>rating</literal>
- in the table <literal>films</literal>:
-<programlisting>
-CREATE UNIQUE INDEX title_idx ON films (title) INCLUDING (director, rating);
-</programlisting>
- </para>
-
<para>
To create an index on the expression <literal>lower(title)</>,
allowing efficient case-insensitive searches:
[ CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ]
{ CHECK ( <replaceable class="PARAMETER">expression</replaceable> ) [ NO INHERIT ] |
- UNIQUE ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) <replaceable class="PARAMETER">index_parameters</replaceable> <optional>INCLUDING (<replaceable class="PARAMETER">column_name</replaceable> [, ...])</optional> |
- PRIMARY KEY ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) <replaceable class="PARAMETER">index_parameters</replaceable> <optional>INCLUDING (<replaceable class="PARAMETER">column_name</replaceable> [, ...])</optional> |
+ UNIQUE ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) <replaceable class="PARAMETER">index_parameters</replaceable> |
+ PRIMARY KEY ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) <replaceable class="PARAMETER">index_parameters</replaceable> |
EXCLUDE [ USING <replaceable class="parameter">index_method</replaceable> ] ( <replaceable class="parameter">exclude_element</replaceable> WITH <replaceable class="parameter">operator</replaceable> [, ... ] ) <replaceable class="parameter">index_parameters</replaceable> [ WHERE ( <replaceable class="parameter">predicate</replaceable> ) ] |
FOREIGN KEY ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) REFERENCES <replaceable class="PARAMETER">reftable</replaceable> [ ( <replaceable class="PARAMETER">refcolumn</replaceable> [, ... ] ) ]
[ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE <replaceable class="parameter">action</replaceable> ] [ ON UPDATE <replaceable class="parameter">action</replaceable> ] }
<varlistentry>
<term><literal>UNIQUE</> (column constraint)</term>
- <term><literal>UNIQUE ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] )
- <optional>INCLUDING ( <replaceable class="PARAMETER">column_name</replaceable> [, ...])</optional></> (table constraint)</term>
+ <term><literal>UNIQUE ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] )</> (table constraint)</term>
+
<listitem>
<para>
The <literal>UNIQUE</literal> constraint specifies that a
primary key constraint defined for the table. (Otherwise it
would just be the same constraint listed twice.)
</para>
-
- <para>
- Adding a unique constraint will automatically create a unique btree
- index on the column or group of columns used in the constraint.
- Optional clause <literal>INCLUDING</literal> allows to add into the index
- a portion of columns on which the uniqueness is not enforced upon.
- Note, that althogh constraint is not enforced upon included columns, it still
- depends on them. Consequently, some operations on these columns (e.g. <literal>DROP COLUMN</literal>)
- can cause cascade constraint and index deletion.
- See paragraph about <literal>INCLUDING</literal> in
- <xref linkend="SQL-CREATEINDEX"> for more information.
- </para>
-
</listitem>
</varlistentry>
<varlistentry>
<term><literal>PRIMARY KEY</> (column constraint)</term>
- <term><literal>PRIMARY KEY ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] )
- <optional>INCLUDING ( <replaceable class="PARAMETER">column_name</replaceable> [, ...])</optional></> (table constraint)</term>
+ <term><literal>PRIMARY KEY ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] )</> (table constraint)</term>
<listitem>
<para>
The <literal>PRIMARY KEY</> constraint specifies that a column or
about the design of the schema, since a primary key implies that other
tables can rely on this set of columns as a unique identifier for rows.
</para>
-
- <para>
- Adding a <literal>PRIMARY KEY</literal> constraint will automatically create a unique btree
- index on the column or group of columns used in the constraint.
- Optional clause <literal>INCLUDING</literal> allows to add into the index
- a portion of columns on which the constraint is not enforced upon.
- Note, that althogh constraint is not enforced upon included columns, it still
- depends on them. Consequently, some operations on these columns (e.g. <literal>DROP COLUMN</literal>)
- can cause cascade constraint and index deletion.
- See paragraph about <literal>INCLUDING</literal> in
- <xref linkend="SQL-CREATEINDEX"> for more information.
- </para>
</listitem>
</varlistentry>
amroutine->amstorage = true;
amroutine->amclusterable = false;
amroutine->ampredlocks = false;
- amroutine->amcaninclude = false;
amroutine->amkeytype = InvalidOid;
amroutine->ambuild = brinbuild;
#include "access/heapam.h"
#include "access/itup.h"
#include "access/tuptoaster.h"
-#include "utils/rel.h"
/* ----------------------------------------------------------------
memcpy(result, source, size);
return result;
}
-
-/*
- * Reform index tuple. Truncate nonkey (INCLUDING) attributes.
- */
-IndexTuple
-index_truncate_tuple(Relation idxrel, IndexTuple olditup)
-{
- TupleDesc itupdesc = RelationGetDescr(idxrel);
- Datum values[INDEX_MAX_KEYS];
- bool isnull[INDEX_MAX_KEYS];
- IndexTuple newitup;
- int indnatts = IndexRelationGetNumberOfAttributes(idxrel);
- int indnkeyatts = IndexRelationGetNumberOfKeyAttributes(idxrel);
-
- Assert(indnatts <= INDEX_MAX_KEYS);
- Assert(indnkeyatts > 0);
- Assert(indnkeyatts < indnatts);
-
- index_deform_tuple(olditup, itupdesc, values, isnull);
-
- /* form new tuple that will contain only key attributes */
- itupdesc->natts = indnkeyatts;
- newitup = index_form_tuple(itupdesc, values, isnull);
- newitup->t_tid = olditup->t_tid;
-
- itupdesc->natts = indnatts;
-
- Assert(IndexTupleSize(newitup) <= IndexTupleSize(olditup));
- return newitup;
-}
amroutine->amstorage = true;
amroutine->amclusterable = false;
amroutine->ampredlocks = false;
- amroutine->amcaninclude = false;
amroutine->amkeytype = InvalidOid;
amroutine->ambuild = ginbuild;
amroutine->amstorage = true;
amroutine->amclusterable = true;
amroutine->ampredlocks = false;
- amroutine->amcaninclude = false;
amroutine->amkeytype = InvalidOid;
amroutine->ambuild = gistbuild;
amroutine->amstorage = false;
amroutine->amclusterable = false;
amroutine->ampredlocks = false;
- amroutine->amcaninclude = false;
amroutine->amkeytype = INT4OID;
amroutine->ambuild = hashbuild;
StringInfoData buf;
Form_pg_index idxrec;
HeapTuple ht_idx;
- int indnkeyatts;
+ int natts = indexRelation->rd_rel->relnatts;
int i;
int keyno;
Oid indexrelid = RelationGetRelid(indexRelation);
Oid indrelid;
AclResult aclresult;
- indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
-
/*
* Check permissions- if the user does not have access to view all of the
* key columns then return NULL to avoid leaking data.
* No table-level access, so step through the columns in the index and
* make sure the user has SELECT rights on all of them.
*/
- for (keyno = 0; keyno < idxrec->indnkeyatts; keyno++)
+ for (keyno = 0; keyno < idxrec->indnatts; keyno++)
{
AttrNumber attnum = idxrec->indkey.values[keyno];
appendStringInfo(&buf, "(%s)=(",
pg_get_indexdef_columns(indexrelid, true));
- for (i = 0; i < indnkeyatts; i++)
+ for (i = 0; i < natts; i++)
{
char *val;
{
int j;
- for (j = 0; j < IndexRelationGetNumberOfAttributes(irel); j++)
+ for (j = 0; j < irel->rd_index->indnatts; j++)
{
if (key[i].sk_attno == irel->rd_index->indkey.values[j])
{
break;
}
}
- if (j == IndexRelationGetNumberOfAttributes(irel))
+ if (j == irel->rd_index->indnatts)
elog(ERROR, "column is not in index");
}
{
int j;
- for (j = 0; j < IndexRelationGetNumberOfAttributes(indexRelation); j++)
+ for (j = 0; j < indexRelation->rd_index->indnatts; j++)
{
if (key[i].sk_attno == indexRelation->rd_index->indkey.values[j])
{
break;
}
}
- if (j == IndexRelationGetNumberOfAttributes(indexRelation))
+ if (j == indexRelation->rd_index->indnatts)
elog(ERROR, "column is not in index");
}
static void _bt_checksplitloc(FindSplitData *state,
OffsetNumber firstoldonright, bool newitemonleft,
int dataitemstoleft, Size firstoldonrightsz);
+static bool _bt_pgaddtup(Page page, Size itemsize, IndexTuple itup,
+ OffsetNumber itup_off);
static bool _bt_isequal(TupleDesc itupdesc, Page page, OffsetNumber offnum,
int keysz, ScanKey scankey);
static void _bt_vacuum_one_page(Relation rel, Buffer buffer, Relation heapRel);
IndexUniqueCheck checkUnique, Relation heapRel)
{
bool is_unique = false;
- int indnkeyatts;
+ int natts = rel->rd_rel->relnatts;
ScanKey itup_scankey;
BTStack stack;
Buffer buf;
OffsetNumber offset;
- Assert(IndexRelationGetNumberOfAttributes(rel) != 0);
- indnkeyatts = IndexRelationGetNumberOfKeyAttributes(rel);
- Assert(indnkeyatts != 0);
-
/* we need an insertion scan key to do our search, so build one */
itup_scankey = _bt_mkscankey(rel, itup);
top:
/* find the first page containing this key */
- stack = _bt_search(rel, indnkeyatts, itup_scankey, false, &buf, BT_WRITE);
+ stack = _bt_search(rel, natts, itup_scankey, false, &buf, BT_WRITE);
offset = InvalidOffsetNumber;
* move right in the tree. See Lehman and Yao for an excruciatingly
* precise description.
*/
- buf = _bt_moveright(rel, buf, indnkeyatts, itup_scankey, false,
+ buf = _bt_moveright(rel, buf, natts, itup_scankey, false,
true, stack, BT_WRITE);
/*
TransactionId xwait;
uint32 speculativeToken;
- offset = _bt_binsrch(rel, buf, indnkeyatts, itup_scankey, false);
+ offset = _bt_binsrch(rel, buf, natts, itup_scankey, false);
xwait = _bt_check_unique(rel, itup, heapRel, buf, offset, itup_scankey,
checkUnique, &is_unique, &speculativeToken);
*/
CheckForSerializableConflictIn(rel, NULL, buf);
/* do the insertion */
- _bt_findinsertloc(rel, &buf, &offset, indnkeyatts, itup_scankey, itup,
+ _bt_findinsertloc(rel, &buf, &offset, natts, itup_scankey, itup,
stack, heapRel);
_bt_insertonpg(rel, buf, InvalidBuffer, stack, itup, offset, false);
}
uint32 *speculativeToken)
{
TupleDesc itupdesc = RelationGetDescr(rel);
- int indnkeyatts = IndexRelationGetNumberOfKeyAttributes(rel);
+ int natts = rel->rd_rel->relnatts;
SnapshotData SnapshotDirty;
OffsetNumber maxoff;
Page page;
* in real comparison, but only for ordering/finding items on
* pages. - vadim 03/24/97
*/
- if (!_bt_isequal(itupdesc, page, offset, indnkeyatts, itup_scankey))
+ if (!_bt_isequal(itupdesc, page, offset, natts, itup_scankey))
break; /* we're past all the equal tuples */
/* okay, we gotta fetch the heap tuple ... */
if (P_RIGHTMOST(opaque))
break;
if (!_bt_isequal(itupdesc, page, P_HIKEY,
- indnkeyatts, itup_scankey))
+ natts, itup_scankey))
break;
/* Advance to next non-dead page --- there must be one */
for (;;)
OffsetNumber i;
bool isroot;
bool isleaf;
- IndexTuple lefthikey;
- int indnatts = IndexRelationGetNumberOfAttributes(rel);
- int indnkeyatts = IndexRelationGetNumberOfKeyAttributes(rel);
/* Acquire a new page to split into */
rbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);
itemsz = ItemIdGetLength(itemid);
item = (IndexTuple) PageGetItem(origpage, itemid);
}
-
- /*
- * We must truncate the "high key" item, before insert it onto the leaf page.
- * It's the only point in insertion process, where we perform truncation.
- * All other functions work with this high key and do not change it.
- */
- if (indnatts != indnkeyatts && P_ISLEAF(lopaque))
- {
- lefthikey = index_truncate_tuple(rel, item);
- itemsz = IndexTupleSize(lefthikey);
- itemsz = MAXALIGN(itemsz);
- }
- else
- lefthikey = item;
-
- if (PageAddItem(leftpage, (Item) lefthikey, itemsz, leftoff,
+ if (PageAddItem(leftpage, (Item) item, itemsz, leftoff,
false, false) == InvalidOffsetNumber)
{
memset(rightpage, 0, BufferGetPageSize(rbuf));
itemid = PageGetItemId(lpage, P_HIKEY);
right_item_sz = ItemIdGetLength(itemid);
item = (IndexTuple) PageGetItem(lpage, itemid);
-
right_item = CopyIndexTuple(item);
ItemPointerSet(&(right_item->t_tid), rbkno, P_HIKEY);
* we insert the tuples in order, so that the given itup_off does
* represent the final position of the tuple!
*/
-bool
+static bool
_bt_pgaddtup(Page page,
Size itemsize,
IndexTuple itup,
/* we need an insertion scan key for the search, so build one */
itup_scankey = _bt_mkscankey(rel, targetkey);
/* find the leftmost leaf page containing this key */
- stack = _bt_search(rel,
- IndexRelationGetNumberOfKeyAttributes(rel),
- itup_scankey, false, &lbuf, BT_READ);
+ stack = _bt_search(rel, rel->rd_rel->relnatts, itup_scankey,
+ false, &lbuf, BT_READ);
/* don't need a pin on the page */
_bt_relbuf(rel, lbuf);
amroutine->amstorage = false;
amroutine->amclusterable = true;
amroutine->ampredlocks = true;
- amroutine->amcaninclude = true;
amroutine->amkeytype = InvalidOid;
amroutine->ambuild = btbuild;
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
- Assert (keysz <= rel->rd_index->indnkeyatts);
-
/*
* The scan key is set up with the attribute number associated with each
* term in the key. It is important that, if the index is multi-key, the
OffsetNumber last_off;
Size pgspc;
Size itupsz;
- BTPageOpaque pageop;
- int indnatts = IndexRelationGetNumberOfAttributes(wstate->index);
- int indnkeyatts = IndexRelationGetNumberOfKeyAttributes(wstate->index);
/*
* This is a handy place to check for cancel interrupts during the btree
ItemId ii;
ItemId hii;
IndexTuple oitup;
- IndexTuple keytup;
- BTPageOpaque opageop = (BTPageOpaque) PageGetSpecialPointer(opage);
/* Create new page of same level */
npage = _bt_blnewpage(state->btps_level);
ItemIdSetUnused(ii); /* redundant */
((PageHeader) opage)->pd_lower -= sizeof(ItemIdData);
- if (indnkeyatts != indnatts && P_ISLEAF(opageop))
- {
- /*
- * It's essential to truncate High key here.
- * The purpose is not just to save more space on this particular page,
- * but to keep whole b-tree structure consistent. Subsequent insertions
- * assume that hikey is already truncated, and so they should not
- * worry about it, when copying the high key into the parent page
- * as a downlink.
- * NOTE It is not crutial for reliability in present,
- * but maybe it will be that in the future.
- */
- keytup = index_truncate_tuple(wstate->index, oitup);
-
- /* delete "wrong" high key, insert keytup as P_HIKEY. */
- PageIndexTupleDelete(opage, P_HIKEY);
-
- if (!_bt_pgaddtup(opage, IndexTupleSize(keytup), keytup, P_HIKEY))
- elog(ERROR, "failed to rewrite compressed item in index \"%s\"",
- RelationGetRelationName(wstate->index));
- }
-
/*
* Link the old page into its parent, using its minimum key. If we
* don't have a parent, we have to create one; this adds a new btree
* Save a copy of the minimum key for the new page. We have to copy
* it off the old page, not the new one, in case we are not at leaf
* level.
- * If tuple contains non-key attributes, truncate them.
- * We perform truncation only for leaf pages,
- * beacuse all tuples at inner pages will be already
- * truncated by the time we handle them.
*/
- if (indnkeyatts != indnatts && P_ISLEAF(opageop))
- state->btps_minkey = index_truncate_tuple(wstate->index, oitup);
- else
- state->btps_minkey = CopyIndexTuple(oitup);
+ state->btps_minkey = CopyIndexTuple(oitup);
/*
* Set the sibling links for both pages.
last_off = P_FIRSTKEY;
}
- pageop = (BTPageOpaque) PageGetSpecialPointer(npage);
/*
* If the new item is the first for its page, stash a copy for later. Note
* this will only happen for the first item on a level; on later pages,
if (last_off == P_HIKEY)
{
Assert(state->btps_minkey == NULL);
- /*
- * Truncate the tuple that we're going to insert
- * into the parent page as a downlink
- */
- if (indnkeyatts != indnatts && P_ISLEAF(pageop))
- state->btps_minkey = index_truncate_tuple(wstate->index, itup);
- else
- state->btps_minkey = CopyIndexTuple(itup);
+ state->btps_minkey = CopyIndexTuple(itup);
}
/*
load1;
TupleDesc tupdes = RelationGetDescr(wstate->index);
int i,
- keysz = IndexRelationGetNumberOfKeyAttributes(wstate->index);
+ keysz = RelationGetNumberOfAttributes(wstate->index);
ScanKey indexScanKey = NULL;
SortSupport sortKeys;
{
ScanKey skey;
TupleDesc itupdesc;
- int indnatts,
- indnkeyatts;
+ int natts;
int16 *indoption;
int i;
itupdesc = RelationGetDescr(rel);
- indnatts = IndexRelationGetNumberOfAttributes(rel);
- indnkeyatts = IndexRelationGetNumberOfKeyAttributes(rel);
+ natts = RelationGetNumberOfAttributes(rel);
indoption = rel->rd_indoption;
- Assert(indnkeyatts != 0);
- Assert(indnkeyatts <= indnatts);
+ skey = (ScanKey) palloc(natts * sizeof(ScanKeyData));
- /*
- * We'll execute search using ScanKey constructed on key columns.
- * Non key (included) columns must be omitted.
- */
- skey = (ScanKey) palloc(indnkeyatts * sizeof(ScanKeyData));
-
- for (i = 0; i < indnkeyatts; i++)
+ for (i = 0; i < natts; i++)
{
FmgrInfo *procinfo;
Datum arg;
_bt_mkscankey_nodata(Relation rel)
{
ScanKey skey;
- int indnkeyatts;
+ int natts;
int16 *indoption;
int i;
- indnkeyatts = IndexRelationGetNumberOfKeyAttributes(rel);
+ natts = RelationGetNumberOfAttributes(rel);
indoption = rel->rd_indoption;
- skey = (ScanKey) palloc(indnkeyatts * sizeof(ScanKeyData));
+ skey = (ScanKey) palloc(natts * sizeof(ScanKeyData));
- for (i = 0; i < indnkeyatts; i++)
+ for (i = 0; i < natts; i++)
{
FmgrInfo *procinfo;
int flags;
amroutine->amstorage = false;
amroutine->amclusterable = false;
amroutine->ampredlocks = false;
- amroutine->amcaninclude = false;
amroutine->amkeytype = InvalidOid;
amroutine->ambuild = spgbuild;
stmt->accessMethod = $8;
stmt->tableSpace = NULL;
stmt->indexParams = $10;
- stmt->indexIncludingParams = NIL;
stmt->options = NIL;
stmt->whereClause = NULL;
stmt->excludeOpNames = NIL;
stmt->accessMethod = $9;
stmt->tableSpace = NULL;
stmt->indexParams = $11;
- stmt->indexIncludingParams = NIL;
stmt->options = NIL;
stmt->whereClause = NULL;
stmt->excludeOpNames = NIL;
relname, (int) ATTRIBUTE_FIXED_PART_SIZE);
boot_reldesc = heap_openrv(makeRangeVar(NULL, relname, -1), NoLock);
- numattr = RelationGetNumberOfAttributes(boot_reldesc);
+ numattr = boot_reldesc->rd_rel->relnatts;
for (i = 0; i < numattr; i++)
{
if (attrtypes[i] == NULL)
is_validated,
RelationGetRelid(rel), /* relation */
attNos, /* attrs in the constraint */
- keycount, /* # key attrs in the constraint */
- keycount, /* # total attrs in the constraint */
+ keycount, /* # attrs in the constraint */
InvalidOid, /* not a domain constraint */
InvalidOid, /* no associated index */
InvalidOid, /* Foreign key fields */
* null, otherwise attempt to ALTER TABLE .. SET NOT NULL
*/
cmds = NIL;
- for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
+ for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
{
AttrNumber attnum = indexInfo->ii_KeyAttrNumbers[i];
HeapTuple atttuple;
namestrcpy(&to->attname, (const char *) lfirst(colnames_item));
colnames_item = lnext(colnames_item);
- /*
- * Code below is concerned to the opclasses which are not used
- * with the included columns.
- */
- if (i >= indexInfo->ii_NumIndexKeyAttrs)
- continue;
-
/*
* Check the opclass and index AM to see if either provides a keytype
* (overriding the attribute type). Opclass takes precedence.
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
indkey->values[i] = indexInfo->ii_KeyAttrNumbers[i];
indcollation = buildoidvector(collationOids, indexInfo->ii_NumIndexAttrs);
- indclass = buildoidvector(classOids, indexInfo->ii_NumIndexKeyAttrs);
+ indclass = buildoidvector(classOids, indexInfo->ii_NumIndexAttrs);
indoption = buildint2vector(coloptions, indexInfo->ii_NumIndexAttrs);
/*
values[Anum_pg_index_indexrelid - 1] = ObjectIdGetDatum(indexoid);
values[Anum_pg_index_indrelid - 1] = ObjectIdGetDatum(heapoid);
values[Anum_pg_index_indnatts - 1] = Int16GetDatum(indexInfo->ii_NumIndexAttrs);
- values[Anum_pg_index_indnkeyatts - 1] = Int16GetDatum(indexInfo->ii_NumIndexKeyAttrs);
values[Anum_pg_index_indisunique - 1] = BoolGetDatum(indexInfo->ii_Unique);
values[Anum_pg_index_indisprimary - 1] = BoolGetDatum(primary);
values[Anum_pg_index_indisexclusion - 1] = BoolGetDatum(isexclusion);
}
/* Store dependency on operator classes */
- for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
+ for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
{
referenced.classId = OperatorClassRelationId;
referenced.objectId = classObjectId[i];
else
Assert(indexRelation->rd_indexcxt != NULL);
- indexRelation->rd_index->indnkeyatts = indexInfo->ii_NumIndexKeyAttrs;
-
/*
* If this is bootstrap (initdb) time, then we don't actually fill in the
* index yet. We'll be creating more indexes and classes later, so we
true,
RelationGetRelid(heapRelation),
indexInfo->ii_KeyAttrNumbers,
- indexInfo->ii_NumIndexKeyAttrs,
indexInfo->ii_NumIndexAttrs,
InvalidOid, /* no domain */
indexRelationId, /* index OID */
IndexInfo *ii = makeNode(IndexInfo);
Form_pg_index indexStruct = index->rd_index;
int i;
- int numAtts;
+ int numKeys;
/* check the number of keys, and copy attr numbers into the IndexInfo */
- numAtts = indexStruct->indnatts;
- if (numAtts < 1 || numAtts > INDEX_MAX_KEYS)
+ numKeys = indexStruct->indnatts;
+ if (numKeys < 1 || numKeys > INDEX_MAX_KEYS)
elog(ERROR, "invalid indnatts %d for index %u",
- numAtts, RelationGetRelid(index));
- ii->ii_NumIndexAttrs = numAtts;
- ii->ii_NumIndexKeyAttrs = indexStruct->indnkeyatts;
- Assert(ii->ii_NumIndexKeyAttrs != 0);
- Assert(ii->ii_NumIndexKeyAttrs <= ii->ii_NumIndexAttrs);
-
- for (i = 0; i < numAtts; i++)
+ numKeys, RelationGetRelid(index));
+ ii->ii_NumIndexAttrs = numKeys;
+ for (i = 0; i < numKeys; i++)
ii->ii_KeyAttrNumbers[i] = indexStruct->indkey.values[i];
/* fetch any expressions needed for expressional indexes */
void
BuildSpeculativeIndexInfo(Relation index, IndexInfo *ii)
{
- int indnkeyatts;
+ int ncols = index->rd_rel->relnatts;
int i;
- indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index);
-
/*
* fetch info for checking unique indexes
*/
if (index->rd_rel->relam != BTREE_AM_OID)
elog(ERROR, "unexpected non-btree speculative unique index");
- ii->ii_UniqueOps = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
- ii->ii_UniqueProcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
- ii->ii_UniqueStrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
+ ii->ii_UniqueOps = (Oid *) palloc(sizeof(Oid) * ncols);
+ ii->ii_UniqueProcs = (Oid *) palloc(sizeof(Oid) * ncols);
+ ii->ii_UniqueStrats = (uint16 *) palloc(sizeof(uint16) * ncols);
/*
* We have to look up the operator's strategy number. This provides a
* cross-check that the operator does match the index.
*/
/* We need the func OIDs and strategy numbers too */
- for (i = 0; i < indnkeyatts; i++)
+ for (i = 0; i < ncols; i++)
{
ii->ii_UniqueStrats[i] = BTEqualStrategyNumber;
ii->ii_UniqueOps[i] =
Assert(indexInfo->ii_Predicate == NIL);
Assert(indexInfo->ii_ExclusionOps == NULL);
Assert(relationDescs[i]->rd_index->indimmediate);
- Assert(indexInfo->ii_NumIndexKeyAttrs != 0);
/*
* FormIndexDatum fills in its values and isnull parameters with the
Oid relId,
const int16 *constraintKey,
int constraintNKeys,
- int constraintNTotalKeys,
Oid domainId,
Oid indexRelId,
Oid foreignRelId,
bool nulls[Natts_pg_constraint];
Datum values[Natts_pg_constraint];
ArrayType *conkeyArray;
- ArrayType *conincludingArray;
ArrayType *confkeyArray;
ArrayType *conpfeqopArray;
ArrayType *conppeqopArray;
else
conkeyArray = NULL;
- if (constraintNTotalKeys > constraintNKeys)
- {
- Datum *conincluding;
- int j = 0;
- int constraintNIncludedKeys = constraintNTotalKeys - constraintNKeys;
-
- conincluding = (Datum *) palloc(constraintNIncludedKeys* sizeof(Datum));
- for (i = constraintNKeys; i < constraintNTotalKeys; i++)
- conincluding[j++] = Int16GetDatum(constraintKey[i]);
- conincludingArray = construct_array(conincluding, constraintNIncludedKeys,
- INT2OID, 2, true, 's');
- }
- else
- conincludingArray = NULL;
-
if (foreignNKeys > 0)
{
Datum *fkdatums;
else
nulls[Anum_pg_constraint_conkey - 1] = true;
- if (conincludingArray)
- values[Anum_pg_constraint_conincluding - 1] = PointerGetDatum(conincludingArray);
- else
- nulls[Anum_pg_constraint_conincluding - 1] = true;
-
if (confkeyArray)
values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
else
relobject.classId = RelationRelationId;
relobject.objectId = relId;
- if (constraintNTotalKeys > 0)
+ if (constraintNKeys > 0)
{
- for (i = 0; i < constraintNTotalKeys; i++)
+ for (i = 0; i < constraintNKeys; i++)
{
relobject.objectSubId = constraintKey[i];
indexInfo = makeNode(IndexInfo);
indexInfo->ii_NumIndexAttrs = 2;
- indexInfo->ii_NumIndexKeyAttrs = 2;
indexInfo->ii_KeyAttrNumbers[0] = 1;
indexInfo->ii_KeyAttrNumbers[1] = 2;
indexInfo->ii_Expressions = NIL;
}
/* Any change in operator class or collation breaks compatibility. */
- old_natts = indexForm->indnkeyatts;
+ old_natts = indexForm->indnatts;
Assert(old_natts == numberOfAttributes);
d = SysCacheGetAttr(INDEXRELID, tuple, Anum_pg_index_indcollation, &isnull);
int16 *coloptions;
IndexInfo *indexInfo;
int numberOfAttributes;
- int numberOfKeyAttributes;
TransactionId limitXmin;
VirtualTransactionId *old_snapshots;
ObjectAddress address;
Snapshot snapshot;
int i;
- if(list_intersection(stmt->indexParams, stmt->indexIncludingParams) != NIL)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("included columns must not intersect with key columns")));
- /*
- * count key attributes in index
- */
- numberOfKeyAttributes = list_length(stmt->indexParams);
-
/*
- * We append any INCLUDING columns onto the indexParams list so that
- * we have one list with all columns. Later we can determine which of these
- * are key columns, and which are just part of the INCLUDING list by check
- * the list position. A list item in a position less than
- * ii_NumIndexKeyAttrs is part of the key columns, and anything equal to
- * and over is part of the INCLUDING columns.
+ * count attributes in index
*/
- stmt->indexParams = list_concat(stmt->indexParams,
- stmt->indexIncludingParams);
numberOfAttributes = list_length(stmt->indexParams);
-
+ if (numberOfAttributes <= 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("must specify at least one column")));
if (numberOfAttributes > INDEX_MAX_KEYS)
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_COLUMNS),
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("access method \"%s\" does not support unique indexes",
accessMethodName)));
- if (list_length(stmt->indexIncludingParams) > 0 && !amRoutine->amcaninclude)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("access method \"%s\" does not support included columns",
- accessMethodName)));
if (numberOfAttributes > 1 && !amRoutine->amcanmulticol)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
*/
indexInfo = makeNode(IndexInfo);
indexInfo->ii_NumIndexAttrs = numberOfAttributes;
- indexInfo->ii_NumIndexKeyAttrs = numberOfKeyAttributes;
indexInfo->ii_Expressions = NIL; /* for now */
indexInfo->ii_ExpressionsState = NIL;
indexInfo->ii_Predicate = make_ands_implicit((Expr *) stmt->whereClause);
typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
- classObjectId = (Oid *) palloc(numberOfKeyAttributes * sizeof(Oid));
+ classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
ComputeIndexAttrs(indexInfo,
typeObjectId, collationObjectId, classObjectId,
ListCell *nextExclOp;
ListCell *lc;
int attn;
- int nkeycols = indexInfo->ii_NumIndexKeyAttrs;
/* Allocate space for exclusion operator info, if needed */
if (exclusionOpNames)
{
- Assert(list_length(exclusionOpNames) == nkeycols);
- indexInfo->ii_ExclusionOps = (Oid *) palloc(sizeof(Oid) * nkeycols);
- indexInfo->ii_ExclusionProcs = (Oid *) palloc(sizeof(Oid) * nkeycols);
- indexInfo->ii_ExclusionStrats = (uint16 *) palloc(sizeof(uint16) * nkeycols);
+ int ncols = list_length(attList);
+
+ Assert(list_length(exclusionOpNames) == ncols);
+ indexInfo->ii_ExclusionOps = (Oid *) palloc(sizeof(Oid) * ncols);
+ indexInfo->ii_ExclusionProcs = (Oid *) palloc(sizeof(Oid) * ncols);
+ indexInfo->ii_ExclusionStrats = (uint16 *) palloc(sizeof(uint16) * ncols);
nextExclOp = list_head(exclusionOpNames);
}
else
Node *expr = attribute->expr;
Assert(expr != NULL);
-
- if (attn >= nkeycols)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("expressions are not supported in included columns")));
atttype = exprType(expr);
attcollation = exprCollation(expr);
collationOidP[attn] = attcollation;
- /*
- * Skip opclass and ordering options for included columns.
- */
- if (attn >= nkeycols)
- {
- colOptionP[attn] = 0;
- attn++;
- continue;
- }
-
/*
* Identify the opclass to use.
*/
RelationGetRelationName(tempRel));
diffname = make_temptable_name_n(tempname, 2);
- relnatts = RelationGetNumberOfAttributes(matviewRel);
+ relnatts = matviewRel->rd_rel->relnatts;
usedForQual = (bool *) palloc0(sizeof(bool) * relnatts);
/* Open SPI context. */
RelationGetIndexExpressions(indexRel) == NIL &&
RelationGetIndexPredicate(indexRel) == NIL)
{
- int indnkeyatts = indexStruct->indnkeyatts;
+ int numatts = indexStruct->indnatts;
int i;
/* Add quals for all columns from this index. */
- for (i = 0; i < indnkeyatts; i++)
+ for (i = 0; i < numatts; i++)
{
int attnum = indexStruct->indkey.values[i];
Oid type;
* Loop over each attribute in the primary key and see if it
* matches the to-be-altered attribute
*/
- for (i = 0; i < indexStruct->indnkeyatts; i++)
+ for (i = 0; i < indexStruct->indnatts; i++)
{
if (indexStruct->indkey.values[i] == attnum)
ereport(ERROR,
RelationGetRelid(rel),
fkattnum,
numfks,
- numfks,
InvalidOid, /* not a domain
* constraint */
indexOid,
* assume a primary key cannot have expressional elements)
*/
*attnamelist = NIL;
- for (i = 0; i < indexStruct->indnkeyatts; i++)
+ for (i = 0; i < indexStruct->indnatts; i++)
{
int pkattno = indexStruct->indkey.values[i];
* partial index; forget it if there are any expressions, too. Invalid
* indexes are out as well.
*/
- if (indexStruct->indnkeyatts == numattrs &&
+ if (indexStruct->indnatts == numattrs &&
indexStruct->indisunique &&
IndexIsValid(indexStruct) &&
heap_attisnull(indexTuple, Anum_pg_index_indpred) &&
RelationGetRelationName(indexRel))));
/* Check index for nullable columns. */
- for (key = 0; key < IndexRelationGetNumberOfKeyAttributes(indexRel); key++)
+ for (key = 0; key < indexRel->rd_index->indnatts; key++)
{
int16 attno = indexRel->rd_index->indkey.values[key];
Form_pg_attribute attr;
RelationGetRelid(rel),
NULL, /* no conkey */
0,
- 0,
InvalidOid, /* no domain */
InvalidOid, /* no index */
InvalidOid, /* no foreign key */
InvalidOid, /* not a relation constraint */
NULL,
0,
- 0,
domainOid, /* domain constraint */
InvalidOid, /* no associated index */
InvalidOid, /* Foreign key fields */
Oid *constr_procs;
uint16 *constr_strats;
Oid *index_collations = index->rd_indcollation;
- int indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index);
+ int index_natts = index->rd_index->indnatts;
IndexScanDesc index_scan;
HeapTuple tup;
ScanKeyData scankeys[INDEX_MAX_KEYS];
* If any of the input values are NULL, the constraint check is assumed to
* pass (i.e., we assume the operators are strict).
*/
- for (i = 0; i < indnkeyatts; i++)
+ for (i = 0; i < index_natts; i++)
{
if (isnull[i])
return true;
*/
InitDirtySnapshot(DirtySnapshot);
- for (i = 0; i < indnkeyatts; i++)
+ for (i = 0; i < index_natts; i++)
{
ScanKeyEntryInitialize(&scankeys[i],
0,
retry:
conflict = false;
found_self = false;
- index_scan = index_beginscan(heap, index, &DirtySnapshot, indnkeyatts, 0);
- index_rescan(index_scan, scankeys, indnkeyatts, NULL, 0);
+ index_scan = index_beginscan(heap, index, &DirtySnapshot, index_natts, 0);
+ index_rescan(index_scan, scankeys, index_natts, NULL, 0);
while ((tup = index_getnext(index_scan,
ForwardScanDirection)) != NULL)
Datum *existing_values, bool *existing_isnull,
Datum *new_values)
{
- int indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index);
+ int index_natts = index->rd_index->indnatts;
int i;
- for (i = 0; i < indnkeyatts; i++)
+ for (i = 0; i < index_natts; i++)
{
/* Assume the exclusion operators are strict */
if (existing_isnull[i])
Expr *leftop; /* expr on lhs of operator */
Expr *rightop; /* expr on rhs ... */
AttrNumber varattno; /* att number used in scan */
- int indnkeyatts;
- indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index);
if (IsA(clause, OpExpr))
{
/* indexkey op const or indexkey op expression */
elog(ERROR, "indexqual doesn't have key on left side");
varattno = ((Var *) leftop)->varattno;
- if (varattno < 1 || varattno > indnkeyatts)
+ if (varattno < 1 || varattno > index->rd_index->indnatts)
elog(ERROR, "bogus index qualification");
/*
opnos_cell = lnext(opnos_cell);
if (index->rd_rel->relam != BTREE_AM_OID ||
- varattno < 1 || varattno > indnkeyatts)
+ varattno < 1 || varattno > index->rd_index->indnatts)
elog(ERROR, "bogus RowCompare index qualification");
opfamily = index->rd_opfamily[varattno - 1];
elog(ERROR, "indexqual doesn't have key on left side");
varattno = ((Var *) leftop)->varattno;
- if (varattno < 1 || varattno > indnkeyatts)
+ if (varattno < 1 || varattno > index->rd_index->indnatts)
elog(ERROR, "bogus index qualification");
/*
COPY_NODE_FIELD(raw_expr);
COPY_STRING_FIELD(cooked_expr);
COPY_NODE_FIELD(keys);
- COPY_NODE_FIELD(including);
COPY_NODE_FIELD(exclusions);
COPY_NODE_FIELD(options);
COPY_STRING_FIELD(indexname);
COPY_STRING_FIELD(accessMethod);
COPY_STRING_FIELD(tableSpace);
COPY_NODE_FIELD(indexParams);
- COPY_NODE_FIELD(indexIncludingParams);
COPY_NODE_FIELD(options);
COPY_NODE_FIELD(whereClause);
COPY_NODE_FIELD(excludeOpNames);
COMPARE_STRING_FIELD(accessMethod);
COMPARE_STRING_FIELD(tableSpace);
COMPARE_NODE_FIELD(indexParams);
- COMPARE_NODE_FIELD(indexIncludingParams);
COMPARE_NODE_FIELD(options);
COMPARE_NODE_FIELD(whereClause);
COMPARE_NODE_FIELD(excludeOpNames);
COMPARE_NODE_FIELD(raw_expr);
COMPARE_STRING_FIELD(cooked_expr);
COMPARE_NODE_FIELD(keys);
- COMPARE_NODE_FIELD(including);
COMPARE_NODE_FIELD(exclusions);
COMPARE_NODE_FIELD(options);
COMPARE_STRING_FIELD(indexname);
WRITE_STRING_FIELD(accessMethod);
WRITE_STRING_FIELD(tableSpace);
WRITE_NODE_FIELD(indexParams);
- WRITE_NODE_FIELD(indexIncludingParams);
WRITE_NODE_FIELD(options);
WRITE_NODE_FIELD(whereClause);
WRITE_NODE_FIELD(excludeOpNames);
case CONSTR_PRIMARY:
appendStringInfoString(str, "PRIMARY_KEY");
WRITE_NODE_FIELD(keys);
- WRITE_NODE_FIELD(including);
WRITE_NODE_FIELD(options);
WRITE_STRING_FIELD(indexname);
WRITE_STRING_FIELD(indexspace);
case CONSTR_UNIQUE:
appendStringInfoString(str, "UNIQUE");
WRITE_NODE_FIELD(keys);
- WRITE_NODE_FIELD(including);
WRITE_NODE_FIELD(options);
WRITE_STRING_FIELD(indexname);
WRITE_STRING_FIELD(indexspace);
{
int indexcol;
- for (indexcol = 0; indexcol < index->nkeycolumns; indexcol++)
+ for (indexcol = 0; indexcol < index->ncolumns; indexcol++)
{
if (match_clause_to_indexcol(index,
indexcol,
bool nulls_first;
PathKey *cpathkey;
- /*
- * INCLUDING columns are stored in index unordered,
- * so they don't support ordered index scan.
- */
- if(i >= index->nkeycolumns)
- break;
-
/* We assume we don't need to make a copy of the tlist item */
indexkey = indextle->expr;
Form_pg_index index;
IndexAmRoutine *amroutine;
IndexOptInfo *info;
- int ncolumns, nkeycolumns;
+ int ncolumns;
int i;
/*
RelationGetForm(indexRelation)->reltablespace;
info->rel = rel;
info->ncolumns = ncolumns = index->indnatts;
- info->nkeycolumns = nkeycolumns = index->indnkeyatts;
-
info->indexkeys = (int *) palloc(sizeof(int) * ncolumns);
info->indexcollations = (Oid *) palloc(sizeof(Oid) * ncolumns);
- info->opfamily = (Oid *) palloc(sizeof(Oid) * nkeycolumns);
- info->opcintype = (Oid *) palloc(sizeof(Oid) * nkeycolumns);
+ info->opfamily = (Oid *) palloc(sizeof(Oid) * ncolumns);
+ info->opcintype = (Oid *) palloc(sizeof(Oid) * ncolumns);
info->canreturn = (bool *) palloc(sizeof(bool) * ncolumns);
for (i = 0; i < ncolumns; i++)
{
info->indexkeys[i] = index->indkey.values[i];
info->indexcollations[i] = indexRelation->rd_indcollation[i];
- info->canreturn[i] = index_can_return(indexRelation, i + 1);
- }
-
- for (i = 0; i < nkeycolumns; i++)
- {
info->opfamily[i] = indexRelation->rd_opfamily[i];
info->opcintype[i] = indexRelation->rd_opcintype[i];
+ info->canreturn[i] = index_can_return(indexRelation, i + 1);
}
info->relam = indexRelation->rd_rel->relam;
Assert(amroutine->amcanorder);
info->sortopfamily = info->opfamily;
- info->reverse_sort = (bool *) palloc(sizeof(bool) * nkeycolumns);
- info->nulls_first = (bool *) palloc(sizeof(bool) * nkeycolumns);
+ info->reverse_sort = (bool *) palloc(sizeof(bool) * ncolumns);
+ info->nulls_first = (bool *) palloc(sizeof(bool) * ncolumns);
- for (i = 0; i < nkeycolumns; i++)
+ for (i = 0; i < ncolumns; i++)
{
int16 opt = indexRelation->rd_indoption[i];
* of current or foreseeable amcanorder index types, it's not
* worth expending more effort on now.
*/
- info->sortopfamily = (Oid *) palloc(sizeof(Oid) * nkeycolumns);
- info->reverse_sort = (bool *) palloc(sizeof(bool) * nkeycolumns);
- info->nulls_first = (bool *) palloc(sizeof(bool) * nkeycolumns);
+ info->sortopfamily = (Oid *) palloc(sizeof(Oid) * ncolumns);
+ info->reverse_sort = (bool *) palloc(sizeof(bool) * ncolumns);
+ info->nulls_first = (bool *) palloc(sizeof(bool) * ncolumns);
- for (i = 0; i < nkeycolumns; i++)
+ for (i = 0; i < ncolumns; i++)
{
int16 opt = indexRelation->rd_indoption[i];
Oid ltopr;
goto next;
/* Build BMS representation of cataloged index attributes */
- for (natt = 0; natt < idxForm->indnkeyatts; natt++)
+ for (natt = 0; natt < idxForm->indnatts; natt++)
{
int attno = idxRel->rd_index->indkey.values[natt];
* just the specified attr is unique.
*/
if (index->unique &&
- index->nkeycolumns == 1 &&
+ index->ncolumns == 1 &&
index->indexkeys[0] == attno &&
(index->indpred == NIL || index->predOK))
return true;
* relation.
*/
Assert(pstate->p_next_resno == 1);
- for (attno = 0; attno < RelationGetNumberOfAttributes(targetrel); attno++)
+ for (attno = 0; attno < targetrel->rd_rel->relnatts; attno++)
{
Form_pg_attribute attr = targetrel->rd_att->attrs[attno];
char *name;
EXPR_KIND_UPDATE_SOURCE);
/* Prepare to assign non-conflicting resnos to resjunk attributes */
- if (pstate->p_next_resno <= RelationGetNumberOfAttributes(pstate->p_target_relation))
- pstate->p_next_resno = RelationGetNumberOfAttributes(pstate->p_target_relation) + 1;
+ if (pstate->p_next_resno <= pstate->p_target_relation->rd_rel->relnatts)
+ pstate->p_next_resno = pstate->p_target_relation->rd_rel->relnatts + 1;
/* Prepare non-junk columns for assignment to target table */
target_rte = pstate->p_target_rangetblentry;
oper_argtypes RuleActionList RuleActionMulti
opt_column_list columnList opt_name_list
sort_clause opt_sort_clause sortby_list index_params
- optincluding opt_including index_including_params
name_list role_list from_clause from_list opt_array_bounds
qualified_name_list any_name any_name_list type_name_list
any_operator expr_list attrs
create_generic_options alter_generic_options
relation_expr_list dostmt_opt_list
transform_element_list transform_type_list
- optcincluding opt_c_including
%type <list> group_by_list
%type <node> group_by_item empty_grouping_set rollup_clause cube_clause
n->initially_valid = !n->skip_validation;
$$ = (Node *)n;
}
- | UNIQUE '(' columnList ')' opt_c_including opt_definition OptConsTableSpace
+ | UNIQUE '(' columnList ')' opt_definition OptConsTableSpace
ConstraintAttributeSpec
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_UNIQUE;
n->location = @1;
n->keys = $3;
- n->including = $5;
- n->options = $6;
+ n->options = $5;
n->indexname = NULL;
- n->indexspace = $7;
- processCASbits($8, @8, "UNIQUE",
+ n->indexspace = $6;
+ processCASbits($7, @7, "UNIQUE",
&n->deferrable, &n->initdeferred, NULL,
NULL, yyscanner);
$$ = (Node *)n;
n->contype = CONSTR_UNIQUE;
n->location = @1;
n->keys = NIL;
- n->including = NIL;
n->options = NIL;
n->indexname = $2;
n->indexspace = NULL;
NULL, yyscanner);
$$ = (Node *)n;
}
- | PRIMARY KEY '(' columnList ')' opt_c_including opt_definition OptConsTableSpace
+ | PRIMARY KEY '(' columnList ')' opt_definition OptConsTableSpace
ConstraintAttributeSpec
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_PRIMARY;
n->location = @1;
n->keys = $4;
- n->including = $6;
- n->options = $7;
+ n->options = $6;
n->indexname = NULL;
- n->indexspace = $8;
- processCASbits($9, @9, "PRIMARY KEY",
+ n->indexspace = $7;
+ processCASbits($8, @8, "PRIMARY KEY",
&n->deferrable, &n->initdeferred, NULL,
NULL, yyscanner);
$$ = (Node *)n;
n->contype = CONSTR_PRIMARY;
n->location = @1;
n->keys = NIL;
- n->including = NIL;
n->options = NIL;
n->indexname = $3;
n->indexspace = NULL;
}
;
-opt_c_including: INCLUDING optcincluding { $$ = $2; }
- | /* EMPTY */ { $$ = NIL; }
- ;
-
-optcincluding : '(' columnList ')' { $$ = $2; }
- ;
-
key_match: MATCH FULL
{
$$ = FKCONSTR_MATCH_FULL;
IndexStmt: CREATE opt_unique INDEX opt_concurrently opt_index_name
ON qualified_name access_method_clause '(' index_params ')'
- opt_including opt_reloptions OptTableSpace where_clause
+ opt_reloptions OptTableSpace where_clause
{
IndexStmt *n = makeNode(IndexStmt);
n->unique = $2;
n->relation = $7;
n->accessMethod = $8;
n->indexParams = $10;
- n->indexIncludingParams = $12;
- n->options = $13;
- n->tableSpace = $14;
- n->whereClause = $15;
+ n->options = $12;
+ n->tableSpace = $13;
+ n->whereClause = $14;
n->excludeOpNames = NIL;
n->idxcomment = NULL;
n->indexOid = InvalidOid;
}
| CREATE opt_unique INDEX opt_concurrently IF_P NOT EXISTS index_name
ON qualified_name access_method_clause '(' index_params ')'
- opt_including opt_reloptions OptTableSpace where_clause
+ opt_reloptions OptTableSpace where_clause
{
IndexStmt *n = makeNode(IndexStmt);
n->unique = $2;
n->relation = $10;
n->accessMethod = $11;
n->indexParams = $13;
- n->indexIncludingParams = $15;
- n->options = $16;
- n->tableSpace = $17;
- n->whereClause = $18;
+ n->options = $15;
+ n->tableSpace = $16;
+ n->whereClause = $17;
n->excludeOpNames = NIL;
n->idxcomment = NULL;
n->indexOid = InvalidOid;
}
;
-optincluding : '(' index_including_params ')' { $$ = $2; }
- ;
-opt_including: INCLUDING optincluding { $$ = $2; }
- | /* EMPTY */ { $$ = NIL; }
- ;
-
-index_including_params: index_elem { $$ = list_make1($1); }
- | index_including_params ',' index_elem { $$ = lappend($1, $3); }
- ;
-
opt_collate: COLLATE any_name { $$ = $2; }
| /*EMPTY*/ { $$ = NIL; }
;
{
int i;
- for (i = 0; i < RelationGetNumberOfAttributes(rd); i++)
+ for (i = 0; i < rd->rd_rel->relnatts; i++)
{
Form_pg_attribute att = rd->rd_att->attrs[i];
* Generate default column list for INSERT.
*/
Form_pg_attribute *attr = pstate->p_target_relation->rd_att->attrs;
- int numcol = RelationGetNumberOfAttributes(pstate->p_target_relation);
+ int numcol = pstate->p_target_relation->rd_rel->relnatts;
int i;
for (i = 0; i < numcol; i++)
/* Build the list of IndexElem */
index->indexParams = NIL;
- index->indexIncludingParams = NIL;
indexpr_item = list_head(indexprs);
- for (keyno = 0; keyno < idxrec->indnkeyatts; keyno++)
+ for (keyno = 0; keyno < idxrec->indnatts; keyno++)
{
IndexElem *iparam;
AttrNumber attnum = idxrec->indkey.values[keyno];
int16 opt = source_idx->rd_indoption[keyno];
+
iparam = makeNode(IndexElem);
if (AttributeNumberIsValid(attnum))
index->indexParams = lappend(index->indexParams, iparam);
}
- /* Handle included columns separately */
- for (keyno = idxrec->indnkeyatts; keyno < idxrec->indnatts; keyno++)
- {
- IndexElem *iparam;
- AttrNumber attnum = idxrec->indkey.values[keyno];
-
- iparam = makeNode(IndexElem);
-
- if (AttributeNumberIsValid(attnum))
- {
- /* Simple index column */
- char *attname;
-
- attname = get_relid_attribute_name(indrelid, attnum);
- keycoltype = get_atttype(indrelid, attnum);
-
- iparam->name = attname;
- iparam->expr = NULL;
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("expressions are not supported in included columns")));
-
- /* Copy the original index column name */
- iparam->indexcolname = pstrdup(NameStr(attrs[keyno]->attname));
-
- /* Add the collation name, if non-default */
- iparam->collation = get_collation(indcollation->values[keyno], keycoltype);
-
- index->indexIncludingParams = lappend(index->indexIncludingParams, iparam);
- }
/* Copy reloptions if any */
datum = SysCacheGetAttr(RELOID, ht_idxrel,
Anum_pg_class_reloptions, &isnull);
IndexStmt *priorindex = lfirst(k);
if (equal(index->indexParams, priorindex->indexParams) &&
- equal(index->indexIncludingParams, priorindex->indexIncludingParams) &&
equal(index->whereClause, priorindex->whereClause) &&
equal(index->excludeOpNames, priorindex->excludeOpNames) &&
strcmp(index->accessMethod, priorindex->accessMethod) == 0 &&
index->tableSpace = constraint->indexspace;
index->whereClause = constraint->where_clause;
index->indexParams = NIL;
- index->indexIncludingParams = NIL;
index->excludeOpNames = NIL;
index->idxcomment = NULL;
index->indexOid = InvalidOid;
heap_rel->rd_rel->relhasoids);
attname = pstrdup(NameStr(attform->attname));
- if (i < index_form->indnkeyatts)
- {
- /*
- * Insist on default opclass and sort options. While the index
- * would still work as a constraint with non-default settings, it
- * might not provide exactly the same uniqueness semantics as
- * you'd get from a normally-created constraint; and there's also
- * the dump/reload problem mentioned above.
- */
- defopclass = GetDefaultOpClass(attform->atttypid,
- index_rel->rd_rel->relam);
- if (indclass->values[i] != defopclass ||
- index_rel->rd_indoption[i] != 0)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("index \"%s\" does not have default sorting behavior", index_name),
- errdetail("Cannot create a primary key or unique constraint using such an index."),
- parser_errposition(cxt->pstate, constraint->location)));
-
- constraint->keys = lappend(constraint->keys, makeString(attname));
- }
- else
- constraint->including = lappend(constraint->including, makeString(attname));
+ /*
+ * Insist on default opclass and sort options. While the index
+ * would still work as a constraint with non-default settings, it
+ * might not provide exactly the same uniqueness semantics as
+ * you'd get from a normally-created constraint; and there's also
+ * the dump/reload problem mentioned above.
+ */
+ defopclass = GetDefaultOpClass(attform->atttypid,
+ index_rel->rd_rel->relam);
+ if (indclass->values[i] != defopclass ||
+ index_rel->rd_indoption[i] != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("index \"%s\" does not have default sorting behavior", index_name),
+ errdetail("Cannot create a primary key or unique constraint using such an index."),
+ parser_errposition(cxt->pstate, constraint->location)));
+ constraint->keys = lappend(constraint->keys, makeString(attname));
}
/* Close the index relation but keep the lock */
* If it's an EXCLUDE constraint, the grammar returns a list of pairs of
* IndexElems and operator names. We have to break that apart into
* separate lists.
- * NOTE that exclusion constraints don't support included nonkey attributes
*/
if (constraint->contype == CONSTR_EXCLUSION)
{
index->indexParams = lappend(index->indexParams, iparam);
}
- /* Here is some ugly code duplication. But we do need it. */
- foreach(lc, constraint->including)
- {
- char *key = strVal(lfirst(lc));
- bool found = false;
- ColumnDef *column = NULL;
- ListCell *columns;
- IndexElem *iparam;
-
- foreach(columns, cxt->columns)
- {
- column = (ColumnDef *) lfirst(columns);
- Assert(IsA(column, ColumnDef));
- if (strcmp(column->colname, key) == 0)
- {
- found = true;
- break;
- }
- }
-
- /*
- * In the ALTER TABLE case, don't complain about index keys not
- * created in the command; they may well exist already. DefineIndex
- * will complain about them if not, and will also take care of marking
- * them NOT NULL.
- */
- if (!found && !cxt->isalter)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_COLUMN),
- errmsg("column \"%s\" named in key does not exist", key),
- parser_errposition(cxt->pstate, constraint->location)));
-
- /* OK, add it to the index definition */
- iparam = makeNode(IndexElem);
- iparam->name = pstrdup(key);
- iparam->expr = NULL;
- iparam->indexcolname = NULL;
- iparam->collation = NIL;
- iparam->opclass = NIL;
- index->indexIncludingParams = lappend(index->indexIncludingParams, iparam);
- }
-
return index;
}
Oid keycoltype;
Oid keycolcollation;
- /*
- * attrsOnly flag is used for building unique-constraint and
- * exclusion-constraint error messages. Included attrs are
- * meaningless there, so do not include them into the message.
- */
- if (attrsOnly && keyno >= idxrec->indnkeyatts)
- break;
-
- /* Report the INCLUDED attributes, if any. */
- if ((!attrsOnly) && keyno == idxrec->indnkeyatts)
- {
- appendStringInfoString(&buf, ") INCLUDING (");
- sep = "";
- }
-
if (!colno)
appendStringInfoString(&buf, sep);
sep = ", ";
attname = get_relid_attribute_name(indrelid, attnum);
if (!colno || colno == keyno + 1)
appendStringInfoString(&buf, quote_identifier(attname));
-
get_atttypetypmodcoll(indrelid, attnum,
&keycoltype, &keycoltypmod,
&keycolcollation);
appendStringInfo(&buf, " COLLATE %s",
generate_collation_name((indcoll)));
- if(keyno >= idxrec->indnkeyatts)
- continue;
-
/* Add the operator class name, if not default */
get_opclass_name(indclass->values[keyno], keycoltype, &buf);
appendStringInfoChar(&buf, ')');
- /* Fetch and build including column list */
- isnull = true;
- val = SysCacheGetAttr(CONSTROID, tup,
- Anum_pg_constraint_conincluding, &isnull);
- if (!isnull)
- {
- appendStringInfoString(&buf, " INCLUDING (");
-
- decompile_column_index_array(val, conForm->conrelid, &buf);
-
- appendStringInfoChar(&buf, ')');
- }
-
indexId = get_constraint_index(constraintId);
/* XXX why do we only print these bits if fullCommand? */
* should match has_unique_index().
*/
if (index->unique &&
- index->nkeycolumns == 1 &&
+ index->ncolumns == 1 &&
(index->indpred == NIL || index->predOK))
vardata->isunique = true;
* NullTest invalidates that theory, even though it sets eqQualHere.
*/
if (index->unique &&
- indexcol == index->nkeycolumns - 1 &&
+ indexcol == index->ncolumns - 1 &&
eqQualHere &&
!found_saop &&
!found_is_null_op)
/*
* add attribute data to relation->rd_att
*/
- need = RelationGetNumberOfAttributes(relation);
+ need = relation->rd_rel->relnatts;
while (HeapTupleIsValid(pg_attribute_tuple = systable_getnext(pg_attribute_scan)))
{
attp = (Form_pg_attribute) GETSTRUCT(pg_attribute_tuple);
if (attp->attnum <= 0 ||
- attp->attnum > RelationGetNumberOfAttributes(relation))
+ attp->attnum > relation->rd_rel->relnatts)
elog(ERROR, "invalid attribute number %d for %s",
attp->attnum, RelationGetRelationName(relation));
if (attrdef == NULL)
attrdef = (AttrDefault *)
MemoryContextAllocZero(CacheMemoryContext,
- RelationGetNumberOfAttributes(relation) *
+ relation->rd_rel->relnatts *
sizeof(AttrDefault));
attrdef[ndef].adnum = attp->attnum;
attrdef[ndef].adbin = NULL;
{
int i;
- for (i = 0; i < RelationGetNumberOfAttributes(relation); i++)
+ for (i = 0; i < relation->rd_rel->relnatts; i++)
Assert(relation->rd_att->attrs[i]->attcacheoff == -1);
}
#endif
* attribute: it must be zero. This eliminates the need for special cases
* for attnum=1 that used to exist in fastgetattr() and index_getattr().
*/
- if (RelationGetNumberOfAttributes(relation) > 0)
+ if (relation->rd_rel->relnatts > 0)
relation->rd_att->attrs[0]->attcacheoff = 0;
/*
if (ndef > 0) /* DEFAULTs */
{
- if (ndef < RelationGetNumberOfAttributes(relation))
+ if (ndef < relation->rd_rel->relnatts)
constr->defval = (AttrDefault *)
repalloc(attrdef, ndef * sizeof(AttrDefault));
else
int2vector *indoption;
MemoryContext indexcxt;
MemoryContext oldcontext;
- int indnatts;
- int indnkeyatts;
+ int natts;
uint16 amsupport;
/*
relation->rd_amhandler = aform->amhandler;
ReleaseSysCache(tuple);
- indnatts = RelationGetNumberOfAttributes(relation);
- if (indnatts != IndexRelationGetNumberOfAttributes(relation))
+ natts = relation->rd_rel->relnatts;
+ if (natts != relation->rd_index->indnatts)
elog(ERROR, "relnatts disagrees with indnatts for index %u",
RelationGetRelid(relation));
- indnkeyatts = IndexRelationGetNumberOfKeyAttributes(relation);
/*
* Make the private context to hold index access info. The reason we need
* Allocate arrays to hold data
*/
relation->rd_opfamily = (Oid *)
- MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
+ MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));
relation->rd_opcintype = (Oid *)
- MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
+ MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));
amsupport = relation->rd_amroutine->amsupport;
if (amsupport > 0)
{
- int nsupport = indnatts * amsupport;
+ int nsupport = natts * amsupport;
relation->rd_support = (RegProcedure *)
MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure));
}
relation->rd_indcollation = (Oid *)
- MemoryContextAllocZero(indexcxt, indnatts * sizeof(Oid));
+ MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));
relation->rd_indoption = (int16 *)
- MemoryContextAllocZero(indexcxt, indnatts * sizeof(int16));
+ MemoryContextAllocZero(indexcxt, natts * sizeof(int16));
/*
* indcollation cannot be referenced directly through the C struct,
&isnull);
Assert(!isnull);
indcoll = (oidvector *) DatumGetPointer(indcollDatum);
- memcpy(relation->rd_indcollation, indcoll->values, indnatts * sizeof(Oid));
+ memcpy(relation->rd_indcollation, indcoll->values, natts * sizeof(Oid));
/*
* indclass cannot be referenced directly through the C struct, because it
*/
IndexSupportInitialize(indclass, relation->rd_support,
relation->rd_opfamily, relation->rd_opcintype,
- amsupport, indnkeyatts);
+ amsupport, natts);
/*
* Similarly extract indoption and copy it to the cache entry
&isnull);
Assert(!isnull);
indoption = (int2vector *) DatumGetPointer(indoptionDatum);
- memcpy(relation->rd_indoption, indoption->values, indnatts * sizeof(int16));
+ memcpy(relation->rd_indoption, indoption->values, natts * sizeof(int16));
/*
* expressions, predicate, exclusion caches will be filled later
{
int attrnum = indexInfo->ii_KeyAttrNumbers[i];
- /*
- * Since we have covering indexes with non-key columns,
- * we must handle them accurately here. non-key columns
- * must be added into indexattrs, since they are in index,
- * and HOT-update shouldn't miss them.
- * Obviously, non-key columns couldn't be referenced by
- * foreign key or identity key. Hence we do not include
- * them into uindexattrs and idindexattrs bitmaps.
- */
if (attrnum != 0)
{
indexattrs = bms_add_member(indexattrs,
attrnum - FirstLowInvalidHeapAttributeNumber);
- if (isKey && i < indexInfo->ii_NumIndexKeyAttrs)
+ if (isKey)
uindexattrs = bms_add_member(uindexattrs,
attrnum - FirstLowInvalidHeapAttributeNumber);
- if (isIDKey && i < indexInfo->ii_NumIndexKeyAttrs)
+ if (isIDKey)
idindexattrs = bms_add_member(idindexattrs,
attrnum - FirstLowInvalidHeapAttributeNumber);
}
Oid **procs,
uint16 **strategies)
{
- int indnkeyatts;
+ int ncols = indexRelation->rd_rel->relnatts;
Oid *ops;
Oid *funcs;
uint16 *strats;
MemoryContext oldcxt;
int i;
- indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
-
/* Allocate result space in caller context */
- *operators = ops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
- *procs = funcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
- *strategies = strats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
+ *operators = ops = (Oid *) palloc(sizeof(Oid) * ncols);
+ *procs = funcs = (Oid *) palloc(sizeof(Oid) * ncols);
+ *strategies = strats = (uint16 *) palloc(sizeof(uint16) * ncols);
/* Quick exit if we have the data cached already */
if (indexRelation->rd_exclstrats != NULL)
{
- memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * indnkeyatts);
- memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * indnkeyatts);
- memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * indnkeyatts);
+ memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * ncols);
+ memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * ncols);
+ memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * ncols);
return;
}
arr = DatumGetArrayTypeP(val); /* ensure not toasted */
nelem = ARR_DIMS(arr)[0];
if (ARR_NDIM(arr) != 1 ||
- nelem != indnkeyatts ||
+ nelem != ncols ||
ARR_HASNULL(arr) ||
ARR_ELEMTYPE(arr) != OIDOID)
elog(ERROR, "conexclop is not a 1-D Oid array");
- memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * indnkeyatts);
+ memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * ncols);
}
systable_endscan(conscan);
RelationGetRelationName(indexRelation));
/* We need the func OIDs and strategy numbers too */
- for (i = 0; i < indnkeyatts; i++)
+ for (i = 0; i < ncols; i++)
{
funcs[i] = get_opcode(ops[i]);
strats[i] = get_op_opfamily_strategy(ops[i],
/* Save a copy of the results in the relcache entry. */
oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
- indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
- indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
- indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
- memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * indnkeyatts);
- memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * indnkeyatts);
- memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * indnkeyatts);
+ indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * ncols);
+ indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * ncols);
+ indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * ncols);
+ memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * ncols);
+ memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * ncols);
+ memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * ncols);
MemoryContextSwitchTo(oldcxt);
}
workMem, randomAccess ? 't' : 'f');
#endif
- state->nKeys = IndexRelationGetNumberOfKeyAttributes(indexRel); //FIXME
+ state->nKeys = RelationGetNumberOfAttributes(indexRel);
TRACE_POSTGRESQL_SORT_START(CLUSTER_SORT,
false, /* no unique check */
workMem, randomAccess ? 't' : 'f');
#endif
- state->nKeys = IndexRelationGetNumberOfKeyAttributes(indexRel);
+ state->nKeys = RelationGetNumberOfAttributes(indexRel);
TRACE_POSTGRESQL_SORT_START(INDEX_SORT,
enforceUnique,
state->enforceUnique = enforceUnique;
indexScanKey = _bt_mkscankey_nodata(indexRel);
+ state->nKeys = RelationGetNumberOfAttributes(indexRel);
/* Prepare SortSupport data for each column */
state->sortKeys = (SortSupport) palloc0(state->nKeys *
i_oid,
i_indexname,
i_indexdef,
- i_indnnkeyatts,
- i_indnatts,
+ i_indnkeys,
i_indkey,
i_indisclustered,
i_indisreplident,
* is not.
*/
resetPQExpBuffer(query);
- if (fout->remoteVersion >= 90600)
- {
- /*
- * In 9.6 we add INCLUDING columns functionality
- * that requires new fields to be added.
- * i.indnkeyattrs is new, and besides we should use
- * i.indnatts instead of t.relnatts for index relations.
- *
- */
- appendPQExpBuffer(query,
- "SELECT t.tableoid, t.oid, "
- "t.relname AS indexname, "
- "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
- "i.indnkeyatts AS indnkeyatts, "
- "i.indnatts AS indnatts, "
- "i.indkey, i.indisclustered, "
- "i.indisreplident, t.relpages, "
- "c.contype, c.conname, "
- "c.condeferrable, c.condeferred, "
- "c.tableoid AS contableoid, "
- "c.oid AS conoid, "
- "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
- "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
- "t.reloptions AS indreloptions "
- "FROM pg_catalog.pg_index i "
- "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
- "LEFT JOIN pg_catalog.pg_constraint c "
- "ON (i.indrelid = c.conrelid AND "
- "i.indexrelid = c.conindid AND "
- "c.contype IN ('p','u','x')) "
- "WHERE i.indrelid = '%u'::pg_catalog.oid "
- "AND i.indisvalid AND i.indisready "
- "ORDER BY indexname",
- tbinfo->dobj.catId.oid);
- }
- else if (fout->remoteVersion >= 90400)
+ if (fout->remoteVersion >= 90400)
{
/*
* the test on indisready is necessary in 9.2, and harmless in
i_oid = PQfnumber(res, "oid");
i_indexname = PQfnumber(res, "indexname");
i_indexdef = PQfnumber(res, "indexdef");
- i_indnnkeyatts = PQfnumber(res, "indnkeyatts");
- i_indnatts = PQfnumber(res, "indnatts");
+ i_indnkeys = PQfnumber(res, "indnkeys");
i_indkey = PQfnumber(res, "indkey");
i_indisclustered = PQfnumber(res, "indisclustered");
i_indisreplident = PQfnumber(res, "indisreplident");
indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
indxinfo[j].indextable = tbinfo;
indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
- indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnnkeyatts));
- indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
+ indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
{
appendPQExpBuffer(q, "%s (",
coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
- for (k = 0; k < indxinfo->indnkeyattrs; k++)
+ for (k = 0; k < indxinfo->indnkeys; k++)
{
int indkey = (int) indxinfo->indkeys[k];
const char *attname;
fmtId(attname));
}
- if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
- appendPQExpBuffer(q, ") INCLUDING (");
-
- for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
- {
- int indkey = (int) indxinfo->indkeys[k];
- const char *attname;
-
- if (indkey == InvalidAttrNumber)
- break;
- attname = getAttrName(indkey, tbinfo);
-
- appendPQExpBuffer(q, "%s%s",
- (k == indxinfo->indnkeyattrs) ? "" : ", ",
- fmtId(attname));
- }
-
appendPQExpBufferChar(q, ')');
if (nonemptyReloptions(indxinfo->indreloptions))
char *indexdef;
char *tablespace; /* tablespace in which index is stored */
char *indreloptions; /* options specified by WITH (...) */
- int indnkeyattrs; /* number of index key attributes*/
- int indnattrs; /* total number of index attributes*/
- Oid *indkeys; /* In spite of the name 'indkeys' this field
- * contains both key and nonkey attributes*/
+ int indnkeys;
+ Oid *indkeys;
bool indisclustered;
bool indisreplident;
/* if there is an associated constraint object, its dumpId: */
bool amclusterable;
/* does AM handle predicate locks? */
bool ampredlocks;
- /* does AM support columns included with clause INCLUDING? */
- bool amcaninclude;
/* type of data stored in index, or InvalidOid if variable */
Oid amkeytype;
#include "access/tupmacs.h"
#include "storage/bufpage.h"
#include "storage/itemptr.h"
-#include "utils/rel.h"
/*
* Index tuple header structure
extern void index_deform_tuple(IndexTuple tup, TupleDesc tupleDescriptor,
Datum *values, bool *isnull);
extern IndexTuple CopyIndexTuple(IndexTuple source);
-extern IndexTuple index_truncate_tuple(Relation idxrel, IndexTuple olditup);
#endif /* ITUP_H */
IndexUniqueCheck checkUnique, Relation heapRel);
extern Buffer _bt_getstackbuf(Relation rel, BTStack stack, int access);
extern void _bt_finish_split(Relation rel, Buffer bbuf, BTStack stack);
-extern bool _bt_pgaddtup(Page page, Size itemsize, IndexTuple itup,
- OffsetNumber itup_off);
+
/*
* prototypes for functions in nbtpage.c
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201604081
+#define CATALOG_VERSION_NO 201604071
#endif
*/
int16 conkey[1];
- /*
- * Columns of conrelid that the constraint does not apply to,
- * but included into the same index with key columns.
- */
- int16 conincluding[1];
-
/*
* If a foreign key, the referenced columns of confrelid
*/
* compiler constants for pg_constraint
* ----------------
*/
-#define Natts_pg_constraint 25
+#define Natts_pg_constraint 24
#define Anum_pg_constraint_conname 1
#define Anum_pg_constraint_connamespace 2
#define Anum_pg_constraint_contype 3
#define Anum_pg_constraint_coninhcount 15
#define Anum_pg_constraint_connoinherit 16
#define Anum_pg_constraint_conkey 17
-#define Anum_pg_constraint_conincluding 18
-#define Anum_pg_constraint_confkey 19
-#define Anum_pg_constraint_conpfeqop 20
-#define Anum_pg_constraint_conppeqop 21
-#define Anum_pg_constraint_conffeqop 22
-#define Anum_pg_constraint_conexclop 23
-#define Anum_pg_constraint_conbin 24
-#define Anum_pg_constraint_consrc 25
+#define Anum_pg_constraint_confkey 18
+#define Anum_pg_constraint_conpfeqop 19
+#define Anum_pg_constraint_conppeqop 20
+#define Anum_pg_constraint_conffeqop 21
+#define Anum_pg_constraint_conexclop 22
+#define Anum_pg_constraint_conbin 23
+#define Anum_pg_constraint_consrc 24
/* ----------------
* initial contents of pg_constraint
CONSTRAINT_ASSERTION /* for future expansion */
} ConstraintCategory;
-extern Oid CreateConstraintEntry(const char* constraintName,
+extern Oid CreateConstraintEntry(const char *constraintName,
Oid constraintNamespace,
char constraintType,
bool isDeferrable,
bool isDeferred,
bool isValidated,
Oid relId,
- const int16* constraintKey,
+ const int16 *constraintKey,
int constraintNKeys,
- int constraintNTotalKeys,
Oid domainId,
Oid indexRelId,
Oid foreignRelId,
- const int16* foreignKey,
- const Oid* pfEqOp,
- const Oid* ppEqOp,
- const Oid* ffEqOp,
+ const int16 *foreignKey,
+ const Oid *pfEqOp,
+ const Oid *ppEqOp,
+ const Oid *ffEqOp,
int foreignNKeys,
char foreignUpdateType,
char foreignDeleteType,
char foreignMatchType,
- const Oid* exclOp,
- Node* conExpr,
- const char* conBin,
- const char* conSrc,
+ const Oid *exclOp,
+ Node *conExpr,
+ const char *conBin,
+ const char *conSrc,
bool conIsLocal,
int conInhCount,
bool conNoInherit,
{
Oid indexrelid; /* OID of the index */
Oid indrelid; /* OID of the relation it indexes */
- int16 indnatts; /* total number of columns in index */
- int16 indnkeyatts; /* number of key columns in index */
+ int16 indnatts; /* number of columns in index */
bool indisunique; /* is this a unique index? */
bool indisprimary; /* is this index for primary key? */
bool indisexclusion; /* is this index for exclusion constraint? */
* compiler constants for pg_index
* ----------------
*/
-#define Natts_pg_index 20
+#define Natts_pg_index 19
#define Anum_pg_index_indexrelid 1
#define Anum_pg_index_indrelid 2
#define Anum_pg_index_indnatts 3
-#define Anum_pg_index_indnkeyatts 4
-#define Anum_pg_index_indisunique 5
-#define Anum_pg_index_indisprimary 6
-#define Anum_pg_index_indisexclusion 7
-#define Anum_pg_index_indimmediate 8
-#define Anum_pg_index_indisclustered 9
-#define Anum_pg_index_indisvalid 10
-#define Anum_pg_index_indcheckxmin 11
-#define Anum_pg_index_indisready 12
-#define Anum_pg_index_indislive 13
-#define Anum_pg_index_indisreplident 14
-#define Anum_pg_index_indkey 15
-#define Anum_pg_index_indcollation 16
-#define Anum_pg_index_indclass 17
-#define Anum_pg_index_indoption 18
-#define Anum_pg_index_indexprs 19
-#define Anum_pg_index_indpred 20
+#define Anum_pg_index_indisunique 4
+#define Anum_pg_index_indisprimary 5
+#define Anum_pg_index_indisexclusion 6
+#define Anum_pg_index_indimmediate 7
+#define Anum_pg_index_indisclustered 8
+#define Anum_pg_index_indisvalid 9
+#define Anum_pg_index_indcheckxmin 10
+#define Anum_pg_index_indisready 11
+#define Anum_pg_index_indislive 12
+#define Anum_pg_index_indisreplident 13
+#define Anum_pg_index_indkey 14
+#define Anum_pg_index_indcollation 15
+#define Anum_pg_index_indclass 16
+#define Anum_pg_index_indoption 17
+#define Anum_pg_index_indexprs 18
+#define Anum_pg_index_indpred 19
/*
* Index AMs that support ordered scans must support these two indoption
* entries for a particular index. Used for both index_build and
* retail creation of index entries.
*
- * NumIndexAttrs total number of columns in this index
- * NumIndexKeyAttrs number of key columns in index
+ * NumIndexAttrs number of columns in this index
* KeyAttrNumbers underlying-rel attribute numbers used as keys
- * (zeroes indicate expressions). It also contains
- * info about included columns.
+ * (zeroes indicate expressions)
* Expressions expr trees for expression entries, or NIL if none
* ExpressionsState exec state for expressions, or NIL if none
* Predicate partial-index predicate, or NIL if none
typedef struct IndexInfo
{
NodeTag type;
- int ii_NumIndexAttrs; /* total number of columns in index */
- int ii_NumIndexKeyAttrs; /* number of key columns in index */
+ int ii_NumIndexAttrs;
AttrNumber ii_KeyAttrNumbers[INDEX_MAX_KEYS];
List *ii_Expressions; /* list of Expr */
List *ii_ExpressionsState; /* list of ExprState */
char *cooked_expr; /* expr, as nodeToString representation */
/* Fields used for unique constraints (UNIQUE and PRIMARY KEY): */
- List *keys; /* String nodes naming referenced key column(s) */
- List *including; /* String nodes naming referenced nonkey column(s) */
+ List *keys; /* String nodes naming referenced column(s) */
/* Fields used for EXCLUSION constraints: */
List *exclusions; /* list of (IndexElem, operator name) pairs */
char *accessMethod; /* name of access method (eg. btree) */
char *tableSpace; /* tablespace, or NULL for default */
List *indexParams; /* columns to index: a list of IndexElem */
- List *indexIncludingParams; /* additional columns to index:
- * a list of IndexElem */
List *options; /* WITH clause options: a list of DefElem */
Node *whereClause; /* qualification (partial-index predicate) */
List *excludeOpNames; /* exclusion operator names, or NIL if none */
* IndexOptInfo
* Per-index information for planning/optimization
*
- * indexkeys[], indexcollations[] each have ncolumns entries.
- * opfamily[], and opcintype[] each have nkeycolumns entries. They do
- * not contain any information about included attributes.
+ * indexkeys[], indexcollations[], opfamily[], and opcintype[]
+ * each have ncolumns entries.
*
- * sortopfamily[], reverse_sort[], and nulls_first[] have
- * nkeycolumns entries, if the index is ordered; but if it is unordered,
+ * sortopfamily[], reverse_sort[], and nulls_first[] likewise have
+ * ncolumns entries, if the index is ordered; but if it is unordered,
* those pointers are NULL.
*
* Zeroes in the indexkeys[] array indicate index columns that are
/* index descriptor information */
int ncolumns; /* number of columns in index */
- int nkeycolumns; /* number of key columns in index */
- int *indexkeys; /* column numbers of index's attributes
- * both key and included columns, or 0 */
+ int *indexkeys; /* column numbers of index's keys, or 0 */
Oid *indexcollations; /* OIDs of collations of index columns */
Oid *opfamily; /* OIDs of operator families for columns */
Oid *opcintype; /* OIDs of opclass declared input data types */
/*
* RelationGetNumberOfAttributes
- * Returns the total number of attributes in a relation.
+ * Returns the number of attributes in a relation.
*/
#define RelationGetNumberOfAttributes(relation) ((relation)->rd_rel->relnatts)
-/*
- * IndexRelationGetNumberOfAttributes
- * Returns the number of attributes in an index.
- */
-#define IndexRelationGetNumberOfAttributes(relation) \
- ((relation)->rd_index->indnatts)
-
-/*
- * IndexRelationGetNumberOfKeyAttributes
- * Returns the number of key attributes in an index.
- */
-#define IndexRelationGetNumberOfKeyAttributes(relation) \
- ((relation)->rd_index->indnkeyatts)
-
/*
* RelationGetDescr
* Returns tuple descriptor for a relation.
-- but this shouldn't:
INSERT INTO func_index_heap VALUES('QWERTY');
--
--- Test unique index with included columns
---
-CREATE TABLE covering_index_heap (f1 int, f2 int, f3 text);
-CREATE UNIQUE INDEX covering_index_index on covering_index_heap (f1,f2) INCLUDING(f3);
-INSERT INTO covering_index_heap VALUES(1,1,'AAA');
-INSERT INTO covering_index_heap VALUES(1,2,'AAA');
--- this should fail because of unique index on f1,f2:
-INSERT INTO covering_index_heap VALUES(1,2,'BBB');
-ERROR: duplicate key value violates unique constraint "covering_index_index"
-DETAIL: Key (f1, f2)=(1, 2) already exists.
--- and this shouldn't:
-INSERT INTO covering_index_heap VALUES(1,4,'AAA');
--- Try to build index on table that already contains data
-CREATE UNIQUE INDEX covering_pkey on covering_index_heap (f1,f2) INCLUDING(f3);
--- Try to use existing covering index as primary key
-ALTER TABLE covering_index_heap ADD CONSTRAINT covering_pkey PRIMARY KEY USING INDEX
-covering_pkey;
-DROP TABLE covering_index_heap;
---
-- Also try building functional, expressional, and partial indexes on
-- tables that already contain data.
--
+++ /dev/null
-/*
- * 1.test CREATE INDEX
- */
- -- Regular index with included columns
-CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
-INSERT INTO tbl select x, 2*x, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-CREATE INDEX tbl_idx ON tbl using btree(c1, c2) INCLUDING (c3,c4);
--- must fail because of intersection of key and included columns
-CREATE INDEX tbl_idx ON tbl using btree(c1, c2) INCLUDING (c1,c3);
-ERROR: included columns must not intersect with key columns
-DROP TABLE tbl;
--- Unique index and unique constraint
-CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
-INSERT INTO tbl select x, 2*x, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-CREATE UNIQUE INDEX tbl_idx_unique ON tbl using btree(c1, c2) INCLUDING (c3,c4);
-ALTER TABLE tbl add UNIQUE USING INDEX tbl_idx_unique;
-ALTER TABLE tbl add UNIQUE(c1, c2) INCLUDING (c3, c4);
-DROP TABLE tbl;
--- Unique index and unique constraint. Both must fail.
-CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
-INSERT INTO tbl select 1, 2, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-CREATE UNIQUE INDEX tbl_idx_unique ON tbl using btree(c1, c2) INCLUDING (c3,c4);
-ERROR: could not create unique index "tbl_idx_unique"
-DETAIL: Key (c1, c2)=(1, 2) is duplicated.
-ALTER TABLE tbl add UNIQUE(c1, c2) INCLUDING (c3, c4);
-ERROR: could not create unique index "tbl_c1_c2_c3_c4_key"
-DETAIL: Key (c1, c2)=(1, 2) is duplicated.
-DROP TABLE tbl;
--- PK constraint
-CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
-INSERT INTO tbl select 1, 2, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-ALTER TABLE tbl add PRIMARY KEY(c1, c2) INCLUDING (c3, c4);
-ERROR: could not create unique index "tbl_pkey"
-DETAIL: Key (c1, c2)=(1, 2) is duplicated.
-DROP TABLE tbl;
-CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
-INSERT INTO tbl select 1, 2, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-CREATE UNIQUE INDEX tbl_idx_unique ON tbl using btree(c1, c2) INCLUDING (c3,c4);
-ERROR: could not create unique index "tbl_idx_unique"
-DETAIL: Key (c1, c2)=(1, 2) is duplicated.
-ALTER TABLE tbl add PRIMARY KEY USING INDEX tbl_idx_unique;
-ERROR: index "tbl_idx_unique" does not exist
-LINE 1: ALTER TABLE tbl add PRIMARY KEY USING INDEX tbl_idx_unique;
- ^
-DROP TABLE tbl;
--- PK constraint. Must fail.
-CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
-INSERT INTO tbl select 1, 2, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-ALTER TABLE tbl add PRIMARY KEY(c1, c2) INCLUDING (c3, c4);
-ERROR: could not create unique index "tbl_pkey"
-DETAIL: Key (c1, c2)=(1, 2) is duplicated.
-DROP TABLE tbl;
-/*
- * 2. Test CREATE TABLE with constraint
- */
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box,
- CONSTRAINT covering UNIQUE(c1,c2) INCLUDING(c3,c4));
-select indexrelid::regclass, indnatts, indnkeyatts, indisunique, indisprimary, indkey, indclass from pg_index where indrelid = 'tbl'::regclass::oid;
- indexrelid | indnatts | indnkeyatts | indisunique | indisprimary | indkey | indclass
-------------+----------+-------------+-------------+--------------+---------+-----------
- covering | 4 | 2 | t | f | 1 2 3 4 | 1978 1978
-(1 row)
-
-select pg_get_constraintdef(oid), conname, conkey, conincluding from pg_constraint where conrelid = 'tbl'::regclass::oid;
- pg_get_constraintdef | conname | conkey | conincluding
-------------------------------------+----------+--------+--------------
- UNIQUE (c1, c2) INCLUDING (c3, c4) | covering | {1,2} | {3,4}
-(1 row)
-
--- ensure that constraint works
-INSERT INTO tbl select 1, 2, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-ERROR: duplicate key value violates unique constraint "covering"
-DETAIL: Key (c1, c2)=(1, 2) already exists.
-DROP TABLE tbl;
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box,
- CONSTRAINT covering PRIMARY KEY(c1,c2) INCLUDING(c3,c4));
-select indexrelid::regclass, indnatts, indnkeyatts, indisunique, indisprimary, indkey, indclass from pg_index where indrelid = 'tbl'::regclass::oid;
- indexrelid | indnatts | indnkeyatts | indisunique | indisprimary | indkey | indclass
-------------+----------+-------------+-------------+--------------+---------+-----------
- covering | 4 | 2 | t | t | 1 2 3 4 | 1978 1978
-(1 row)
-
-select pg_get_constraintdef(oid), conname, conkey, conincluding from pg_constraint where conrelid = 'tbl'::regclass::oid;
- pg_get_constraintdef | conname | conkey | conincluding
------------------------------------------+----------+--------+--------------
- PRIMARY KEY (c1, c2) INCLUDING (c3, c4) | covering | {1,2} | {3,4}
-(1 row)
-
--- ensure that constraint works
-INSERT INTO tbl select 1, 2, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-ERROR: duplicate key value violates unique constraint "covering"
-DETAIL: Key (c1, c2)=(1, 2) already exists.
-INSERT INTO tbl select 1, NULL, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-ERROR: null value in column "c2" violates not-null constraint
-DETAIL: Failing row contains (1, null, 3, (4,4),(4,4)).
-INSERT INTO tbl select x, 2*x, NULL, NULL from generate_series(1,10) as x;
-DROP TABLE tbl;
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box,
- UNIQUE(c1,c2) INCLUDING(c3,c4));
-select indexrelid::regclass, indnatts, indnkeyatts, indisunique, indisprimary, indkey, indclass from pg_index where indrelid = 'tbl'::regclass::oid;
- indexrelid | indnatts | indnkeyatts | indisunique | indisprimary | indkey | indclass
----------------------+----------+-------------+-------------+--------------+---------+-----------
- tbl_c1_c2_c3_c4_key | 4 | 2 | t | f | 1 2 3 4 | 1978 1978
-(1 row)
-
-select pg_get_constraintdef(oid), conname, conkey, conincluding from pg_constraint where conrelid = 'tbl'::regclass::oid;
- pg_get_constraintdef | conname | conkey | conincluding
-------------------------------------+---------------------+--------+--------------
- UNIQUE (c1, c2) INCLUDING (c3, c4) | tbl_c1_c2_c3_c4_key | {1,2} | {3,4}
-(1 row)
-
--- ensure that constraint works
-INSERT INTO tbl select 1, 2, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-ERROR: duplicate key value violates unique constraint "tbl_c1_c2_c3_c4_key"
-DETAIL: Key (c1, c2)=(1, 2) already exists.
-DROP TABLE tbl;
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box,
- PRIMARY KEY(c1,c2) INCLUDING(c3,c4));
-select indexrelid::regclass, indnatts, indnkeyatts, indisunique, indisprimary, indkey, indclass from pg_index where indrelid = 'tbl'::regclass::oid;
- indexrelid | indnatts | indnkeyatts | indisunique | indisprimary | indkey | indclass
-------------+----------+-------------+-------------+--------------+---------+-----------
- tbl_pkey | 4 | 2 | t | t | 1 2 3 4 | 1978 1978
-(1 row)
-
-select pg_get_constraintdef(oid), conname, conkey, conincluding from pg_constraint where conrelid = 'tbl'::regclass::oid;
- pg_get_constraintdef | conname | conkey | conincluding
------------------------------------------+----------+--------+--------------
- PRIMARY KEY (c1, c2) INCLUDING (c3, c4) | tbl_pkey | {1,2} | {3,4}
-(1 row)
-
--- ensure that constraint works
-INSERT INTO tbl select 1, 2, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-ERROR: duplicate key value violates unique constraint "tbl_pkey"
-DETAIL: Key (c1, c2)=(1, 2) already exists.
-INSERT INTO tbl select 1, NULL, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-ERROR: null value in column "c2" violates not-null constraint
-DETAIL: Failing row contains (1, null, 3, (4,4),(4,4)).
-INSERT INTO tbl select x, 2*x, NULL, NULL from generate_series(1,10) as x;
-DROP TABLE tbl;
-/*
- * 3.0 Test ALTER TABLE DROP COLUMN.
- * Any column deletion leads to index deletion.
- */
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 int);
-CREATE UNIQUE INDEX tbl_idx ON tbl using btree(c1, c2, c3, c4);
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
- indexdef
------------------------------------------------------------------
- CREATE UNIQUE INDEX tbl_idx ON tbl USING btree (c1, c2, c3, c4)
-(1 row)
-
-ALTER TABLE tbl DROP COLUMN c3;
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
- indexdef
-----------
-(0 rows)
-
-DROP TABLE tbl;
-/*
- * 3.1 Test ALTER TABLE DROP COLUMN.
- * Included column deletion leads to the index deletion,
- * as well as key columns deletion. It's explained in documentation.
- */
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box);
-CREATE UNIQUE INDEX tbl_idx ON tbl using btree(c1, c2) INCLUDING(c3,c4);
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
- indexdef
-----------------------------------------------------------------------------
- CREATE UNIQUE INDEX tbl_idx ON tbl USING btree (c1, c2) INCLUDING (c3, c4)
-(1 row)
-
-ALTER TABLE tbl DROP COLUMN c3;
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
- indexdef
-----------
-(0 rows)
-
-DROP TABLE tbl;
-/*
- * 3.2 Test ALTER TABLE DROP COLUMN.
- * Included column deletion leads to the index deletion.
- * as well as key columns deletion. It's explained in documentation.
- */
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box, UNIQUE(c1, c2) INCLUDING(c3,c4));
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
- indexdef
-----------------------------------------------------------------------------------------
- CREATE UNIQUE INDEX tbl_c1_c2_c3_c4_key ON tbl USING btree (c1, c2) INCLUDING (c3, c4)
-(1 row)
-
-ALTER TABLE tbl DROP COLUMN c3;
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
- indexdef
-----------
-(0 rows)
-
-ALTER TABLE tbl DROP COLUMN c1;
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
- indexdef
-----------
-(0 rows)
-
-DROP TABLE tbl;
-/*
- * 4. CREATE INDEX CONCURRENTLY
- */
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box, UNIQUE(c1, c2) INCLUDING(c3,c4));
-INSERT INTO tbl select x, 2*x, 3*x, box('4,4,4,4') from generate_series(1,1000) as x;
-CREATE UNIQUE INDEX CONCURRENTLY on tbl (c1, c2) INCLUDING (c3, c4);
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
- indexdef
-----------------------------------------------------------------------------------------
- CREATE UNIQUE INDEX tbl_c1_c2_c3_c4_idx ON tbl USING btree (c1, c2) INCLUDING (c3, c4)
- CREATE UNIQUE INDEX tbl_c1_c2_c3_c4_key ON tbl USING btree (c1, c2) INCLUDING (c3, c4)
-(2 rows)
-
-DROP TABLE tbl;
-/*
- * 5. REINDEX
- */
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box, UNIQUE(c1, c2) INCLUDING(c3,c4));
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
- indexdef
-----------------------------------------------------------------------------------------
- CREATE UNIQUE INDEX tbl_c1_c2_c3_c4_key ON tbl USING btree (c1, c2) INCLUDING (c3, c4)
-(1 row)
-
-ALTER TABLE tbl DROP COLUMN c3;
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
- indexdef
-----------
-(0 rows)
-
-REINDEX INDEX tbl_c1_c2_c3_c4_key;
-ERROR: relation "tbl_c1_c2_c3_c4_key" does not exist
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
- indexdef
-----------
-(0 rows)
-
-ALTER TABLE tbl DROP COLUMN c1;
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
- indexdef
-----------
-(0 rows)
-
-DROP TABLE tbl;
-/*
- * 7. Check various AMs. All but brtee must fail.
- */
-CREATE TABLE tbl (c1 int,c2 int, c3 box, c4 box);
-CREATE INDEX on tbl USING brin(c1, c2) INCLUDING (c3, c4);
-ERROR: access method "brin" does not support included columns
-CREATE INDEX on tbl USING gist(c3) INCLUDING (c4);
-ERROR: access method "gist" does not support included columns
-CREATE INDEX on tbl USING spgist(c3) INCLUDING (c4);
-ERROR: access method "spgist" does not support included columns
-CREATE INDEX on tbl USING gin(c1, c2) INCLUDING (c3, c4);
-ERROR: access method "gin" does not support included columns
-CREATE INDEX on tbl USING hash(c1, c2) INCLUDING (c3, c4);
-WARNING: hash indexes are not WAL-logged and their use is discouraged
-ERROR: access method "hash" does not support included columns
-CREATE INDEX on tbl USING rtree(c1, c2) INCLUDING (c3, c4);
-NOTICE: substituting access method "gist" for obsolete method "rtree"
-ERROR: access method "gist" does not support included columns
-CREATE INDEX on tbl USING btree(c1, c2) INCLUDING (c3, c4);
-DROP TABLE tbl;
-/*
- * 8. Update, delete values in indexed table.
- */
-CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
-INSERT INTO tbl select x, 2*x, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-CREATE UNIQUE INDEX tbl_idx_unique ON tbl using btree(c1, c2) INCLUDING (c3,c4);
-UPDATE tbl SET c1 = 100 WHERE c1 = 2;
-UPDATE tbl SET c1 = 1 WHERE c1 = 3;
--- should fail
-UPDATE tbl SET c2 = 2 WHERE c1 = 1;
-ERROR: duplicate key value violates unique constraint "tbl_idx_unique"
-DETAIL: Key (c1, c2)=(1, 2) already exists.
-UPDATE tbl SET c3 = 1;
-DELETE FROM tbl WHERE c1 = 5 OR c3 = 12;
-DROP TABLE tbl;
-/*
- * 9. Alter column type.
- */
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box, UNIQUE(c1, c2) INCLUDING(c3,c4));
-INSERT INTO tbl select x, 2*x, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-ALTER TABLE tbl ALTER c1 TYPE bigint;
-ALTER TABLE tbl ALTER c3 TYPE bigint;
-\d tbl
- Table "public.tbl"
- Column | Type | Modifiers
---------+---------+-----------
- c1 | bigint |
- c2 | integer |
- c3 | bigint |
- c4 | box |
-Indexes:
- "tbl_c1_c2_c3_c4_key" UNIQUE CONSTRAINT, btree (c1, c2) INCLUDING (c3, c4)
-
-DROP TABLE tbl;
# ----------
test: create_misc create_operator
# These depend on the above two
-test: create_index create_view index_including
+test: create_index create_view
# ----------
# Another group of parallel tests
test: create_misc
test: create_operator
test: create_index
-test: index_including
test: create_view
test: create_aggregate
test: create_function_3
-- but this shouldn't:
INSERT INTO func_index_heap VALUES('QWERTY');
---
--- Test unique index with included columns
---
-CREATE TABLE covering_index_heap (f1 int, f2 int, f3 text);
-CREATE UNIQUE INDEX covering_index_index on covering_index_heap (f1,f2) INCLUDING(f3);
-
-INSERT INTO covering_index_heap VALUES(1,1,'AAA');
-INSERT INTO covering_index_heap VALUES(1,2,'AAA');
--- this should fail because of unique index on f1,f2:
-INSERT INTO covering_index_heap VALUES(1,2,'BBB');
--- and this shouldn't:
-INSERT INTO covering_index_heap VALUES(1,4,'AAA');
--- Try to build index on table that already contains data
-CREATE UNIQUE INDEX covering_pkey on covering_index_heap (f1,f2) INCLUDING(f3);
--- Try to use existing covering index as primary key
-ALTER TABLE covering_index_heap ADD CONSTRAINT covering_pkey PRIMARY KEY USING INDEX
-covering_pkey;
-DROP TABLE covering_index_heap;
-
-
--
-- Also try building functional, expressional, and partial indexes on
-- tables that already contain data.
+++ /dev/null
-/*
- * 1.test CREATE INDEX
- */
- -- Regular index with included columns
-CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
-INSERT INTO tbl select x, 2*x, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-CREATE INDEX tbl_idx ON tbl using btree(c1, c2) INCLUDING (c3,c4);
--- must fail because of intersection of key and included columns
-CREATE INDEX tbl_idx ON tbl using btree(c1, c2) INCLUDING (c1,c3);
-DROP TABLE tbl;
-
--- Unique index and unique constraint
-CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
-INSERT INTO tbl select x, 2*x, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-CREATE UNIQUE INDEX tbl_idx_unique ON tbl using btree(c1, c2) INCLUDING (c3,c4);
-ALTER TABLE tbl add UNIQUE USING INDEX tbl_idx_unique;
-ALTER TABLE tbl add UNIQUE(c1, c2) INCLUDING (c3, c4);
-DROP TABLE tbl;
-
--- Unique index and unique constraint. Both must fail.
-CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
-INSERT INTO tbl select 1, 2, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-CREATE UNIQUE INDEX tbl_idx_unique ON tbl using btree(c1, c2) INCLUDING (c3,c4);
-ALTER TABLE tbl add UNIQUE(c1, c2) INCLUDING (c3, c4);
-DROP TABLE tbl;
-
--- PK constraint
-CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
-INSERT INTO tbl select 1, 2, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-ALTER TABLE tbl add PRIMARY KEY(c1, c2) INCLUDING (c3, c4);
-DROP TABLE tbl;
-
-CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
-INSERT INTO tbl select 1, 2, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-CREATE UNIQUE INDEX tbl_idx_unique ON tbl using btree(c1, c2) INCLUDING (c3,c4);
-ALTER TABLE tbl add PRIMARY KEY USING INDEX tbl_idx_unique;
-DROP TABLE tbl;
--- PK constraint. Must fail.
-CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
-INSERT INTO tbl select 1, 2, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-ALTER TABLE tbl add PRIMARY KEY(c1, c2) INCLUDING (c3, c4);
-DROP TABLE tbl;
-
-
-/*
- * 2. Test CREATE TABLE with constraint
- */
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box,
- CONSTRAINT covering UNIQUE(c1,c2) INCLUDING(c3,c4));
-select indexrelid::regclass, indnatts, indnkeyatts, indisunique, indisprimary, indkey, indclass from pg_index where indrelid = 'tbl'::regclass::oid;
-select pg_get_constraintdef(oid), conname, conkey, conincluding from pg_constraint where conrelid = 'tbl'::regclass::oid;
--- ensure that constraint works
-INSERT INTO tbl select 1, 2, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-DROP TABLE tbl;
-
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box,
- CONSTRAINT covering PRIMARY KEY(c1,c2) INCLUDING(c3,c4));
-select indexrelid::regclass, indnatts, indnkeyatts, indisunique, indisprimary, indkey, indclass from pg_index where indrelid = 'tbl'::regclass::oid;
-select pg_get_constraintdef(oid), conname, conkey, conincluding from pg_constraint where conrelid = 'tbl'::regclass::oid;
--- ensure that constraint works
-INSERT INTO tbl select 1, 2, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-INSERT INTO tbl select 1, NULL, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-INSERT INTO tbl select x, 2*x, NULL, NULL from generate_series(1,10) as x;
-DROP TABLE tbl;
-
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box,
- UNIQUE(c1,c2) INCLUDING(c3,c4));
-select indexrelid::regclass, indnatts, indnkeyatts, indisunique, indisprimary, indkey, indclass from pg_index where indrelid = 'tbl'::regclass::oid;
-select pg_get_constraintdef(oid), conname, conkey, conincluding from pg_constraint where conrelid = 'tbl'::regclass::oid;
--- ensure that constraint works
-INSERT INTO tbl select 1, 2, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-DROP TABLE tbl;
-
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box,
- PRIMARY KEY(c1,c2) INCLUDING(c3,c4));
-select indexrelid::regclass, indnatts, indnkeyatts, indisunique, indisprimary, indkey, indclass from pg_index where indrelid = 'tbl'::regclass::oid;
-select pg_get_constraintdef(oid), conname, conkey, conincluding from pg_constraint where conrelid = 'tbl'::regclass::oid;
--- ensure that constraint works
-INSERT INTO tbl select 1, 2, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-INSERT INTO tbl select 1, NULL, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-INSERT INTO tbl select x, 2*x, NULL, NULL from generate_series(1,10) as x;
-DROP TABLE tbl;
-
-
-/*
- * 3.0 Test ALTER TABLE DROP COLUMN.
- * Any column deletion leads to index deletion.
- */
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 int);
-CREATE UNIQUE INDEX tbl_idx ON tbl using btree(c1, c2, c3, c4);
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
-ALTER TABLE tbl DROP COLUMN c3;
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
-DROP TABLE tbl;
-
-/*
- * 3.1 Test ALTER TABLE DROP COLUMN.
- * Included column deletion leads to the index deletion,
- * as well as key columns deletion. It's explained in documentation.
- */
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box);
-CREATE UNIQUE INDEX tbl_idx ON tbl using btree(c1, c2) INCLUDING(c3,c4);
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
-ALTER TABLE tbl DROP COLUMN c3;
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
-DROP TABLE tbl;
-
-/*
- * 3.2 Test ALTER TABLE DROP COLUMN.
- * Included column deletion leads to the index deletion.
- * as well as key columns deletion. It's explained in documentation.
- */
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box, UNIQUE(c1, c2) INCLUDING(c3,c4));
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
-ALTER TABLE tbl DROP COLUMN c3;
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
-ALTER TABLE tbl DROP COLUMN c1;
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
-DROP TABLE tbl;
-
-
-/*
- * 4. CREATE INDEX CONCURRENTLY
- */
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box, UNIQUE(c1, c2) INCLUDING(c3,c4));
-INSERT INTO tbl select x, 2*x, 3*x, box('4,4,4,4') from generate_series(1,1000) as x;
-CREATE UNIQUE INDEX CONCURRENTLY on tbl (c1, c2) INCLUDING (c3, c4);
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
-DROP TABLE tbl;
-
-
-/*
- * 5. REINDEX
- */
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box, UNIQUE(c1, c2) INCLUDING(c3,c4));
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
-ALTER TABLE tbl DROP COLUMN c3;
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
-REINDEX INDEX tbl_c1_c2_c3_c4_key;
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
-ALTER TABLE tbl DROP COLUMN c1;
-select indexdef from pg_indexes where tablename = 'tbl' order by indexname;
-DROP TABLE tbl;
-
-/*
- * 7. Check various AMs. All but brtee must fail.
- */
-CREATE TABLE tbl (c1 int,c2 int, c3 box, c4 box);
-CREATE INDEX on tbl USING brin(c1, c2) INCLUDING (c3, c4);
-CREATE INDEX on tbl USING gist(c3) INCLUDING (c4);
-CREATE INDEX on tbl USING spgist(c3) INCLUDING (c4);
-CREATE INDEX on tbl USING gin(c1, c2) INCLUDING (c3, c4);
-CREATE INDEX on tbl USING hash(c1, c2) INCLUDING (c3, c4);
-CREATE INDEX on tbl USING rtree(c1, c2) INCLUDING (c3, c4);
-CREATE INDEX on tbl USING btree(c1, c2) INCLUDING (c3, c4);
-DROP TABLE tbl;
-
-/*
- * 8. Update, delete values in indexed table.
- */
-CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
-INSERT INTO tbl select x, 2*x, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-CREATE UNIQUE INDEX tbl_idx_unique ON tbl using btree(c1, c2) INCLUDING (c3,c4);
-UPDATE tbl SET c1 = 100 WHERE c1 = 2;
-UPDATE tbl SET c1 = 1 WHERE c1 = 3;
--- should fail
-UPDATE tbl SET c2 = 2 WHERE c1 = 1;
-UPDATE tbl SET c3 = 1;
-DELETE FROM tbl WHERE c1 = 5 OR c3 = 12;
-DROP TABLE tbl;
-
-/*
- * 9. Alter column type.
- */
-CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box, UNIQUE(c1, c2) INCLUDING(c3,c4));
-INSERT INTO tbl select x, 2*x, 3*x, box('4,4,4,4') from generate_series(1,10) as x;
-ALTER TABLE tbl ALTER c1 TYPE bigint;
-ALTER TABLE tbl ALTER c3 TYPE bigint;
-\d tbl
-DROP TABLE tbl;
-