Skip to content

Commit

Permalink
Only C, POSIX and ICU collations now allowed
Browse files Browse the repository at this point in the history
- ALTER COLLATION ... REFRESH VERSION forbidden when there are OrioleDB indexes
  using collation
- Added collation check for ALTER COLUMN TYPE
  • Loading branch information
homper authored and akorotkov committed Sep 9, 2023
1 parent 9402e42 commit fcd00b5
Show file tree
Hide file tree
Showing 16 changed files with 424 additions and 80 deletions.
8 changes: 4 additions & 4 deletions .pgtags
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
13: patches13_14
14: patches14_14
15: patches15_15
16: patches16_15
13: patches13_15
14: patches14_15
15: patches15_17
16: patches16_17
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -180,14 +180,18 @@ ifeq ($(shell expr $(MAJORVERSION) \>= 15), 1)
ISOLATIONCHECKS += isol_merge
endif

PG_REGRESS_ARGS=--no-locale --encoding=UTF8

regresscheck: | install
$(pg_regress_check) \
--temp-config orioledb_regression.conf \
$(PG_REGRESS_ARGS) \
$(REGRESSCHECKS)

isolationcheck: | install
$(pg_isolation_regress_check) \
--temp-config orioledb_isolation.conf \
$(PG_REGRESS_ARGS) \
$(ISOLATIONCHECKS)

