@@ -48,49 +48,91 @@ local function get_index_for_condition(space_indexes, space_format, condition)
48
48
end
49
49
end
50
50
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
55
61
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
59
78
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::
63
89
end
64
90
65
- -- check that sharding key is included in the scan index fields
66
91
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
72
94
return nil
73
95
end
74
96
75
- local field_value = scan_value_fields_values [fieldno ]
97
+ sharding_key [i ] = filled_fields [v .fieldno ]
98
+ end
76
99
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
80
117
end
81
118
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
83
123
end
84
124
85
- return sharding_key
125
+ return nil
86
126
end
87
127
88
128
-- We need to construct after_tuple by field_names
89
129
-- because if `fields` option is specified we have after_tuple with partial fields
90
130
-- and these fields are ordered by field_names + primary key + scan key
91
131
-- this order can be differ from order in space format
92
132
-- 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
+
94
136
if tuple == nil then
95
137
return nil
96
138
end
@@ -99,15 +141,10 @@ local function construct_after_tuple_by_fields(space_format, field_names, tuple)
99
141
return tuple
100
142
end
101
143
102
- local positions = {}
103
144
local transformed_tuple = {}
104
145
105
- for i , field in ipairs (space_format ) do
106
- positions [field .name ] = i
107
- end
108
-
109
146
for i , field_name in ipairs (field_names ) do
110
- local fieldno = positions [field_name ]
147
+ local fieldno = fieldno_map [field_name ]
111
148
if fieldno == nil then
112
149
return nil , FilterFieldsError :new (
113
150
' Space format doesn\' t contain field named %q' , field_name
@@ -145,6 +182,8 @@ function select_plan.new(space, conditions, opts)
145
182
local scan_value
146
183
local scan_condition_num
147
184
185
+ local fieldno_map = utils .get_format_fieldno_map (space_format )
186
+
148
187
-- search index to iterate over
149
188
for i , condition in ipairs (conditions ) do
150
189
scan_index = get_index_for_condition (space_indexes , space_format , condition )
@@ -176,9 +215,7 @@ function select_plan.new(space, conditions, opts)
176
215
177
216
-- handle opts.first
178
217
local total_tuples_count
179
- local scan_after_tuple , err = construct_after_tuple_by_fields (
180
- space_format , field_names , opts .after_tuple
181
- )
218
+ local scan_after_tuple , err = construct_after_tuple_by_fields (fieldno_map , field_names , opts .after_tuple )
182
219
if err ~= nil then
183
220
return nil , err
184
221
end
@@ -230,9 +267,11 @@ function select_plan.new(space, conditions, opts)
230
267
local sharding_index = opts .sharding_key_as_index_obj or primary_index
231
268
232
269
-- 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 )
270
+ local sharding_key = get_sharding_key_from_scan_value (scan_value , scan_index , scan_iter , sharding_index )
271
+
272
+ if sharding_key == nil then
273
+ sharding_key = extract_sharding_key_from_conditions (conditions , sharding_index ,
274
+ space_indexes , fieldno_map )
236
275
end
237
276
238
277
local plan = {
@@ -251,4 +290,9 @@ function select_plan.new(space, conditions, opts)
251
290
return plan
252
291
end
253
292
293
+ select_plan .internal = {
294
+ get_sharding_key_from_scan_value = get_sharding_key_from_scan_value ,
295
+ extract_sharding_key_from_conditions = extract_sharding_key_from_conditions
296
+ }
297
+
254
298
return select_plan
0 commit comments