Skip to content

Commit 186259d

Browse files
committed
Fix select by part of sharding key equal
Before this patch it wasn't checked that all fields of sharding key are specified if scan index is a sharding index detect if fully sharding key is specified So, for select w/ {'=', 'primary', {0, nil}} condition was performed on the only one storage and it returned only one tuple
1 parent a54597b commit 186259d

File tree

7 files changed

+108
-16
lines changed

7 files changed

+108
-16
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1010
### Fixed
1111

1212
* Fixed typo in error for case when failed to get `bucket_id`
13+
* Fixed select by part of sharding key equal. Before this patch
14+
selecting by equality of partially specified multipart primary index
15+
value was misinterpreted as a selecting by fully specified key value.
1316

1417
## [0.3.0] - 2020-10-26
1518

crud/select/plan.lua

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,18 @@ local function validate_conditions(conditions, space_indexes, space_format)
5353
return true
5454
end
5555

56-
local function extract_sharding_key_from_scan_key(scan_key, scan_index, sharding_index)
56+
local function extract_sharding_key_from_scan_value(scan_value, scan_index, sharding_index)
57+
if #scan_value < #sharding_index.parts then
58+
return nil
59+
end
60+
5761
if scan_index.id == sharding_index.id then
58-
return scan_key
62+
return scan_value
5963
end
6064

61-
local scan_key_fields_values = {}
62-
for i, scan_key_part in ipairs(scan_index.parts) do
63-
scan_key_fields_values[scan_key_part.fieldno] = scan_key[i]
65+
local scan_value_fields_values = {}
66+
for i, scan_index_part in ipairs(scan_index.parts) do
67+
scan_value_fields_values[scan_index_part.fieldno] = scan_value[i]
6468
end
6569

6670
-- check that sharding key is included in the scan index fields
@@ -69,11 +73,11 @@ local function extract_sharding_key_from_scan_key(scan_key, scan_index, sharding
6973
local fieldno = sharding_key_part.fieldno
7074

7175
-- sharding key isn't included in scan key
72-
if scan_key_fields_values[fieldno] == nil then
76+
if scan_value_fields_values[fieldno] == nil then
7377
return nil
7478
end
7579

76-
local field_value = scan_key_fields_values[fieldno]
80+
local field_value = scan_value_fields_values[fieldno]
7781

7882
-- sharding key contains nil values
7983
if field_value == nil then
@@ -165,7 +169,7 @@ function select_plan.new(space, conditions, opts)
165169
-- get sharding key value
166170
local sharding_key
167171
if scan_value ~= nil and (scan_iter == box.index.EQ or scan_iter == box.index.REQ) then
168-
sharding_key = extract_sharding_key_from_scan_key(scan_value, scan_index, sharding_index)
172+
sharding_key = extract_sharding_key_from_scan_value(scan_value, scan_index, sharding_index)
169173
end
170174

171175
if sharding_key ~= nil then

test/entrypoint/srv_select.lua

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,34 @@ package.preload['customers-storage'] = function()
5151
})
5252
customers_space:create_index('full_name', {
5353
parts = {
54-
{ field = 'name', collation = 'unicode_ci' },
55-
{ field = 'last_name', collation = 'unicode_ci' },
54+
{field = 'name', collation = 'unicode_ci'},
55+
{field = 'last_name', collation = 'unicode_ci'} ,
5656
},
5757
unique = false,
5858
if_not_exists = true,
5959
})
60+
61+
local coord_space = box.schema.space.create('coord', {
62+
format = {
63+
{name = 'x', type = 'unsigned'},
64+
{name = 'y', type = 'unsigned'},
65+
{name = 'bucket_id', type = 'unsigned'},
66+
},
67+
if_not_exists = true,
68+
engine = engine,
69+
})
70+
-- primary index
71+
coord_space:create_index('primary', {
72+
parts = {
73+
{field = 'x'},
74+
{field = 'y'},
75+
},
76+
if_not_exists = true,
77+
})
78+
coord_space:create_index('bucket_id', {
79+
parts = { {field = 'bucket_id'} },
80+
if_not_exists = true,
81+
})
6082
end,
6183
dependencies = {'cartridge.roles.crud-storage'},
6284
}