$(TESTGRESCHECKS_PART_1) $(TESTGRESCHECKS_PART_2): | install
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ See [our dockerhub](https://hub.docker.com/r/orioledb/orioledb) for details.

Before building and installing OrioleDB, one should ensure to have the following:

* [PostgreSQL with extensibility patches](https://github.com/orioledb/postgres): [13 (tag: patches13_14)](https://github.com/orioledb/postgres/tree/patches13_14), [14 (tag: patches14_14)](https://github.com/orioledb/postgres/tree/patches14_14), [15 (tag: patches15_15)](https://github.com/orioledb/postgres/tree/patches15_15), or [16 (tag: patches16_15)](https://github.com/orioledb/postgres/tree/patches16_15);
* [PostgreSQL with extensibility patches](https://github.com/orioledb/postgres): [13 (tag: patches13_15)](https://github.com/orioledb/postgres/tree/patches13_15), [14 (tag: patches14_15)](https://github.com/orioledb/postgres/tree/patches14_15), [15 (tag: patches15_17)](https://github.com/orioledb/postgres/tree/patches15_17), or [16 (tag: patches16_17)](https://github.com/orioledb/postgres/tree/patches16_17);
* Development package of libzstd;
* python 3.5+ with testgres package.

Expand Down
6 changes: 6 additions & 0 deletions doc/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ OrioleDB is implemented using the table access method interface. Therefore, to

OrioleDB uses index-organized tables. So, the selection of the primary key is a very critical decision affecting performance. If you specify no primary key, then a hidden surrogate primary key will be created over the virtual `ctid` column.

Collations
----------
OrioleDB tables support only ICU, C, and POSIX collations. So, make sure the cluster or database is set up with default collations that fall under those options, otherwise you have to write COLLATE for every "text" field of the table.

ALTER COLLATION REFRESH VERSION is also disabled for collations that used for fields and indexes of orioledb tables.

Example
-------

Expand Down
1 change: 1 addition & 0 deletions include/catalog/o_sys_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,7 @@ extern void o_amproc_cache_tup_print(BTreeDescr *desc, StringInfo buf,
/* o_collation_cache.c */
O_SYS_CACHE_DECLS(collation_cache, OCollation, 1);
extern HeapTuple o_collation_cache_search_htup(TupleDesc tupdesc, Oid colloid);
extern void orioledb_save_collation(Oid colloid);

/* o_database_cache.c */
typedef struct ODatabase
Expand Down
1 change: 0 additions & 1 deletion include/catalog/o_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,6 @@ extern void o_table_fill_constr(OTable *o_table, Relation rel, int fieldnum,
extern void o_tupdesc_load_constr(TupleDesc tupdesc, OTable *o_table,
OIndexDescr *descr);
extern char *o_get_type_name(Oid typid, int32 typmod);
extern char *o_get_collation_name(Oid colid);

static inline int
o_table_fieldnum(OTable *table, const char *name)
Expand Down
96 changes: 96 additions & 0 deletions src/catalog/ddl.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ static void orioledb_ExecutorRun_hook(QueryDesc *queryDesc,
bool execute_once);
static void o_alter_column_type(AlterTableCmd *cmd, const char *queryString,
Relation rel);
static void o_find_collation_dependencies(Oid colloid);

void
orioledb_setup_ddl_hooks(void)
Expand Down Expand Up @@ -1009,6 +1010,13 @@ orioledb_utility_command(PlannedStmt *pstmt,
}
}
}
else if (IsA(pstmt->utilityStmt, AlterCollationStmt))
{
AlterCollationStmt *astmt = (AlterCollationStmt *) pstmt->utilityStmt;
Oid collOid = get_collation_oid(astmt->collname, false);

o_find_collation_dependencies(collOid);
}

if (call_next)
{
Expand Down Expand Up @@ -1055,6 +1063,93 @@ o_alter_column_type(AlterTableCmd *cmd, const char *queryString, Relation rel)
}
}

static void
o_find_collation_dependencies(Oid colloid)
{
Relation depRel;
ScanKeyData key[2];
SysScanDesc depScan;
HeapTuple depTup;
HeapTuple collationtup;
Form_pg_collation collform;

/* since this function recurses, it could be driven to stack overflow */
check_stack_depth();

/*
* We scan pg_depend to find those things that depend on the given type.
* (We assume we can ignore refobjsubid for a type.)
*/
depRel = table_open(DependRelationId, AccessShareLock);

ScanKeyInit(&key[0],
Anum_pg_depend_refclassid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(CollationRelationId));
ScanKeyInit(&key[1],
Anum_pg_depend_refobjid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(colloid));

depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
NULL, 2, key);

collationtup = SearchSysCache1(COLLOID, colloid);
if (!HeapTupleIsValid(collationtup))
elog(ERROR, "cache lookup failed for collation (%u)", colloid);
collform = (Form_pg_collation) GETSTRUCT(collationtup);

while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
{
Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
Relation rel;

/* Else, ignore dependees that aren't user columns of relations */
/* (we assume system columns are never of interesting types) */
if (pg_depend->classid != RelationRelationId)
continue;

rel = relation_open(pg_depend->objid, AccessShareLock);

if ((rel->rd_rel->relkind == RELKIND_RELATION ||
rel->rd_rel->relkind == RELKIND_MATVIEW) &&
is_orioledb_rel(rel))
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot refresh collation \"%s\" because "
"orioledb table \"%s\" uses it",
collform->collname.data,
RelationGetRelationName(rel))));
}
else if (rel->rd_rel->relkind == RELKIND_INDEX)
{
Relation tbl;

tbl = relation_open(rel->rd_index->indrelid, AccessShareLock);

if ((tbl->rd_rel->relkind == RELKIND_RELATION ||
tbl->rd_rel->relkind == RELKIND_MATVIEW) &&
is_orioledb_rel(tbl))
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot refresh collation \"%s\" because "
"orioledb index \"%s\" uses it",
collform->collname.data,
RelationGetRelationName(rel))));
}
relation_close(tbl, AccessShareLock);
}

relation_close(rel, AccessShareLock);
}
ReleaseSysCache(collationtup);
systable_endscan(depScan);

relation_close(depRel, AccessShareLock);
}

