On Mon, Jan 22, 2018 at 12:48:45PM +0100, Daniel Gustafsson wrote: > Gotcha. I’ve added some tests to the patch. The test for CREATE > FUNCTION was omitted for now awaiting the outcome of the discussion > around isStrict and isCachable.
That makes sense. > Not sure how much they’re worth in "make check” though as it’s quite > easy to add a new option checked with pg_strcasecmp which then isn’t > tested. Still, it might aid review so definitely worth it. Thanks for making those, this eases the review lookups. There are a couple of code paths that remained untested: - contrib/unaccent/ - contrib/dict_xsyn/ - contrib/dict_int/ - The combinations of toast reloptions is pretty particular as option namespaces also go through pg_strcasecmp, so I think that those should be tested as well (your patch includes a test for fillfactor, which is a good base by the way). - check_option for CREATE VIEW and ALTER VIEW SET. - ALTER TEXT SEARCH CONFIGURATION for copy/parser options. - CREATE TYPE AS RANGE with DefineRange(). There are as well two things I have spotted on the way: 1) fillRelOptions() can safely use strcmp. 2) indexam.sgml mentions using pg_strcasecmp() for consistency with the core code when defining amproperty for an index AM. Well, with this patch I think that for consistency with the core code that would involve using strcmp instead, extension developers can of course still use pg_strcasecmp. Those are changed as well in the attached, which applies on top of your v6. I have added as well in it the tests I spotted were missing. If this looks right to you, I am fine to switch this patch as ready for committer, without considering the issues with isCachable and isStrict in CREATE FUNCTION of course. -- Michael
diff --git a/contrib/dict_int/expected/dict_int.out b/contrib/dict_int/expected/dict_int.out index 3b766ec52a..20d172c730 100644 --- a/contrib/dict_int/expected/dict_int.out +++ b/contrib/dict_int/expected/dict_int.out @@ -300,3 +300,6 @@ select ts_lexize('intdict', '314532610153'); {314532} (1 row) +-- invalid: non-lowercase quoted identifiers +ALTER TEXT SEARCH DICTIONARY intdict ("Maxlen" = 4); +ERROR: unrecognized intdict parameter: "Maxlen" diff --git a/contrib/dict_int/sql/dict_int.sql b/contrib/dict_int/sql/dict_int.sql index 8ffec6b770..05d2149101 100644 --- a/contrib/dict_int/sql/dict_int.sql +++ b/contrib/dict_int/sql/dict_int.sql @@ -51,3 +51,6 @@ select ts_lexize('intdict', '252281774'); select ts_lexize('intdict', '313425'); select ts_lexize('intdict', '641439323669'); select ts_lexize('intdict', '314532610153'); + +-- invalid: non-lowercase quoted identifiers +ALTER TEXT SEARCH DICTIONARY intdict ("Maxlen" = 4); diff --git a/contrib/dict_xsyn/expected/dict_xsyn.out b/contrib/dict_xsyn/expected/dict_xsyn.out index 9b95e13559..4cc42956c7 100644 --- a/contrib/dict_xsyn/expected/dict_xsyn.out +++ b/contrib/dict_xsyn/expected/dict_xsyn.out @@ -140,3 +140,6 @@ SELECT ts_lexize('xsyn', 'grb'); (1 row) +-- invalid: non-lowercase quoted identifiers +ALTER TEXT SEARCH DICTIONARY xsyn ("Matchorig" = false); +ERROR: unrecognized xsyn parameter: "Matchorig" diff --git a/contrib/dict_xsyn/sql/dict_xsyn.sql b/contrib/dict_xsyn/sql/dict_xsyn.sql index 49511061d0..ab1380c0a2 100644 --- a/contrib/dict_xsyn/sql/dict_xsyn.sql +++ b/contrib/dict_xsyn/sql/dict_xsyn.sql @@ -43,3 +43,6 @@ ALTER TEXT SEARCH DICTIONARY xsyn (RULES='xsyn_sample', KEEPORIG=false, MATCHORI SELECT ts_lexize('xsyn', 'supernova'); SELECT ts_lexize('xsyn', 'sn'); SELECT ts_lexize('xsyn', 'grb'); + +-- invalid: non-lowercase quoted identifiers +ALTER TEXT SEARCH DICTIONARY xsyn ("Matchorig" = false); diff --git a/contrib/unaccent/expected/unaccent.out b/contrib/unaccent/expected/unaccent.out index b93105e9c7..30c061fe51 100644 --- a/contrib/unaccent/expected/unaccent.out +++ b/contrib/unaccent/expected/unaccent.out @@ -61,3 +61,6 @@ SELECT ts_lexize('unaccent', ' {} (1 row) +-- invalid: non-lowercase quoted identifiers +ALTER TEXT SEARCH DICTIONARY unaccent ("Rules" = 'my_rules'); +ERROR: unrecognized Unaccent parameter: "Rules" diff --git a/contrib/unaccent/sql/unaccent.sql b/contrib/unaccent/sql/unaccent.sql index 310213994f..f18f934377 100644 --- a/contrib/unaccent/sql/unaccent.sql +++ b/contrib/unaccent/sql/unaccent.sql @@ -16,3 +16,6 @@ SELECT unaccent('unaccent', ' SELECT ts_lexize('unaccent', 'foobar'); SELECT ts_lexize('unaccent', ''); SELECT ts_lexize('unaccent', ''); + +-- invalid: non-lowercase quoted identifiers +ALTER TEXT SEARCH DICTIONARY unaccent ("Rules" = 'my_rules'); diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml index a7f6c8dc6a..6a5d307c69 100644 --- a/doc/src/sgml/indexam.sgml +++ b/doc/src/sgml/indexam.sgml @@ -439,7 +439,7 @@ amproperty (Oid index_oid, int attno, If the core code does not recognize the property name then <parameter>prop</parameter> is <literal>AMPROP_UNKNOWN</literal>. Access methods can define custom property names by - checking <parameter>propname</parameter> for a match (use <function>pg_strcasecmp</function> + checking <parameter>propname</parameter> for a match (use <function>strcmp</function> to match, for consistency with the core code); for names known to the core code, it's better to inspect <parameter>prop</parameter>. If the <structfield>amproperty</structfield> method returns <literal>true</literal> then diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index a6de891eec..c82c28d781 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -1260,7 +1260,7 @@ fillRelOptions(void *rdopts, Size basesize, for (j = 0; j < numelems; j++) { - if (pg_strcasecmp(options[i].gen->name, elems[j].optname) == 0) + if (strcmp(options[i].gen->name, elems[j].optname) == 0) { relopt_string *optstring; char *itempos = ((char *) rdopts) + elems[j].offset; diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out index 552d7b09dc..0a34eddac2 100644 --- a/src/test/regress/expected/create_table.out +++ b/src/test/regress/expected/create_table.out @@ -866,3 +866,14 @@ DROP TABLE parted_col_comment; -- invalid: non-lowercase quoted reloptions identifiers CREATE TABLE tas_case WITH ("Fillfactor" = 10) AS SELECT 1 a; ERROR: unrecognized parameter "Fillfactor" +CREATE TABLE tas_case (a text) WITH ("Oids" = true); +ERROR: unrecognized parameter "Oids" +-- options with namespaces used with non-lowercase and quotes, all should fail +CREATE TABLE tas_case (a text) WITH ("Toast"."Autovacuum_vacuum_cost_limit" = 1); +ERROR: unrecognized parameter namespace "Toast" +CREATE TABLE tas_case (a text) WITH ("Toast.Autovacuum_vacuum_cost_limit" = 1); +ERROR: unrecognized parameter "Toast.Autovacuum_vacuum_cost_limit" +CREATE TABLE tas_case (a text) WITH ("Toast".autovacuum_vacuum_cost_limit = 1); +ERROR: unrecognized parameter namespace "Toast" +CREATE TABLE tas_case (a text) WITH (toast."Autovacuum_vacuum_cost_limit" = 1); +ERROR: unrecognized parameter "Autovacuum_vacuum_cost_limit" diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out index 2139860861..fd2a81a930 100644 --- a/src/test/regress/expected/create_type.out +++ b/src/test/regress/expected/create_type.out @@ -182,3 +182,5 @@ WARNING: type attribute "Passedbyvalue" not recognized LINE 7: "Passedbyvalue" ^ ERROR: type input function must be specified +CREATE TYPE int4_range AS RANGE ("Subtype" = int4, "Subtype_diff" = int4mi); +ERROR: type attribute "Subtype" not recognized diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out index 4468c85d77..a3d8869908 100644 --- a/src/test/regress/expected/create_view.out +++ b/src/test/regress/expected/create_view.out @@ -1712,3 +1712,13 @@ DROP SCHEMA temp_view_test CASCADE; NOTICE: drop cascades to 27 other objects DROP SCHEMA testviewschm2 CASCADE; NOTICE: drop cascades to 62 other objects +-- invalid: non-lowercase quoted identifiers +-- Check for both CREATE VIEW and ALTER VIEW SET +CREATE TABLE tt24 (a int); +CREATE VIEW tt24v WITH ("Check_option" = 'local') AS SELECT * FROM tt24; +ERROR: unrecognized parameter "Check_option" +CREATE VIEW tt24v WITH (check_option = 'local') AS SELECT * FROM tt24; +ALTER VIEW tt24v SET "Check_option" = 'local'; +ERROR: syntax error at or near ""Check_option"" at character 22 +DROP TABLE tt24 CASCADE; +NOTICE: drop cascades to view tt24v diff --git a/src/test/regress/expected/tsdicts.out b/src/test/regress/expected/tsdicts.out index e01402d42b..b3141ce59e 100644 --- a/src/test/regress/expected/tsdicts.out +++ b/src/test/regress/expected/tsdicts.out @@ -590,3 +590,5 @@ CREATE TEXT SEARCH DICTIONARY tsdict_case ERROR: text search template is required ALTER TEXT SEARCH DICTIONARY tsdict_case ("Dictfile" = ispell_sample); ERROR: text search dictionary "tsdict_case" does not exist +CREATE TEXT SEARCH CONFIGURATION thesaurus_tst ("Copy" = synonym_tst); +ERROR: text search configuration parameter "Copy" not recognized diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql index 3142817b22..0f9f75fda6 100644 --- a/src/test/regress/sql/create_table.sql +++ b/src/test/regress/sql/create_table.sql @@ -710,3 +710,9 @@ DROP TABLE parted_col_comment; -- invalid: non-lowercase quoted reloptions identifiers CREATE TABLE tas_case WITH ("Fillfactor" = 10) AS SELECT 1 a; +CREATE TABLE tas_case (a text) WITH ("Oids" = true); +-- options with namespaces used with non-lowercase and quotes, all should fail +CREATE TABLE tas_case (a text) WITH ("Toast"."Autovacuum_vacuum_cost_limit" = 1); +CREATE TABLE tas_case (a text) WITH ("Toast.Autovacuum_vacuum_cost_limit" = 1); +CREATE TABLE tas_case (a text) WITH ("Toast".autovacuum_vacuum_cost_limit = 1); +CREATE TABLE tas_case (a text) WITH (toast."Autovacuum_vacuum_cost_limit" = 1); diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql index ef9acdb4f6..c990813d1a 100644 --- a/src/test/regress/sql/create_type.sql +++ b/src/test/regress/sql/create_type.sql @@ -136,7 +136,6 @@ SELECT format_type(atttypid,atttypmod) FROM pg_attribute WHERE attrelid = 'mytab'::regclass AND attnum > 0; -- invalid: non-lowercase quoted identifiers - CREATE TYPE case_int42 ( "Internallength" = 4, "Input" = int42_in, @@ -145,3 +144,4 @@ CREATE TYPE case_int42 ( "Default" = 42, "Passedbyvalue" ); +CREATE TYPE int4_range AS RANGE ("Subtype" = int4, "Subtype_diff" = int4mi); diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql index b4e7a8793c..ec4f5203ab 100644 --- a/src/test/regress/sql/create_view.sql +++ b/src/test/regress/sql/create_view.sql @@ -584,3 +584,11 @@ select pg_get_ruledef(oid, true) from pg_rewrite \set VERBOSITY terse \\ -- suppress cascade details DROP SCHEMA temp_view_test CASCADE; DROP SCHEMA testviewschm2 CASCADE; + +-- invalid: non-lowercase quoted identifiers +-- Check for both CREATE VIEW and ALTER VIEW SET +CREATE TABLE tt24 (a int); +CREATE VIEW tt24v WITH ("Check_option" = 'local') AS SELECT * FROM tt24; +CREATE VIEW tt24v WITH (check_option = 'local') AS SELECT * FROM tt24; +ALTER VIEW tt24v SET "Check_option" = 'local'; +DROP TABLE tt24 CASCADE; diff --git a/src/test/regress/sql/tsdicts.sql b/src/test/regress/sql/tsdicts.sql index 77ba073cca..75513600de 100644 --- a/src/test/regress/sql/tsdicts.sql +++ b/src/test/regress/sql/tsdicts.sql @@ -198,3 +198,4 @@ CREATE TEXT SEARCH DICTIONARY tsdict_case ); ALTER TEXT SEARCH DICTIONARY tsdict_case ("Dictfile" = ispell_sample); +CREATE TEXT SEARCH CONFIGURATION thesaurus_tst ("Copy" = synonym_tst);
signature.asc
Description: PGP signature