Skip to content

Commit 50d9e71

Browse files
bigbesTotktonada
authored andcommitted
Fix select() by space_no and index_name
When a space exists, but a client side schema does not know about it at the moment (say, right after connection), and when a user calls select() with a space id (number) and name of an index (string), the problem appears: the client raises the following error: | TarantoolParsingException: Failed to parse schema (index) However it should successfully perform the request. The problem is that when there is no record for a space in client's schema, it is not possible to save a record for an index of this space. The idea of the fix is to verify whether we know about a space even when a numeric ID is already provided. If a client has no record about the space, it fetches a schema and verify whether the space appears. If so, there is no more problem described above. Otherwise the client raises an error that the space with given ID does not exist. While we're here, ensure that return values of tarantool_schema_*() are checked against -1, not Zend's FAILURE macro (which is only guaranteed to be less than zero) in the modified code. Also ensure that the FAILURE macro is returned from the get_spaceno_by_name() function, not -1. Closes tarantool#42 @Totktonada: polish code, polish test, write the description.
1 parent e67cb23 commit 50d9e71

File tree

5 files changed

+96
-15
lines changed

5 files changed

+96
-15
lines changed

src/tarantool.c

+36-15
Original file line numberDiff line numberDiff line change
@@ -631,21 +631,30 @@ int convert_iterator(zval *iter, int all) {
631631
}
632632

