@@ -48,49 +48,91 @@ local function get_index_for_condition(space_indexes, space_format, condition)
4848 end
4949end
5050
51- local function extract_sharding_key_from_scan_value (scan_value , scan_index , sharding_index )
52- if # scan_value < # sharding_index .parts then
53- return nil
54- end
51+ local function extract_sharding_key_from_conditions (conditions , sharding_index , space_indexes , fieldno_map )
52+ dev_checks (' table' , ' table' , ' table' , ' table' )
53+
54+ -- If name is both valid index name and field name,
55+ -- it is interpreted as index name.
56+ local filled_fields = {}
57+ for _ , condition in ipairs (conditions ) do
58+ if condition .operator ~= compare_conditions .operators .EQ then
59+ goto continue
60+ end
5561
56- if scan_index .id == sharding_index .id then
57- return scan_value
58- end
62+ local index = space_indexes [condition .operand ]
63+ if index ~= nil then
64+ for i , part in ipairs (index .parts ) do
65+ -- Consider the following case:
66+ -- index_0: {'foo', 'bar'},
67+ -- index_1: {'baz', 'bar'},
68+ -- conditions: {{'==', 'index_0', {1, 2}}, {'==', 'index_1', {3, nil}}}.
69+ -- To check that nil parts will not overwrite already filled_fields,
70+ -- we verify that filled_fields[part.fieldno] is empty. If there are
71+ -- more than one non-null different value in conditions with equal operator,
72+ -- request is already in conflict and it doesn't matter what sharding key we
73+ -- will return.
74+ if filled_fields [part .fieldno ] == nil then
75+ filled_fields [part .fieldno ] = condition .values [i ]
76+ end
77+ end
5978
60- local scan_value_fields_values = {}
61- for i , scan_index_part in ipairs (scan_index .parts ) do
62- scan_value_fields_values [scan_index_part .fieldno ] = scan_value [i ]
79+ goto continue
80+ end
81+
82+ local fieldno = fieldno_map [condition .operand ]
83+ if fieldno == nil then
84+ goto continue
85+ end
86+ filled_fields [fieldno ] = condition .values [1 ]
87+
88+ :: continue::
6389 end
6490
65- -- check that sharding key is included in the scan index fields
6691 local sharding_key = {}
67- for _ , sharding_key_part in ipairs (sharding_index .parts ) do
68- local fieldno = sharding_key_part .fieldno
69-
70- -- sharding key isn't included in scan key
71- if scan_value_fields_values [fieldno ] == nil then
92+ for i , v in ipairs (sharding_index .parts ) do
93+ if filled_fields [v .fieldno ] == nil then
7294 return nil
7395 end
7496
75- local field_value = scan_value_fields_values [fieldno ]
97+ sharding_key [i ] = filled_fields [v .fieldno ]
98+ end
7699
77- -- sharding key contains nil values
78- if field_value == nil then
79- return nil
100+ return sharding_key
101+ end
102+
103+ local function get_sharding_key_from_scan_value (scan_value , scan_index , scan_iter , sharding_index )
104+ dev_checks (' ?' , ' table' , ' number' , ' table' )
105+
106+ if scan_value == nil then
107+ return nil
108+ end
109+
110+ if scan_iter ~= box .index .EQ and scan_iter ~= box .index .REQ then
111+ return nil
112+ end
113+
114+ if scan_index .id == sharding_index .id then
115+ if type (scan_value ) ~= ' table' then
116+ return scan_value
80117 end
81118
82- table.insert (sharding_key , field_value )
119+ for i , _ in ipairs (sharding_index .parts ) do
120+ if scan_value [i ] == nil then return nil end
121+ end
122+ return scan_value
83123 end
84124
85- return sharding_key
125+ return nil
86126end
87127
88128-- We need to construct after_tuple by field_names
89129-- because if `fields` option is specified we have after_tuple with partial fields
90130-- and these fields are ordered by field_names + primary key + scan key
91131-- this order can be differ from order in space format
92132-- so we need to cast after_tuple to space format for scrolling tuples on storage
93- local function construct_after_tuple_by_fields (space_format , field_names , tuple )
133+ local function construct_after_tuple_by_fields (fieldno_map , field_names , tuple )
134+ dev_checks (' table' , ' ?table' , ' ?table|cdata' )
135+
94136 if tuple == nil then
95137 return nil
96138 end
@@ -99,15 +141,10 @@ local function construct_after_tuple_by_fields(space_format, field_names, tuple)
99141 return tuple
100142 end
101143
102- local positions = {}
103144 local transformed_tuple = {}
104145
105- for i , field in ipairs (space_format ) do
106- positions [field .name ] = i
107- end
108-
109146 for i , field_name in ipairs (field_names ) do
110- local fieldno = positions [field_name ]
147+ local fieldno = fieldno_map [field_name ]
111148 if fieldno == nil then
112149 return nil , FilterFieldsError :new (
113150 ' Space format doesn\' t contain field named %q' , field_name
@@ -145,6 +182,8 @@ function select_plan.new(space, conditions, opts)
145182 local scan_value
146183 local scan_condition_num
147184
185+ local fieldno_map = utils .get_format_fieldno_map (space_format )
186+
148187 -- search index to iterate over
149188 for i , condition in ipairs (conditions ) do
150189 scan_index = get_index_for_condition (space_indexes , space_format , condition )
@@ -177,7 +216,7 @@ function select_plan.new(space, conditions, opts)
177216 -- handle opts.first
178217 local total_tuples_count
179218 local scan_after_tuple , err = construct_after_tuple_by_fields (
180- space_format , field_names , opts .after_tuple
219+ fieldno_map , field_names , opts .after_tuple
181220 )
182221 if err ~= nil then
183222 return nil , err
@@ -230,9 +269,11 @@ function select_plan.new(space, conditions, opts)
230269 local sharding_index = opts .sharding_key_as_index_obj or primary_index
231270
232271 -- get sharding key value
233- local sharding_key
234- if scan_value ~= nil and (scan_iter == box .index .EQ or scan_iter == box .index .REQ ) then
235- sharding_key = extract_sharding_key_from_scan_value (scan_value , scan_index , sharding_index )
272+ local sharding_key = get_sharding_key_from_scan_value (scan_value , scan_index , scan_iter , sharding_index )
273+
274+ if sharding_key == nil then
275+ sharding_key = extract_sharding_key_from_conditions (conditions , sharding_index ,
276+ space_indexes , fieldno_map )
236277 end
237278
238279 local plan = {
@@ -251,4 +292,9 @@ function select_plan.new(space, conditions, opts)
251292 return plan
252293end
253294
295+ select_plan .internal = {
296+ get_sharding_key_from_scan_value = get_sharding_key_from_scan_value ,
297+ extract_sharding_key_from_conditions = extract_sharding_key_from_conditions
298+ }
299+
254300return select_plan
0 commit comments