Added support for provider, deterministic, version and RULES parameter while creating collation. #5611

pull/7307/head
JyotiEdb 2024-03-19 16:52:22 +05:30 committed by GitHub
parent cee0945a78
commit 25074e46b4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 201 additions and 13 deletions

View File

@ -50,6 +50,16 @@ settings:
* Use the *LC_CTYPE* field to specify a locale with specified character * Use the *LC_CTYPE* field to specify a locale with specified character
classification. The locale must be applicable to the current database encoding. classification. The locale must be applicable to the current database encoding.
(See CREATE DATABASE for details.) (See CREATE DATABASE for details.)
* Use the drop-down listbox next to *Locale Provider* to select a locale services associated
with the collation. Possible values are: icu, libc. libc is the default.
* Move the switch next to *Deterministic* to *YES* to specify whether the collation should use
deterministic comparisons. By default, this option is set to true. In a
deterministic comparison, strings that are not byte-wise equal are considered
unequal, even if they are considered logically equal in the comparison.
* Use the *Rules* field to specify a rules for customizing the behavior of the collation.
It includes considerations such as character ordering, case sensitivity, and accent
sensitivity.
* Use the *Version* field to specify version string to store with the collation object.
Click the *SQL* tab to continue. Click the *SQL* tab to continue.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -89,7 +89,7 @@ export default class CollationSchema extends BaseUISchema {
readonly: function (state) { return !obj.isNew(state); }, readonly: function (state) { return !obj.isNew(state); },
deps: ['lc_collate', 'lc_type', 'copy_collation'], deps: ['lc_collate', 'lc_type', 'copy_collation'],
disabled: function (state) { disabled: function (state) {
// Enable localy only if lc_* & copy_collation is not provided // Enable locale only if lc_* & copy_collation is not provided
if (state.lc_collate || state.lc_type) if (state.lc_collate || state.lc_type)
return true; return true;
return state.copy_collation; return state.copy_collation;
@ -109,6 +109,68 @@ export default class CollationSchema extends BaseUISchema {
disabled: obj.disableFields, disabled: obj.disableFields,
deps: ['locale', 'copy_collation'], deps: ['locale', 'copy_collation'],
}, },
{
id: 'provider', label: gettext('Locale Provider'),
editable: false, type: 'select',mode: ['create', 'edit'], group: gettext('Definition'),
readonly: function (state) { return !obj.isNew(state); },
options: [{
label: gettext('icu'),
value: 'icu',
}, {
label: gettext('libc'),
value: 'libc',
}],
min_version: 120000,
deps: ['copy_collation'],
disabled: function (state) {
return state.copy_collation;
}
},
{
id: 'provider', label: gettext('Locale Provider'),
type: 'text',mode: ['properties'], group: gettext('Definition'),
readonly: true,
min_version: 120000,
},
{
id: 'is_deterministic', label: gettext('Deterministic'),
type: 'switch', group: gettext('Definition'),
default: false,
readonly: function (state) { return !obj.isNew(state); },
mode: ['properties', 'edit', 'create'],
min_version: 120000,
helpMessageMode: ['edit', 'create'],
deps: ['copy_collation'],
disabled: function (state) {
return state.copy_collation;
}
},
{
id: 'rules', label: gettext('Rules'),
editable: true, type: 'text', group: gettext('Definition'),
readonly: function (state) { return !obj.isNew(state); },
mode: ['properties', 'edit', 'create'],
deps: ['provider','is_deterministic','copy_collation'],
depChange: (state)=>{
if (state.provider !== 'icu')
return { rules: '' };
},
disabled: function(state) {
if (state.copy_collation)
return true;
return state.provider !== 'icu' || (state.provider == 'icu' && state.is_deterministic);
},
min_version: 160000,
},
{
id: 'version', label: gettext('Version'), type: 'text', group: gettext('Definition'),
readonly: function (state) { return !obj.isNew(state); },
mode: ['properties','create', 'edit'], min_version: 120000,
deps: ['copy_collation'],
disabled: function (state) {
return state.copy_collation;
}
},
{ {
id: 'is_sys_obj', label: gettext('System collation?'), id: 'is_sys_obj', label: gettext('System collation?'),
cell: 'boolean', type: 'switch', mode: ['properties'], cell: 'boolean', type: 'switch', mode: ['properties'],
@ -164,4 +226,3 @@ export default class CollationSchema extends BaseUISchema {
} }
} }

View File

@ -1,5 +1,6 @@
SELECT c.oid, c.collname AS name, COALESCE(c.collcollate, c.colliculocale) AS lc_collate, SELECT c.oid, c.collname AS name, COALESCE(c.collcollate, c.colliculocale) AS lc_collate,
COALESCE(c.collctype, c.colliculocale) AS lc_type, COALESCE(c.collctype, c.colliculocale) AS lc_type, c.collisdeterministic AS is_deterministic, c.collversion AS version,
c.collprovider AS provider,
pg_catalog.pg_get_userbyid(c.collowner) AS owner, description, n.nspname AS schema pg_catalog.pg_get_userbyid(c.collowner) AS owner, description, n.nspname AS schema
FROM pg_catalog.pg_collation c FROM pg_catalog.pg_collation c
JOIN pg_catalog.pg_namespace n ON n.oid=c.collnamespace JOIN pg_catalog.pg_namespace n ON n.oid=c.collnamespace

View File

@ -0,0 +1,10 @@
SELECT c.oid, c.collname AS name, COALESCE(c.collcollate, c.colliculocale) AS lc_collate,
COALESCE(c.collctype, c.colliculocale) AS lc_type, c.collisdeterministic AS is_deterministic, c.collversion AS version,
c.collprovider AS provider, c.collprovider AS rules,
pg_catalog.pg_get_userbyid(c.collowner) AS owner, description, n.nspname AS schema
FROM pg_catalog.pg_collation c
JOIN pg_catalog.pg_namespace n ON n.oid=c.collnamespace
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=c.oid AND des.classoid='pg_collation'::regclass)
WHERE c.collnamespace = {{scid}}::oid
{% if coid %} AND c.oid = {{coid}}::oid {% endif %}
ORDER BY c.collname;

