Skip to content

Commit 52771f0

Browse files
committed
ODBC-305,ODBC-308,ODBC-309 - fixes and testcases
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.
1 parent 8d3164f commit 52771f0

File tree

9 files changed

+369
-165
lines changed

9 files changed

+369
-165
lines changed

libmariadb

ma_desc.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -844,8 +844,7 @@ SQLRETURN MADB_DescSetField(SQLHDESC DescriptorHandle,
844844
/* Application may set IPD's field SQL_DESC_UNNAMED to SQL_UNNAMED only */
845845
if (FieldIdentifier == SQL_DESC_UNNAMED && (SQLSMALLINT)(SQLULEN)ValuePtr == SQL_NAMED)
846846
{
847-
MADB_SetError(&Desc->Error, MADB_ERR_HY092, NULL, 0);
848-
ret= Desc->Error.ReturnValue;
847+
ret= MADB_SetError(&Desc->Error, MADB_ERR_HY092, NULL, 0);
849848
}
850849

851850
if (!SQL_SUCCEEDED(ret))
@@ -921,7 +920,15 @@ SQLRETURN MADB_DescSetField(SQLHDESC DescriptorHandle,
921920
DescRecord->Precision= (SQLSMALLINT)(SQLLEN)ValuePtr;
922921
break;
923922
case SQL_DESC_SCALE:
924-
DescRecord->Scale= (SQLSMALLINT)(SQLLEN)ValuePtr;
923+
if ((SQLSMALLINT)(SQLLEN)ValuePtr > MADB_MAX_SCALE)
924+
{
925+
DescRecord->Scale= MADB_MAX_SCALE;
926+
ret= MADB_SetError(&Desc->Error, MADB_ERR_01S02, NULL, 0);
927+
}
928+
else
929+
{
930+
DescRecord->Scale= (SQLSMALLINT)(SQLLEN)ValuePtr;
931+
}
925932
break;
926933
case SQL_DESC_TYPE:
927934
DescRecord->Type= (SQLSMALLINT)(SQLLEN)ValuePtr;

ma_helper.c

Lines changed: 97 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -984,96 +984,129 @@ int MADB_CharToSQLNumeric(char *buffer, MADB_Desc *Ard, MADB_DescRecord *ArdReco
984984
int ret= 0;
985985

986986
if (!buffer || !number)
987+
{
987988
return ret;
989+
}
988990

989991
p= trim(buffer);
990992
MADB_NumericInit(number, ArdRecord);
991993

992-
if (!(number->sign= (*p=='-') ? 0 : 1))
994+
/* Determining the sign of the number. From now on we dean with unsigned number */
995+
if (!(number->sign = (*p == '-') ? 0 : 1))
996+
{
993997
p++;
998+
}
999+
/* Empty string - nothing to do*/
9941000
if (!*p)
995-
return FALSE;
1001+
{
1002+
return ret;
1003+
}
9961004

9971005
if (number->precision == 0)
9981006
{
9991007
number->precision= MADB_DEFAULT_PRECISION;
10001008
}
10011009

1002-
while (*p=='0')
1010+
/* Skipping leading zeroes */
1011+
while (*p == '0')
10031012
{
1004-
p++;
1013+
++p;
10051014
}
10061015
if (*p)
10071016
{
10081017
int i;
1009-
int bit, hval, tv, dig, sta, olen;
1010-
int tmp_digit= 0;
1018+
unsigned int bit, hval, tv, dig, sta, olen;
10111019
int leading_zeros= 0;
10121020
char *dot= strchr(p, '.');
10131021
char digits[100];
1014-
short digits_count= 0;
1022+
unsigned short digits_count= 0; /* integer part digits count*/
1023+
1024+
if (dot == NULL)
1025+
{
1026+
char* end= p;
1027+
while (*end && isdigit(0x000000ff & *end))
1028+
++end;
10151029

1016-
/* Overflow check */
1017-
if (number->precision > 0 && (dot - p) > number->precision)
1030+
digits_count= (unsigned short)(end - p);
1031+
}
1032+
else
1033+
{
1034+
digits_count= (unsigned short)(dot - p);
1035+
}
1036+
/* Overflow checks */
1037+
if (digits_count > MADB_DEFAULT_PRECISION + 1 ) /* 16 bytes of FF make up 39 digits number */
1038+
{
10181039
return MADB_ERR_22003;
1019-
1040+
}
1041+
if (number->precision > 0 && digits_count > number->precision)
1042+
{
1043+
/* if scale is negative, and we have just enough zeroes at the end - we are fine, there is no overflow */
1044+
if (number->scale < 0 && (number->precision - number->scale) >= digits_count)
1045+
{
1046+
/* Checking that all digits past presision are '0'. Otherwise - overflow */
1047+
for (i = digits_count - number->precision; i > 0; --i)
1048+
{
1049+
if (*(p + digits_count - i) != '0')
1050+
{
1051+
return MADB_ERR_22003;
1052+
}
1053+
}
1054+
}
1055+
else
1056+
{
1057+
return MADB_ERR_22003;
1058+
}
1059+
}
1060+
1061+
memcpy(digits, p, digits_count);
1062+
10201063
if (dot && number->scale > 0)
10211064
{
1022-
short digits_total= 0,
1023-
digits_significant= 0;
1024-
digits_count= (short)(dot - p);
1025-
memcpy(digits, p, digits_count);
1065+
short digits_total= 0, /* fractional part total digits */
1066+
digits_significant= 0; /* fractional part significant digits(not counting 0 at the end) */
1067+
10261068
p= dot + 1;
10271069
while (*p)
10281070
{
10291071
/* ignore non numbers */
10301072
if (!isdigit(0x000000ff & *p))
10311073
break;
1032-
digits_total++;
1074+
++digits_total;
10331075
/* ignore trailing zeros */
10341076
if (*p != '0')
10351077
{
10361078
digits_significant= digits_total;
10371079
}
1038-
p++;
1080+
++p;
10391081
}
10401082

1041-
if (digits_count + number->scale > number->precision)
1083+
/* 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 */
1084+
if (digits_count + digits_significant > number->precision && digits_significant <= number->scale)
10421085
{
1043-
int i;
1086+
return MADB_ERR_22003;
10441087
/* if digits are zero there is no overflow */
1045-
for (i=1; i <= digits_significant; i++)
1088+
/*for (p= dot + 1; p <= dot + digits_significant; ++p)
10461089
{
1047-
p= dot + i;
10481090
if (*p != '0')
1049-
return MADB_ERR_22003;
1050-
}
1091+
1092+
}*/
10511093
}
10521094

1053-
memcpy(digits + digits_count, dot + 1, digits_significant);
1054-
if (number->scale > digits_significant)
1095+
if (digits_significant > number->scale)
1096+
{
1097+
ret= MADB_ERR_01S07;
1098+
memcpy(digits + digits_count, dot + 1, number->scale);
1099+
}
1100+
else
10551101
{
1056-
for (i= digits_count + digits_significant; i < number->precision && i < digits_count +number->scale; ++i)
1102+
memcpy(digits + digits_count, dot + 1, digits_significant);
1103+
1104+
for (i= digits_count + digits_significant; i < digits_count + number->scale; ++i)
10571105
{
10581106
digits[i]= '0';
10591107
}
1060-
digits_significant= number->scale;
1061-
}
1062-
digits_count+= digits_significant;
1063-
}
1064-
else
1065-
{
1066-
char *start= p;
1067-
while (*p && isdigit(0x000000ff & *p))
1068-
p++;
1069-
/* check overflow */
1070-
if (p - start > number->precision)
1071-
{
1072-
return MADB_ERR_22003;
10731108
}
1074-
digits_count= (short)(p - start);
1075-
memcpy(digits, start, digits_count);
1076-
number->scale= ArdRecord->Scale ? ArdRecord->Scale : 0;
1109+
digits_count+= number->scale;
10771110
}
10781111

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

1085-
digits[number->precision]= 0;
1118+
//if (digits_count <= number->precision)
1119+
{
1120+
digits[digits_count/*number->precision*/]= 0;
1121+
}
10861122
Val= _atoi64(digits);
10871123

10881124
OldVal= Val;
10891125
Val= (Val + RoundNumber / 2) / RoundNumber * RoundNumber;
10901126
if (OldVal != Val)
1127+
{
10911128
return MADB_ERR_22003;
1092-
_snprintf(digits, sizeof(digits), "%lld", Val);
1129+
}
1130+
_snprintf(digits, sizeof(digits), "%lld", Val/RoundNumber);
10931131
digits_count= (short)strlen(digits);
10941132
if (digits_count > number->precision)
10951133
return MADB_ERR_22003;
10961134
}
10971135

1098-
digits_count= MIN(digits_count, MADB_DEFAULT_PRECISION);
1136+
digits_count= MIN(digits_count, MADB_DEFAULT_PRECISION + 1);
10991137
for (hval = 0, bit = 1L, sta = 0, olen = 0; sta < digits_count;)
11001138
{
11011139
for (dig = 0, i = sta; i < digits_count; i++)
@@ -1111,20 +1149,28 @@ int MADB_CharToSQLNumeric(char *buffer, MADB_Desc *Ard, MADB_DescRecord *ArdReco
11111149
bit <<= 1;
11121150
if (bit >= (1L << 8))
11131151
{
1114-
number->val[olen++] = hval;
1115-
hval = 0;
1116-
bit = 1L;
1117-
if (olen >= SQL_MAX_NUMERIC_LEN - 1)
1152+
if (olen >= SQL_MAX_NUMERIC_LEN)
11181153
{
11191154
//number->scale = sta - number->precision;
1120-
//ret= MADB_ERR_22003;
1155+
ret= MADB_ERR_22003;
11211156
break;
11221157
}
1158+
number->val[olen++] = hval;
1159+
hval = 0;
1160+
bit = 1L;
1161+
11231162
}
11241163
}
1125-
if (hval && olen < SQL_MAX_NUMERIC_LEN - 1)
1164+
if (hval != 0)
11261165
{
1127-
number->val[olen++] = hval;
1166+
if (olen < SQL_MAX_NUMERIC_LEN)
1167+
{
1168+
number->val[olen++] = hval;
1169+
}
1170+
else
1171+
{
1172+
ret= MADB_ERR_22003;
1173+
}
11281174
}
11291175
}
11301176
return ret;

ma_odbc.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -420,12 +420,13 @@ int DSNPrompt_Lookup(MADB_Prompt *prompt, const char *SetupLibName);
420420

421421
int DSNPrompt_Free (MADB_Prompt *prompt);
422422

423-
int InitClientCharset (Client_Charset *cc, const char * name);
424-
void CopyClientCharset(Client_Charset * Src, Client_Charset * Dst);
425-
void CloseClientCharset(Client_Charset *cc);
423+
int InitClientCharset (Client_Charset *cc, const char *name);
424+
void CopyClientCharset (Client_Charset *Src, Client_Charset *Dst);
425+
void CloseClientCharset(Client_Charset *cc);
426426

427427
/* Default precision of SQL_NUMERIC */
428428
#define MADB_DEFAULT_PRECISION 38
429+
#define MADB_MAX_SCALE MADB_DEFAULT_PRECISION
429430
#define BINARY_CHARSETNR 63
430431
/* Inexistent param id */
431432
#define MADB_NOPARAM -1

0 commit comments

Comments
 (0)