static void
o_find_composite_type_dependencies(Oid typeOid, Relation origRelation)
{
Expand Down Expand Up @@ -1776,6 +1871,7 @@ orioledb_object_access_hook(ObjectAccessType access, Oid classId, Oid objectId,

if (!rewrite)
{
orioledb_save_collation(field->collation);
fill_current_oxid_csn(&oxid, &csn);
o_tables_meta_lock();
o_tables_update(o_table, oxid, csn);
Expand Down
28 changes: 28 additions & 0 deletions src/catalog/o_collation_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ o_collation_cache_fill_entry(Pointer *entry_ptr, OSysCacheKey *key,
Oid colloid;
Datum datum;
bool isNull;
bool valid;

colloid = DatumGetObjectId(key->keys[0]);

Expand All @@ -93,6 +94,17 @@ o_collation_cache_fill_entry(Pointer *entry_ptr, OSysCacheKey *key,
elog(ERROR, "cache lookup failed for collation (%u)", colloid);
collform = (Form_pg_collation) GETSTRUCT(collationtup);

valid = collform->collprovider == COLLPROVIDER_ICU ||
lc_collate_is_c(colloid);

#if PG_VERSION_NUM >= 150000
valid = valid || (colloid == DEFAULT_COLLATION_OID &&
default_locale.provider == COLLPROVIDER_ICU);
#endif
if (!valid)
elog(ERROR,
"Only C, POSIX and ICU collations supported for orioledb tables");

prev_context = MemoryContextSwitchTo(collation_cache->mcxt);
if (o_collation != NULL) /* Existed o_collation updated */
{
Expand Down Expand Up @@ -282,3 +294,19 @@ o_collation_cache_search_htup(TupleDesc tupdesc, Oid colloid)
}
return result;
}

void
orioledb_save_collation(Oid colloid)
{
if (OidIsValid(colloid))
{
XLogRecPtr cur_lsn;
Oid datoid;
OClassArg arg = {.sys_table = true};

o_sys_cache_set_datoid_lsn(&cur_lsn, &datoid);
o_class_cache_add_if_needed(datoid, CollationRelationId, cur_lsn,
(Pointer) &arg);
o_collation_cache_add_if_needed(datoid, colloid, cur_lsn, NULL);
}
}
5 changes: 3 additions & 2 deletions src/catalog/o_indices.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "miscadmin.h"
#include "optimizer/optimizer.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"

PG_FUNCTION_INFO_V1(orioledb_index_oids);
PG_FUNCTION_INFO_V1(orioledb_index_description);
Expand Down Expand Up @@ -1114,7 +1115,7 @@ describe_index(TupleDesc tupdesc, ORelOids oids, OIndexType type)
{
OTableField *field = &index->leafFields[i];
char *typename = o_get_type_name(field->typid, field->typmod);
char *colname = o_get_collation_name(field->collation);
char *colname = get_collation_name(field->collation);

if (max_column_str < strlen(NameStr(field->name)))
max_column_str = strlen(NameStr(field->name));
Expand Down Expand Up @@ -1144,7 +1145,7 @@ describe_index(TupleDesc tupdesc, ORelOids oids, OIndexType type)
{
OTableField *field = &index->leafFields[i];
char *typename = o_get_type_name(field->typid, field->typmod);
char *colname = o_get_collation_name(field->collation);
char *colname = get_collation_name(field->collation);

appendStringInfo(&buf, format.data,
NameStr(field->name),
Expand Down
74 changes: 27 additions & 47 deletions src/catalog/o_tables.c
Original file line number Diff line number Diff line change
Expand Up @@ -417,18 +417,8 @@ o_table_fill_index(OTable *o_table, OIndexNumber ix_num, Relation index_rel)
exprField->align = typeTup->typalign;
exprField->typmod = exprTypmod(indexkey);
exprField->collation = exprCollation(indexkey);
if (OidIsValid(exprField->collation))
{
XLogRecPtr cur_lsn;
Oid datoid;
OClassArg arg = {.sys_table = true};

o_sys_cache_set_datoid_lsn(&cur_lsn, &datoid);
o_class_cache_add_if_needed(datoid, CollationRelationId,
cur_lsn, (Pointer) &arg);
o_collation_cache_add_if_needed(datoid, exprField->collation,
cur_lsn, NULL);
}

orioledb_save_collation(exprField->collation);

ReleaseSysCache(tuple);

Expand Down Expand Up @@ -511,18 +501,7 @@ o_table_fill_index(OTable *o_table, OIndexNumber ix_num, Relation index_rel)
ix_field->nullsOrdering = SORTBY_NULLS_FIRST;
}
}
if (OidIsValid(ix_field->collation))
{
XLogRecPtr cur_lsn;
Oid datoid;
OClassArg arg = {.sys_table = true};

o_sys_cache_set_datoid_lsn(&cur_lsn, &datoid);
o_class_cache_add_if_needed(datoid, CollationRelationId, cur_lsn,
(Pointer) &arg);
o_collation_cache_add_if_needed(datoid, ix_field->collation,
cur_lsn, NULL);
}
orioledb_save_collation(ix_field->collation);
}
}

Expand Down Expand Up @@ -619,6 +598,27 @@ o_table_fill_constr(OTable *o_table, Relation rel, int fieldnum,
MemoryContextSwitchTo(oldcxt);
}

void
orioledb_attr_to_field(OTableField *field, Form_pg_attribute attr)
{
strlcpy(NameStr(field->name), NameStr(attr->attname), NAMEDATALEN);
field->typid = attr->atttypid;
field->collation = attr->attcollation;
field->typmod = attr->atttypmod;
field->typlen = attr->attlen;
field->ndims = attr->attndims;
field->byval = attr->attbyval;
field->align = attr->attalign;
field->storage = attr->attstorage;
#if PG_VERSION_NUM >= 140000
field->compression = attr->attcompression;
#endif
field->droped = attr->attisdropped;
field->notnull = attr->attnotnull;
field->hasmissing = attr->atthasmissing;
field->hasdef = attr->atthasdef;
}

OTable *
o_table_tableam_create(ORelOids oids, TupleDesc tupdesc)
{
Expand All @@ -641,18 +641,7 @@ o_table_tableam_create(ORelOids oids, TupleDesc tupdesc)
OTableField *field = &o_table->fields[i];

orioledb_attr_to_field(field, attr);
if (OidIsValid(field->collation))
{
XLogRecPtr cur_lsn;
Oid datoid;
OClassArg arg = {.sys_table = true};

o_sys_cache_set_datoid_lsn(&cur_lsn, &datoid);
o_class_cache_add_if_needed(datoid, CollationRelationId, cur_lsn,
(Pointer) &arg);
o_collation_cache_add_if_needed(datoid, field->collation, cur_lsn,
NULL);
}
orioledb_save_collation(field->collation);
}
o_table->nindices = 0;
o_table_resize_constr(o_table);
Expand Down Expand Up @@ -1249,15 +1238,6 @@ o_get_type_name(Oid typid, int32 typmod)
FORMAT_TYPE_ALLOW_INVALID);
}

char *
o_get_collation_name(Oid colid)
{
if (colid < FirstGenbkiObjectId)
return get_collation_name(colid);
else
return psprintf("%u", colid);
}

static text *
describe_table(ORelOids oids)
{
Expand All @@ -1284,7 +1264,7 @@ describe_table(ORelOids oids)
{
OTableField *field = &table->fields[i];
char *typename = o_get_type_name(field->typid, field->typmod);
char *colname = o_get_collation_name(field->collation);
char *colname = get_collation_name(field->collation);

if (max_column_str < strlen(NameStr(field->name)))
max_column_str = strlen(NameStr(field->name));
Expand Down Expand Up @@ -1323,7 +1303,7 @@ describe_table(ORelOids oids)
{
OTableField *field = &table->fields[i];
char *typename = o_get_type_name(field->typid, field->typmod);
char *colname = o_get_collation_name(field->collation);
char *colname = get_collation_name(field->collation);

appendStringInfo(&buf, format.data,
NameStr(field->name),
Expand Down
Loading

0 comments on commit fcd00b5

Please sign in to comment.