Permalink
Browse files

Test-runner: support for SQL.

Implement a basic SQL parser.

Implement SQL statements: INSERT, UPDATE, DELETE,
PING.

Add a test case that tests INSERT/SELECT/DELETE.

Other changes:

Remove support for result-prefix from admin.py
Rename admin.py to tarantool (tarantool client).
Add readline support to tarantool client.
Make sql.g and sql.py independent from yapps
Add gdb support to ./test-run
Disable all optimizations when compiling with DEBUG.
Fix a few bugs discovered by trial and error in silverbox
protocol description.
Add automatic reconnection in case of server disconnect
to test connections. This is used to automatically
reconnect to the server after server restart or reinstall.
Implement soft and hard (with and without removal of vardir)
server restart.
Make show.test results independent from other tests (data I/O
skews statistics, and there is no way to reset it without
restarting the server).
Add  TCP_NODELAY to fiber sockets.
  • Loading branch information...
1 parent 1b98b39 commit 7ff8c17a94f57329f933852d28ffff26b9baa85b @kostja kostja committed Dec 22, 2010
View
@@ -14,3 +14,4 @@ lcov
tarantool_version.h
test/var
test/lib/*.pyc
+test/lib/*/*.pyc
View
2 TODO
@@ -1,4 +1,4 @@
-We're using launchpad for tasks tracking and bugs.
+We're using launchpad for task tracking and bugs.
Please use http://blueprints.launchpad.net/tarantool and
http://bugs.launchpad.net/tarantool respectively.
View
@@ -924,6 +924,11 @@ tcp_server_handler(void *data)
close(fd);
continue;
}
+ if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
+ &one, sizeof(one)) == -1) {
+ say_syserror("setsockopt failed");
+ /* Do nothing, not a fatal error. */
+ }
snprintf(name, sizeof(name), "%i/handler", server->port);
h = fiber_create(name, fd, -1, server->handler, data);
View
@@ -148,7 +148,7 @@ read_varint32(struct tbuf *buf)
(b[2] & 0x7f) << 14 | (b[3] & 0x7f) << 7 | (b[4] & 0x7f);
}
- raise(ERR_CODE_UNKNOWN_ERROR, "imposible happend");
+ raise(ERR_CODE_UNKNOWN_ERROR, "impossible happened");
return 0;
}
View
@@ -15,22 +15,22 @@
;
; int32 - a 32-bit integer in big-endian format (Intel x86)
;
-; int32_ber - a 1 to 5 byte BER encoding of a 32 bit integer
+; int32_varint - a 1 to 5 byte representation of an integer
;
-; BER stands for Basic Encoding Rules, and allows to unequivocally
-; compact a 32-bit integer into 1 to 5 bytes depending on its value.
-; For more information, see
-; http://en.wikipedia.org/wiki/Basic_Encoding_Rules and
-; http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf,
-; chapter 8.3 Encoding of an Integer Value
+; This is what Perl's "pack" function calls "BER compressed
+; integer (BER stands for Basic Encoding Rules, but in reality it
+; has little to do with ASN.1 standard).
+; See http://en.wikipedia.org/wiki/LEB128
+; for encoding description, or core/pickle.c for implementation
+; in tarantool.
; All requests and responses utilize the same basic structure:
<packet> ::= <request> | <response>
<request> ::= <header><request_body>
-<response> ::= <header><return_code><response_body>
+<response> ::= <header><return_code>{<response_body>}
;
; <header> has a fixed structure of three 4-byte integers (12 bytes):
@@ -54,7 +54,7 @@
;
; <body_length> tells the sender or receiver the length of data
; that follows the header. If there is no data, <body_length> is 0.
-; However, <request_body> or <response_body> are always present.
+; However, <request_body> is always present.
;
; The only exception is <ping>: its request body is empty, and
; so is response. In other words, <ping> request packet
@@ -76,7 +76,8 @@
<request_id> ::= <int32>
-; <request_body> holds actual command data.
+; <request_body> holds actual command data. It is
+; only present if <return_code> is 0 (success).
; Its format and interpretation are defined by the value of
; request <type>.
@@ -102,6 +103,10 @@
; keys to use in lookup. When more than one key is given, they
; specify a disjunctive search condition (key1 or key2 or ...).
;
+; Note, that <tuple> is mandatory, and tuple <count>
+; must be non-zero.
+; To select all keys in the namespace, use
+;
<select_request_body> ::= <namespace_no><index_no>
<offset><limit><count><tuple>+
@@ -156,13 +161,13 @@
; define fields of those key that is used for search.
;
-<field> ::= <data_length_ber><data>
+<field> ::= <int32_varint><data>
;
-; BER-encoded integer
+; Compressed integer
;
-<data_length_ber> ::= <int8>+
+<int32_varint> ::= <int8>+
;
; SELECT may return zero, one or several tuples.
; <select_response_body> starts with the number of found
@@ -184,7 +189,7 @@
; boundaries: in Tarantool, tuples have variable cardinality.
;
-<fq_tuple> ::= <size><cardinality><field>+
+<fq_tuple> ::= <size><cardinality><tuple>
<size> ::= <int32>
@@ -199,7 +204,7 @@
; The only defined flag BOX_RETURN_TUPLE (0x01) indicates
; that it is required to return the inserted tuple back:
-<flags> ::= 0 | 1
+<flags> ::= <int32>
;
; A tuple may already exist. In that case INSERT
@@ -264,7 +269,7 @@
;
; Return the number of deleted tuples.
-; Currently it's always 1
+; Currently it's always 0 or 1
;
<delete_response_body> ::= <count>
@@ -297,9 +302,6 @@
; -----------------------------
; 0x00000000 -- ERR_CODE_OK
;
-; 0x00003600 -- ERR_CODE_NOTHING
-; The query does not support data modification or return
-;
; Completion status 1 (try again)
; -------------------------------
; 0x00000401 -- ERR_CODE_NODE_IS_RO
View
@@ -18,7 +18,7 @@ ifneq (,$(findstring _release,$(OBJDIR)))
CFLAGS += -DNDEBUG
else ifneq (,$(findstring _debug,$(OBJDIR)))
DEBUG=1
- CFLAGS += -DDEBUG -fno-omit-frame-pointer
+ CFLAGS += -DDEBUG -fno-omit-frame-pointer -O0 -ggdb
else ifneq (,$(findstring _test,$(OBJDIR)))
CFLAGS += --coverage -DCOVERAGE -DNDEBUG
else ifneq (,$(findstring _coverage,$(OBJDIR)))
View
@@ -1,5 +1,9 @@
# encoding: tarantool
-#
+#
+# clear statistics:
+server.stop(True)
+server.install(True)
+server.start(True)
exec admin "show stat"
exec admin "help"
exec admin "show configuration"
View
@@ -0,0 +1,25 @@
+ping
+ok
+---
+select * from t0
+An error occurred: ERR_CODE_ILLEGAL_PARAMS, 'Illegal parameters'
+insert into t0 values (1, "I am a tuple")
+Insert OK, 1 row affected
+select * from t0 where k0 = 1
+Found 1 tuple:
+[1, 'I am a tuple']
+select * from t0 where k0 = 0
+No match
+select * from t0 where k0 = 2
+No match
+select * from t0 where k0 = 1
+Found 1 tuple:
+[1, 'I am a tuple']
+save snapshot
+ok
+select * from t0 where k0 = 1
+Found 1 tuple:
+[1, 'I am a tuple']
+select * from t0 where k0 = 1
+Found 1 tuple:
+[1, 'I am a tuple']
View
@@ -0,0 +1,18 @@
+# encoding: tarantool
+exec sql 'ping'
+# xxx: bug -- currently selects no rows
+exec sql 'select * from t0'
+exec sql 'insert into t0 values (1, "I am a tuple")'
+exec sql 'select * from t0 where k0 = 1'
+# currently there is no way to find out how many records
+# a namespace contains
+exec sql 'select * from t0 where k0 = 0'
+exec sql 'select * from t0 where k0 = 2'
+server.restart()
+exec sql 'select * from t0 where k0 = 1'
+exec admin "save snapshot"
+exec sql 'select * from t0 where k0 = 1'
+server.restart()
+exec sql 'select * from t0 where k0 = 1'
+
+# vim: syntax=python
View
@@ -0,0 +1,2 @@
+sql.py: sql.g
+ yapps sql.g
View
@@ -0,0 +1,64 @@
+import sql_ast
+
+%%
+
+parser sql:
+
+ ignore: '\\s+'
+ token NUM: '[0-9]+'
+ token ID: '[a-z_]+[0-9]+'
+ token STR: '"([^\\"]+|\\\\.)*"'
+ token PING: 'ping'
+ token INSERT: 'insert'
+ token UPDATE: 'update'
+ token DELETE: 'delete'
+ token SELECT: 'select'
+ token INTO: 'into'
+ token FROM: 'from'
+ token WHERE: 'where'
+ token VALUES: 'values'
+ token SET: 'set'
+ token END: '\\s*$'
+
+ rule sql: (insert {{ stmt = insert }} |
+ update {{ stmt = update }} |
+ delete {{ stmt = delete }} |
+ select {{ stmt = select }} |
+ ping {{ stmt = ping }}) END {{ return stmt }}
+
+ rule insert: INSERT [INTO] ID VALUES value_list
+ {{ return sql_ast.StatementInsert(ID, value_list) }}
+ rule update: UPDATE ID SET update_list opt_where
+ {{ return sql_ast.StatementUpdate(ID, update_list, opt_where) }}
+ rule delete: DELETE FROM ID opt_where
+ {{ return sql_ast.StatementDelete(ID, opt_where) }}
+ rule select: SELECT '\*' FROM ID opt_where
+ {{ return sql_ast.StatementSelect(ID, opt_where) }}
+ rule ping: PING
+ {{ return sql_ast.StatementPing() }}
+ rule predicate: ID '=' constant
+ {{ return (ID, constant) }}
+ rule opt_where: {{ return None }}
+ | WHERE predicate
+ {{ return predicate }}
+ rule value_list: '\(' expr {{ value_list = [expr] }}
+ [("," expr {{ value_list.append(expr) }} )+]
+ '\)' {{ return value_list }}
+ rule update_list: predicate {{ update_list = [predicate] }}
+ [(',' predicate {{ update_list.append(predicate) }})+]
+ {{ return update_list }}
+ rule expr: constant {{ return constant }}
+ rule constant: NUM {{ return int(NUM) }} | STR {{ return STR[1:-1] }}
+%%
+
+# SQL is case-insensitive, but in yapps it's not possible to
+# specify that a token must match in case-insensitive fashion.
+# This is hack to add re.IGNORECASE flag to all regular
+# expressions that represent tokens in the generated grammar.
+
+sqlScanner.patterns = map(lambda tup:
+ (tup[0], re.compile(tup[1].pattern, re.IGNORECASE)),
+ sqlScanner.patterns)
+
+# vim: nospell syntax=off ts=4 et
+
Oops, something went wrong.

0 comments on commit 7ff8c17

Please sign in to comment.