test/integration/select_test.lua

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,3 +791,25 @@ add('test_select_with_collations', function(g)
791791
local objects = crud.unflatten_rows(result.rows, result.metadata)
792792
t.assert_equals(objects, helpers.get_objects_by_idxs(customers, {2, 4}))
793793
end)
794+
795+
add('test_multipart_primary_index', function(g)
796+
local coords = helpers.insert_objects(g, 'coord', {
797+
{ x = 0, y = 0 }, -- 1
798+
{ x = 0, y = 1 }, -- 2
799+
{ x = 0, y = 2 }, -- 3
800+
{ x = 1, y = 3 }, -- 4
801+
{ x = 1, y = 4 }, -- 5
802+
})
803+
804+
local conditions = {{'=', 'primary', 0}}
805+
local result, err = g.cluster.main_server.net_box:call('crud.select', {'coord', conditions})
806+
t.assert_equals(err, nil)
807+
local objects = crud.unflatten_rows(result.rows, result.metadata)
808+
t.assert_equals(objects, helpers.get_objects_by_idxs(coords, {1, 2, 3}))
809+
810+
local conditions = {{'=', 'primary', {0, 2}}}
811+
local result, err = g.cluster.main_server.net_box:call('crud.select', {'coord', conditions})
812+
t.assert_equals(err, nil)
813+
local objects = crud.unflatten_rows(result.rows, result.metadata)
814+
t.assert_equals(objects, helpers.get_objects_by_idxs(coords, {3}))
815+
end)

test/unit/select_filters_test.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ g.before_all = function()
3737
})
3838
customers_space:create_index('full_name', { -- id: 2
3939
parts = {
40-
{ field = 'name', collation = 'unicode_ci' },
41-
{ field = 'last_name', is_nullable = true },
40+
{field = 'name', collation = 'unicode_ci'},
41+
{field = 'last_name', is_nullable = true},
4242
},
4343
unique = false,
4444
if_not_exists = true,

test/unit/select_plan_bad_indexes_test.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ g.before_all = function()
5454
customers_space:create_index('full_name_hash', {
5555
type = 'HASH',
5656
parts = {
57-
{ field = 'name', collation = 'unicode_ci' },
58-
{ field = 'last_name'},
57+
{field = 'name', collation = 'unicode_ci'},
58+
{field = 'last_name'},
5959
},
6060
if_not_exists = true,
6161
})

test/unit/select_plan_test.lua

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ g.before_all = function()
3333
})
3434
customers_space:create_index('full_name', { -- id: 2
3535
parts = {
36-
{ field = 'name', collation = 'unicode_ci' },
37-
{ field = 'last_name', is_nullable = true },
36+
{field = 'name', collation = 'unicode_ci'},
37+
{field = 'last_name', is_nullable = true},
3838
},
3939
unique = false,
4040
if_not_exists = true,
@@ -44,6 +44,25 @@ g.before_all = function()
4444
unique = false,
4545
if_not_exists = true,
4646
})
47+
48+
-- is used for multipart primary index tests
49+
local coord_space = box.schema.space.create('coord', {
50+
format = {
51+
{name = 'x', type = 'unsigned'},
52+
{name = 'y', type = 'unsigned'},
53+
{name = 'bucket_id', type = 'unsigned'},
54+
},
55+
if_not_exists = true,
56+
})
57+
-- primary index
58+
coord_space:create_index('primary', {
59+
parts = { {field = 'x'}, {field = 'y'} },
60+
if_not_exists = true,
61+
})
62+
coord_space:create_index('bucket_id', {
63+
parts = { {field = 'bucket_id'} },
64+
if_not_exists = true,
65+
})
4766
end
4867

4968
g.after_all(function()
@@ -187,6 +206,28 @@ g.test_is_scan_by_full_sharding_key_eq = function()
187206

188207
t.assert_equals(plan.total_tuples_count, nil)
189208
t.assert_equals(plan.sharding_key, nil)
209+
210+
-- multipart primary index
211+
212+
-- specified only first part
213+
local plan, err = select_plan.new(box.space.coord, {
214+
cond_funcs.eq('primary', 0),
215+
})
216+
217+
t.assert_equals(err, nil)
218+
219+
t.assert_equals(plan.total_tuples_count, nil)
220+
t.assert_equals(plan.sharding_key, nil)
221+
222+
-- specified both parts
223+
local plan, err = select_plan.new(box.space.coord, {
224+
cond_funcs.eq('primary', {1, 0}),
225+
})
226+
227+
t.assert_equals(err, nil)
228+
229+
t.assert_equals(plan.total_tuples_count, 1)
230+
t.assert_equals(plan.sharding_key, {1, 0})
190231
end
191232

192233
g.test_first = function()

0 commit comments

Comments
 (0)