Skip to content

Commit 60f5421

Browse files
authored
Bug: Equal Condition (#18)
1 parent 2d614e2 commit 60f5421

File tree

7 files changed

+111
-42
lines changed

7 files changed

+111
-42
lines changed

crud/select.lua

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,13 @@ local function build_select_iterator(space_name, user_conditions, opts)
158158
return nil, SelectError:new("Failed to get replicasets to select from: %s", err)
159159
end
160160

161-
local key_parts = space.index[plan.scanner.index_id].parts
161+
local scan_index = space.index[plan.scanner.index_id]
162+
local primary_index = space.index[0]
163+
164+
local cmp_key_parts = utils.merge_primary_key_parts(scan_index.parts, primary_index.parts)
165+
local cmp_operator = select_comparators.get_cmp_operator(plan.scanner.iter)
162166
local tuples_comparator, err = select_comparators.gen_tuples_comparator(
163-
plan.scanner.operator, key_parts
167+
cmp_operator, cmp_key_parts
164168
)
165169
if err ~= nil then
166170
return nil, SelectError:new("Failed to generate comparator function: %s", err)
@@ -169,7 +173,6 @@ local function build_select_iterator(space_name, user_conditions, opts)
169173
local iter = Iterator.new({
170174
space_name = space_name,
171175
space_format = space_format,
172-
key_parts = key_parts,
173176
iteration_func = select_iteration,
174177
comparator = tuples_comparator,
175178

crud/select/comparators.lua

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,15 @@ local function gen_array_cmp_func(target, key_parts)
150150
end
151151
end
152152

153+
local cmp_operators_by_tarantool_iter = {
154+
[box.index.GT] = operators.GT,
155+
[box.index.GE] = operators.GT,
156+
[box.index.EQ] = operators.GT,
157+
[box.index.LT] = operators.LT,
158+
[box.index.LE] = operators.LT,
159+
[box.index.REQ] = operators.LT,
160+
}
161+
153162
local array_cmp_funcs_by_operators = {
154163
[operators.EQ] = array_eq,
155164
[operators.LT] = array_lt,
@@ -158,23 +167,35 @@ local array_cmp_funcs_by_operators = {
158167
[operators.GE] = array_ge,
159168
}
160169

161-
function comparators.gen_func(operator, key_parts)
162-
local cmp_func = array_cmp_funcs_by_operators[operator]
170+
--[=[
171+
Each tarantool iterator returns tuples in a strictly defined order
172+
(scan key merged with primary key is used to guarantee that)
173+
GE, GT and EQ interators return tuples in ascending order
174+
LE, LT and REQ - in descending
175+
--]=]
176+
function comparators.get_cmp_operator(tarantool_iter)
177+
local cmp_operator = cmp_operators_by_tarantool_iter[tarantool_iter]
178+
assert(cmp_operator ~= nil, 'Unknown Tarantool iterator %q', tarantool_iter)
179+
180+
return cmp_operator
181+
end
163182

183+
function comparators.gen_func(cmp_operator, key_parts)
184+
local cmp_func = array_cmp_funcs_by_operators[cmp_operator]
164185
if cmp_func == nil then
165-
return nil, ComparatorsError:new('Unsupported operator %q', operator)
186+
return nil, ComparatorsError:new('Unsupported operator %q', cmp_operator)
166187
end
167188

168189
local func, err = gen_array_cmp_func(cmp_func, key_parts)
169190
if err ~= nil then
170-
return nil, ComparatorsError:new('Failed to generate comparator function %q', operator)
191+
return nil, ComparatorsError:new('Failed to generate comparator function %q', cmp_operator)
171192
end
172193

173194
return func
174195
end
175196

176-
function comparators.gen_tuples_comparator(operator, key_parts)
177-
local keys_comparator, err = comparators.gen_func(operator, key_parts)
197+
function comparators.gen_tuples_comparator(cmp_operator, key_parts)
198+
local keys_comparator, err = comparators.gen_func(cmp_operator, key_parts)
178199
if err ~= nil then
179200
return nil, ComparatorsError:new("Failed to generate comparator function: %s", err)
180201
end

crud/select/conditions.lua

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,6 @@ local tarantool_iter_by_cond_operators = {
2222
[conditions.operators.GE] = box.index.GE,
2323
}
2424

25-
function conditions.get_scroll_operator(operator)
26-
if operator == conditions.operators.GE or operator == conditions.GT or operator == conditions.EQ then
27-
return conditions.operators.GT
28-
end
29-
30-
if operator == conditions.operators.LE or operator == conditions.LT or operator == conditions.REQ then
31-
return conditions.operators.LT
32-
end
33-
34-
return operator
35-
end
36-
37-
function conditions.is_greater(operator)
38-
return operator == conditions.operators.GE or operator == conditions.operators.GT
39-
end
40-
41-
function conditions.is_less(operator)
42-
return operator == conditions.operators.LE or operator == conditions.operators.LT
43-
end
44-
4525
function _G.checkers.condition_operator(p)
4626
for _, op in pairs(conditions.operators) do
4727
if op == p then

crud/select/executor.lua

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ local log = require('log')
33

44
local select_filters = require('crud.select.filters')
55
local select_comparators = require('crud.select.comparators')
6-
local select_conditions = require('crud.select.conditions')
76

87
local utils = require('crud.common.utils')
98

@@ -16,10 +15,10 @@ local function scroll_to_after_tuple(gen, param, state, space, scanner)
1615
local scan_index = space.index[scanner.index_id]
1716
local primary_index = space.index[0]
1817

19-
local scroll_operator = select_conditions.get_scroll_operator(scanner.operator)
2018
local scroll_key_parts = utils.merge_primary_key_parts(scan_index.parts, primary_index.parts)
2119

22-
local scroll_comparator, err = select_comparators.gen_tuples_comparator(scroll_operator, scroll_key_parts)
20+
local cmp_operator = select_comparators.get_cmp_operator(scanner.iter)
21+
local scroll_comparator, err = select_comparators.gen_tuples_comparator(cmp_operator, scroll_key_parts)
2322
if err ~= nil then
2423
return nil, ScrollToAfterError:new("Failed to generate comparator to scroll: %s", err)
2524
end
@@ -59,9 +58,10 @@ function executor.execute(plan)
5958
if scan_value == nil then
6059
scan_value = scanner.after_tuple
6160
else
62-
local scan_comparator, err = select_comparators.gen_tuples_comparator(scanner.operator, index.parts)
61+
local cmp_operator = select_comparators.get_cmp_operator(scanner.iter)
62+
local scan_comparator, err = select_comparators.gen_tuples_comparator(cmp_operator, index.parts)
6363
if err ~= nil then
64-
log.warnf("Failed to generate comparator to scan value: %s", err)
64+
log.warn("Failed to generate comparator for scan value: %s", err)
6565
elseif scan_comparator(scanner.after_tuple, scan_value) then
6666
local after_tuple_key = utils.extract_key(scanner.after_tuple, index.parts)
6767
scan_value = after_tuple_key

crud/select/iterator.lua

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ function Iterator.new(opts)
2020
checks({
2121
space_name = 'string',
2222
space_format = 'table',
23-
key_parts = 'table',
2423
comparator = 'function',
2524
iteration_func = 'function',
2625

crud/select/plan.lua

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,11 @@ local function validate_conditions(conditions, space_indexes, space_format)
259259
return true
260260
end
261261

262-
local function is_scan_by_full_sharding_key_eq(plan, scan_index_parts, sharding_key_parts)
262+
local function is_scan_by_full_sharding_key_eq(plan, scan_index, sharding_index)
263+
if scan_index.id ~= sharding_index.id then
264+
return false
265+
end
266+
263267
if plan.scanner.value == nil then
264268
return false
265269
end
@@ -269,13 +273,13 @@ local function is_scan_by_full_sharding_key_eq(plan, scan_index_parts, sharding_
269273
end
270274

271275
local scan_index_fieldnos = {}
272-
for _, part in ipairs(scan_index_parts) do
276+
for _, part in ipairs(scan_index.parts) do
273277
scan_index_fieldnos[part.fieldno] = true
274278
end
275279

276280
-- check that sharding key is included in the scan index fields
277-
for part_num, sharding_key_part in ipairs(sharding_key_parts) do
278-
local fieldno = sharding_key_part.fieldno
281+
for part_num, sharding_index_part in ipairs(sharding_index.parts) do
282+
local fieldno = sharding_index_part.fieldno
279283
if scan_index_fieldnos[fieldno] == nil or plan.scanner.value[part_num] == nil then
280284
return false
281285
end
@@ -317,9 +321,9 @@ function select_plan.new(space, conditions, opts)
317321
filter_conditions = filter_conditions,
318322
}
319323

320-
local scan_index_parts = space_indexes[scanner.index_id]
321-
local sharding_key_parts = space_indexes[0] -- XXX: only sharding by primary key is supported
322-
if is_scan_by_full_sharding_key_eq(plan, scan_index_parts, sharding_key_parts) then
324+
local scan_index = space_indexes[scanner.index_id]
325+
local sharding_index = space_indexes[0] -- XXX: only sharding by primary key is supported
326+
if is_scan_by_full_sharding_key_eq(plan, scan_index, sharding_index) then
323327
plan.scanner.limit = 1
324328
plan.is_scan_by_full_sharding_key_eq = true
325329
end

test/integration/select_test.lua

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,68 @@ add('test_select_all_with_batch_size', function(g)
294294
t.assert_equals(objects, get_by_ids(customers, {1, 2, 3, 4, 5, 6}))
295295
end)
296296

297+
add('test_eq_condition_with_index', function(g)
298+
local customers = insert_customers(g, {
299+
{
300+
id = 1, name = "Elizabeth", last_name = "Jackson",
301+
age = 33, city = "New York",
302+
}, {
303+
id = 2, name = "Mary", last_name = "Brown",
304+
age = 46, city = "Los Angeles",
305+
}, {
306+
id = 3, name = "David", last_name = "Smith",
307+
age = 33, city = "Los Angeles",
308+
}, {
309+
id = 4, name = "William", last_name = "Smith",
310+
age = 81, city = "Chicago",
311+
},{
312+
id = 5, name = "Hector", last_name = "Barbossa",
313+
age = 33, city = "Chicago",
314+
},{
315+
id = 6, name = "William", last_name = "White",
316+
age = 81, city = "Chicago",
317+
},{
318+
id = 7, name = "Jack", last_name = "Sparrow",
319+
age = 33, city = "Chicago",
320+
},
321+
})
322+
323+
table.sort(customers, function(obj1, obj2) return obj1.id < obj2.id end)
324+
325+
local conditions = {
326+
{'==', 'age', 33},
327+
}
328+
329+
-- no after
330+
local objects, err = g.cluster.main_server.net_box:eval([[
331+
local crud = require('crud')
332+
333+
local conditions = ...
334+
335+
local objects, err = crud.select('customers', conditions)
336+
return objects, err
337+
]], {conditions})
338+
339+
t.assert_equals(err, nil)
340+
t.assert_equals(objects, get_by_ids(customers, {1, 3, 5, 7})) -- in id order
341+
342+
-- after obj 3
343+
local after = customers[3]
344+
local objects, err = g.cluster.main_server.net_box:eval([[
345+
local crud = require('crud')
346+
347+
local conditions, after = ...
348+
349+
local objects, err = crud.select('customers', conditions, {
350+
after = after,
351+
})
352+
return objects, err
353+
]], {conditions, after})
354+
355+
t.assert_equals(err, nil)
356+
t.assert_equals(objects, get_by_ids(customers, {5, 7})) -- in id order
357+
end)
358+
297359
add('test_ge_condition_with_index', function(g)
298360
local customers = insert_customers(g, {
299361
{

0 commit comments

Comments
 (0)