View File

@ -1,12 +1,36 @@
{% if data %} {% if data %}
CREATE COLLATION{% if add_not_exists_clause %} IF NOT EXISTS{% endif %} {{ conn|qtIdent(data.schema, data.name) }} CREATE COLLATION{% if add_not_exists_clause %} IF NOT EXISTS{% endif %} {{ conn|qtIdent(data.schema, data.name) }}
{% if not data.copy_collation %}
{# if user has provided lc_collate & lc_type #} {# if user has provided lc_collate & lc_type #}
{% if data.lc_collate and data.lc_type %} {% if data.lc_collate and data.lc_type and data.provider and data.is_deterministic%}
(LC_COLLATE = {{ data.lc_collate|qtLiteral(conn) }}, LC_CTYPE = {{ data.lc_type|qtLiteral(conn) }}); {% if data.version %}
(LC_COLLATE = {{ data.lc_collate|qtLiteral(conn) }}, LC_CTYPE = {{ data.lc_type|qtLiteral(conn) }}, PROVIDER = {{ data.provider|qtLiteral(conn) }}, DETERMINISTIC = {{ data.is_deterministic|qtLiteral(conn) }}, VERSION = {{ data.version|qtLiteral(conn) }});
{% else %}
(LC_COLLATE = {{ data.lc_collate|qtLiteral(conn) }}, LC_CTYPE = {{ data.lc_type|qtLiteral(conn) }}, PROVIDER = {{ data.provider|qtLiteral(conn) }}, DETERMINISTIC = {{ data.is_deterministic|qtLiteral(conn) }});
{% endif %}
{% endif %}
{% if data.lc_collate and data.lc_type and data.provider and not data.is_deterministic and data.rules %}
{% if data.version %}
(LC_COLLATE = {{ data.lc_collate|qtLiteral(conn) }}, LC_CTYPE = {{ data.lc_type|qtLiteral(conn) }}, PROVIDER = {{ data.provider|qtLiteral(conn) }}, RULES = {{ data.rules|qtLiteral(conn) }}, VERSION = {{ data.version|qtLiteral(conn) }}, DETERMINISTIC = FALSE);
{% else %}
(LC_COLLATE = {{ data.lc_collate|qtLiteral(conn) }}, LC_CTYPE = {{ data.lc_type|qtLiteral(conn) }}, PROVIDER = {{ data.provider|qtLiteral(conn) }}, RULES = {{ data.rules|qtLiteral(conn) }}, DETERMINISTIC = FALSE);
{% endif %}
{% endif %} {% endif %}
{# if user has provided locale only #} {# if user has provided locale only #}
{% if data.locale %} {% if data.locale and data.provider and data.is_deterministic%}
(LOCALE = {{ data.locale|qtLiteral(conn) }}); {% if data.version %}
(LOCALE = {{ data.locale|qtLiteral(conn) }}, PROVIDER = {{ data.provider|qtLiteral(conn) }}, DETERMINISTIC = {{ data.is_deterministic|qtLiteral(conn) }}, VERSION = {{ data.version|qtLiteral(conn) }});
{% else %}
(LOCALE = {{ data.locale|qtLiteral(conn) }}, PROVIDER = {{ data.provider|qtLiteral(conn) }}, DETERMINISTIC = {{ data.is_deterministic|qtLiteral(conn) }});
{% endif %}
{% endif %}
{% if data.locale and data.provider and data.version and not data.is_deterministic and data.rules %}
{% if data.version %}
(LOCALE = {{ data.locale|qtLiteral(conn) }}, PROVIDER = {{ data.provider|qtLiteral(conn) }}, RULES = {{ data.rules|qtLiteral(conn) }}, VERSION = {{ data.version|qtLiteral(conn) }}, DETERMINISTIC = FALSE);
{% else %}
(LOCALE = {{ data.locale|qtLiteral(conn) }}, PROVIDER = {{ data.provider|qtLiteral(conn) }}, RULES = {{ data.rules|qtLiteral(conn) }}, DETERMINISTIC = FALSE);
{% endif %}
{% endif %}
{% endif %} {% endif %}
{# if user has choosed to copy from existing collation #} {# if user has choosed to copy from existing collation #}
{% if data.copy_collation %} {% if data.copy_collation %}

View File

@ -1,5 +1,7 @@
SELECT c.oid, c.collname AS name, c.collcollate AS lc_collate, c.collctype AS lc_type, SELECT c.oid, c.collname AS name, c.collcollate AS lc_collate, c.collctype AS lc_type,
pg_catalog.pg_get_userbyid(c.collowner) AS owner, description, n.nspname AS schema pg_catalog.pg_get_userbyid(c.collowner) AS owner, c.collisdeterministic AS is_deterministic, c.collversion AS version,
c.collprovider AS provider, c.description, n.nspname AS schema
FROM pg_catalog.pg_collation c FROM pg_catalog.pg_collation c
JOIN pg_catalog.pg_namespace n ON n.oid=c.collnamespace JOIN pg_catalog.pg_namespace n ON n.oid=c.collnamespace
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=c.oid AND des.classoid='pg_collation'::regclass) LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=c.oid AND des.classoid='pg_collation'::regclass)

View File

@ -14,6 +14,10 @@
"mock_data": {}, "mock_data": {},
"expected_data": { "expected_data": {
"status_code": 200 "status_code": 200
},
"inventory_data": {
"server_min_version": 160000,
"skip_msg": "Create collation: With valid data are not supported by PG 16.0 and below."
} }
}, },
{ {
@ -98,6 +102,10 @@
"name": "Get Collation", "name": "Get Collation",
"url": "/browser/collation/obj/", "url": "/browser/collation/obj/",
"is_positive_test": true, "is_positive_test": true,
"inventory_data": {
"server_min_version": 160000,
"skip_msg": "Get Collation are not supported by PG 16.0 and below."
},
"mocking_required": false, "mocking_required": false,
"mock_data": {}, "mock_data": {},
"expected_data": { "expected_data": {
@ -109,6 +117,10 @@
"url": "/browser/collation/obj/", "url": "/browser/collation/obj/",
"error_fetching_collation": true, "error_fetching_collation": true,
"is_positive_test": false, "is_positive_test": false,
"inventory_data": {
"server_min_version": 160000,
"skip_msg": "Error while fetching a Collation are not supported by PG 16.0 and below."
},
"mocking_required": true, "mocking_required": true,
"mock_data": { "mock_data": {
"function_name": "pgadmin.utils.driver.psycopg3.connection.Connection.execute_dict", "function_name": "pgadmin.utils.driver.psycopg3.connection.Connection.execute_dict",
@ -123,6 +135,10 @@
"url": "/browser/collation/obj/", "url": "/browser/collation/obj/",
"wrong_collation_id": true, "wrong_collation_id": true,
"is_positive_test": false, "is_positive_test": false,
"inventory_data": {
"server_min_version": 160000,
"skip_msg": "Fetch collation using wrong collation id are not supported by PG 16.0 and below."
},
"mocking_required": false, "mocking_required": false,
"mock_data": { "mock_data": {
}, },
@ -134,6 +150,10 @@
"name": "Get Collation list", "name": "Get Collation list",
"url": "/browser/collation/obj/", "url": "/browser/collation/obj/",
"is_positive_test": true, "is_positive_test": true,
"inventory_data": {
"server_min_version": 160000,
"skip_msg": "Get Collation list are not supported by PG 16.0 and below."
},
"collation_list": true, "collation_list": true,
"mocking_required": false, "mocking_required": false,
"mock_data": {}, "mock_data": {},
@ -214,6 +234,10 @@
"name": "Update Collation", "name": "Update Collation",
"url": "/browser/collation/obj/", "url": "/browser/collation/obj/",
"is_positive_test": true, "is_positive_test": true,
"inventory_data": {
"server_min_version": 160000,
"skip_msg": "Update Collation are not supported by PG 16.0 and below."
},
"mocking_required": false, "mocking_required": false,
"test_data": { "test_data": {
"description": "This is collation update comment", "description": "This is collation update comment",
@ -377,6 +401,10 @@
"name": "Get Collation SQL", "name": "Get Collation SQL",
"url": "/browser/collation/sql/", "url": "/browser/collation/sql/",
"is_positive_test": true, "is_positive_test": true,
"inventory_data": {
"server_min_version": 160000,
"skip_msg": "Get Collation SQL are not supported by PG 16.0 and below."
},
"mocking_required": false, "mocking_required": false,
"mock_data": {}, "mock_data": {},
"expected_data": { "expected_data": {
@ -401,6 +429,10 @@
"name": "Get collation msql: With existing collation id.", "name": "Get collation msql: With existing collation id.",
"url": "/browser/collation/msql/", "url": "/browser/collation/msql/",
"is_positive_test": true, "is_positive_test": true,
"inventory_data": {
"server_min_version": 160000,
"skip_msg": "Get collation msql are not supported by PG 16.0 and below."
},
"msql": true, "msql": true,
"mocking_required": false, "mocking_required": false,
"mock_data": {}, "mock_data": {},

View File

@ -3,7 +3,7 @@
-- DROP COLLATION IF EXISTS testschema."Cl1_$%{}[]()&*^!@""'`\/#a"; -- DROP COLLATION IF EXISTS testschema."Cl1_$%{}[]()&*^!@""'`\/#a";
CREATE COLLATION IF NOT EXISTS testschema."Cl1_$%{}[]()&*^!@""'`\/#a" CREATE COLLATION IF NOT EXISTS testschema."Cl1_$%{}[]()&*^!@""'`\/#a"
(LC_COLLATE = 'C', LC_CTYPE = 'C'); (LC_COLLATE = 'C', LC_CTYPE = 'C', PROVIDER = 'c', DETERMINISTIC = true);
ALTER COLLATION testschema."Cl1_$%{}[]()&*^!@""'`\/#a" ALTER COLLATION testschema."Cl1_$%{}[]()&*^!@""'`\/#a"
OWNER TO <OWNER>; OWNER TO <OWNER>;

View File

@ -3,7 +3,7 @@
-- DROP COLLATION IF EXISTS testschema."Cl1_$%{}[]()&*^!@""'`\/#"; -- DROP COLLATION IF EXISTS testschema."Cl1_$%{}[]()&*^!@""'`\/#";
CREATE COLLATION IF NOT EXISTS testschema."Cl1_$%{}[]()&*^!@""'`\/#" CREATE COLLATION IF NOT EXISTS testschema."Cl1_$%{}[]()&*^!@""'`\/#"
(LC_COLLATE = 'C', LC_CTYPE = 'C'); (LC_COLLATE = 'C', LC_CTYPE = 'C', PROVIDER = 'c', DETERMINISTIC = true);
ALTER COLLATION testschema."Cl1_$%{}[]()&*^!@""'`\/#" ALTER COLLATION testschema."Cl1_$%{}[]()&*^!@""'`\/#"
OWNER TO <OWNER>; OWNER TO <OWNER>;

View File

@ -0,0 +1,12 @@
-- Collation: Cl1_$%{}[]()&*^!@"'`\/#b;
-- DROP COLLATION IF EXISTS testschema."Cl1_$%{}[]()&*^!@""'`\/#b";
CREATE COLLATION IF NOT EXISTS testschema."Cl1_$%{}[]()&*^!@""'`\/#b"
(LC_COLLATE = 'locale', LC_CTYPE = 'locale', PROVIDER = 'i', DETERMINISTIC = true, VERSION = '1');
ALTER COLLATION testschema."Cl1_$%{}[]()&*^!@""'`\/#b"
OWNER TO <OWNER>;
COMMENT ON COLLATION testschema."Cl1_$%{}[]()&*^!@""'`\/#b"
IS 'Description for extra params';

View File

@ -11,8 +11,10 @@
"copy_collation": "pg_catalog.\"C\"", "copy_collation": "pg_catalog.\"C\"",
"description": "Description" "description": "Description"
}, },
"store_object_id": true,
"expected_sql_file": "create_collation.sql" "expected_sql_file": "create_collation.sql"
}, { },
{
"type": "alter", "type": "alter",
"name": "Alter Collation", "name": "Alter Collation",
"endpoint": "NODE-collation.obj_id", "endpoint": "NODE-collation.obj_id",
@ -25,13 +27,32 @@
}, },
"expected_sql_file": "alter_collation.sql", "expected_sql_file": "alter_collation.sql",
"expected_msql_file": "msql_collation.sql" "expected_msql_file": "msql_collation.sql"
}, { },
{
"type": "delete", "type": "delete",
"name": "Drop Collation", "name": "Drop Collation",
"endpoint": "NODE-collation.delete_id", "endpoint": "NODE-collation.delete_id",
"data": { "data": {
"name": "Cl1_$%{}[]()&*^!@\"'`\\/#a" "name": "Cl1_$%{}[]()&*^!@\"'`\\/#b"
} }
},
{
"type": "create",
"name": "Create Collation with extra parameters",
"endpoint": "NODE-collation.obj",
"sql_endpoint": "NODE-collation.sql_id",
"data": {
"name": "Cl1_$%{}[]()&*^!@\"'`\\/#b",
"schema": "testschema",
"owner": "postgres",
"description": "Description for extra params",
"locale": "locale",
"provider": "icu",
"is_deterministic": true,
"version": "1"
},
"store_object_id": true,
"expected_sql_file": "create_collation_with_extra_params.sql"
} }
] ]
} }

