diff --git a/test/box/protocol.result b/test/box/protocol.result index cbeedabbc341a75a98e00694aa59de19cfa553f0..07366ba5a901c426145f9f3bd06b67ed8b31f6a9 100644 --- a/test/box/protocol.result +++ b/test/box/protocol.result @@ -1,3 +1,5 @@ return_code: 0 return_code: ER_ILLEGAL_PARAMS, Illegal parameters, tuple count must be positive return_code: ER_NO_SUCH_INDEX, No index #1 is defined in space 0 +delete from t0 where k0 = 1 +Delete OK, 1 row affected diff --git a/test/box/protocol.test b/test/box/protocol.test index e70396105a7c9a24395e264867906773070faa5c..9c7db26a20aa7b90088d6978eea0e399c4ef02f4 100644 --- a/test/box/protocol.test +++ b/test/box/protocol.test @@ -1,3 +1,5 @@ +# encoding: tarantool +# import subprocess import sys import os @@ -7,3 +9,6 @@ p = subprocess.Popen([ os.path.join(builddir, "test/box/protocol") ], p.wait() for line in p.stdout.readlines(): sys.stdout.write(line) + +exec sql "delete from t0 where k0 = 1" +# vim: syntax=python diff --git a/test/box/sql.result b/test/box/sql.result index 7bf86c60510e7fb5f308324af097584dca812123..9c298c7efc77e96b64e9480749fdfc89f6f99862 100644 --- a/test/box/sql.result +++ b/test/box/sql.result @@ -53,8 +53,8 @@ An error occurred: ER_NO_SUCH_FIELD, 'Field 1000 was not found in the tuple' select * from t0 where k0 = 1 Found 1 tuple: [1, 'Huh', 'I am a new field! I was added via append'] -insert into t0 values (1, 'I am a new tuple', 'stub') -Insert OK, 1 row affected +replace into t0 values (1, 'I am a new tuple', 'stub') +Replace OK, 1 row affected update t0 set k1 = 'Huh', k2 = 'Oh-ho-ho' where k0=1 Update OK, 1 row affected select * from t0 where k0 = 1 diff --git a/test/box/sql.test b/test/box/sql.test index 28eec05198da3ffbf7004f7d98ddfb1aecdb3c7a..f950f5da8de6dfa4b835211c3f4004d07c9722a5 100644 --- a/test/box/sql.test +++ b/test/box/sql.test @@ -30,7 +30,7 @@ exec sql "select * from t0 where k0 = 1" # this is illegal exec sql "update t0 set k1 = 'Huh', k1000 = 'invalid field' where k0=1" exec sql "select * from t0 where k0 = 1" -exec sql "insert into t0 values (1, 'I am a new tuple', 'stub')" +exec sql "replace into t0 values (1, 'I am a new tuple', 'stub')" exec sql "update t0 set k1 = 'Huh', k2 = 'Oh-ho-ho' where k0=1" exec sql "select * from t0 where k0 = 1" # check empty strings diff --git a/test/box_big/sql.result b/test/box_big/sql.result index bc16af0b073b6df9d862ee27617f08d3168bcf0c..0edcb14011b7e64e427d69870a6defcec0669dfe 100644 --- a/test/box_big/sql.result +++ b/test/box_big/sql.result @@ -76,8 +76,8 @@ Delete OK, 1 row affected # insert into t1 values ('key1', 'part1', 'part2') Insert OK, 1 row affected -insert into t1 values ('key1', 'part1', 'part2') -Insert OK, 1 row affected +replace into t1 values ('key1', 'part1', 'part2') +Replace OK, 1 row affected insert into t1 values ('key2', 'part1', 'part2_a') Insert OK, 1 row affected insert into t1 values ('key3', 'part1', 'part2_b') @@ -241,7 +241,7 @@ Found 1 tuple: select * from t4 where k1='Britney' Found 1 tuple: ['Spears', 'Britney'] -insert into t4 values ('Spears') +replace into t4 values ('Spears') An error occurred: ER_ILLEGAL_PARAMS, 'Illegal parameters, tuple must have all indexed fields' select * from t4 where k0='Spears' Found 1 tuple: diff --git a/test/box_big/sql.test b/test/box_big/sql.test index 20839b4ec8b379002afba601a5638104bf9ba6b5..1ebf223dfc5f979a1cb9dc1d054aed9e3dfdcccd 100644 --- a/test/box_big/sql.test +++ b/test/box_big/sql.test @@ -53,7 +53,7 @@ print """# #""" exec sql "insert into t1 values ('key1', 'part1', 'part2')" # Test a duplicate insert on unique index that once resulted in a crash (bug #926080) -exec sql "insert into t1 values ('key1', 'part1', 'part2')" +exec sql "replace into t1 values ('key1', 'part1', 'part2')" exec sql "insert into t1 values ('key2', 'part1', 'part2_a')" exec sql "insert into t1 values ('key3', 'part1', 'part2_b')" exec admin "lua for k, v in box.space[1]:pairs() do print(v) end" @@ -125,7 +125,7 @@ exec sql "insert into t4 values ('Spears', 'Britney')" exec sql "select * from t4 where k0='Spears'" exec sql "select * from t4 where k1='Britney'" # try to insert the incoplete tuple -exec sql "insert into t4 values ('Spears')" +exec sql "replace into t4 values ('Spears')" # check that nothing has been updated exec sql "select * from t4 where k0='Spears'" # cleanup diff --git a/test/lib/sql.g b/test/lib/sql.g index 2e41965d5681285c6626438bb1c80f1bb41efa4e..4a15ba41bf713441a0231ad1bb5986c5cbc3a92f 100644 --- a/test/lib/sql.g +++ b/test/lib/sql.g @@ -18,6 +18,7 @@ parser sql: token STR: '\'([^\']+|\\\\.)*\'' token PING: 'ping' token INSERT: 'insert' + token REPLACE: 'replace' token UPDATE: 'update' token DELETE: 'delete' token SELECT: 'select' @@ -32,6 +33,7 @@ parser sql: token END: '\\s*$' rule sql: (insert {{ stmt = insert }} | + replace {{ stmt = replace }} | update {{ stmt = update }} | delete {{ stmt = delete }} | select {{ stmt = select }} | @@ -40,6 +42,8 @@ parser sql: rule insert: INSERT [INTO] ident VALUES value_list {{ return sql_ast.StatementInsert(ident, value_list) }} + rule replace: REPLACE [INTO] ident VALUES value_list + {{ return sql_ast.StatementReplace(ident, value_list) }} rule update: UPDATE ident SET update_list opt_simple_where {{ return sql_ast.StatementUpdate(ident, update_list, opt_simple_where) }} rule delete: DELETE FROM ident opt_simple_where diff --git a/test/lib/sql.py b/test/lib/sql.py index ad5b92331629c14eea1e855c43480b60d9b64a1b..e8cdb062953b418d543301376c8ec6a36339bdbc 100644 --- a/test/lib/sql.py +++ b/test/lib/sql.py @@ -23,6 +23,7 @@ class sqlScanner(runtime.Scanner): ('STR', re.compile("'([^']+|\\\\.)*'")), ('PING', re.compile('ping')), ('INSERT', re.compile('insert')), + ('REPLACE', re.compile('replace')), ('UPDATE', re.compile('update')), ('DELETE', re.compile('delete')), ('SELECT', re.compile('select')), @@ -43,10 +44,13 @@ class sql(runtime.Parser): Context = runtime.Context def sql(self, _parent=None): _context = self.Context(_parent, self._scanner, 'sql', []) - _token = self._peek('INSERT', 'UPDATE', 'DELETE', 'SELECT', 'CALL', 'PING', context=_context) + _token = self._peek('INSERT', 'REPLACE', 'UPDATE', 'DELETE', 'SELECT', 'CALL', 'PING', context=_context) if _token == 'INSERT': insert = self.insert(_context) stmt = insert + elif _token == 'REPLACE': + replace = self.replace(_context) + stmt = replace elif _token == 'UPDATE': update = self.update(_context) stmt = update @@ -75,6 +79,16 @@ class sql(runtime.Parser): value_list = self.value_list(_context) return sql_ast.StatementInsert(ident, value_list) + def replace(self, _parent=None): + _context = self.Context(_parent, self._scanner, 'replace', []) + REPLACE = self._scan('REPLACE', context=_context) + if self._peek('INTO', 'ID', context=_context) == 'INTO': + INTO = self._scan('INTO', context=_context) + ident = self.ident(_context) + VALUES = self._scan('VALUES', context=_context) + value_list = self.value_list(_context) + return sql_ast.StatementReplace(ident, value_list) + def update(self, _parent=None): _context = self.Context(_parent, self._scanner, 'update', []) UPDATE = self._scan('UPDATE', context=_context) diff --git a/test/lib/sql_ast.py b/test/lib/sql_ast.py index 71fa7723917964a5a769f2239cc1883f8a9d519a..0f353dfb17088f39f8a9a86a517f8ac917d75a1d 100644 --- a/test/lib/sql_ast.py +++ b/test/lib/sql_ast.py @@ -210,7 +210,7 @@ class StatementInsert(StatementPing): def __init__(self, table_name, value_list): self.space_no = table_name - self.flags = 0 + self.flags = 0x02 # ADD self.value_list = value_list def pack(self): @@ -226,6 +226,26 @@ class StatementInsert(StatementPing): (tuple_count,) = struct.unpack("<L", response[4:8]) return "Insert OK, {0} row affected".format(tuple_count) +class StatementReplace(StatementPing): + reqeust_type = INSERT_REQUEST_TYPE + + def __init__(self, table_name, value_list): + self.space_no = table_name + self.flags = 0x04 # REPLACE + self.value_list = value_list + + def pack(self): + buf = ctypes.create_string_buffer(PACKET_BUF_LEN) + (buf, offset) = pack_tuple(self.value_list, buf, INSERT_REQUEST_FIXED_LEN) + struct.pack_into("<LL", buf, 0, self.space_no, self.flags) + return buf[:offset] + + def unpack(self, response): + (return_code,) = struct.unpack("<L", response[:4]) + if return_code: + return format_error(return_code, response) + (tuple_count,) = struct.unpack("<L", response[4:8]) + return "Replace OK, {0} row affected".format(tuple_count) class StatementUpdate(StatementPing): reqeust_type = UPDATE_REQUEST_TYPE