[Tarantool-patches] [PATCH v3 6/8] sql: remove implicit cast for comparison

Nikita Pettik korablev at tarantool.org
Tue Jun 30 02:51:29 MSK 2020


On 25 Jun 18:17, imeevma at tarantool.org wrote:
> Thank you for review! My answers and new patch below.
> 
> On 22.06.2020 15:25, Nikita Pettik wrote:
> > On 17 Jun 15:36, imeevma at tarantool.org wrote:
> >> @@ -2399,14 +2387,6 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
> >>  	default:       res2 = res>=0;     break;
> >>  	}
> >>  
> >> -	/* Undo any changes made by mem_apply_type() to the input registers. */
> >> -	assert((pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn));
> >> -	pIn1->flags = flags1;
> >> -	pIn1->field_type = ft_p1;
> >> -	assert((pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn));
> >> -	pIn3->flags = flags3;
> >> -	pIn3->field_type = ft_p3;
> >> -
> >
> > Replace these assertions with relevant ones.
> >
> Not sure if this is necessary, since now we have much less flag
> changes after removal of mem_apply_type().

Не понял как это связано...Твои изменения не затрагивают
инвариант MEM_Dyn.
 
> >> @@ -0,0 +1,281 @@
> >> +#!/usr/bin/env tarantool
> >> +test = require("sqltester")
> >> +test:plan(32)
> >> +
> >> +--
> >> +
> >> +test:execsql([[
> >> +    CREATE TABLE t1(x TEXT primary key);
> >> +    INSERT INTO t1 VALUES('1');
> >> +    CREATE TABLE t2(x INTEGER primary key);
> >> +    INSERT INTO t2 VALUES(1);
> >> +    CREATE TABLE t3(x DOUBLE primary key);
> >> +    INSERT INTO t3 VALUES(1.0);
> >
> > What about table with scalar/any fields?
> >
> I think this is too big a problem to solve it here.

Гораздо лучше потом клепать фоллоу-апы, точечно затыкая креши..
Я бы добавил хотя бы самых базовых примеров.

>  			i = pIn3->u.i;
> @@ -3617,7 +3595,38 @@ skip_truncate:
>  	assert(oc!=OP_SeekGE || r.default_rc==+1);
>  	assert(oc!=OP_SeekLT || r.default_rc==+1);
>  
> +	/*
> +	 * Make sure that the types of all the fields in the tuple
> +	 * that will be used in the iterator match the field types
> +	 * of the space.
> +	 */
>  	r.aMem = &aMem[pOp->p3];
> +	for (int i = 0; i < r.nField; ++i) {
> +		enum field_type type = r.key_def->parts[i].type;
> +		struct Mem *mem = &r.aMem[i];
> +		if (mem_check_type(mem, type) == 0 ||
> +		    mem_convert_numeric(mem, type, true) == 0)
> +			continue;

Я бы все-таки разбил бы эту проверку на два условия:

if (...)
	continue
if (...)
	continue

А еще лучше вынести этот чанк в хелпер.

> +		/*
> +		 * If the number was not converted without loss,
> +		 * we will not find tuples using the EQ iterator.
> +		 */

Пожайлуста, не используй двойное отрицание - комментарий очень
сложно воспринимать. Давай это переформулируем, можно пример
добавить. Это довольно скользкое место.

> +		if ((mem->flags & MEM_Real) != 0 &&
> +		    (type == FIELD_TYPE_INTEGER ||
> +		     type == FIELD_TYPE_UNSIGNED)) {
> +			assert(eqOnly == 1);
> +			res = 1;
> +			goto seek_not_found;
> +		}
> +		if ((mem->flags & (MEM_Int | MEM_UInt)) != 0 &&
> +		    type == FIELD_TYPE_DOUBLE && eqOnly == 1) {
> +			res = 1;
> +			goto seek_not_found;
> +		}
> +		diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
> +			field_type_strs[type], mem_type_to_str(mem));
> +		goto abort_due_to_error;
> +	}
>  #ifdef SQL_DEBUG
>  	{ int i; for(i=0; i<r.nField; i++) assert(memIsValid(&r.aMem[i])); }
>  #endif
> @@ -4744,7 +4753,25 @@ case OP_IdxGE:  {       /* jump */
>  		assert(pOp->opcode==OP_IdxGE || pOp->opcode==OP_IdxLT);
>  		r.default_rc = 0;
>  	}
> +
> +	/*
> +	 * Make sure that the types of all the fields in the tuple
> +	 * that will be used in the iterator comparable with the
> +	 * fields of the space.
> +	 */
>  	r.aMem = &aMem[pOp->p3];
> +	for (int i = 0; i < r.nField; ++i) {
> +		enum field_type type = r.key_def->parts[i].type;
> +		struct Mem *mem = &r.aMem[i];

Как-то мне эти два места (выше в SeekGE) вообще не нравятся.
Какие-то они запутанные. Давай подумаем как можно зарефакторить их.

> +		if (mem_check_type(mem, type) == 0)
> +			continue;
> +		if (sql_type_is_numeric(type) &&
> +		    (mem->flags & (MEM_Real | MEM_Int | MEM_UInt)) != 0)
> +			continue;
> +		diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
> +			field_type_strs[type], mem_type_to_str(mem));
> +		goto abort_due_to_error;
> +	}
>  #ifdef SQL_DEBUG
>  	{ int i; for(i=0; i<r.nField; i++) assert(memIsValid(&r.aMem[i])); }
>  #endif
> diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
> index 6d8768865..1d7c76670 100644
> --- a/src/box/sql/wherecode.c
> +++ b/src/box/sql/wherecode.c
> @@ -335,72 +335,6 @@ disableTerm(WhereLevel * pLevel, WhereTerm * pTerm)
>  	}
>  }
>  
> -/**
> - * Code an OP_ApplyType opcode to apply the column type string
> - * @types to the n registers starting at @base.
> - *
> - * As an optimization, SCALAR entries (which are no-ops) at the
> - * beginning and end of @types are ignored.  If all entries in
> - * @types are SCALAR, then no code gets generated.
> - *
> - * This routine makes its own copy of @types so that the caller is
> - * free to modify @types after this routine returns.
> - */
> -static void
> -emit_apply_type(Parse *pParse, int base, int n, enum field_type *types)

Ты в следующем коммите как раз делаешь клин-ап. Давай эту функцию
там и удалим (как и остальные).

>  			nConstraint++;
>  		}
> -		sqlDbFree(db, start_types);
> -		sqlDbFree(db, end_types);
>  
>  		/* Top of the loop body */
>  		pLevel->p2 = sqlVdbeCurrentAddr(v);
> diff --git a/test/sql-tap/gh-4230-del-impl-cast-str-to-num.test.lua b/test/sql-tap/gh-4230-del-impl-cast-str-to-num.test.lua
> new file mode 100755
> index 000000000..b405a11b6
> --- /dev/null
> +++ b/test/sql-tap/gh-4230-del-impl-cast-str-to-num.test.lua

Когда кто-то ищет где посмотреть тесты связанные с типами,
первое что приходит в голову - грепнуть *types*. Этот тест
по сути ничего и не тестирует (уверен, эти пути уже покрыты
в других тестах), зато хорошо отображает работу системы типов.
Я бы просто подумал о других разработчиках, и все же замержил
его в какой-нибудь тест типа sql/types.test.lua.


More information about the Tarantool-patches mailing list