View File

@ -77,6 +77,9 @@ class CollationAddTestCase(BaseTestGenerator):
self.test_data['name'] = "collation_add_%s" % str(uuid.uuid4())[1:8] self.test_data['name'] = "collation_add_%s" % str(uuid.uuid4())[1:8]
self.test_data['owner'] = self.server["username"] self.test_data['owner'] = self.server["username"]
self.test_data['schema'] = self.schema_name self.test_data['schema'] = self.schema_name
self.test_data['provider'] = "icu"
self.test_data['is_deterministic'] = True
self.test_data['version'] = "test"
if self.is_positive_test: if self.is_positive_test:
response = self.create_collation() response = self.create_collation()

View File

@ -27,6 +27,10 @@ class CollationGetTestCase(BaseTestGenerator):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
if hasattr(self, 'inventory_data') and \
self.server_information['server_version']\
< self.inventory_data['server_min_version']:
self.skipTest(self.inventory_data['skip_msg'])
self.schema_info = parent_node_dict["schema"][-1] self.schema_info = parent_node_dict["schema"][-1]
self.schema_name = self.schema_info["schema_name"] self.schema_name = self.schema_info["schema_name"]
self.schema_id = self.schema_info["schema_id"] self.schema_id = self.schema_info["schema_id"]

View File

@ -28,6 +28,10 @@ class CollationPutTestCase(BaseTestGenerator):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
if hasattr(self, 'inventory_data') and \
self.server_information['server_version'] \
< self.inventory_data['server_min_version']:
self.skipTest(self.inventory_data['skip_msg'])
self.schema_info = parent_node_dict["schema"][-1] self.schema_info = parent_node_dict["schema"][-1]
self.schema_name = self.schema_info["schema_name"] self.schema_name = self.schema_info["schema_name"]
self.db_name = parent_node_dict["database"][-1]["db_name"] self.db_name = parent_node_dict["database"][-1]["db_name"]

View File

@ -27,6 +27,10 @@ class CollationSqlTestCase(BaseTestGenerator):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
if hasattr(self, 'inventory_data') and \
self.server_information['server_version'] \
< self.inventory_data['server_min_version']:
self.skipTest(self.inventory_data['skip_msg'])
self.schema_info = parent_node_dict["schema"][-1] self.schema_info = parent_node_dict["schema"][-1]
self.schema_name = self.schema_info["schema_name"] self.schema_name = self.schema_info["schema_name"]
self.schema_id = self.schema_info["schema_id"] self.schema_id = self.schema_info["schema_id"]