diff --git a/bin/expected/repack.out b/bin/expected/repack.out index 3a44f3a..25e15b0 100644 --- a/bin/expected/repack.out +++ b/bin/expected/repack.out @@ -314,3 +314,35 @@ ERROR: relation "tbl_uk" must have a primary key or not-null unique keys \! pg_repack --dbname=contrib_regression --no-order --table=tbl_nn_puk ERROR: relation "tbl_nn_puk" must have a primary key or not-null unique keys -- => ERROR +-- +-- pg_repack issue #3 +-- +CREATE TABLE issue3 (col1 int NOT NULL, col2 text NOT NULL); +CREATE UNIQUE INDEX issue3_idx1 ON issue3 (col1, col2 DESC); +CREATE UNIQUE INDEX issue3_idx2 ON issue3 (col1 DESC, col2 text_pattern_ops); +CREATE UNIQUE INDEX issue3_idx3 ON issue3 (col1 DESC, col2 DESC); +CREATE UNIQUE INDEX issue3_idx4 ON issue3 (col1 NULLS FIRST, col2 text_pattern_ops DESC NULLS LAST); +SELECT repack.get_index_keys('issue3_idx1'::regclass::oid, 'issue3'::regclass::oid); + get_index_keys +----------------- + col1, col2 DESC +(1 row) + +SELECT repack.get_index_keys('issue3_idx2'::regclass::oid, 'issue3'::regclass::oid); + get_index_keys +--------------------------- + col1 DESC, col2 USING ~<~ +(1 row) + +SELECT repack.get_index_keys('issue3_idx3'::regclass::oid, 'issue3'::regclass::oid); + get_index_keys +---------------------- + col1 DESC, col2 DESC +(1 row) + +SELECT repack.get_index_keys('issue3_idx4'::regclass::oid, 'issue3'::regclass::oid); + get_index_keys +-------------------------------------------------- + col1 NULLS FIRST, col2 DESC USING ~<~ NULLS LAST +(1 row) + diff --git a/bin/sql/repack.sql b/bin/sql/repack.sql index 9d385dc..1446a9a 100644 --- a/bin/sql/repack.sql +++ b/bin/sql/repack.sql @@ -187,3 +187,17 @@ CREATE UNIQUE INDEX tbl_nn_puk_pcol1_idx ON tbl_nn_puk(col1) WHERE col1 < 10; -- => OK \! pg_repack --dbname=contrib_regression --no-order --table=tbl_nn_puk -- => ERROR + +-- +-- pg_repack issue #3 +-- +CREATE TABLE issue3 (col1 int NOT NULL, col2 text NOT NULL); +CREATE UNIQUE INDEX issue3_idx1 ON issue3 (col1, col2 DESC); +CREATE UNIQUE INDEX issue3_idx2 ON issue3 (col1 DESC, col2 text_pattern_ops); +CREATE UNIQUE INDEX issue3_idx3 ON issue3 (col1 DESC, col2 DESC); +CREATE UNIQUE INDEX issue3_idx4 ON issue3 (col1 NULLS FIRST, col2 text_pattern_ops DESC NULLS LAST); + +SELECT repack.get_index_keys('issue3_idx1'::regclass::oid, 'issue3'::regclass::oid); +SELECT repack.get_index_keys('issue3_idx2'::regclass::oid, 'issue3'::regclass::oid); +SELECT repack.get_index_keys('issue3_idx3'::regclass::oid, 'issue3'::regclass::oid); +SELECT repack.get_index_keys('issue3_idx4'::regclass::oid, 'issue3'::regclass::oid); diff --git a/lib/repack.c b/lib/repack.c index 21aa538..72bf81d 100644 --- a/lib/repack.c +++ b/lib/repack.c @@ -472,6 +472,36 @@ parse_indexdef(IndexDef *stmt, Oid index, Oid table) stmt->options = sql; } +/* + * Parse the trailing ... [ DESC ] [ NULLS { FIRST | LAST } ] from an index + * definition column. + * Returned values point to token. \0's are inserted to separate parsed parts. + */ +static void +parse_desc_nulls(char *token, char **desc, char **nulls) +{ +#if PG_VERSION_NUM >= 80300 + char *pos; + + /* easier to walk backwards than to parse quotes and escapes... */ + if (NULL != (pos = strstr(token, " NULLS FIRST"))) + { + *nulls = pos + 1; + *pos = '\0'; + } + else if (NULL != (pos = strstr(token, " NULLS LAST"))) + { + *nulls = pos + 1; + *pos = '\0'; + } + if (NULL != (pos = strstr(token, " DESC"))) + { + *desc = pos + 1; + *pos = '\0'; + } +#endif +} + /** * @fn Datum repack_get_index_keys(PG_FUNCTION_ARGS) * @brief Get key definition of the index. @@ -514,12 +544,18 @@ repack_get_index_keys(PG_FUNCTION_ARGS) for (nattr = 0, next = stmt.columns; next; nattr++) { char *opcname; + char *coldesc = NULL; + char *colnulls = NULL; token = next; while (isspace((unsigned char) *token)) token++; next = skip_until(index, next, ','); + parse_desc_nulls(token, &coldesc, &colnulls); opcname = skip_until(index, token, ' '); + appendStringInfoString(&str, token); + if (coldesc) + appendStringInfo(&str, " %s", coldesc); if (opcname) { /* lookup default operator name from operator class */ @@ -556,12 +592,11 @@ repack_get_index_keys(PG_FUNCTION_ARGS) elog(ERROR, "missing operator %d(%u,%u) in opfamily %u", strategy, opcintype, opcintype, opfamily); - opcname[-1] = '\0'; - appendStringInfo(&str, "%s USING %s", token, get_opname(oprid)); + appendStringInfo(&str, " USING %s", get_opname(oprid)); } - else - appendStringInfoString(&str, token); + if (colnulls) + appendStringInfo(&str, " %s", colnulls); if (next) appendStringInfoString(&str, ", "); }