From d40f4d8c136101a9c1cd73f94d19e1ad96d4a699 Mon Sep 17 00:00:00 2001 From: TimelordUK Date: Sat, 24 Oct 2026 18:59:58 +0100 Subject: [PATCH] fix: numeric strings read decimal, money and smallmoney as exact text, as numeric (#498) decimal is numeric under another name, but under numeric strings it went through a double (digits lost, "5" where numeric gives "5.00"). SQL_DECIMAL now takes numeric's path: the driver's text, every digit and the scale. Both get the zero before the point the driver leaves out ("-0.50", was "-.50"). Prepared statements still bind these columns as a double: corpus scripts/issue-498-prepared pins it as known-bug. scripts/issue-498 is agreed. Co-Authored-By: Claude Opus 5.5 (1M context) --- cpp/include/odbc/odbc_statement_legacy.h | 1 + cpp/src/odbc/odbc_statement_legacy.cpp | 43 ++++++++++++++++++- lib/index.d.ts | 4 +- test/contract/HANDOVER.md | 12 +++--- .../corpus/scripts/issue-498-prepared.txt | 20 +++++++++ test/contract/corpus/scripts/issue-498.txt | 29 +++---------- .../scripts/issue-498-prepared.win32.json | 1 + .../native/scripts/issue-498.win32.json | 2 +- test/contract/scripts/issue-498-prepared.js | 18 ++++++++ test/contract/scripts/issue-498.js | 16 +------ test/params-complete-refactored.test.js | 21 +++++++-- 11 files changed, 117 insertions(+), 50 deletions(-) create mode 100644 test/contract/corpus/scripts/issue-498-prepared.txt create mode 100644 test/contract/native/scripts/issue-498-prepared.win32.json create mode 100644 test/contract/scripts/issue-498-prepared.js diff --git a/cpp/include/odbc/odbc_statement_legacy.h b/cpp/include/odbc/odbc_statement_legacy.h index 28d38a33..e1f421f9 100644 --- a/cpp/include/odbc/odbc_statement_legacy.h +++ b/cpp/include/odbc/odbc_statement_legacy.h @@ -151,6 +151,7 @@ class OdbcStatementLegacy : public IOdbcStatement { SQLRETURN poll_check(SQLRETURN ret, shared_ptr> vec, const bool direct); bool get_data_binary(size_t row_id, size_t column); bool get_data_decimal(size_t row_id, size_t column); + bool get_data_numeric_string(size_t row_id, size_t column); bool get_data_numeric(size_t row_id, size_t column); bool get_data_bit(size_t row_id, size_t column); bool get_data_timestamp(size_t row_id, size_t column); diff --git a/cpp/src/odbc/odbc_statement_legacy.cpp b/cpp/src/odbc/odbc_statement_legacy.cpp index 52d9c923..6862d3d2 100644 --- a/cpp/src/odbc/odbc_statement_legacy.cpp +++ b/cpp/src/odbc/odbc_statement_legacy.cpp @@ -1458,15 +1458,17 @@ bool OdbcStatementLegacy::dispatch( } break; + // decimal (and money, smallmoney) is numeric under another name: under numeric strings + // both are the driver's exact text, never a double (#498) case SQL_NUMERIC: + case SQL_DECIMAL: if (_numericStringEnabled) { - res = try_read_string(false, row_id, column); + res = get_data_numeric_string(row_id, column); } else { res = get_data_decimal(row_id, column); } break; - case SQL_DECIMAL: case SQL_REAL: case SQL_FLOAT: case SQL_DOUBLE: @@ -1976,6 +1978,43 @@ bool OdbcStatementLegacy::get_data_decimal(const size_t row_id, const size_t col return true; } +// a numeric or decimal as the driver's text, which keeps every digit and the scale ("5.00"). +// the driver leaves out the zero before the point ("-.50"); it is put back ("-0.50"). +bool OdbcStatementLegacy::get_data_numeric_string(const size_t row_id, const size_t column) { + // 38 digits, a sign and a point + constexpr SQLLEN capacity = 64; + constexpr auto unit = static_cast(sizeof(uint16_t)); + std::vector text(capacity, 0); + SQLLEN value_len = 0; + const auto ret = _odbcApi->SQLGetData(_statement->get_handle(), + static_cast(column + 1), + SQL_C_WCHAR, + text.data(), + capacity * unit, + &value_len); + if (!check_odbc_error(ret)) { + SQL_LOG_DEBUG_STREAM("get_data_numeric_string failed to get data"); + return false; + } + if (value_len == SQL_NULL_DATA) { + _resultset->add_column(row_id, make_shared(column)); + return true; + } + auto len = static_cast(value_len / unit); + if (len >= static_cast(capacity)) { + len = static_cast(capacity) - 1; + } + text.resize(len); + const auto sign = !text.empty() && text[0] == u'-' ? 1 : 0; + if (text.size() > static_cast(sign) && text[sign] == u'.') { + text.insert(text.begin() + sign, u'0'); + } + const auto size = text.size(); + const auto storage = make_shared>(std::move(text)); + _resultset->add_column(row_id, make_shared(column, storage, 0, size)); + return true; +} + bool OdbcStatementLegacy::get_data_binary(const size_t row_id, const size_t column) { auto storage = make_shared(); diff --git a/lib/index.d.ts b/lib/index.d.ts index 9c270ddc..0c085a74 100755 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -754,7 +754,9 @@ declare namespace MsNodeSqlV8 { id: number /** * optionally return all number based columns as strings - * to prevent exceeding max numeric for JS + * to prevent exceeding max numeric for JS. numeric, decimal, money and + * smallmoney are the server's exact text, with their scale and a leading + * zero ('5.00', '-0.50'); float and real are the text String(n) gives. * @param numericString boolean true for numers as strings. */ setUseNumericString: (numericString: boolean) => void diff --git a/test/contract/HANDOVER.md b/test/contract/HANDOVER.md index cf1df23d..2161fffc 100644 --- a/test/contract/HANDOVER.md +++ b/test/contract/HANDOVER.md @@ -49,11 +49,13 @@ Repros in `repro/i497.js`, `repro/i498.js`; corpus `scripts/issue-497` (+ `-ns`, - **bigint max read as a double** came back as INT64_MIN: the int64 range check used bounds that round to 2^63. Bounds exact as doubles now. - **#498 part 1 fixed:** a double under numeric strings is `String(n)`'s text (`"1e-10"`), not `%f`. -- **#498 part 2 open, the owner's call:** `decimal`, `money` and `smallmoney` are still read as a - double, so under numeric strings digits beyond a double are lost (`decimal(38,2)` with 20 - integer digits, large `money`); a prepared statement binds `numeric` as a double too. The fix, - reading `SQL_DECIMAL` as text like `SQL_NUMERIC`, changes what users get: the driver's text - keeps the scale (`"5.00"`) and has no leading zero (`".0000001"`, as `numeric` already does). +- **#498 part 2 fixed (owner's call: option 1, no new config):** under numeric strings `decimal`, + `money` and `smallmoney` are read as the driver's text, as `numeric` is - they are the same + type to SQL Server, and gave different text ("5" against "5.00"). Both now get the leading zero + the driver leaves out ("-0.50", not "-.50"). Corpus `scripts/issue-498` agreed. +- **#498 still open: prepared statements** bind `numeric`/`decimal` result columns as a double + (`bound_datum.cpp` reserve, `reserved_decimal`), so they still lose digits under numeric + strings. Pinned `known-bug` in `scripts/issue-498-prepared`; needs a text binding. - The replay keeps whole rows for scripts now (`run-one.js`), so a script's column values replay. A transcript stops at 400 lines: split a script that needs more (as `issue-497-ns`). diff --git a/test/contract/corpus/scripts/issue-498-prepared.txt b/test/contract/corpus/scripts/issue-498-prepared.txt new file mode 100644 index 00000000..5247eb1f --- /dev/null +++ b/test/contract/corpus/scripts/issue-498-prepared.txt @@ -0,0 +1,20 @@ +# scenario: scripts/issue-498-prepared +# status: known-bug +# script: test/contract/scripts/issue-498-prepared.js +# #498: a prepared statement binds numeric and decimal result columns as a double, so column 1 +# loses digits (should be "12345678901234567.89") +setup: submitted +setup: rowcount 1 +setup: cb ok rows=0 more=false +setup: done +setup: free +== prepared, numeric strings on +ps: submitted +ps: meta n,d,f +ps: row +ps: column 0 "1.0123456789" +ps: column 1 "12345678901234568" +ps: column 2 "1e-10" +ps: done +ps: free +check ok diff --git a/test/contract/corpus/scripts/issue-498.txt b/test/contract/corpus/scripts/issue-498.txt index 033bd652..ecf9a15a 100644 --- a/test/contract/corpus/scripts/issue-498.txt +++ b/test/contract/corpus/scripts/issue-498.txt @@ -1,9 +1,6 @@ # scenario: scripts/issue-498 -# status: known-bug +# status: agreed # script: test/contract/scripts/issue-498.js -# #498: doubles now print as String(n) does. still open: decimal and money are read as a double, -# so digits a double cannot hold are lost (c6, c8, c10), and a prepared statement binds numeric -# as a double too (ps column 1). numeric's text has no leading zero (c14 ".0000001") -- c0 cast(0.1234567890123 as float); c1 cast(1e-10 as float); c2 cast(1.5e300 as float); c3 cast(-2.5 as float); c4 cast(0.12345678 as real); c5 cast(1.0123456789 as decimal(38,10)); c6 cast(12345678901234567890.12 as decimal(38,2)); c7 cast(0.0000001 as decimal(10,7)); c8 cast(9007199254740993 as decimal(19,0)); c9 cast(709 as decimal(10,0)); c10 cast(922337203685477.5807 as money); c11 cast(-0.0001 as money); c12 cast(1.2345 as smallmoney); c13 cast(1.0123456789 as numeric(38,10)); c14 cast(0.0000001 as numeric(10,7)); c15 cast(9223372036854775807 as bigint) == numeric strings off plain: submitted @@ -37,30 +34,16 @@ ns: column 2 "1.5e+300" ns: column 3 "-2.5" ns: column 4 "0.12345678359270096" ns: column 5 "1.0123456789" -ns: column 6 "12345678901234567000" -ns: column 7 "1e-7" -ns: column 8 "9007199254740992" +ns: column 6 "12345678901234567890.12" +ns: column 7 "0.0000001" +ns: column 8 "9007199254740993" ns: column 9 "709" -ns: column 10 "922337203685477.6" +ns: column 10 "922337203685477.5807" ns: column 11 "-0.0001" ns: column 12 "1.2345" ns: column 13 "1.0123456789" -ns: column 14 ".0000001" +ns: column 14 "0.0000001" ns: column 15 "9223372036854775807" ns: done ns: free -setup: submitted -setup: rowcount 1 -setup: cb ok rows=0 more=false -setup: done -setup: free -== prepared, numeric strings on -ps: submitted -ps: meta n,d,f -ps: row -ps: column 0 "1.0123456789" -ps: column 1 "12345678901234568" -ps: column 2 "1e-10" -ps: done -ps: free check ok diff --git a/test/contract/native/scripts/issue-498-prepared.win32.json b/test/contract/native/scripts/issue-498-prepared.win32.json new file mode 100644 index 00000000..bd0db7a8 --- /dev/null +++ b/test/contract/native/scripts/issue-498-prepared.win32.json @@ -0,0 +1 @@ +{"scenario":"scripts/issue-498-prepared","transcript":["setup: submitted","setup: rowcount 1","setup: cb ok rows=0 more=false","setup: done","setup: free","== prepared, numeric strings on","ps: submitted","ps: meta n,d,f","ps: row","ps: column 0 \"1.0123456789\"","ps: column 1 \"12345678901234568\"","ps: column 2 \"1e-10\"","ps: done","ps: free","check ok"],"log":[{"ev":"call","id":0,"t":11.7,"name":"open","args":["",0]},{"ev":"return","of":0,"t":31.7,"result":[null,{"success":true}]},{"ev":"call","id":2,"t":33.5,"name":"query","args":[0,{"query_str":"create table #p (n numeric(38,10), d decimal(38,2), f float); insert #p values (1.0123456789, 12345678901234567.89, 1e-10)","query_timeout":0,"query_polling":false,"query_tz_adjustment":0,"numeric_string":false,"bigint_as_native":false,"stateChangeCallback":{"$":"function"}},[]]},{"ev":"state","of":2,"t":33.7,"change":{"handle":{"connectionId":0,"statementId":0},"oldState":"STATEMENT_CREATED","newState":"STATEMENT_BINDING"}},{"ev":"state","of":2,"t":33.8,"change":{"handle":{"connectionId":0,"statementId":0},"oldState":"STATEMENT_BINDING","newState":"STATEMENT_SUBMITTED"}},{"ev":"state","of":2,"t":35,"change":{"handle":{"connectionId":0,"statementId":0},"oldState":"STATEMENT_SUBMITTED","newState":"STATEMENT_READING"}},{"ev":"return","of":2,"t":35,"result":[null,{"meta":[],"handle":{"connectionId":0,"statementId":0},"endOfRows":true,"endOfResults":false,"rowCount":1},true]},{"ev":"call","id":7,"t":35.2,"name":"nextResultSet","args":[0,{"connectionId":0,"statementId":0}]},{"ev":"return","of":7,"t":35.3,"result":[null,{"meta":[],"handle":{"connectionId":0,"statementId":0},"endOfRows":true,"endOfResults":true,"rowCount":1}]},{"ev":"call","id":9,"t":35.6,"name":"releaseStatement","args":[0,{"connectionId":0,"statementId":0}]},{"ev":"state","of":2,"t":35.7,"change":{"handle":{"connectionId":0,"statementId":0},"oldState":"STATEMENT_READING","newState":"STATEMENT_CLOSED"}},{"ev":"return","of":9,"t":35.7,"result":[null,true]},{"ev":"call","id":12,"t":187.8,"name":"prepare","args":[1,{"query_str":"select n, d, f from #p where 1 = ?","numeric_string":true,"bigint_as_native":false,"stateChangeCallback":{"$":"function"}}]},{"ev":"state","of":12,"t":189.5,"change":{"handle":{"connectionId":0,"statementId":1},"oldState":"STATEMENT_CREATED","newState":"STATEMENT_PREPARED"}},{"ev":"return","of":12,"t":189.5,"result":[null,{"meta":[{"name":"n","nullable":true,"type":"number","sqlType":"numeric","size":38},{"name":"d","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"f","nullable":true,"type":"number","sqlType":"float","size":53}],"handle":{"connectionId":0,"statementId":1},"endOfRows":true,"endOfResults":false,"rowCount":0}]},{"ev":"call","id":15,"t":189.8,"name":"bindQuery","args":[1,[1]]},{"ev":"state","of":12,"t":189.9,"change":{"handle":{"connectionId":0,"statementId":1},"oldState":"STATEMENT_PREPARED","newState":"STATEMENT_SUBMITTED"}},{"ev":"return","of":15,"t":193.5,"result":[null,{"meta":[{"name":"n","nullable":true,"type":"number","sqlType":"numeric","size":38},{"name":"d","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"f","nullable":true,"type":"number","sqlType":"float","size":53}],"handle":{"connectionId":0,"statementId":1},"endOfRows":false,"endOfResults":false,"rowCount":0}]},{"ev":"call","id":18,"t":193.7,"name":"fetchRows","args":[1,{"connectionId":0,"statementId":1},{"asArrays":true,"batchSize":50,"asObjects":false}]},{"ev":"return","of":18,"t":194.5,"result":[null,{"endOfRows":false,"endOfResults":false,"rowCount":1,"data":[["1.0123456789","12345678901234568","1e-10"]]}]},{"ev":"call","id":20,"t":194.7,"name":"fetchRows","args":[1,{"connectionId":0,"statementId":1},{"asArrays":true,"batchSize":50,"asObjects":false}]},{"ev":"return","of":20,"t":194.7,"result":[null,{"endOfRows":true,"endOfResults":false,"rowCount":0,"data":[]}]},{"ev":"call","id":22,"t":194.8,"name":"nextResultSet","args":[1,{"connectionId":0,"statementId":1}]},{"ev":"return","of":22,"t":194.9,"result":[null,{"meta":[{"name":"n","nullable":true,"type":"number","sqlType":"numeric","size":38},{"name":"d","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"f","nullable":true,"type":"number","sqlType":"float","size":53}],"handle":{"connectionId":0,"statementId":1},"endOfRows":true,"endOfResults":true,"rowCount":0}]},{"ev":"call","id":24,"t":195,"name":"releaseStatement","args":[1,{"connectionId":0,"statementId":1}]},{"ev":"state","of":12,"t":195,"change":{"handle":{"connectionId":0,"statementId":1},"oldState":"STATEMENT_SUBMITTED","newState":"STATEMENT_CLOSED"}},{"ev":"return","of":24,"t":195.5,"result":[null,true]},{"ev":"call","id":27,"t":346.3,"name":"query","args":[2,{"query_str":"select 1 as n","query_timeout":0,"query_polling":false,"query_tz_adjustment":0,"numeric_string":false,"bigint_as_native":false,"stateChangeCallback":{"$":"function"}},[]]},{"ev":"state","of":27,"t":346.4,"change":{"handle":{"connectionId":0,"statementId":2},"oldState":"STATEMENT_CREATED","newState":"STATEMENT_BINDING"}},{"ev":"state","of":27,"t":346.4,"change":{"handle":{"connectionId":0,"statementId":2},"oldState":"STATEMENT_BINDING","newState":"STATEMENT_SUBMITTED"}},{"ev":"state","of":27,"t":347.4,"change":{"handle":{"connectionId":0,"statementId":2},"oldState":"STATEMENT_SUBMITTED","newState":"STATEMENT_READING"}},{"ev":"return","of":27,"t":347.5,"result":[null,{"meta":[{"name":"n","nullable":false,"type":"number","sqlType":"int","size":10}],"handle":{"connectionId":0,"statementId":2},"endOfRows":true,"endOfResults":false,"rowCount":0},true]},{"ev":"call","id":32,"t":347.6,"name":"fetchRows","args":[2,{"connectionId":0,"statementId":2},{"asArrays":true,"batchSize":50,"asObjects":false}]},{"ev":"return","of":32,"t":347.6,"result":[null,{"endOfRows":true,"endOfResults":false,"rowCount":0,"data":[[1]]}]},{"ev":"call","id":34,"t":347.7,"name":"nextResultSet","args":[2,{"connectionId":0,"statementId":2}]},{"ev":"return","of":34,"t":347.8,"result":[null,{"meta":[{"name":"n","nullable":false,"type":"number","sqlType":"int","size":10}],"handle":{"connectionId":0,"statementId":2},"endOfRows":true,"endOfResults":true,"rowCount":0}]},{"ev":"call","id":36,"t":347.9,"name":"releaseStatement","args":[2,{"connectionId":0,"statementId":2}]},{"ev":"state","of":27,"t":347.9,"change":{"handle":{"connectionId":0,"statementId":2},"oldState":"STATEMENT_READING","newState":"STATEMENT_CLOSED"}},{"ev":"return","of":36,"t":347.9,"result":[null,true]},{"ev":"call","id":39,"t":348.1,"name":"close","args":[]},{"ev":"return","of":39,"t":348.2,"result":[null,true]}]} \ No newline at end of file diff --git a/test/contract/native/scripts/issue-498.win32.json b/test/contract/native/scripts/issue-498.win32.json index 7109918c..ecca9931 100644 --- a/test/contract/native/scripts/issue-498.win32.json +++ b/test/contract/native/scripts/issue-498.win32.json @@ -1 +1 @@ -{"scenario":"scripts/issue-498","transcript":["-- c0 cast(0.1234567890123 as float); c1 cast(1e-10 as float); c2 cast(1.5e300 as float); c3 cast(-2.5 as float); c4 cast(0.12345678 as real); c5 cast(1.0123456789 as decimal(38,10)); c6 cast(12345678901234567890.12 as decimal(38,2)); c7 cast(0.0000001 as decimal(10,7)); c8 cast(9007199254740993 as decimal(19,0)); c9 cast(709 as decimal(10,0)); c10 cast(922337203685477.5807 as money); c11 cast(-0.0001 as money); c12 cast(1.2345 as smallmoney); c13 cast(1.0123456789 as numeric(38,10)); c14 cast(0.0000001 as numeric(10,7)); c15 cast(9223372036854775807 as bigint)","== numeric strings off","plain: submitted","plain: meta c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15","plain: row","plain: column 0 0.1234567890123","plain: column 1 1e-10","plain: column 2 1.5e+300","plain: column 3 -2.5","plain: column 4 0.12345678359270096","plain: column 5 1.0123456789","plain: column 6 12345678901234567000","plain: column 7 1e-7","plain: column 8 9007199254740992","plain: column 9 709","plain: column 10 922337203685477.6","plain: column 11 -0.0001","plain: column 12 1.2345","plain: column 13 1.0123456789","plain: column 14 1e-7","plain: column 15 9223372036854776000","plain: done","plain: free","== numeric strings on","ns: submitted","ns: meta c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15","ns: row","ns: column 0 \"0.1234567890123\"","ns: column 1 \"1e-10\"","ns: column 2 \"1.5e+300\"","ns: column 3 \"-2.5\"","ns: column 4 \"0.12345678359270096\"","ns: column 5 \"1.0123456789\"","ns: column 6 \"12345678901234567000\"","ns: column 7 \"1e-7\"","ns: column 8 \"9007199254740992\"","ns: column 9 \"709\"","ns: column 10 \"922337203685477.6\"","ns: column 11 \"-0.0001\"","ns: column 12 \"1.2345\"","ns: column 13 \"1.0123456789\"","ns: column 14 \".0000001\"","ns: column 15 \"9223372036854775807\"","ns: done","ns: free","setup: submitted","setup: rowcount 1","setup: cb ok rows=0 more=false","setup: done","setup: free","== prepared, numeric strings on","ps: submitted","ps: meta n,d,f","ps: row","ps: column 0 \"1.0123456789\"","ps: column 1 \"12345678901234568\"","ps: column 2 \"1e-10\"","ps: done","ps: free","check ok"],"log":[{"ev":"call","id":0,"t":10.7,"name":"open","args":["",0]},{"ev":"return","of":0,"t":30,"result":[null,{"success":true}]},{"ev":"call","id":2,"t":31.6,"name":"query","args":[0,{"query_str":"select cast(0.1234567890123 as float) as c0, cast(1e-10 as float) as c1, cast(1.5e300 as float) as c2, cast(-2.5 as float) as c3, cast(0.12345678 as real) as c4, cast(1.0123456789 as decimal(38,10)) as c5, cast(12345678901234567890.12 as decimal(38,2)) as c6, cast(0.0000001 as decimal(10,7)) as c7, cast(9007199254740993 as decimal(19,0)) as c8, cast(709 as decimal(10,0)) as c9, cast(922337203685477.5807 as money) as c10, cast(-0.0001 as money) as c11, cast(1.2345 as smallmoney) as c12, cast(1.0123456789 as numeric(38,10)) as c13, cast(0.0000001 as numeric(10,7)) as c14, cast(9223372036854775807 as bigint) as c15","numeric_string":false,"bigint_as_native":false,"stateChangeCallback":{"$":"function"}},[]]},{"ev":"state","of":2,"t":31.8,"change":{"handle":{"connectionId":0,"statementId":0},"oldState":"STATEMENT_CREATED","newState":"STATEMENT_BINDING"}},{"ev":"state","of":2,"t":32,"change":{"handle":{"connectionId":0,"statementId":0},"oldState":"STATEMENT_BINDING","newState":"STATEMENT_SUBMITTED"}},{"ev":"state","of":2,"t":32.6,"change":{"handle":{"connectionId":0,"statementId":0},"oldState":"STATEMENT_SUBMITTED","newState":"STATEMENT_READING"}},{"ev":"return","of":2,"t":32.8,"result":[null,{"meta":[{"name":"c0","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c1","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c2","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c3","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c4","nullable":true,"type":"number","sqlType":"real","size":24},{"name":"c5","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"c6","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"c7","nullable":true,"type":"number","sqlType":"decimal","size":10},{"name":"c8","nullable":true,"type":"number","sqlType":"decimal","size":19},{"name":"c9","nullable":true,"type":"number","sqlType":"decimal","size":10},{"name":"c10","nullable":true,"type":"number","sqlType":"money","size":19},{"name":"c11","nullable":true,"type":"number","sqlType":"money","size":19},{"name":"c12","nullable":true,"type":"number","sqlType":"smallmoney","size":10},{"name":"c13","nullable":true,"type":"number","sqlType":"numeric","size":38},{"name":"c14","nullable":true,"type":"number","sqlType":"numeric","size":10},{"name":"c15","nullable":true,"type":"number","sqlType":"bigint","size":19}],"handle":{"connectionId":0,"statementId":0},"endOfRows":true,"endOfResults":false,"rowCount":0},true]},{"ev":"call","id":7,"t":33,"name":"fetchRows","args":[0,{"connectionId":0,"statementId":0},{"asArrays":true,"batchSize":50,"asObjects":false}]},{"ev":"return","of":7,"t":33.2,"result":[null,{"endOfRows":true,"endOfResults":false,"rowCount":0,"data":[[0.1234567890123,1e-10,1.5e+300,-2.5,0.12345678359270096,1.0123456789,12345678901234567000,1e-7,9007199254740992,709,922337203685477.6,-0.0001,1.2345,1.0123456789,1e-7,9223372036854776000]]}]},{"ev":"call","id":9,"t":33.5,"name":"nextResultSet","args":[0,{"connectionId":0,"statementId":0}]},{"ev":"return","of":9,"t":33.6,"result":[null,{"meta":[{"name":"c0","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c1","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c2","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c3","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c4","nullable":true,"type":"number","sqlType":"real","size":24},{"name":"c5","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"c6","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"c7","nullable":true,"type":"number","sqlType":"decimal","size":10},{"name":"c8","nullable":true,"type":"number","sqlType":"decimal","size":19},{"name":"c9","nullable":true,"type":"number","sqlType":"decimal","size":10},{"name":"c10","nullable":true,"type":"number","sqlType":"money","size":19},{"name":"c11","nullable":true,"type":"number","sqlType":"money","size":19},{"name":"c12","nullable":true,"type":"number","sqlType":"smallmoney","size":10},{"name":"c13","nullable":true,"type":"number","sqlType":"numeric","size":38},{"name":"c14","nullable":true,"type":"number","sqlType":"numeric","size":10},{"name":"c15","nullable":true,"type":"number","sqlType":"bigint","size":19}],"handle":{"connectionId":0,"statementId":0},"endOfRows":true,"endOfResults":true,"rowCount":0}]},{"ev":"call","id":11,"t":33.9,"name":"releaseStatement","args":[0,{"connectionId":0,"statementId":0}]},{"ev":"state","of":2,"t":34,"change":{"handle":{"connectionId":0,"statementId":0},"oldState":"STATEMENT_READING","newState":"STATEMENT_CLOSED"}},{"ev":"return","of":11,"t":34,"result":[null,true]},{"ev":"call","id":14,"t":187.7,"name":"query","args":[1,{"query_str":"select cast(0.1234567890123 as float) as c0, cast(1e-10 as float) as c1, cast(1.5e300 as float) as c2, cast(-2.5 as float) as c3, cast(0.12345678 as real) as c4, cast(1.0123456789 as decimal(38,10)) as c5, cast(12345678901234567890.12 as decimal(38,2)) as c6, cast(0.0000001 as decimal(10,7)) as c7, cast(9007199254740993 as decimal(19,0)) as c8, cast(709 as decimal(10,0)) as c9, cast(922337203685477.5807 as money) as c10, cast(-0.0001 as money) as c11, cast(1.2345 as smallmoney) as c12, cast(1.0123456789 as numeric(38,10)) as c13, cast(0.0000001 as numeric(10,7)) as c14, cast(9223372036854775807 as bigint) as c15","numeric_string":true,"bigint_as_native":false,"stateChangeCallback":{"$":"function"}},[]]},{"ev":"state","of":14,"t":187.8,"change":{"handle":{"connectionId":0,"statementId":1},"oldState":"STATEMENT_CREATED","newState":"STATEMENT_BINDING"}},{"ev":"state","of":14,"t":187.8,"change":{"handle":{"connectionId":0,"statementId":1},"oldState":"STATEMENT_BINDING","newState":"STATEMENT_SUBMITTED"}},{"ev":"state","of":14,"t":189,"change":{"handle":{"connectionId":0,"statementId":1},"oldState":"STATEMENT_SUBMITTED","newState":"STATEMENT_READING"}},{"ev":"return","of":14,"t":189.1,"result":[null,{"meta":[{"name":"c0","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c1","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c2","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c3","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c4","nullable":true,"type":"number","sqlType":"real","size":24},{"name":"c5","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"c6","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"c7","nullable":true,"type":"number","sqlType":"decimal","size":10},{"name":"c8","nullable":true,"type":"number","sqlType":"decimal","size":19},{"name":"c9","nullable":true,"type":"number","sqlType":"decimal","size":10},{"name":"c10","nullable":true,"type":"number","sqlType":"money","size":19},{"name":"c11","nullable":true,"type":"number","sqlType":"money","size":19},{"name":"c12","nullable":true,"type":"number","sqlType":"smallmoney","size":10},{"name":"c13","nullable":true,"type":"number","sqlType":"numeric","size":38},{"name":"c14","nullable":true,"type":"number","sqlType":"numeric","size":10},{"name":"c15","nullable":true,"type":"number","sqlType":"bigint","size":19}],"handle":{"connectionId":0,"statementId":1},"endOfRows":true,"endOfResults":false,"rowCount":0},true]},{"ev":"call","id":19,"t":189.1,"name":"fetchRows","args":[1,{"connectionId":0,"statementId":1},{"asArrays":true,"batchSize":50,"asObjects":false}]},{"ev":"return","of":19,"t":189.2,"result":[null,{"endOfRows":true,"endOfResults":false,"rowCount":0,"data":[["0.1234567890123","1e-10","1.5e+300","-2.5","0.12345678359270096","1.0123456789","12345678901234567000","1e-7","9007199254740992","709","922337203685477.6","-0.0001","1.2345","1.0123456789",".0000001","9223372036854775807"]]}]},{"ev":"call","id":21,"t":189.3,"name":"nextResultSet","args":[1,{"connectionId":0,"statementId":1}]},{"ev":"return","of":21,"t":189.4,"result":[null,{"meta":[{"name":"c0","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c1","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c2","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c3","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c4","nullable":true,"type":"number","sqlType":"real","size":24},{"name":"c5","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"c6","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"c7","nullable":true,"type":"number","sqlType":"decimal","size":10},{"name":"c8","nullable":true,"type":"number","sqlType":"decimal","size":19},{"name":"c9","nullable":true,"type":"number","sqlType":"decimal","size":10},{"name":"c10","nullable":true,"type":"number","sqlType":"money","size":19},{"name":"c11","nullable":true,"type":"number","sqlType":"money","size":19},{"name":"c12","nullable":true,"type":"number","sqlType":"smallmoney","size":10},{"name":"c13","nullable":true,"type":"number","sqlType":"numeric","size":38},{"name":"c14","nullable":true,"type":"number","sqlType":"numeric","size":10},{"name":"c15","nullable":true,"type":"number","sqlType":"bigint","size":19}],"handle":{"connectionId":0,"statementId":1},"endOfRows":true,"endOfResults":true,"rowCount":0}]},{"ev":"call","id":23,"t":189.4,"name":"releaseStatement","args":[1,{"connectionId":0,"statementId":1}]},{"ev":"state","of":14,"t":189.5,"change":{"handle":{"connectionId":0,"statementId":1},"oldState":"STATEMENT_READING","newState":"STATEMENT_CLOSED"}},{"ev":"return","of":23,"t":189.5,"result":[null,true]},{"ev":"call","id":26,"t":344,"name":"query","args":[2,{"query_str":"create table #p (n numeric(38,10), d decimal(38,2), f float); insert #p values (1.0123456789, 12345678901234567.89, 1e-10)","query_timeout":0,"query_polling":false,"query_tz_adjustment":0,"numeric_string":false,"bigint_as_native":false,"stateChangeCallback":{"$":"function"}},[]]},{"ev":"state","of":26,"t":344.2,"change":{"handle":{"connectionId":0,"statementId":2},"oldState":"STATEMENT_CREATED","newState":"STATEMENT_BINDING"}},{"ev":"state","of":26,"t":344.2,"change":{"handle":{"connectionId":0,"statementId":2},"oldState":"STATEMENT_BINDING","newState":"STATEMENT_SUBMITTED"}},{"ev":"state","of":26,"t":346.2,"change":{"handle":{"connectionId":0,"statementId":2},"oldState":"STATEMENT_SUBMITTED","newState":"STATEMENT_READING"}},{"ev":"return","of":26,"t":346.2,"result":[null,{"meta":[],"handle":{"connectionId":0,"statementId":2},"endOfRows":true,"endOfResults":false,"rowCount":1},true]},{"ev":"call","id":31,"t":346.2,"name":"nextResultSet","args":[2,{"connectionId":0,"statementId":2}]},{"ev":"return","of":31,"t":346.3,"result":[null,{"meta":[],"handle":{"connectionId":0,"statementId":2},"endOfRows":true,"endOfResults":true,"rowCount":1}]},{"ev":"call","id":33,"t":346.4,"name":"releaseStatement","args":[2,{"connectionId":0,"statementId":2}]},{"ev":"state","of":26,"t":346.4,"change":{"handle":{"connectionId":0,"statementId":2},"oldState":"STATEMENT_READING","newState":"STATEMENT_CLOSED"}},{"ev":"return","of":33,"t":346.4,"result":[null,true]},{"ev":"call","id":36,"t":499.5,"name":"prepare","args":[3,{"query_str":"select n, d, f from #p where 1 = ?","numeric_string":true,"bigint_as_native":false,"stateChangeCallback":{"$":"function"}}]},{"ev":"state","of":36,"t":501,"change":{"handle":{"connectionId":0,"statementId":3},"oldState":"STATEMENT_CREATED","newState":"STATEMENT_PREPARED"}},{"ev":"return","of":36,"t":501,"result":[null,{"meta":[{"name":"n","nullable":true,"type":"number","sqlType":"numeric","size":38},{"name":"d","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"f","nullable":true,"type":"number","sqlType":"float","size":53}],"handle":{"connectionId":0,"statementId":3},"endOfRows":true,"endOfResults":false,"rowCount":0}]},{"ev":"call","id":39,"t":501.2,"name":"bindQuery","args":[3,[1]]},{"ev":"state","of":36,"t":501.3,"change":{"handle":{"connectionId":0,"statementId":3},"oldState":"STATEMENT_PREPARED","newState":"STATEMENT_SUBMITTED"}},{"ev":"return","of":39,"t":504.6,"result":[null,{"meta":[{"name":"n","nullable":true,"type":"number","sqlType":"numeric","size":38},{"name":"d","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"f","nullable":true,"type":"number","sqlType":"float","size":53}],"handle":{"connectionId":0,"statementId":3},"endOfRows":false,"endOfResults":false,"rowCount":0}]},{"ev":"call","id":42,"t":504.6,"name":"fetchRows","args":[3,{"connectionId":0,"statementId":3},{"asArrays":true,"batchSize":50,"asObjects":false}]},{"ev":"return","of":42,"t":505.3,"result":[null,{"endOfRows":false,"endOfResults":false,"rowCount":1,"data":[["1.0123456789","12345678901234568","1e-10"]]}]},{"ev":"call","id":44,"t":505.4,"name":"fetchRows","args":[3,{"connectionId":0,"statementId":3},{"asArrays":true,"batchSize":50,"asObjects":false}]},{"ev":"return","of":44,"t":505.4,"result":[null,{"endOfRows":true,"endOfResults":false,"rowCount":0,"data":[]}]},{"ev":"call","id":46,"t":505.4,"name":"nextResultSet","args":[3,{"connectionId":0,"statementId":3}]},{"ev":"return","of":46,"t":505.5,"result":[null,{"meta":[{"name":"n","nullable":true,"type":"number","sqlType":"numeric","size":38},{"name":"d","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"f","nullable":true,"type":"number","sqlType":"float","size":53}],"handle":{"connectionId":0,"statementId":3},"endOfRows":true,"endOfResults":true,"rowCount":0}]},{"ev":"call","id":48,"t":505.6,"name":"releaseStatement","args":[3,{"connectionId":0,"statementId":3}]},{"ev":"state","of":36,"t":505.6,"change":{"handle":{"connectionId":0,"statementId":3},"oldState":"STATEMENT_SUBMITTED","newState":"STATEMENT_CLOSED"}},{"ev":"return","of":48,"t":506.1,"result":[null,true]},{"ev":"call","id":51,"t":669.6,"name":"query","args":[4,{"query_str":"select 1 as n","query_timeout":0,"query_polling":false,"query_tz_adjustment":0,"numeric_string":false,"bigint_as_native":false,"stateChangeCallback":{"$":"function"}},[]]},{"ev":"state","of":51,"t":669.8,"change":{"handle":{"connectionId":0,"statementId":4},"oldState":"STATEMENT_CREATED","newState":"STATEMENT_BINDING"}},{"ev":"state","of":51,"t":669.8,"change":{"handle":{"connectionId":0,"statementId":4},"oldState":"STATEMENT_BINDING","newState":"STATEMENT_SUBMITTED"}},{"ev":"state","of":51,"t":670.7,"change":{"handle":{"connectionId":0,"statementId":4},"oldState":"STATEMENT_SUBMITTED","newState":"STATEMENT_READING"}},{"ev":"return","of":51,"t":670.7,"result":[null,{"meta":[{"name":"n","nullable":false,"type":"number","sqlType":"int","size":10}],"handle":{"connectionId":0,"statementId":4},"endOfRows":true,"endOfResults":false,"rowCount":0},true]},{"ev":"call","id":56,"t":670.8,"name":"fetchRows","args":[4,{"connectionId":0,"statementId":4},{"asArrays":true,"batchSize":50,"asObjects":false}]},{"ev":"return","of":56,"t":670.8,"result":[null,{"endOfRows":true,"endOfResults":false,"rowCount":0,"data":[[1]]}]},{"ev":"call","id":58,"t":670.9,"name":"nextResultSet","args":[4,{"connectionId":0,"statementId":4}]},{"ev":"return","of":58,"t":671,"result":[null,{"meta":[{"name":"n","nullable":false,"type":"number","sqlType":"int","size":10}],"handle":{"connectionId":0,"statementId":4},"endOfRows":true,"endOfResults":true,"rowCount":0}]},{"ev":"call","id":60,"t":671,"name":"releaseStatement","args":[4,{"connectionId":0,"statementId":4}]},{"ev":"state","of":51,"t":671,"change":{"handle":{"connectionId":0,"statementId":4},"oldState":"STATEMENT_READING","newState":"STATEMENT_CLOSED"}},{"ev":"return","of":60,"t":671,"result":[null,true]},{"ev":"call","id":63,"t":671.2,"name":"close","args":[]},{"ev":"return","of":63,"t":671.3,"result":[null,true]}]} \ No newline at end of file +{"scenario":"scripts/issue-498","transcript":["-- c0 cast(0.1234567890123 as float); c1 cast(1e-10 as float); c2 cast(1.5e300 as float); c3 cast(-2.5 as float); c4 cast(0.12345678 as real); c5 cast(1.0123456789 as decimal(38,10)); c6 cast(12345678901234567890.12 as decimal(38,2)); c7 cast(0.0000001 as decimal(10,7)); c8 cast(9007199254740993 as decimal(19,0)); c9 cast(709 as decimal(10,0)); c10 cast(922337203685477.5807 as money); c11 cast(-0.0001 as money); c12 cast(1.2345 as smallmoney); c13 cast(1.0123456789 as numeric(38,10)); c14 cast(0.0000001 as numeric(10,7)); c15 cast(9223372036854775807 as bigint)","== numeric strings off","plain: submitted","plain: meta c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15","plain: row","plain: column 0 0.1234567890123","plain: column 1 1e-10","plain: column 2 1.5e+300","plain: column 3 -2.5","plain: column 4 0.12345678359270096","plain: column 5 1.0123456789","plain: column 6 12345678901234567000","plain: column 7 1e-7","plain: column 8 9007199254740992","plain: column 9 709","plain: column 10 922337203685477.6","plain: column 11 -0.0001","plain: column 12 1.2345","plain: column 13 1.0123456789","plain: column 14 1e-7","plain: column 15 9223372036854776000","plain: done","plain: free","== numeric strings on","ns: submitted","ns: meta c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15","ns: row","ns: column 0 \"0.1234567890123\"","ns: column 1 \"1e-10\"","ns: column 2 \"1.5e+300\"","ns: column 3 \"-2.5\"","ns: column 4 \"0.12345678359270096\"","ns: column 5 \"1.0123456789\"","ns: column 6 \"12345678901234567890.12\"","ns: column 7 \"0.0000001\"","ns: column 8 \"9007199254740993\"","ns: column 9 \"709\"","ns: column 10 \"922337203685477.5807\"","ns: column 11 \"-0.0001\"","ns: column 12 \"1.2345\"","ns: column 13 \"1.0123456789\"","ns: column 14 \"0.0000001\"","ns: column 15 \"9223372036854775807\"","ns: done","ns: free","check ok"],"log":[{"ev":"call","id":0,"t":11,"name":"open","args":["",0]},{"ev":"return","of":0,"t":31.8,"result":[null,{"success":true}]},{"ev":"call","id":2,"t":33.3,"name":"query","args":[0,{"query_str":"select cast(0.1234567890123 as float) as c0, cast(1e-10 as float) as c1, cast(1.5e300 as float) as c2, cast(-2.5 as float) as c3, cast(0.12345678 as real) as c4, cast(1.0123456789 as decimal(38,10)) as c5, cast(12345678901234567890.12 as decimal(38,2)) as c6, cast(0.0000001 as decimal(10,7)) as c7, cast(9007199254740993 as decimal(19,0)) as c8, cast(709 as decimal(10,0)) as c9, cast(922337203685477.5807 as money) as c10, cast(-0.0001 as money) as c11, cast(1.2345 as smallmoney) as c12, cast(1.0123456789 as numeric(38,10)) as c13, cast(0.0000001 as numeric(10,7)) as c14, cast(9223372036854775807 as bigint) as c15","numeric_string":false,"bigint_as_native":false,"stateChangeCallback":{"$":"function"}},[]]},{"ev":"state","of":2,"t":33.5,"change":{"handle":{"connectionId":0,"statementId":0},"oldState":"STATEMENT_CREATED","newState":"STATEMENT_BINDING"}},{"ev":"state","of":2,"t":33.7,"change":{"handle":{"connectionId":0,"statementId":0},"oldState":"STATEMENT_BINDING","newState":"STATEMENT_SUBMITTED"}},{"ev":"state","of":2,"t":34.4,"change":{"handle":{"connectionId":0,"statementId":0},"oldState":"STATEMENT_SUBMITTED","newState":"STATEMENT_READING"}},{"ev":"return","of":2,"t":34.5,"result":[null,{"meta":[{"name":"c0","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c1","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c2","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c3","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c4","nullable":true,"type":"number","sqlType":"real","size":24},{"name":"c5","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"c6","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"c7","nullable":true,"type":"number","sqlType":"decimal","size":10},{"name":"c8","nullable":true,"type":"number","sqlType":"decimal","size":19},{"name":"c9","nullable":true,"type":"number","sqlType":"decimal","size":10},{"name":"c10","nullable":true,"type":"number","sqlType":"money","size":19},{"name":"c11","nullable":true,"type":"number","sqlType":"money","size":19},{"name":"c12","nullable":true,"type":"number","sqlType":"smallmoney","size":10},{"name":"c13","nullable":true,"type":"number","sqlType":"numeric","size":38},{"name":"c14","nullable":true,"type":"number","sqlType":"numeric","size":10},{"name":"c15","nullable":true,"type":"number","sqlType":"bigint","size":19}],"handle":{"connectionId":0,"statementId":0},"endOfRows":true,"endOfResults":false,"rowCount":0},true]},{"ev":"call","id":7,"t":34.9,"name":"fetchRows","args":[0,{"connectionId":0,"statementId":0},{"asArrays":true,"batchSize":50,"asObjects":false}]},{"ev":"return","of":7,"t":35.1,"result":[null,{"endOfRows":true,"endOfResults":false,"rowCount":0,"data":[[0.1234567890123,1e-10,1.5e+300,-2.5,0.12345678359270096,1.0123456789,12345678901234567000,1e-7,9007199254740992,709,922337203685477.6,-0.0001,1.2345,1.0123456789,1e-7,9223372036854776000]]}]},{"ev":"call","id":9,"t":35.3,"name":"nextResultSet","args":[0,{"connectionId":0,"statementId":0}]},{"ev":"return","of":9,"t":35.4,"result":[null,{"meta":[{"name":"c0","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c1","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c2","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c3","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c4","nullable":true,"type":"number","sqlType":"real","size":24},{"name":"c5","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"c6","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"c7","nullable":true,"type":"number","sqlType":"decimal","size":10},{"name":"c8","nullable":true,"type":"number","sqlType":"decimal","size":19},{"name":"c9","nullable":true,"type":"number","sqlType":"decimal","size":10},{"name":"c10","nullable":true,"type":"number","sqlType":"money","size":19},{"name":"c11","nullable":true,"type":"number","sqlType":"money","size":19},{"name":"c12","nullable":true,"type":"number","sqlType":"smallmoney","size":10},{"name":"c13","nullable":true,"type":"number","sqlType":"numeric","size":38},{"name":"c14","nullable":true,"type":"number","sqlType":"numeric","size":10},{"name":"c15","nullable":true,"type":"number","sqlType":"bigint","size":19}],"handle":{"connectionId":0,"statementId":0},"endOfRows":true,"endOfResults":true,"rowCount":0}]},{"ev":"call","id":11,"t":35.7,"name":"releaseStatement","args":[0,{"connectionId":0,"statementId":0}]},{"ev":"state","of":2,"t":35.8,"change":{"handle":{"connectionId":0,"statementId":0},"oldState":"STATEMENT_READING","newState":"STATEMENT_CLOSED"}},{"ev":"return","of":11,"t":35.8,"result":[null,true]},{"ev":"call","id":14,"t":199.4,"name":"query","args":[1,{"query_str":"select cast(0.1234567890123 as float) as c0, cast(1e-10 as float) as c1, cast(1.5e300 as float) as c2, cast(-2.5 as float) as c3, cast(0.12345678 as real) as c4, cast(1.0123456789 as decimal(38,10)) as c5, cast(12345678901234567890.12 as decimal(38,2)) as c6, cast(0.0000001 as decimal(10,7)) as c7, cast(9007199254740993 as decimal(19,0)) as c8, cast(709 as decimal(10,0)) as c9, cast(922337203685477.5807 as money) as c10, cast(-0.0001 as money) as c11, cast(1.2345 as smallmoney) as c12, cast(1.0123456789 as numeric(38,10)) as c13, cast(0.0000001 as numeric(10,7)) as c14, cast(9223372036854775807 as bigint) as c15","numeric_string":true,"bigint_as_native":false,"stateChangeCallback":{"$":"function"}},[]]},{"ev":"state","of":14,"t":199.6,"change":{"handle":{"connectionId":0,"statementId":1},"oldState":"STATEMENT_CREATED","newState":"STATEMENT_BINDING"}},{"ev":"state","of":14,"t":199.6,"change":{"handle":{"connectionId":0,"statementId":1},"oldState":"STATEMENT_BINDING","newState":"STATEMENT_SUBMITTED"}},{"ev":"state","of":14,"t":200.8,"change":{"handle":{"connectionId":0,"statementId":1},"oldState":"STATEMENT_SUBMITTED","newState":"STATEMENT_READING"}},{"ev":"return","of":14,"t":200.8,"result":[null,{"meta":[{"name":"c0","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c1","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c2","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c3","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c4","nullable":true,"type":"number","sqlType":"real","size":24},{"name":"c5","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"c6","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"c7","nullable":true,"type":"number","sqlType":"decimal","size":10},{"name":"c8","nullable":true,"type":"number","sqlType":"decimal","size":19},{"name":"c9","nullable":true,"type":"number","sqlType":"decimal","size":10},{"name":"c10","nullable":true,"type":"number","sqlType":"money","size":19},{"name":"c11","nullable":true,"type":"number","sqlType":"money","size":19},{"name":"c12","nullable":true,"type":"number","sqlType":"smallmoney","size":10},{"name":"c13","nullable":true,"type":"number","sqlType":"numeric","size":38},{"name":"c14","nullable":true,"type":"number","sqlType":"numeric","size":10},{"name":"c15","nullable":true,"type":"number","sqlType":"bigint","size":19}],"handle":{"connectionId":0,"statementId":1},"endOfRows":true,"endOfResults":false,"rowCount":0},true]},{"ev":"call","id":19,"t":200.9,"name":"fetchRows","args":[1,{"connectionId":0,"statementId":1},{"asArrays":true,"batchSize":50,"asObjects":false}]},{"ev":"return","of":19,"t":201,"result":[null,{"endOfRows":true,"endOfResults":false,"rowCount":0,"data":[["0.1234567890123","1e-10","1.5e+300","-2.5","0.12345678359270096","1.0123456789","12345678901234567890.12","0.0000001","9007199254740993","709","922337203685477.5807","-0.0001","1.2345","1.0123456789","0.0000001","9223372036854775807"]]}]},{"ev":"call","id":21,"t":201,"name":"nextResultSet","args":[1,{"connectionId":0,"statementId":1}]},{"ev":"return","of":21,"t":201.1,"result":[null,{"meta":[{"name":"c0","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c1","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c2","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c3","nullable":true,"type":"number","sqlType":"float","size":53},{"name":"c4","nullable":true,"type":"number","sqlType":"real","size":24},{"name":"c5","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"c6","nullable":true,"type":"number","sqlType":"decimal","size":38},{"name":"c7","nullable":true,"type":"number","sqlType":"decimal","size":10},{"name":"c8","nullable":true,"type":"number","sqlType":"decimal","size":19},{"name":"c9","nullable":true,"type":"number","sqlType":"decimal","size":10},{"name":"c10","nullable":true,"type":"number","sqlType":"money","size":19},{"name":"c11","nullable":true,"type":"number","sqlType":"money","size":19},{"name":"c12","nullable":true,"type":"number","sqlType":"smallmoney","size":10},{"name":"c13","nullable":true,"type":"number","sqlType":"numeric","size":38},{"name":"c14","nullable":true,"type":"number","sqlType":"numeric","size":10},{"name":"c15","nullable":true,"type":"number","sqlType":"bigint","size":19}],"handle":{"connectionId":0,"statementId":1},"endOfRows":true,"endOfResults":true,"rowCount":0}]},{"ev":"call","id":23,"t":201.1,"name":"releaseStatement","args":[1,{"connectionId":0,"statementId":1}]},{"ev":"state","of":14,"t":201.2,"change":{"handle":{"connectionId":0,"statementId":1},"oldState":"STATEMENT_READING","newState":"STATEMENT_CLOSED"}},{"ev":"return","of":23,"t":201.2,"result":[null,true]},{"ev":"call","id":26,"t":514.2,"name":"query","args":[2,{"query_str":"select 1 as n","query_timeout":0,"query_polling":false,"query_tz_adjustment":0,"numeric_string":false,"bigint_as_native":false,"stateChangeCallback":{"$":"function"}},[]]},{"ev":"state","of":26,"t":514.3,"change":{"handle":{"connectionId":0,"statementId":2},"oldState":"STATEMENT_CREATED","newState":"STATEMENT_BINDING"}},{"ev":"state","of":26,"t":514.4,"change":{"handle":{"connectionId":0,"statementId":2},"oldState":"STATEMENT_BINDING","newState":"STATEMENT_SUBMITTED"}},{"ev":"state","of":26,"t":515.4,"change":{"handle":{"connectionId":0,"statementId":2},"oldState":"STATEMENT_SUBMITTED","newState":"STATEMENT_READING"}},{"ev":"return","of":26,"t":515.4,"result":[null,{"meta":[{"name":"n","nullable":false,"type":"number","sqlType":"int","size":10}],"handle":{"connectionId":0,"statementId":2},"endOfRows":true,"endOfResults":false,"rowCount":0},true]},{"ev":"call","id":31,"t":515.5,"name":"fetchRows","args":[2,{"connectionId":0,"statementId":2},{"asArrays":true,"batchSize":50,"asObjects":false}]},{"ev":"return","of":31,"t":515.6,"result":[null,{"endOfRows":true,"endOfResults":false,"rowCount":0,"data":[[1]]}]},{"ev":"call","id":33,"t":515.7,"name":"nextResultSet","args":[2,{"connectionId":0,"statementId":2}]},{"ev":"return","of":33,"t":515.7,"result":[null,{"meta":[{"name":"n","nullable":false,"type":"number","sqlType":"int","size":10}],"handle":{"connectionId":0,"statementId":2},"endOfRows":true,"endOfResults":true,"rowCount":0}]},{"ev":"call","id":35,"t":515.8,"name":"releaseStatement","args":[2,{"connectionId":0,"statementId":2}]},{"ev":"state","of":26,"t":515.8,"change":{"handle":{"connectionId":0,"statementId":2},"oldState":"STATEMENT_READING","newState":"STATEMENT_CLOSED"}},{"ev":"return","of":35,"t":515.8,"result":[null,true]},{"ev":"call","id":38,"t":516,"name":"close","args":[]},{"ev":"return","of":38,"t":516.1,"result":[null,true]}]} \ No newline at end of file diff --git a/test/contract/scripts/issue-498-prepared.js b/test/contract/scripts/issue-498-prepared.js new file mode 100644 index 00000000..8eb3c280 --- /dev/null +++ b/test/contract/scripts/issue-498-prepared.js @@ -0,0 +1,18 @@ +'use strict' + +// #498 through a prepared statement: it binds numeric, decimal and float result columns as a +// double, so under numeric strings numeric and decimal lose what a double cannot hold. + +module.exports = async t => { + t.query('setup', 'create table #p (n numeric(38,10), d decimal(38,2), f float); ' + + 'insert #p values (1.0123456789, 12345678901234567.89, 1e-10)', null, { callback: true }) + await t.settled('setup') + const ps = await new Promise((resolve, reject) => { + t.conn.prepare({ query_str: 'select n, d, f from #p where 1 = ?', numeric_string: true }, + (err, p) => err ? reject(err) : resolve(p)) + }) + t.section('prepared, numeric strings on') + t.watch('ps', ps.preparedQuery([1]), { columns: true }) + await t.next('ps', 'done') + await new Promise(resolve => ps.free(resolve)) +} diff --git a/test/contract/scripts/issue-498.js b/test/contract/scripts/issue-498.js index 9e3bdf84..d629ac5c 100644 --- a/test/contract/scripts/issue-498.js +++ b/test/contract/scripts/issue-498.js @@ -2,8 +2,8 @@ // #498: under numeric strings, float, real, decimal and money were printed with %f (six // decimal places, no exponent): 1e-10 came back as "0.000000". each value is read with -// numeric strings off and on; the strings should keep the value. then the same through a -// prepared statement. +// numeric strings off and on; the strings should keep the value. decimal and money are the +// driver's exact text, as numeric is. prepared statements: issue-498-prepared. const VALUES = [ 'cast(0.1234567890123 as float)', @@ -34,16 +34,4 @@ module.exports = async t => { await t.settled(label) } - // a prepared statement binds these columns as double, numeric included - t.query('setup', 'create table #p (n numeric(38,10), d decimal(38,2), f float); ' + - 'insert #p values (1.0123456789, 12345678901234567.89, 1e-10)', null, { callback: true }) - await t.settled('setup') - const ps = await new Promise((resolve, reject) => { - t.conn.prepare({ query_str: 'select n, d, f from #p where 1 = ?', numeric_string: true }, - (err, p) => err ? reject(err) : resolve(p)) - }) - t.section('prepared, numeric strings on') - t.watch('ps', ps.preparedQuery([1]), { columns: true }) - await t.next('ps', 'done') - await new Promise(resolve => ps.free(resolve)) } diff --git a/test/params-complete-refactored.test.js b/test/params-complete-refactored.test.js index adca3e58..5a8e0cae 100644 --- a/test/params-complete-refactored.test.js +++ b/test/params-complete-refactored.test.js @@ -981,13 +981,26 @@ describe('Parameter Tests', function () { assert.deepStrictEqual(result.first[0], { f1: '1e-10', f2: '0.1234567890123', f3: '1.5e+300', f4: '-2.5', r1: '0.5' }) }) - it('should return decimal and money as strings without %f padding', async function () { + // decimal is numeric under another name: both are the server's exact text + it('should return decimal and money as their exact text', async function () { const result = await env.theConnection.promises.query({ - query_str: 'select cast(1.0123456789 as decimal(38,10)) as d1, cast(0.0000001 as decimal(10,7)) as d2, ' + - 'cast(-0.0001 as money) as m1, cast(1.2345 as smallmoney) as m2', + query_str: 'select cast(1.0123456789 as decimal(38,10)) as d1, cast(12345678901234567890.12 as decimal(38,2)) as d2, ' + + 'cast(9007199254740993 as decimal(19,0)) as d3, cast(922337203685477.5807 as money) as m1, ' + + 'cast(-0.0001 as money) as m2, cast(1.2345 as smallmoney) as m3', numeric_string: true }) - assert.deepStrictEqual(result.first[0], { d1: '1.0123456789', d2: '1e-7', m1: '-0.0001', m2: '1.2345' }) + assert.deepStrictEqual(result.first[0], { + d1: '1.0123456789', d2: '12345678901234567890.12', d3: '9007199254740993', m1: '922337203685477.5807', m2: '-0.0001', m3: '1.2345' + }) + }) + + it('should return decimal and numeric with their scale and a leading zero', async function () { + const result = await env.theConnection.promises.query({ + query_str: 'select cast(5 as decimal(5,2)) as d1, cast(-0.5 as decimal(5,2)) as d2, cast(0 as decimal(5,2)) as d3, ' + + 'cast(5 as numeric(5,2)) as n1, cast(-0.5 as numeric(5,2)) as n2, cast(0.0000001 as numeric(10,7)) as n3, cast(null as decimal(5,2)) as nul', + numeric_string: true + }) + assert.deepStrictEqual(result.first[0], { d1: '5.00', d2: '-0.50', d3: '0.00', n1: '5.00', n2: '-0.50', n3: '0.0000001', nul: null }) }) })