[tarantool-patches] Re: [PATCH 01/13] sql: Convert big integers from string

Stanislav Zudin szudin at tarantool.org
Mon Apr 1 23:39:06 MSK 2019



On 25.03.2019 18:10, n.pettik wrote:
> 
> 
>> On 15 Mar 2019, at 18:45, Stanislav Zudin <szudin at tarantool.org> wrote:
>>
>> Correctly handles the signed and unsigned integers on the way from sql
>> expression to VDBE.
>> VDBE doesn't distinguish yet signed and unsigned integers.
> 
> Firstly, please add tag to each patch related to patch-set:
> 
> Part of #….
> 
> Or
> 
> Needed for #…

Got it.

> 
> Secondly, several tests fail on this patch:
> Failed tasks:
> - [sql-tap/cast.test.lua, memtx]
> - [sql-tap/tkt-a8a0d2996a.test.lua, memtx]
> - [sql-tap/misc3.test.lua, memtx]
> - [sql-tap/in4.test.lua, memtx]
> 
> sql/gh-2347-max-int-literals.test.lua           vinyl           [ fail ]
> 

The final commit does pass these tests.

> AFAIK we follow policy stating that each separate patch
> shouldn’t break existing tests. Mb you should reconsider
> structure of your patch-set.
> 
>> src/box/sql/expr.c   |  23 ++++---
>> src/box/sql/main.c   |   2 +-
>> src/box/sql/sqlInt.h |  63 +++++++++++------
>> src/box/sql/util.c   | 160 +++++++++++++++++++------------------------
>> src/box/sql/vdbe.c   |   2 +-
>> 5 files changed, 125 insertions(+), 125 deletions(-)
>>
>> diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
>> index 82688dff3..3fbfab7a0 100644
>> --- a/src/box/sql/expr.c
>> +++ b/src/box/sql/expr.c
>> @@ -3335,23 +3335,24 @@ expr_code_int(struct Parse *parse, struct Expr *expr, bool is_neg,
>> 		int64_t value;
>> 		const char *z = expr->u.zToken;
>> 		assert(z != NULL);
>> -		int c = sql_dec_or_hex_to_i64(z, &value);
>> -		if (c == 1 || (c == 2 && !is_neg) ||
>> -		    (is_neg && value == SMALLEST_INT64)) {
>> +		enum atoi_result c = sql_dec_or_hex_to_i64(z, is_neg, &value);
> 
> I suggest to make all atoi return -1 in case of errors (including overflow),
> and 0 in case of successful conversion. Error itself you can set via diag_set().
> Sign of the result you can pass via output param.
> This way would be more Tarantool-like.

Accepted. Fixed.

> 
> Moreover, instead of storing UINT in INT, I suggest to use fair enum and
> output param is_uint/is_negative/is_whatever/…
> 
> Finally, please add comment explaining that unsigned value is returned
> only in case when value can’t be fitted into int64 range. I don’t see
> such explanation, so at the first sight code may look weird.

Done.
BTW. The declaration of atoi* function contains such explanation

> 
>> +		switch(c) {
>> +		case ATOI_OVERFLOW:
>> 			if (sql_strnicmp(z, "0x", 2) == 0) {
>> 				sqlErrorMsg(parse,
>> -						"hex literal too big: %s%s",
>> -						is_neg ? "-" : "", z);
>> +					    "hex literal too big: %s%s",
>> +					    is_neg ? "-" : "", z);
>> 			} else {
>> 				sqlErrorMsg(parse,
>> -						"oversized integer: %s%s",
>> -						is_neg ? "-" : "", z);
>> +					    "oversized integer: %s%s",
>> +					    is_neg ? "-" : "", z);
>> 			}
>> -		} else {
>> -			if (is_neg)
>> -				value = c == 2 ? SMALLEST_INT64 : -value;
>> +			break;
>> +		case ATOI_UNSIGNED:
>> +		case ATOI_SIGNED:
>> 			sqlVdbeAddOp4Dup8(v, OP_Int64, 0, mem, 0,
>> -					      (u8 *)&value, P4_INT64);
>> +					  (u8 *)&value, P4_INT64);
>> +			break;
>> 		}
>> 	}
>> }
>>
>>
>> index c89e2e8ab..be77f72f8 100644
>> --- a/src/box/sql/util.c
>> +++ b/src/box/sql/util.c
>> @@ -591,110 +591,56 @@ sqlAtoF(const char *z, double *pResult, int length)
>> #endif				/* SQL_OMIT_FLOATING_POINT */
>> -int
>> +enum atoi_result
>> sql_atoi64(const char *z, int64_t *val, int length)
>> {
>> -	int incr = 1;
>> -	u64 u = 0;
>> 	int neg = 0;		/* assume positive */
>> -	int i;
>> -	int c = 0;
>> -	int nonNum = 0;		/* True if input contains UTF16 with high byte non-zero */
>> -	const char *zStart;
>> 	const char *zEnd = z + length;
>> -	incr = 1;
>> +	int incr = 1;
>> 	while (z < zEnd && sqlIsspace(*z))
>> 		z += incr;
>> -	if (z < zEnd) {
>> -		if (*z == '-') {
>> -			neg = 1;
>> -			z += incr;
>> -		} else if (*z == '+') {
>> -			z += incr;
>> -		}
>> -	}
>> -	zStart = z;
>> -	/* Skip leading zeros. */
>> -	while (z < zEnd && z[0] == '0') {
>> +
>> +	if (z >= zEnd)
>> +		return ATOI_OVERFLOW; /* invalid format */
> 
> It’s not fair to return OVERFLOW result in case of “invalid format”.
> See my comment concerning return values above.
> 
>> +	if (*z == '-') {
>> +		neg = 1;
>> 		z += incr;
>> 	}
>> -	for (i = 0; &z[i] < zEnd && (c = z[i]) >= '0' && c <= '9';
>> -	     i += incr) {
>> -		u = u * 10 + c - '0';
>> -	}
>> -	if (u > LARGEST_INT64) {
>> -		*val = neg ? SMALLEST_INT64 : LARGEST_INT64;
>> -	} else if (neg) {
>> -		*val = -(i64) u;
>> +
>> +	char* end = NULL;
> 
> According to docs, you should set errno to 0 before
> calling this function.

Good point.
Fixed.

> 
>> +	u64 u = strtoull(z, &end, 10);
>> +	if (end == z)
>> +		return ATOI_OVERFLOW;
> 
> In this case, it’s not overflow but error like “"No digits were found”.
> 
>> +	if (errno == ERANGE)
>> +		return ATOI_OVERFLOW;
> 
> Not only ERANGE errors can occur.
> Correct way of testing on occurred errors is shown here:
> https://linux.die.net/man/3/strtol
> 
>   if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
>              || (errno != 0 && val == 0))

IMO the (errno != 0) covers all faulty cases.

> 
> If these error should be caught before, then add assertions pls.
> 
> 




More information about the Tarantool-patches mailing list