diff --git a/src/box/call.c b/src/box/call.c index d3d6877a2aac272cefbabfe7ab3afca4150af262..33124779341356f4310c62b3eb4d034803d04733 100644 --- a/src/box/call.c +++ b/src/box/call.c @@ -203,10 +203,9 @@ box_process_call(struct call_request *request, struct port *port) } if (in_txn()) { - /* The procedure forgot to call box.commit() */ - say_warn("a transaction is active at return from '%.*s'", - name_len, name); + diag_set(ClientError, ER_FUNCTION_TX_ACTIVE); txn_rollback(); + return -1; } return 0; @@ -225,13 +224,9 @@ box_process_eval(struct call_request *request, struct port *port) } if (in_txn()) { - /* The procedure forgot to call box.commit() */ - const char *expr = request->expr; - assert(expr != NULL); - uint32_t expr_len = mp_decode_strl(&expr); - say_warn("a transaction is active at return from EVAL '%.*s'", - expr_len, expr); + diag_set(ClientError, ER_FUNCTION_TX_ACTIVE); txn_rollback(); + return -1; } return 0; diff --git a/src/box/errcode.h b/src/box/errcode.h index 676bda266263d6ae346b6fdb60b105016cb85a21..20d11cd16127fefcbe5e132056db200d0d714cd3 100644 --- a/src/box/errcode.h +++ b/src/box/errcode.h @@ -82,7 +82,7 @@ struct errcode_record { /* 27 */_(ER_FORMAT_MISMATCH_INDEX_PART, "Field %s has type '%s' in space format, but type '%s' in index definition") \ /* 28 */_(ER_UNKNOWN_UPDATE_OP, "Unknown UPDATE operation") \ /* 29 */_(ER_UPDATE_FIELD, "Field %u UPDATE error: %s") \ - /* 30 */_(ER_UNUSED2, "") \ + /* 30 */_(ER_FUNCTION_TX_ACTIVE, "Transaction is active at return from function") \ /* 31 */_(ER_KEY_PART_COUNT, "Invalid key part count (expected [0..%u], got %u)") \ /* 32 */_(ER_PROC_LUA, "%s") \ /* 33 */_(ER_NO_SUCH_PROC, "Procedure '%.*s' is not defined") \ diff --git a/src/box/iproto.cc b/src/box/iproto.cc index 4ff0b2fad324834995427a694e4ce8dd16dbc30e..4b1b3860307cb3708a1cced9f893d57640c59848 100644 --- a/src/box/iproto.cc +++ b/src/box/iproto.cc @@ -1230,6 +1230,7 @@ tx_process_call_on_yield(struct trigger *trigger, void *event) { (void)event; struct iproto_msg *msg = (struct iproto_msg *)trigger->data; + TRASH(&msg->call); tx_discard_input(msg); trigger_clear(trigger); } diff --git a/test/box/misc.result b/test/box/misc.result index d35567e314dba88f86ced8b12927f39a0ccd62c1..cd2f76f5daa05e52ffca5d1f65f531ec093fe2ec 100644 --- a/test/box/misc.result +++ b/test/box/misc.result @@ -332,7 +332,7 @@ t; - 'box.error.ACCESS_DENIED : 42' - 'box.error.CANT_CREATE_COLLATION : 150' - 'box.error.USER_EXISTS : 46' - - 'box.error.WAL_IO : 40' + - 'box.error.TUPLE_FORMAT_LIMIT : 16' - 'box.error.RTREE_RECT : 101' - 'box.error.PRIV_GRANTED : 89' - 'box.error.CREATE_SPACE : 9' @@ -355,7 +355,7 @@ t; - 'box.error.CFG : 59' - 'box.error.NO_SUCH_FIELD : 37' - 'box.error.CONNECTION_TO_SELF : 117' - - 'box.error.FUNCTION_MAX : 54' + - 'box.error.PROC_LUA : 32' - 'box.error.ILLEGAL_PARAMS : 1' - 'box.error.PARTIAL_KEY : 136' - 'box.error.SAVEPOINT_NO_TRANSACTION : 114' @@ -382,7 +382,8 @@ t; - 'box.error.FUNCTION_EXISTS : 52' - 'box.error.UPDATE_ARG_TYPE : 26' - 'box.error.CROSS_ENGINE_TRANSACTION : 81' - - 'box.error.FORMAT_MISMATCH_INDEX_PART : 27' + - 'box.error.IDENTIFIER : 70' + - 'box.error.FUNCTION_TX_ACTIVE : 30' - 'box.error.NO_SUCH_ENGINE : 57' - 'box.error.COMMIT_IN_SUB_STMT : 122' - 'box.error.injection : table: <address> @@ -391,71 +392,71 @@ t; - 'box.error.DECOMPRESSION : 124' - 'box.error.CREATE_SEQUENCE : 142' - 'box.error.CREATE_USER : 43' - - 'box.error.ITERATOR_TYPE : 72' + - 'box.error.RELOAD_CFG : 58' - 'box.error.INSTANCE_UUID_MISMATCH : 66' - 'box.error.SPACE_FIELD_IS_DUPLICATE : 149' - 'box.error.SYSTEM : 115' - 'box.error.KEY_PART_IS_TOO_LONG : 118' - 'box.error.SEQUENCE_OVERFLOW : 147' - - 'box.error.INJECTION : 8' + - 'box.error.FUNCTION_MAX : 54' - 'box.error.NO_SUCH_SAVEPOINT : 61' - - 'box.error.INVALID_XLOG_TYPE : 125' + - 'box.error.INVALID_MSGPACK : 20' - 'box.error.TRUNCATE_SYSTEM_SPACE : 137' - 'box.error.WRONG_INDEX_OPTIONS : 108' - 'box.error.INVALID_VYLOG_FILE : 133' - 'box.error.INDEX_FIELD_COUNT_LIMIT : 127' - 'box.error.VY_QUOTA_TIMEOUT : 135' - 'box.error.USER_MAX : 56' - - 'box.error.PROC_RET : 21' + - 'box.error.PRIV_NOT_GRANTED : 91' - 'box.error.TUPLE_NOT_ARRAY : 22' - 'box.error.KEY_PART_COUNT : 31' - 'box.error.ALTER_SPACE : 12' - 'box.error.ACTIVE_TRANSACTION : 79' - 'box.error.EXACT_FIELD_COUNT : 38' - 'box.error.DROP_SEQUENCE : 144' - - 'box.error.RELOAD_CFG : 58' - - 'box.error.PROC_LUA : 32' - - 'box.error.MORE_THAN_ONE_TUPLE : 41' - - 'box.error.SUB_STMT_MAX : 121' + - 'box.error.ITERATOR_TYPE : 72' + - 'box.error.PROC_RET : 21' - 'box.error.UPSERT_UNIQUE_SECONDARY_KEY : 105' - - 'box.error.SPACE_EXISTS : 10' + - 'box.error.SUB_STMT_MAX : 121' - 'box.error.UNKNOWN_REQUEST_TYPE : 48' - - 'box.error.UNKNOWN : 0' + - 'box.error.SPACE_EXISTS : 10' + - 'box.error.FORMAT_MISMATCH_INDEX_PART : 27' + - 'box.error.ROLE_NOT_GRANTED : 92' - 'box.error.NO_SUCH_SPACE : 36' - 'box.error.WRONG_INDEX_PARTS : 107' - - 'box.error.ROLE_NOT_GRANTED : 92' - - 'box.error.SPLICE : 25' + - 'box.error.UPDATE_INTEGER_OVERFLOW : 95' - 'box.error.MIN_FIELD_COUNT : 39' - 'box.error.REPLICASET_UUID_MISMATCH : 63' + - 'box.error.UPDATE_FIELD : 29' - 'box.error.COMPRESSION : 119' - 'box.error.INVALID_ORDER : 68' - - 'box.error.UPDATE_FIELD : 29' - 'box.error.INDEX_EXISTS : 85' - - 'box.error.TUPLE_FORMAT_LIMIT : 16' + - 'box.error.UNKNOWN : 0' + - 'box.error.MORE_THAN_ONE_TUPLE : 41' - 'box.error.DROP_PRIMARY_KEY : 17' - 'box.error.NULLABLE_PRIMARY : 152' - 'box.error.NO_SUCH_SEQUENCE : 145' - - 'box.error.UNSUPPORTED : 5' + - 'box.error.DROP_SPACE : 11' - 'box.error.INVALID_UUID : 64' - - 'box.error.IDENTIFIER : 70' + - 'box.error.INJECTION : 8' - 'box.error.TIMEOUT : 78' - 'box.error.REPLICA_MAX : 73' - - 'box.error.DROP_SPACE : 11' - - 'box.error.INVALID_MSGPACK : 20' + - 'box.error.SPLICE : 25' + - 'box.error.UNSUPPORTED : 5' - 'box.error.MISSING_REQUEST_FIELD : 69' - 'box.error.MISSING_SNAPSHOT : 93' - 'box.error.WRONG_SPACE_OPTIONS : 111' - 'box.error.READONLY : 7' - - 'box.error.UPDATE_INTEGER_OVERFLOW : 95' + - 'box.error.WAL_IO : 40' - 'box.error.NO_SUCH_ROLE : 82' - 'box.error.NO_CONNECTION : 77' - 'box.error.INVALID_XLOG_ORDER : 76' - 'box.error.WRONG_SCHEMA_VERSION : 109' - 'box.error.ROLLBACK_IN_SUB_STMT : 123' - - 'box.error.UNSUPPORTED_INDEX_FEATURE : 112' - 'box.error.PROTOCOL : 104' + - 'box.error.INVALID_XLOG_TYPE : 125' - 'box.error.INDEX_PART_TYPE_MISMATCH : 24' - - 'box.error.PRIV_NOT_GRANTED : 91' + - 'box.error.UNSUPPORTED_INDEX_FEATURE : 112' ... test_run:cmd("setopt delimiter ''"); --- diff --git a/test/box/net.box.result b/test/box/net.box.result index 1e16c5328d1ddef75ef7194d4e412006ee5f9298..8f7f07f9f54a8e2dbc50db807ef94dfa0bdb425f 100644 --- a/test/box/net.box.result +++ b/test/box/net.box.result @@ -148,6 +148,18 @@ cn:eval('!invalid expression') --- - error: 'eval:1: unexpected symbol near ''!''' ... +-- box.commit() missing at return of CALL/EVAL +function no_commit() box.begin() fiber.sleep(0.001) end +--- +... +cn:call('no_commit') +--- +- error: Transaction is active at return from function +... +cn:eval('no_commit()') +--- +- error: Transaction is active at return from function +... remote.self:eval('return 1+1, 2+2') --- - 2 diff --git a/test/box/net.box.test.lua b/test/box/net.box.test.lua index 99099251d0b02249a2de436d9e9a7cc40fd27b1f..7c2e64cb3224df72c0bb15d1792b3de492e25217 100644 --- a/test/box/net.box.test.lua +++ b/test/box/net.box.test.lua @@ -55,6 +55,11 @@ cn:eval('error("exception")') cn:eval('box.error(0)') cn:eval('!invalid expression') +-- box.commit() missing at return of CALL/EVAL +function no_commit() box.begin() fiber.sleep(0.001) end +cn:call('no_commit') +cn:eval('no_commit()') + remote.self:eval('return 1+1, 2+2') remote.self:eval('return') remote.self:eval('error("exception")') diff --git a/test/box/transaction.result b/test/box/transaction.result index 746f7e12c23067cc2f4149e0b23c8a7e37d3e76e..2a4b3b289b4d833da65883db35a5167a744d7d5e 100644 --- a/test/box/transaction.result +++ b/test/box/transaction.result @@ -287,33 +287,6 @@ test:select{1} - - [1] ... -- --- gh-793 box.rollback() is not invoked after CALL --- -function test() box.begin() end ---- -... -box.schema.func.create('test') ---- -... -box.schema.user.grant('guest', 'execute', 'function', 'test') ---- -... -cn = require('net.box').connect(box.cfg.listen) ---- -... -cn:call('test') -- first CALL starts transaction ---- -... -cn:call('test') -- iproto reuses fiber on the second call ---- -... -cn = nil ---- -... -box.schema.func.drop('test') ---- -... --- -- Test statement-level rollback -- box.space.test:truncate() diff --git a/test/box/transaction.test.lua b/test/box/transaction.test.lua index cda0eb151a08b9294ec3e9a8669858140e2c22d9..25027e72645dce049200505d359e1d36cf510798 100644 --- a/test/box/transaction.test.lua +++ b/test/box/transaction.test.lua @@ -128,17 +128,6 @@ box.begin() test:insert{1} box.rollback() test:select{1} box.begin() test:insert{1} box.commit() test:select{1} --- --- gh-793 box.rollback() is not invoked after CALL --- -function test() box.begin() end -box.schema.func.create('test') -box.schema.user.grant('guest', 'execute', 'function', 'test') -cn = require('net.box').connect(box.cfg.listen) -cn:call('test') -- first CALL starts transaction -cn:call('test') -- iproto reuses fiber on the second call -cn = nil -box.schema.func.drop('test') -- -- Test statement-level rollback