Skip to content

Commit

Permalink
ODBC-305,ODBC-308,ODBC-309 - fixes and testcases
Browse files Browse the repository at this point in the history
This commit combines fixes of processing SQL_NUMERIC type, i.e.
converting it in both directions - to and from. Problems include
icorrect conversion, not detecting or incorrect detecting of overflows. It also contains
testcases and fixes for testcases.
ODBC-309 is more general about not returning data conversion warnings
during query execution. That caused not returning warning of numeric
fractional truncation in some cases.
C/C submodule has been updated to v.3.1.12
The testcase for ODBC-235, that doesn't not reproduce the problem, but
implements sane feature use in defined conditions.
  • Loading branch information
lawrinn committed Apr 14, 2021
1 parent 8d3164f commit 52771f0
Show file tree
Hide file tree
Showing 9 changed files with 369 additions and 165 deletions.
2 changes: 1 addition & 1 deletion libmariadb
13 changes: 10 additions & 3 deletions ma_desc.c
Original file line number Diff line number Diff line change
Expand Up @@ -844,8 +844,7 @@ SQLRETURN MADB_DescSetField(SQLHDESC DescriptorHandle,
/* Application may set IPD's field SQL_DESC_UNNAMED to SQL_UNNAMED only */
if (FieldIdentifier == SQL_DESC_UNNAMED && (SQLSMALLINT)(SQLULEN)ValuePtr == SQL_NAMED)
{
MADB_SetError(&Desc->Error, MADB_ERR_HY092, NULL, 0);
ret= Desc->Error.ReturnValue;
ret= MADB_SetError(&Desc->Error, MADB_ERR_HY092, NULL, 0);
}

if (!SQL_SUCCEEDED(ret))
Expand Down Expand Up @@ -921,7 +920,15 @@ SQLRETURN MADB_DescSetField(SQLHDESC DescriptorHandle,
DescRecord->Precision= (SQLSMALLINT)(SQLLEN)ValuePtr;
break;
case SQL_DESC_SCALE:
DescRecord->Scale= (SQLSMALLINT)(SQLLEN)ValuePtr;
if ((SQLSMALLINT)(SQLLEN)ValuePtr > MADB_MAX_SCALE)
{
DescRecord->Scale= MADB_MAX_SCALE;
ret= MADB_SetError(&Desc->Error, MADB_ERR_01S02, NULL, 0);
}
else
{
DescRecord->Scale= (SQLSMALLINT)(SQLLEN)ValuePtr;
}
break;
case SQL_DESC_TYPE:
DescRecord->Type= (SQLSMALLINT)(SQLLEN)ValuePtr;
Expand Down
148 changes: 97 additions & 51 deletions ma_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -984,96 +984,129 @@ int MADB_CharToSQLNumeric(char *buffer, MADB_Desc *Ard, MADB_DescRecord *ArdReco
int ret= 0;

if (!buffer || !number)
{
return ret;
}

p= trim(buffer);
MADB_NumericInit(number, ArdRecord);

if (!(number->sign= (*p=='-') ? 0 : 1))
/* Determining the sign of the number. From now on we dean with unsigned number */
if (!(number->sign = (*p == '-') ? 0 : 1))
{
p++;
}
/* Empty string - nothing to do*/
if (!*p)
return FALSE;
{
return ret;
}

if (number->precision == 0)
{
number->precision= MADB_DEFAULT_PRECISION;
}

while (*p=='0')
/* Skipping leading zeroes */
while (*p == '0')
{
p++;
++p;
}
if (*p)
{
int i;
int bit, hval, tv, dig, sta, olen;
int tmp_digit= 0;
unsigned int bit, hval, tv, dig, sta, olen;
int leading_zeros= 0;
char *dot= strchr(p, '.');
char digits[100];
short digits_count= 0;
unsigned short digits_count= 0; /* integer part digits count*/

if (dot == NULL)
{
char* end= p;
while (*end && isdigit(0x000000ff & *end))
++end;

/* Overflow check */
if (number->precision > 0 && (dot - p) > number->precision)
digits_count= (unsigned short)(end - p);
}
else
{
digits_count= (unsigned short)(dot - p);
}
/* Overflow checks */
if (digits_count > MADB_DEFAULT_PRECISION + 1 ) /* 16 bytes of FF make up 39 digits number */
{
return MADB_ERR_22003;

}
if (number->precision > 0 && digits_count > number->precision)
{
/* if scale is negative, and we have just enough zeroes at the end - we are fine, there is no overflow */
if (number->scale < 0 && (number->precision - number->scale) >= digits_count)
{
/* Checking that all digits past presision are '0'. Otherwise - overflow */
for (i = digits_count - number->precision; i > 0; --i)
{
if (*(p + digits_count - i) != '0')
{
return MADB_ERR_22003;
}
}
}
else
{
return MADB_ERR_22003;
}
}

memcpy(digits, p, digits_count);

if (dot && number->scale > 0)
{
short digits_total= 0,
digits_significant= 0;
digits_count= (short)(dot - p);
memcpy(digits, p, digits_count);
short digits_total= 0, /* fractional part total digits */
digits_significant= 0; /* fractional part significant digits(not counting 0 at the end) */

p= dot + 1;
while (*p)
{
/* ignore non numbers */
if (!isdigit(0x000000ff & *p))
break;
digits_total++;
++digits_total;
/* ignore trailing zeros */
if (*p != '0')
{
digits_significant= digits_total;
}
p++;
++p;
}

if (digits_count + number->scale > number->precision)
/* Kinda tricky. let's say precision is 5.2. 1234.5 is fine, 1234.56 is overflow, 123.456 fractional overflow with rounding and warning */
if (digits_count + digits_significant > number->precision && digits_significant <= number->scale)
{
int i;
return MADB_ERR_22003;
/* if digits are zero there is no overflow */
for (i=1; i <= digits_significant; i++)
/*for (p= dot + 1; p <= dot + digits_significant; ++p)
{
p= dot + i;
if (*p != '0')
return MADB_ERR_22003;
}
}*/
}

memcpy(digits + digits_count, dot + 1, digits_significant);
if (number->scale > digits_significant)
if (digits_significant > number->scale)
{
ret= MADB_ERR_01S07;
memcpy(digits + digits_count, dot + 1, number->scale);
}
else
{
for (i= digits_count + digits_significant; i < number->precision && i < digits_count +number->scale; ++i)
memcpy(digits + digits_count, dot + 1, digits_significant);

for (i= digits_count + digits_significant; i < digits_count + number->scale; ++i)
{
digits[i]= '0';
}
digits_significant= number->scale;
}
digits_count+= digits_significant;
}
else
{
char *start= p;
while (*p && isdigit(0x000000ff & *p))
p++;
/* check overflow */
if (p - start > number->precision)
{
return MADB_ERR_22003;
}
digits_count= (short)(p - start);
memcpy(digits, start, digits_count);
number->scale= ArdRecord->Scale ? ArdRecord->Scale : 0;
digits_count+= number->scale;
}

/* Rounding */
Expand All @@ -1082,20 +1115,25 @@ int MADB_CharToSQLNumeric(char *buffer, MADB_Desc *Ard, MADB_DescRecord *ArdReco
int64_t OldVal, Val;
int64_t RoundNumber= (int64_t)pow(10.0, -number->scale);

digits[number->precision]= 0;
//if (digits_count <= number->precision)
{
digits[digits_count/*number->precision*/]= 0;
}
Val= _atoi64(digits);

OldVal= Val;
Val= (Val + RoundNumber / 2) / RoundNumber * RoundNumber;
if (OldVal != Val)
{
return MADB_ERR_22003;
_snprintf(digits, sizeof(digits), "%lld", Val);
}
_snprintf(digits, sizeof(digits), "%lld", Val/RoundNumber);
digits_count= (short)strlen(digits);
if (digits_count > number->precision)
return MADB_ERR_22003;
}

digits_count= MIN(digits_count, MADB_DEFAULT_PRECISION);
digits_count= MIN(digits_count, MADB_DEFAULT_PRECISION + 1);
for (hval = 0, bit = 1L, sta = 0, olen = 0; sta < digits_count;)
{
for (dig = 0, i = sta; i < digits_count; i++)
Expand All @@ -1111,20 +1149,28 @@ int MADB_CharToSQLNumeric(char *buffer, MADB_Desc *Ard, MADB_DescRecord *ArdReco
bit <<= 1;
if (bit >= (1L << 8))
{
number->val[olen++] = hval;
hval = 0;
bit = 1L;
if (olen >= SQL_MAX_NUMERIC_LEN - 1)
if (olen >= SQL_MAX_NUMERIC_LEN)
{
//number->scale = sta - number->precision;
//ret= MADB_ERR_22003;
ret= MADB_ERR_22003;
break;
}
number->val[olen++] = hval;
hval = 0;
bit = 1L;

}
}
if (hval && olen < SQL_MAX_NUMERIC_LEN - 1)
if (hval != 0)
{
number->val[olen++] = hval;
if (olen < SQL_MAX_NUMERIC_LEN)
{
number->val[olen++] = hval;
}
else
{
ret= MADB_ERR_22003;
}
}
}
return ret;
Expand Down
7 changes: 4 additions & 3 deletions ma_odbc.h
Original file line number Diff line number Diff line change
Expand Up @@ -420,12 +420,13 @@ int DSNPrompt_Lookup(MADB_Prompt *prompt, const char *SetupLibName);

int DSNPrompt_Free (MADB_Prompt *prompt);

int InitClientCharset (Client_Charset *cc, const char * name);
void CopyClientCharset(Client_Charset * Src, Client_Charset * Dst);
void CloseClientCharset(Client_Charset *cc);
int InitClientCharset (Client_Charset *cc, const char *name);
void CopyClientCharset (Client_Charset *Src, Client_Charset *Dst);
void CloseClientCharset(Client_Charset *cc);

/* Default precision of SQL_NUMERIC */
#define MADB_DEFAULT_PRECISION 38
#define MADB_MAX_SCALE MADB_DEFAULT_PRECISION
#define BINARY_CHARSETNR 63
/* Inexistent param id */
#define MADB_NOPARAM -1
Expand Down
Loading

0 comments on commit 52771f0

Please sign in to comment.