633633
int get_spaceno_by_name(tarantool_connection *obj, zval *name) {
634-
if (Z_TYPE_P(name) == IS_LONG)
635-
return Z_LVAL_P(name);
636-
if (Z_TYPE_P(name) != IS_STRING) {
634+
if (Z_TYPE_P(name) != IS_STRING && Z_TYPE_P(name) != IS_LONG) {
637635
tarantool_throw_exception("Space ID must be String or Long");
638636
return FAILURE;
639637
}
640-
int32_t space_no = tarantool_schema_get_sid_by_string(obj->schema,
641-
Z_STRVAL_P(name), Z_STRLEN_P(name));
642-
if (space_no != FAILURE)
643-
return space_no;
644-
638+
int32_t space_no;
645639
tarantool_tp_update(obj->tps);
646-
tp_select(obj->tps, SPACE_SPACE, INDEX_SPACE_NAME, 0, 4096);
647-
tp_key(obj->tps, 1);
648-
tp_encode_str(obj->tps, Z_STRVAL_P(name), Z_STRLEN_P(name));
640+
if (Z_TYPE_P(name) == IS_LONG) {
641+
space_no = tarantool_schema_get_sid_by_number(obj->schema,
642+
Z_LVAL_P(name));
643+
if (space_no != -1)
644+
return space_no;
645+
tp_select(obj->tps, SPACE_SPACE, INDEX_SPACE_NO, 0, 4096);
646+
tp_key(obj->tps, 1);
647+
tp_encode_uint(obj->tps, Z_LVAL_P(name));
648+
} else {
649+
space_no = tarantool_schema_get_sid_by_string(obj->schema,
650+
Z_STRVAL_P(name),
651+
Z_STRLEN_P(name));
652+
if (space_no != -1)
653+
return space_no;
654+
tp_select(obj->tps, SPACE_SPACE, INDEX_SPACE_NAME, 0, 4096);
655+
tp_key(obj->tps, 1);
656+
tp_encode_str(obj->tps, Z_STRVAL_P(name), Z_STRLEN_P(name));
657+
}
649658
tp_reqid(obj->tps, TARANTOOL_G(sync_counter)++);
650659

651660
obj->value->len = tp_used(obj->tps);
@@ -679,10 +688,22 @@ int get_spaceno_by_name(tarantool_connection *obj, zval *name) {
679688
tarantool_throw_parsingexception("schema (space)");
680689
return FAILURE;
681690
}
682-
space_no = tarantool_schema_get_sid_by_string(obj->schema,
683-
Z_STRVAL_P(name), Z_STRLEN_P(name));
684-
if (space_no == FAILURE)
685-
THROW_EXC("No space '%s' defined", Z_STRVAL_P(name));
691+
692+
if (Z_TYPE_P(name) == IS_LONG) {
693+
space_no = tarantool_schema_get_sid_by_number(obj->schema,
694+
Z_LVAL_P(name));
695+
if (space_no == -1) {
696+
THROW_EXC("No space %d defined", Z_LVAL_P(name));
697+
}
698+
} else {
699+
space_no = tarantool_schema_get_sid_by_string(obj->schema,
700+
Z_STRVAL_P(name),
701+
Z_STRLEN_P(name));
702+
if (space_no == -1) {
703+
THROW_EXC("No space '%s' defined", Z_STRVAL_P(name));
704+
}
705+
}
706+
686707
return space_no;
687708
}
688709

src/tarantool_proto.h

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#define SPACE_SPACE 281
1313
#define SPACE_INDEX 289
1414

15+
#define INDEX_SPACE_NO 0
16+
#define INDEX_INDEX_NO 0
1517
#define INDEX_SPACE_NAME 2
1618
#define INDEX_INDEX_NAME 2
1719

src/tarantool_schema.c

+19
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,25 @@ tarantool_schema_get_sid_by_string(
557557
return space->space_number;
558558
}
559559

560+
int32_t
561+
tarantool_schema_get_sid_by_number(
562+
struct tarantool_schema *schema_obj,
563+
uint32_t sid
564+
) {
565+
struct mh_schema_space_t *schema = schema_obj->space_hash;
566+
struct schema_key space_key = {
567+
(void *)&sid,
568+
sizeof(uint32_t),
569+
sid, /* ignored */
570+
};
571+
mh_int_t space_slot = mh_schema_space_find(schema, &space_key, NULL);
572+
if (space_slot == mh_end(schema))
573+
return -1;
574+
const struct schema_space_value *space =
575+
*mh_schema_space_node(schema, space_slot);
576+
return space->space_number;
577+
}
578+
560579
int32_t
561580
tarantool_schema_get_iid_by_string(
562581
struct tarantool_schema *schema_obj, uint32_t sid,

src/tarantool_schema.h

+2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ int32_t
5656
tarantool_schema_get_sid_by_string(struct tarantool_schema *, const char *,
5757
uint32_t);
5858
int32_t
59+
tarantool_schema_get_sid_by_number(struct tarantool_schema *, uint32_t);
60+
int32_t
5961
tarantool_schema_get_iid_by_string(struct tarantool_schema *, uint32_t,
6062
const char *, uint32_t);
6163
int32_t

test/DMLTest.php

+37
Original file line numberDiff line numberDiff line change
@@ -468,4 +468,41 @@ public function test_18_02_delete_loop() {
468468
gc_collect_cycles();
469469
gc_collect_cycles();
470470
}
471+
472+
public function test_19_select_space_no_index_name_known() {
473+
/*
474+
* gh-42: 'Failed to parse schema (index)' at select()
475+
* error when a space is passed as a number, but an index
476+
* is passed as a name.
477+
*
478+
* The problem appears when a schema is not fetched yet,
479+
* so let's test it on a new client instance.
480+
*/
481+
$port = TestHelpers::getTarantoolPort();
482+
$tarantool = new Tarantool('localhost', $port, 'test');
483+
484+
$vindex_id = 289;
485+
$res = $tarantool->select($vindex_id, [$vindex_id], 'primary', 1);
486+
$this->assertEquals($res[0][0], $vindex_id);
487+
}
488+
489+
public function test_20_select_space_no_index_name_unknown() {
490+
/*
491+
* Related to gh-42, see above. This case is to verify
492+
* that the client gives an error in the case when unknown
493+
* space id is passed (together with some index name).
494+
*
495+
* One of transient versions of gh-42 patch had a mistake
496+
* on the error path that cause a segfault. This case
497+
* triggers execution of the corresponding code.
498+
*/
499+
$port = TestHelpers::getTarantoolPort();
500+
$tarantool = new Tarantool('localhost', $port, 'test');
501+
502+
$this->expectException(TarantoolException::class);
503+
$this->expectExceptionMessage('No space 1024 defined');
504+
505+
$unknown_space_id = 1024;
506+
$tarantool->select($unknown_space_id, [], 'primary');
507+
}
471508
}

0 commit comments

Comments
 (0)