diff options
Diffstat (limited to 'storage/ndb/src/old_files/client/odbc/common/DataField.cpp')
-rw-r--r-- | storage/ndb/src/old_files/client/odbc/common/DataField.cpp | 3023 |
1 files changed, 3023 insertions, 0 deletions
diff --git a/storage/ndb/src/old_files/client/odbc/common/DataField.cpp b/storage/ndb/src/old_files/client/odbc/common/DataField.cpp new file mode 100644 index 00000000000..11aae7d893b --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/DataField.cpp @@ -0,0 +1,3023 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "DataField.hpp" + +#ifndef INT_MAX +#define INT_MAX (2147483647) +#endif + +#ifndef INT_MIN +#define INT_MIN (-INT_MAX - 1) +#endif + +#ifndef UINT_MAX +#define UINT_MAX 4294967295U +#endif + +#ifndef FLT_MAX +#define FLT_MAX (3.402823466E+38F) +#endif +#ifndef FLT_MIN +#define FLT_MIN (1.175494351E-38F) +#endif + +#ifdef NDB_WIN32 +#define FMT_I64 "%I64d" +#define FMT_U64 "%I64u" +#else +#define FMT_I64 "%lld" +#define FMT_U64 "%llu" +#endif + +#ifdef NDB_WIN32 +#define strtoll(str, endptr, base) strtoint64(str, endptr, base) +#define strtoull(str, endptr, base) strtouint64(str, endptr, base) + +static Int64 +strtoint64(const char *str, char **endptr, int base) +{ + Int64 x = 0; + while (*str == ' ') + str++; + const char* p = str; + while ('0' <= *p && *p <= '9') + x = 10 * x + *p++ - '0'; + if (p == str) { + *endptr = 0; + return 0; + } + *endptr = (char*)p; + return x; +} + +static Uint64 +strtouint64(const char *str, char **endptr, int base) +{ + Uint64 x = 0; + while (*str == ' ') + str++; + const char* p = str; + while ('0' <= *p && *p <= '9') + x = 10 * x + *p++ - '0'; + if (p == str) { + *endptr = 0; + return 0; + } + *endptr = (char*)p; + return x; +} +#endif + +// LexSpec + +void +LexSpec::convert(Ctx& ctx, const BaseString& value, SqlField& out) +{ + const SqlSpec& sqlSpec = out.sqlSpec(); + const SqlType& sqlType = sqlSpec.sqlType(); + out.alloc(); + if (sqlType.type() == SqlType::Char) { + const SqlChar* s = (const SqlChar*)value.c_str(); + out.sqlChar(s, SQL_NTS); + return; + } + if (sqlType.type() == SqlType::Bigint) { + char* endptr = 0; + SqlBigint n = static_cast<SqlBigint>(strtoll(value.c_str(), &endptr, 10)); + if (endptr == 0 || *endptr != 0) { + ctx.pushStatus(Error::Gen, "cannot convert '%s' to integer", value.c_str()); + return; + } + out.sqlBigint(n); + return; + } + if (sqlType.type() == SqlType::Double) { + char* endptr = 0; + SqlDouble x = static_cast<SqlDouble>(strtod(value.c_str(), &endptr)); + if (endptr == 0 || *endptr != 0) { + ctx.pushStatus(Error::Gen, "cannot convert '%s' to number", value.c_str()); + return; + } + out.sqlDouble(x); + return; + } + if (sqlType.type() == SqlType::Null) { + out.u_null.m_nullFlag = true; + return; + } + ctx_assert(false); +} + +// SqlField + +void +SqlField::alloc() +{ + ctx_assert(sqlSpec().store() == SqlSpec::Physical); + const SqlType& sqlType = sqlSpec().sqlType(); + if (sqlType.type() == SqlType::Char || sqlType.type() == SqlType::Varchar) { + unsigned n = sqlType.length(); + if (sqlType.type() == SqlType::Varchar) + n += 2; + if (n > SqlField_CharSmall) { + u_data.m_sqlChar = new SqlChar[n]; + } + } + if (sqlType.type() == SqlType::Binary || sqlType.type() == SqlType::Varbinary) { + unsigned n = sqlType.length(); + if (sqlType.type() == SqlType::Varbinary) + n += 2; + if (n > SqlField_CharSmall) { + u_data.m_sqlChar = new SqlChar[n]; + } + } +} + +void +SqlField::alloc(const SqlField& sqlField) +{ + alloc(); + const SqlType& sqlType = sqlSpec().sqlType(); + if (sqlType.type() == SqlType::Char || sqlType.type() == SqlType::Varchar) { + unsigned n = sqlType.length(); + if (sqlType.type() == SqlType::Varchar) + n += 2; + if (n > SqlField_CharSmall) { + memcpy(u_data.m_sqlChar, sqlField.u_data.m_sqlChar, n); + } + } + if (sqlType.type() == SqlType::Binary || sqlType.type() == SqlType::Varbinary) { + unsigned n = sqlType.length(); + if (sqlType.type() == SqlType::Varbinary) + n += 2; + if (n > SqlField_CharSmall) { + memcpy(u_data.m_sqlChar, sqlField.u_data.m_sqlChar, n); + } + } +} + +const void* +SqlField::addr() const +{ + if (sqlSpec().store() == SqlSpec::Reference) { + ctx_assert(u_data.m_sqlField != 0); + return u_data.m_sqlField->addr(); + } + const SqlType& sqlType = sqlSpec().sqlType(); + if (sqlType.type() == SqlType::Char || sqlType.type() == SqlType::Varchar) { + unsigned n = sqlType.length(); + if (sqlType.type() == SqlType::Varchar) + n += 2; + if (n > SqlField_CharSmall) { + return static_cast<const void*>(u_data.m_sqlChar); + } + return static_cast<const void*>(u_data.m_sqlCharSmall); + } + if (sqlType.type() == SqlType::Binary || sqlType.type() == SqlType::Varbinary) { + unsigned n = sqlType.length(); + if (sqlType.type() == SqlType::Varbinary) + n += 2; + if (n > SqlField_CharSmall) { + return static_cast<const void*>(u_data.m_sqlChar); + } + return static_cast<const void*>(u_data.m_sqlCharSmall); + } + if (sqlType.type() == SqlType::Smallint) { + return static_cast<const void*>(&u_data.m_sqlSmallint); + } + if (sqlType.type() == SqlType::Integer) { + return static_cast<const void*>(&u_data.m_sqlInteger); + } + if (sqlType.type() == SqlType::Bigint) { + return static_cast<const void*>(&u_data.m_sqlBigint); + } + if (sqlType.type() == SqlType::Real) { + return static_cast<const void*>(&u_data.m_sqlReal); + } + if (sqlType.type() == SqlType::Double) { + return static_cast<const void*>(&u_data.m_sqlDouble); + } + if (sqlType.type() == SqlType::Datetime) { + return static_cast<const void*>(&u_data.m_sqlDatetime); + } + ctx_assert(false); // SqlType::Null has no address + return 0; +} + +void* +SqlField::addr() +{ + const SqlType& sqlType = sqlSpec().sqlType(); + if (sqlType.type() == SqlType::Char || sqlType.type() == SqlType::Varchar) { + unsigned n = sqlType.length(); + if (sqlType.type() == SqlType::Varchar) + n += 2; + if (n > SqlField_CharSmall) { + return static_cast<void*>(u_data.m_sqlChar); + } + return static_cast<void*>(u_data.m_sqlCharSmall); + } + if (sqlType.type() == SqlType::Binary || sqlType.type() == SqlType::Varbinary) { + unsigned n = sqlType.length(); + if (sqlType.type() == SqlType::Varbinary) + n += 2; + if (n > SqlField_CharSmall) { + return static_cast<void*>(u_data.m_sqlChar); + } + return static_cast<void*>(u_data.m_sqlCharSmall); + } + if (sqlType.type() == SqlType::Smallint) { + return static_cast<void*>(&u_data.m_sqlSmallint); + } + if (sqlType.type() == SqlType::Integer) { + return static_cast<void*>(&u_data.m_sqlInteger); + } + if (sqlType.type() == SqlType::Bigint) { + return static_cast<void*>(&u_data.m_sqlBigint); + } + if (sqlType.type() == SqlType::Real) { + return static_cast<void*>(&u_data.m_sqlReal); + } + if (sqlType.type() == SqlType::Double) { + return static_cast<void*>(&u_data.m_sqlDouble); + } + if (sqlType.type() == SqlType::Datetime) { + return static_cast<void*>(&u_data.m_sqlDatetime); + } + ctx_assert(false); // SqlType::Null has no address + return 0; +} + +unsigned +SqlField::allocSize() const +{ + const SqlType& sqlType = sqlSpec().sqlType(); + unsigned n = sqlType.size(); + if (sqlType.type() == SqlType::Varchar || sqlType.type() == SqlType::Varbinary) { + n += 2; + } + return n; +} + +void +SqlField::free() +{ + ctx_assert(sqlSpec().store() == SqlSpec::Physical); + const SqlType& sqlType = sqlSpec().sqlType(); + if (sqlType.type() == SqlType::Char || sqlType.type() == SqlType::Varchar) { + unsigned n = sqlType.length(); + if (sqlType.type() == SqlType::Varchar) + n += 2; + if (n > SqlField_CharSmall) { + delete[] u_data.m_sqlChar; + u_data.m_sqlChar = 0; // safety since dtor used explicitly + } + } + if (sqlType.type() == SqlType::Binary || sqlType.type() == SqlType::Varbinary) { + unsigned n = sqlType.length(); + if (sqlType.type() == SqlType::Varbinary) + n += 2; + if (n > SqlField_CharSmall) { + delete[] u_data.m_sqlChar; + u_data.m_sqlChar = 0; // safety since dtor used explicitly + } + } +} + +// get + +const SqlChar* +SqlField::sqlChar() const +{ + if (sqlSpec().store() == SqlSpec::Reference) { + ctx_assert(u_data.m_sqlField != 0); + return u_data.m_sqlField->sqlChar(); + } + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Char); + if (sqlType.length() > SqlField_CharSmall) + return u_data.m_sqlChar; + return u_data.m_sqlCharSmall; +} + +const SqlChar* +SqlField::sqlVarchar(unsigned* length) const +{ +#if NDB_VERSION_MAJOR >= 3 + if (sqlSpec().store() == SqlSpec::Reference) { + ctx_assert(u_data.m_sqlField != 0); + return u_data.m_sqlField->sqlVarchar(length); + } + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Varchar); + const SqlChar* sqlChar; + unsigned n = sqlType.length(); + if (2 + n > SqlField_CharSmall) + sqlChar = u_data.m_sqlChar; + else + sqlChar = u_data.m_sqlCharSmall; + if (length != 0) + *length = (sqlChar[0] << 8) | sqlChar[1]; // big-endian + return sqlChar + 2; +#else + if (sqlSpec().store() == SqlSpec::Reference) { + ctx_assert(u_data.m_sqlField != 0); + return u_data.m_sqlField->sqlVarchar(length); + } + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Varchar); + const SqlChar* sqlChar; + unsigned n = sqlType.length(); + if (n + 2 > SqlField_CharSmall) + sqlChar = u_data.m_sqlChar; + else + sqlChar = u_data.m_sqlCharSmall; + if (length != 0) + *length = (sqlChar[n + 0] << 8) | sqlChar[n + 1]; // big-endian + return sqlChar; +#endif +} + +const SqlChar* +SqlField::sqlBinary() const +{ + if (sqlSpec().store() == SqlSpec::Reference) { + ctx_assert(u_data.m_sqlField != 0); + return u_data.m_sqlField->sqlChar(); + } + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Binary); + if (sqlType.length() > SqlField_CharSmall) + return u_data.m_sqlChar; + return u_data.m_sqlCharSmall; +} + +const SqlChar* +SqlField::sqlVarbinary(unsigned* length) const +{ +#if NDB_VERSION_MAJOR >= 3 + if (sqlSpec().store() == SqlSpec::Reference) { + ctx_assert(u_data.m_sqlField != 0); + return u_data.m_sqlField->sqlVarchar(length); + } + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Varbinary); + const SqlChar* sqlChar; + unsigned n = sqlType.length(); + if (2 + n > SqlField_CharSmall) + sqlChar = u_data.m_sqlChar; + else + sqlChar = u_data.m_sqlCharSmall; + if (length != 0) + *length = (sqlChar[0] << 8) | sqlChar[1]; // big-endian + return sqlChar + 2; +#else + if (sqlSpec().store() == SqlSpec::Reference) { + ctx_assert(u_data.m_sqlField != 0); + return u_data.m_sqlField->sqlVarchar(length); + } + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Varbinary); + const SqlChar* sqlChar; + unsigned n = sqlType.length(); + if (n + 2 > SqlField_CharSmall) + sqlChar = u_data.m_sqlChar; + else + sqlChar = u_data.m_sqlCharSmall; + if (length != 0) + *length = (sqlChar[n + 0] << 8) | sqlChar[n + 1]; // big-endian + return sqlChar; +#endif +} + +SqlSmallint +SqlField::sqlSmallint() const +{ + if (sqlSpec().store() == SqlSpec::Reference) { + ctx_assert(u_data.m_sqlField != 0); + return u_data.m_sqlField->sqlSmallint(); + } + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Smallint); + return u_data.m_sqlSmallint; +} + +SqlInteger +SqlField::sqlInteger() const +{ + if (sqlSpec().store() == SqlSpec::Reference) { + ctx_assert(u_data.m_sqlField != 0); + return u_data.m_sqlField->sqlInteger(); + } + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Integer); + return u_data.m_sqlInteger; +} + +SqlBigint +SqlField::sqlBigint() const +{ + if (sqlSpec().store() == SqlSpec::Reference) { + ctx_assert(u_data.m_sqlField != 0); + return u_data.m_sqlField->sqlBigint(); + } + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Bigint); + return u_data.m_sqlBigint; +} + +SqlReal +SqlField::sqlReal() const +{ + if (sqlSpec().store() == SqlSpec::Reference) { + ctx_assert(u_data.m_sqlField != 0); + return u_data.m_sqlField->sqlReal(); + } + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Real); + return u_data.m_sqlReal; +} + +SqlDouble +SqlField::sqlDouble() const +{ + if (sqlSpec().store() == SqlSpec::Reference) { + ctx_assert(u_data.m_sqlField != 0); + return u_data.m_sqlField->sqlDouble(); + } + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Double); + return u_data.m_sqlDouble; +} + +SqlDatetime +SqlField::sqlDatetime() const +{ + if (sqlSpec().store() == SqlSpec::Reference) { + ctx_assert(u_data.m_sqlField != 0); + return u_data.m_sqlField->sqlDatetime(); + } + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Datetime); + return u_data.m_sqlDatetime; +} + +// set + +void +SqlField::sqlChar(const SqlChar* value, int length) +{ + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Char); + unsigned n = sqlType.length(); + SqlChar* p = n > SqlField_CharSmall ? u_data.m_sqlChar : u_data.m_sqlCharSmall; + const SqlChar* q = value; + unsigned m = length == SQL_NTS ? strlen((const char*)q) : length; + ctx_assert(m <= n); + for (unsigned i = 0; i < m; i++) + *p++ = *q++; + for (unsigned i = m; i < n; i++) + *p++ = 0x20; // space + u_null.m_nullFlag = false; +} + +void +SqlField::sqlVarchar(const SqlChar* value, int length) +{ +#if NDB_VERSION_MAJOR >= 3 + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Varchar); + unsigned n = sqlType.length(); + SqlChar* p = 2 + n > SqlField_CharSmall ? u_data.m_sqlChar : u_data.m_sqlCharSmall; + const SqlChar* q = value; + unsigned m = length == SQL_NTS ? strlen((const char*)q) : length; + ctx_assert(m <= n); + *p++ = (m >> 8) & 0xff; // big-endian + *p++ = (m & 0xff); + for (unsigned i = 0; i < m; i++) + *p++ = *q++; + for (unsigned i = m; i < n; i++) + *p++ = 0x0; // null + u_null.m_nullFlag = false; +#else + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Varchar); + unsigned n = sqlType.length(); + SqlChar* p = n + 2 > SqlField_CharSmall ? u_data.m_sqlChar : u_data.m_sqlCharSmall; + const SqlChar* q = value; + unsigned m = length == SQL_NTS ? strlen((const char*)q) : length; + ctx_assert(m <= n); + for (unsigned i = 0; i < m; i++) + *p++ = *q++; + for (unsigned i = m; i < n; i++) + *p++ = 0x0; // null + *p++ = (m >> 8) & 0xff; // big-endian + *p++ = (m & 0xff); + u_null.m_nullFlag = false; +#endif +} + +void +SqlField::sqlBinary(const SqlChar* value, int length) +{ + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Binary); + unsigned n = sqlType.length(); + SqlChar* p = n > SqlField_CharSmall ? u_data.m_sqlChar : u_data.m_sqlCharSmall; + const SqlChar* q = value; + unsigned m = length; + ctx_assert(m <= n); + for (unsigned i = 0; i < m; i++) + *p++ = *q++; + for (unsigned i = m; i < n; i++) + *p++ = 0x0; // null + u_null.m_nullFlag = false; +} + +void +SqlField::sqlVarbinary(const SqlChar* value, int length) +{ +#if NDB_VERSION_MAJOR >= 3 + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Varbinary); + unsigned n = sqlType.length(); + SqlChar* p = 2 + n > SqlField_CharSmall ? u_data.m_sqlChar : u_data.m_sqlCharSmall; + const SqlChar* q = value; + unsigned m = length; + ctx_assert(m <= n); + *p++ = (m >> 8) & 0xff; // big-endian + *p++ = (m & 0xff); + for (unsigned i = 0; i < m; i++) + *p++ = *q++; + for (unsigned i = m; i < n; i++) + *p++ = 0x0; // null + u_null.m_nullFlag = false; +#else + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Varbinary); + unsigned n = sqlType.length(); + SqlChar* p = n + 2 > SqlField_CharSmall ? u_data.m_sqlChar : u_data.m_sqlCharSmall; + const SqlChar* q = value; + unsigned m = length; + ctx_assert(m <= n); + for (unsigned i = 0; i < m; i++) + *p++ = *q++; + for (unsigned i = m; i < n; i++) + *p++ = 0x0; // null + *p++ = (m >> 8) & 0xff; // big-endian + *p++ = (m & 0xff); + u_null.m_nullFlag = false; +#endif +} + +void +SqlField::sqlSmallint(SqlSmallint value) +{ + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Smallint); + u_data.m_sqlSmallint = value; + u_null.m_nullFlag = false; +} + +void +SqlField::sqlInteger(SqlInteger value) +{ + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Integer); + u_data.m_sqlInteger = value; + u_null.m_nullFlag = false; +} + +void +SqlField::sqlBigint(SqlBigint value) +{ + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Bigint); + u_data.m_sqlBigint = value; + u_null.m_nullFlag = false; +} + +void +SqlField::sqlReal(SqlReal value) +{ + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Real); + u_data.m_sqlReal = value; + u_null.m_nullFlag = false; +} + +void +SqlField::sqlDouble(SqlDouble value) +{ + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Double); + u_data.m_sqlDouble = value; + u_null.m_nullFlag = false; +} + +void +SqlField::sqlDatetime(SqlDatetime value) +{ + const SqlType& sqlType = sqlSpec().sqlType(); + ctx_assert(sqlType.type() == SqlType::Datetime); + u_data.m_sqlDatetime = value; + u_null.m_nullFlag = false; +} + +// get and and set null + +bool +SqlField::sqlNull() const +{ + if (sqlSpec().store() == SqlSpec::Reference) { + ctx_assert(u_data.m_sqlField != 0); + return u_data.m_sqlField->sqlNull(); + } + return u_null.m_nullFlag; +} + +void +SqlField::sqlNull(bool value) +{ + u_null.m_nullFlag = value; +} + +unsigned +SqlField::trim() const +{ + const SqlType& sqlType = sqlSpec().sqlType(); + unsigned n = 0; + const SqlChar* s = 0; + if (sqlType.type() == SqlType::Char) { + n = sqlType.length(); + s = sqlChar(); + } else if (sqlType.type() == SqlType::Varchar) { + s = sqlVarchar(&n); + } else { + ctx_assert(false); + return 0; + } + while (n > 0 && s[n - 1] == 0x20) + n--; + return n; +} + +void +SqlField::copy(Ctx& ctx, SqlField& out) const +{ + const SqlField& f1 = *this; + SqlField& f2 = out; + const SqlType& t1 = f1.sqlSpec().sqlType(); + const SqlType& t2 = f2.sqlSpec().sqlType(); + ctx_assert(t1.type() == t2.type()); + if (f1.sqlNull()) { + f2.sqlNull(true); + return; + } + if (t1.type() == SqlType::Char) { + f2.sqlChar(f1.sqlChar(), t1.length()); + return; + } + if (t1.type() == SqlType::Varchar) { + unsigned length; + const SqlChar* s1 = f1.sqlVarchar(&length); + f2.sqlVarchar(s1, length); + return; + } + if (t1.type() == SqlType::Binary) { + f2.sqlBinary(f1.sqlBinary(), t1.length()); + return; + } + if (t1.type() == SqlType::Varbinary) { + unsigned length; + const SqlChar* s1 = f1.sqlVarbinary(&length); + f2.sqlVarbinary(s1, length); + return; + } + if (t1.type() == SqlType::Smallint) { + f2.sqlSmallint(f1.sqlSmallint()); + return; + } + if (t1.type() == SqlType::Integer) { + f2.sqlInteger(f1.sqlInteger()); + return; + } + if (t1.type() == SqlType::Bigint) { + f2.sqlBigint(f1.sqlBigint()); + return; + } + if (t1.type() == SqlType::Real) { + f2.sqlReal(f1.sqlReal()); + return; + } + if (t1.type() == SqlType::Double) { + f2.sqlDouble(f1.sqlDouble()); + return; + } + if (t1.type() == SqlType::Datetime) { + f2.sqlDatetime(f1.sqlDatetime()); + return; + } + ctx_assert(false); +} + +bool +SqlField::cast(Ctx& ctx, SqlField& out) const +{ + const SqlField& f1 = *this; + SqlField& f2 = out; + if (f1.sqlNull()) { + f2.sqlNull(true); + return true; + } + const SqlType& t1 = f1.sqlSpec().sqlType(); + const SqlType& t2 = f2.sqlSpec().sqlType(); + if (t1.type() == SqlType::Char) { + if (t2.type() == SqlType::Char) { + unsigned n1 = f1.trim(); + if (n1 > t2.length()) + return false; + f2.sqlChar(f1.sqlChar(), n1); + return true; + } + if (t2.type() == SqlType::Varchar) { + unsigned n1 = t1.length(); + if (n1 > t2.length()) + return false; + f2.sqlVarchar(f1.sqlChar(), n1); + return true; + } + if (t2.type() == SqlType::Binary) { + unsigned n1 = t1.length(); + if (n1 > t2.length()) + return false; + f2.sqlBinary(f1.sqlChar(), n1); + return true; + } + if (t2.type() == SqlType::Varbinary) { + unsigned n1 = t1.length(); + if (n1 > t2.length()) + return false; + f2.sqlVarbinary(f1.sqlChar(), n1); + return true; + } + ctx_assert(false); + return false; + } + if (t1.type() == SqlType::Varchar) { + if (t2.type() == SqlType::Char) { + unsigned n1 = f1.trim(); + if (n1 > t2.length()) + return false; + f2.sqlChar(f1.sqlVarchar(0), n1); + return true; + } + if (t2.type() == SqlType::Varchar) { + unsigned n1 = f1.trim(); + if (n1 > t2.length()) + return false; + f2.sqlVarchar(f1.sqlVarchar(0), n1); + return true; + } + if (t2.type() == SqlType::Binary) { + unsigned n1 = t1.length(); + if (n1 > t2.length()) + return false; + f2.sqlBinary(f1.sqlVarchar(0), n1); + return true; + } + if (t2.type() == SqlType::Varbinary) { + unsigned n1 = t1.length(); + if (n1 > t2.length()) + return false; + f2.sqlVarbinary(f1.sqlVarchar(0), n1); + return true; + } + ctx_assert(false); + return false; + } + if (t1.type() == SqlType::Binary) { + if (t2.type() == SqlType::Binary) { + unsigned n1 = t1.length(); + if (n1 > t2.length()) + return false; + f2.sqlBinary(f1.sqlBinary(), n1); + return true; + } + if (t2.type() == SqlType::Varbinary) { + unsigned n1 = t1.length(); + if (n1 > t2.length()) + return false; + f2.sqlVarbinary(f1.sqlBinary(), n1); + return true; + } + ctx_assert(false); + return false; + } + if (t1.type() == SqlType::Varbinary) { + if (t2.type() == SqlType::Binary) { + unsigned n1 = t1.length(); + if (n1 > t2.length()) + return false; + f2.sqlBinary(f1.sqlVarbinary(0), n1); + return true; + } + if (t2.type() == SqlType::Varbinary) { + unsigned n1 = t1.length(); + if (n1 > t2.length()) + return false; + f2.sqlVarbinary(f1.sqlVarbinary(0), n1); + return true; + } + ctx_assert(false); + return false; + } + if (t1.type() == SqlType::Smallint) { + if (! t2.unSigned()) { + SqlSmallint x1 = f1.sqlSmallint(); + if (t2.type() == SqlType::Smallint) { + f2.sqlSmallint(x1); + return true; + } + if (t2.type() == SqlType::Integer) { + SqlInteger x2 = static_cast<SqlInteger>(x1); + f2.sqlInteger(x2); + return true; + } + if (t2.type() == SqlType::Bigint) { + SqlBigint x2 = static_cast<SqlBigint>(x1); + f2.sqlBigint(x2); + return true; + } + if (t2.type() == SqlType::Real) { + SqlReal x2 = static_cast<SqlReal>(x1); + f2.sqlReal(x2); + return true; + } + if (t2.type() == SqlType::Double) { + SqlDouble x2 = static_cast<SqlDouble>(x1); + f2.sqlDouble(x2); + return true; + } + } else { + SqlUsmallint x1 = f1.sqlSmallint(); + if (t2.type() == SqlType::Smallint) { + f2.sqlSmallint(x1); + return true; + } + if (t2.type() == SqlType::Integer) { + SqlUinteger x2 = static_cast<SqlUinteger>(x1); + f2.sqlInteger(x2); + return true; + } + if (t2.type() == SqlType::Bigint) { + SqlUbigint x2 = static_cast<SqlUbigint>(x1); + f2.sqlBigint(x2); + return true; + } + } + ctx_assert(false); + return false; + } + if (t1.type() == SqlType::Integer) { + if (! t2.unSigned()) { + SqlInteger x1 = f1.sqlInteger(); + if (t2.type() == SqlType::Smallint) { + SqlSmallint x2 = static_cast<SqlSmallint>(x1); + if (x1 != static_cast<SqlInteger>(x2)) + return false; + f2.sqlSmallint(x2); + return true; + } + if (t2.type() == SqlType::Integer) { + f2.sqlInteger(x1); + return true; + } + if (t2.type() == SqlType::Bigint) { + SqlBigint x2 = static_cast<SqlBigint>(x1); + f2.sqlBigint(x2); + return true; + } + if (t2.type() == SqlType::Real) { + SqlReal x2 = static_cast<SqlReal>(x1); + f2.sqlReal(x2); + return true; + } + if (t2.type() == SqlType::Double) { + SqlDouble x2 = static_cast<SqlDouble>(x1); + f2.sqlDouble(x2); + return true; + } + } else { + SqlUinteger x1 = f1.sqlInteger(); + if (t2.type() == SqlType::Smallint) { + SqlUsmallint x2 = static_cast<SqlUsmallint>(x1); + if (x1 != static_cast<SqlUinteger>(x2)) + return false; + f2.sqlSmallint(x2); + return true; + } + if (t2.type() == SqlType::Integer) { + f2.sqlInteger(x1); + return true; + } + if (t2.type() == SqlType::Bigint) { + SqlUbigint x2 = static_cast<SqlUbigint>(x1); + f2.sqlBigint(x2); + return true; + } + } + ctx_assert(false); + return false; + } + if (t1.type() == SqlType::Bigint) { + if (! t2.unSigned()) { + SqlBigint x1 = f1.sqlBigint(); + if (t2.type() == SqlType::Smallint) { + SqlSmallint x2 = static_cast<SqlSmallint>(x1); + if (x1 != static_cast<SqlBigint>(x2)) + return false; + f2.sqlSmallint(x2); + return true; + } + if (t2.type() == SqlType::Integer) { + SqlInteger x2 = static_cast<SqlInteger>(x1); + if (x1 != static_cast<SqlBigint>(x2)) + return false; + f2.sqlInteger(x2); + return true; + } + if (t2.type() == SqlType::Bigint) { + f2.sqlBigint(x1); + return true; + } + if (t2.type() == SqlType::Real) { + SqlReal x2 = static_cast<SqlReal>(x1); + f2.sqlReal(x2); + return true; + } + if (t2.type() == SqlType::Double) { + SqlDouble x2 = static_cast<SqlDouble>(x1); + f2.sqlDouble(x2); + return true; + } + } else { + SqlUbigint x1 = f1.sqlBigint(); + if (t2.type() == SqlType::Smallint) { + SqlUsmallint x2 = static_cast<SqlUsmallint>(x1); + if (x1 != static_cast<SqlUbigint>(x2)) + return false; + f2.sqlSmallint(x2); + return true; + } + if (t2.type() == SqlType::Integer) { + SqlUinteger x2 = static_cast<SqlUinteger>(x1); + if (x1 != static_cast<SqlUbigint>(x2)) + return false; + f2.sqlInteger(x2); + return true; + } + if (t2.type() == SqlType::Bigint) { + f2.sqlBigint(x1); + return true; + } + } + ctx_assert(false); + return false; + } + if (t1.type() == SqlType::Real) { + SqlReal x1 = f1.sqlReal(); + int off = 0; + if (x1 > 0.0 && x1 - floor(x1) >= 0.5) + off = 1; + if (x1 < 0.0 && x1 - floor(x1) <= 0.5) + off = -1; + bool b = (x1 - floor(x1) < 0.5); + if (t2.type() == SqlType::Smallint) { + SqlSmallint x2 = static_cast<SqlSmallint>(x1) + off; + if (fabs(x1 - static_cast<SqlReal>(x2)) >= 1.0) + return false; + f2.sqlSmallint(x2); + return true; + } + if (t2.type() == SqlType::Integer) { + SqlInteger x2 = static_cast<SqlInteger>(x1) + off; + if (fabs(x1 - static_cast<SqlReal>(x2)) >= 1.0) + return false; + f2.sqlInteger(x2); + return true; + } + if (t2.type() == SqlType::Bigint) { + SqlBigint x2 = static_cast<SqlBigint>(x1) + off; + if (fabs(x1 - static_cast<SqlReal>(x2)) >= 1.0) + return false; + f2.sqlBigint(x2); + return true; + } + if (t2.type() == SqlType::Real) { + f2.sqlReal(x1); + return true; + } + if (t2.type() == SqlType::Double) { + SqlDouble x2 = static_cast<SqlDouble>(x1); + f2.sqlDouble(x2); + return true; + } + ctx_assert(false); + return false; + } + if (t1.type() == SqlType::Double) { + SqlDouble x1 = f1.sqlDouble(); + int off = 0; + if (x1 > 0.0 && x1 - floor(x1) >= 0.5) + off = 1; + if (x1 < 0.0 && x1 - floor(x1) <= 0.5) + off = -1; + bool b = (x1 - floor(x1) < 0.5); + if (t2.type() == SqlType::Smallint) { + SqlSmallint x2 = static_cast<SqlSmallint>(x1) + off; + if (fabs(x1 - static_cast<SqlDouble>(x2)) >= 1.0) + return false; + f2.sqlSmallint(x2); + return true; + } + if (t2.type() == SqlType::Integer) { + SqlInteger x2 = static_cast<SqlInteger>(x1) + off; + if (fabs(x1 - static_cast<SqlDouble>(x2)) >= 1.0) + return false; + f2.sqlInteger(x2); + return true; + } + if (t2.type() == SqlType::Bigint) { + SqlBigint x2 = static_cast<SqlBigint>(x1) + off; + if (fabs(x1 - static_cast<SqlDouble>(x2)) >= 1.0) + return false; + f2.sqlBigint(x2); + return true; + } + if (t2.type() == SqlType::Real) { + SqlReal x2 = static_cast<SqlReal>(x1); + if (fabs(x1 - static_cast<SqlDouble>(x2)) >= 1.0) // XXX + return false; + f2.sqlReal(x1); + return true; + } + if (t2.type() == SqlType::Double) { + f2.sqlDouble(x1); + return true; + } + ctx_assert(false); + return false; + } + ctx_assert(false); + return false; +} + +bool +SqlField::less(const SqlField& sqlField) const +{ + const SqlField& f1 = *this; + const SqlField& f2 = sqlField; + const SqlType& t1 = f1.sqlSpec().sqlType(); + const SqlType& t2 = f2.sqlSpec().sqlType(); + ctx_assert(t1.type() == t2.type()); + if (t1.type() == SqlType::Char) { + const SqlChar* s1 = f1.sqlChar(); + const SqlChar* s2 = f2.sqlChar(); + unsigned n1 = t1.length(); + unsigned n2 = t2.length(); + SqlChar c1 = 0; + SqlChar c2 = 0; + unsigned i = 0; + while (i < n1 || i < n2) { + c1 = i < n1 ? s1[i] : 0x20; + c2 = i < n2 ? s2[i] : 0x20; + if (c1 != c2) + break; + i++; + } + return (c1 < c2); + } + if (t1.type() == SqlType::Varchar) { + unsigned n1, n2; + const SqlChar* s1 = f1.sqlVarchar(&n1); + const SqlChar* s2 = f2.sqlVarchar(&n2); + SqlChar c1 = 0; + SqlChar c2 = 0; + unsigned i = 0; + while (i < n1 || i < n2) { + c1 = i < n1 ? s1[i] : 0x0; + c2 = i < n2 ? s2[i] : 0x0; + if (c1 != c2) + break; + i++; + } + return (c1 < c2); + } + if (t1.type() == SqlType::Smallint) { + ctx_assert(t1.unSigned() == t2.unSigned()); + if (! t1.unSigned()) { + SqlSmallint x1 = f1.sqlSmallint(); + SqlSmallint x2 = f2.sqlSmallint(); + return (x1 < x2); + } else { + SqlUsmallint x1 = f1.sqlSmallint(); + SqlUsmallint x2 = f2.sqlSmallint(); + return (x1 < x2); + } + } + if (t1.type() == SqlType::Integer) { + ctx_assert(t1.unSigned() == t2.unSigned()); + if (! t1.unSigned()) { + SqlInteger x1 = f1.sqlInteger(); + SqlInteger x2 = f2.sqlInteger(); + return (x1 < x2); + } else { + SqlUinteger x1 = f1.sqlInteger(); + SqlUinteger x2 = f2.sqlInteger(); + return (x1 < x2); + } + } + if (t1.type() == SqlType::Bigint) { + ctx_assert(t1.unSigned() == t2.unSigned()); + if (! t1.unSigned()) { + SqlBigint x1 = f1.sqlBigint(); + SqlBigint x2 = f2.sqlBigint(); + return (x1 < x2); + } else { + SqlUbigint x1 = f1.sqlBigint(); + SqlUbigint x2 = f2.sqlBigint(); + return (x1 < x2); + } + } + if (t1.type() == SqlType::Real) { + SqlReal x1 = f1.sqlReal(); + SqlReal x2 = f2.sqlReal(); + return (x1 < x2); + } + if (t1.type() == SqlType::Double) { + SqlDouble x1 = f1.sqlDouble(); + SqlDouble x2 = f2.sqlDouble(); + return (x1 < x2); + } + if (t1.type() == SqlType::Datetime) { + SqlDatetime x1 = f1.sqlDatetime(); + SqlDatetime x2 = f2.sqlDatetime(); + return x1.less(x2); + } + ctx_assert(false); +} + +// copy from external + +static bool +copyin_char_char(Ctx& ctx, char* value, unsigned n, const char* ptr, const SQLINTEGER* ind, int* off, SqlChar* addr, int fieldId) +{ + if (off != 0 && *off >= 0) { + if ((unsigned)*off > n) { + ctx.pushStatus(Sqlstate::_22001, Error::Gen, "input parameter %d truncated (%u > %u)", fieldId, (unsigned)*off, n); + return false; + } + value += *off; + n -= *off; + } + unsigned m; + if (ind == 0 || *ind == SQL_NTS) + m = strlen(ptr); + else + m = *ind; + if (m > n) { + ctx.pushStatus(Sqlstate::_22001, Error::Gen, "input parameter %d truncated (%u > %u)", fieldId, m, n); + return false; + } + for (unsigned i = 0; i < m; i++) + value[i] = ptr[i]; + if (off != 0 && *off >= 0) + *off += m; + for (unsigned i = m; i < n; i++) + value[i] = addr == 0 ? 0x20 : 0x0; + if (addr != 0) { + if (off != 0 && *off >= 0) + m = *off; + addr[0] = (m >> 8) & 0xff; + addr[1] = (m & 0xff); + } + return true; +} + +static bool +copyin_binary_binary(Ctx& ctx, char* value, unsigned n, const char* ptr, const SQLINTEGER* ind, int* off, SqlChar* addr, int fieldId) +{ + if (off != 0 && *off >= 0) { + if ((unsigned)*off > n) { + ctx.pushStatus(Sqlstate::_22001, Error::Gen, "input parameter %d truncated (%u > %u)", fieldId, (unsigned)*off, n); + return false; + } + value += *off; + n -= *off; + } + if (ind == 0) { + ctx.pushStatus(Sqlstate::_22001, Error::Gen, "input parameter %d missing length", fieldId); + return false; + } + if (*ind < 0) { + ctx.pushStatus(Sqlstate::_22001, Error::Gen, "input parameter %d invalid length %d", fieldId, (int)*ind); + return false; + } + unsigned m; + m = *ind; + if (m > n) { + ctx.pushStatus(Sqlstate::_22001, Error::Gen, "input parameter %d truncated (%u > %u)", fieldId, m, n); + return false; + } + for (unsigned i = 0; i < m; i++) + value[i] = ptr[i]; + if (off != 0 && *off >= 0) + *off += m; + for (unsigned i = m; i < n; i++) + value[i] = addr == 0 ? 0x0 : 0x0; // just null + if (addr != 0) { + if (off != 0 && *off >= 0) + m = *off; + addr[0] = (m >> 8) & 0xff; + addr[1] = (m & 0xff); + } + return true; +} + +static bool +copyin_signed_char(Ctx& ctx, SqlBigint* value, const char* ptr, int fieldId) +{ + errno = 0; + char* endptr = 0; + SqlBigint x = strtoll(ptr, &endptr, 10); + if (endptr == 0 || *endptr != 0) { + errno = 0; + endptr = 0; + double y = strtod(ptr, &endptr); + if (endptr == 0 || *endptr != 0) { + ctx.pushStatus(Sqlstate::_22005, Error::Gen, "input parameter %d value %s not numeric", fieldId, ptr); + return false; + } else if (errno != 0) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "input parameter %d value %s overflow", fieldId, ptr); + return false; + } + // XXX should handle 123.000 + ctx.pushStatus(Sqlstate::_01004, Error::Gen, "input parameter %d value %s truncated", fieldId, ptr); + x = static_cast<SqlBigint>(y); + } else if (errno != 0) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "input parameter %d value %s overflow", fieldId, ptr); + return false; + } + *value = x; + return true; +} + +static bool +copyin_double_char(Ctx& ctx, SqlDouble* value, const char* ptr, int fieldId) +{ + errno = 0; + char* endptr = 0; + double x = strtod(ptr, &endptr); + if (endptr == 0 || *endptr != 0) { + ctx.pushStatus(Sqlstate::_22005, Error::Gen, "input parameter %d value %s not numeric", fieldId, ptr); + return false; + } else if (errno != 0) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "input parameter %d value %s overflow", fieldId, ptr); + return false; + } + *value = x; + return true; +} + +void +SqlField::copyin(Ctx& ctx, ExtField& extField) +{ + ctx_assert(extField.extSpec().extType().type() != ExtType::Unbound); + ctx_assert(sqlSpec().store() == SqlSpec::Physical); + SQLINTEGER* indPtr = extField.m_indPtr; + const int fieldId = extField.fieldId(); + if (indPtr != 0 && *indPtr == SQL_NULL_DATA) { + sqlNull(true); + return; + } + const SqlType& sqlType = sqlSpec().sqlType(); + const ExtType& extType = extField.extSpec().extType(); + if (extField.m_pos > 0) { + if (sqlType.type() == SqlType::Char && extType.type() == ExtType::Char) + ; + else if (sqlType.type() == SqlType::Varchar && extType.type() == ExtType::Char) + ; + else { + char buf[40]; + sqlType.print(buf, sizeof(buf)); + ctx.pushStatus(Sqlstate::_HY019, Error::Gen, "cannot send %s data in pieces", buf); + return; + } + } + if (sqlType.type() == SqlType::Char || sqlType.type() == SqlType::Varchar) { + unsigned length = 0; + char* value = 0; + SqlChar* laddr = 0; // Varchar length address + if (sqlType.type() == SqlType::Char) { + length = sqlType.length(); + if (length > SqlField_CharSmall) + value = reinterpret_cast<char *>(u_data.m_sqlChar); + else + value = reinterpret_cast<char *>(u_data.m_sqlCharSmall); + laddr = 0; + } else { +#if NDB_VERSION_MAJOR >= 3 + length = sqlType.length(); + if (2 + length > SqlField_CharSmall) + value = reinterpret_cast<char *>(u_data.m_sqlChar + 2); + else + value = reinterpret_cast<char *>(u_data.m_sqlCharSmall + 2); + laddr = (SqlChar*)value - 2; +#else + length = sqlType.length(); + if (length + 2 > SqlField_CharSmall) + value = reinterpret_cast<char *>(u_data.m_sqlChar); + else + value = reinterpret_cast<char *>(u_data.m_sqlCharSmall); + laddr = (SqlChar*)value + length; +#endif + } + if (extType.type() == ExtType::Char) { + const char* dataPtr = static_cast<char*>(extField.m_dataPtr); + int* off = 0; + if (extField.m_pos >= 0) + off = &extField.m_pos; + if (! copyin_char_char(ctx, value, length, dataPtr, indPtr, off, laddr, fieldId)) + return; + sqlNull(false); + return; + } + if (extType.type() == ExtType::Short || extType.type() == ExtType::Sshort) { + const short* dataPtr = static_cast<short*>(extField.m_dataPtr); + char buf[100]; + sprintf(buf, "%hd", *dataPtr); + if (! copyin_char_char(ctx, value, length, buf, indPtr, 0, laddr, fieldId)) + return; + sqlNull(false); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ushort) { + const unsigned short* dataPtr = static_cast<unsigned short*>(extField.m_dataPtr); + char buf[100]; + sprintf(buf, "%hu", *dataPtr); + if (! copyin_char_char(ctx, value, length, buf, indPtr, 0, laddr, fieldId)) + return; + sqlNull(false); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Long || extType.type() == ExtType::Slong) { + const long* dataPtr = static_cast<long*>(extField.m_dataPtr); + char buf[100]; + sprintf(buf, "%ld", *dataPtr); + if (! copyin_char_char(ctx, value, length, buf, indPtr, 0, laddr, fieldId)) + return; + sqlNull(false); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ulong) { + const unsigned long* dataPtr = static_cast<unsigned long*>(extField.m_dataPtr); + char buf[100]; + sprintf(buf, "%lu", *dataPtr); + if (! copyin_char_char(ctx, value, length, buf, indPtr, 0, laddr, fieldId)) + return; + sqlNull(false); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Sbigint) { + const SQLBIGINT* dataPtr = static_cast<SQLBIGINT*>(extField.m_dataPtr); + char buf[100]; + sprintf(buf, FMT_I64, *dataPtr); + if (! copyin_char_char(ctx, value, length, buf, indPtr, 0, laddr, fieldId)) + return; + sqlNull(false); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ubigint) { + const SQLUBIGINT* dataPtr = static_cast<SQLUBIGINT*>(extField.m_dataPtr); + char buf[100]; + sprintf(buf, FMT_U64, *dataPtr); + if (! copyin_char_char(ctx, value, length, buf, indPtr, 0, laddr, fieldId)) + return; + sqlNull(false); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Float) { + const float* dataPtr = static_cast<float*>(extField.m_dataPtr); + char buf[100]; + sprintf(buf, "%.7f", (double)*dataPtr); + if (! copyin_char_char(ctx, value, length, buf, indPtr, 0, laddr, fieldId)) + return; + sqlNull(false); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Double) { + const double* dataPtr = static_cast<double*>(extField.m_dataPtr); + char buf[100]; + sprintf(buf, "%.14f", *dataPtr); + if (! copyin_char_char(ctx, value, length, buf, indPtr, 0, laddr, fieldId)) + return; + sqlNull(false); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + } + if (sqlType.type() == SqlType::Binary || sqlType.type() == SqlType::Varbinary) { + unsigned length = 0; + char* value = 0; + SqlChar* laddr = 0; // Varbinary length address + if (sqlType.type() == SqlType::Binary) { + length = sqlType.length(); + if (length > SqlField_CharSmall) + value = reinterpret_cast<char *>(u_data.m_sqlChar); + else + value = reinterpret_cast<char *>(u_data.m_sqlCharSmall); + laddr = 0; + } else { +#if NDB_VERSION_MAJOR >= 3 + length = sqlType.length(); + if (2 + length > SqlField_CharSmall) + value = reinterpret_cast<char *>(u_data.m_sqlChar + 2); + else + value = reinterpret_cast<char *>(u_data.m_sqlCharSmall + 2); + laddr = (SqlChar*)value - 2; +#else + length = sqlType.length(); + if (length + 2 > SqlField_CharSmall) + value = reinterpret_cast<char *>(u_data.m_sqlChar); + else + value = reinterpret_cast<char *>(u_data.m_sqlCharSmall); + laddr = (SqlChar*)value + length; +#endif + } + if (extType.type() == ExtType::Binary) { + const char* dataPtr = static_cast<char*>(extField.m_dataPtr); + int* off = 0; + if (extField.m_pos >= 0) + off = &extField.m_pos; + if (! copyin_binary_binary(ctx, value, length, dataPtr, indPtr, off, laddr, fieldId)) + return; + sqlNull(false); + return; + } + } + if (sqlType.type() == SqlType::Smallint) { + SqlSmallint value; + if (extType.type() == ExtType::Char) { + const char* dataPtr = static_cast<char*>(extField.m_dataPtr); + SqlBigint x; + if (! copyin_signed_char(ctx, &x, dataPtr, fieldId)) + return; + value = x; + sqlSmallint(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Short || extType.type() == ExtType::Sshort) { + short* dataPtr = static_cast<short*>(extField.m_dataPtr); + value = *dataPtr; + sqlSmallint(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ushort) { + unsigned short* dataPtr = static_cast<unsigned short*>(extField.m_dataPtr); + value = *dataPtr; + sqlSmallint(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Long || extType.type() == ExtType::Slong) { + long* dataPtr = static_cast<long*>(extField.m_dataPtr); + value = *dataPtr; + sqlSmallint(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ulong) { + unsigned long* dataPtr = static_cast<unsigned long*>(extField.m_dataPtr); + value = *dataPtr; + sqlSmallint(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Sbigint) { + SQLBIGINT* dataPtr = static_cast<SQLBIGINT*>(extField.m_dataPtr); + value = *dataPtr; + sqlSmallint(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ubigint) { + SQLUBIGINT* dataPtr = static_cast<SQLUBIGINT*>(extField.m_dataPtr); + value = *dataPtr; + sqlSmallint(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Float) { + float* dataPtr = static_cast<float*>(extField.m_dataPtr); + value = (SqlSmallint)*dataPtr; + sqlSmallint(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Double) { + double* dataPtr = static_cast<double*>(extField.m_dataPtr); + value = (SqlSmallint)*dataPtr; + sqlSmallint(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + } + if (sqlType.type() == SqlType::Integer) { + SqlInteger value; + if (extType.type() == ExtType::Char) { + const char* dataPtr = static_cast<char*>(extField.m_dataPtr); + SqlBigint x; + if (! copyin_signed_char(ctx, &x, dataPtr, fieldId)) + return; + value = x; + sqlInteger(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Short || extType.type() == ExtType::Sshort) { + short* dataPtr = static_cast<short*>(extField.m_dataPtr); + value = *dataPtr; + sqlInteger(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ushort) { + unsigned short* dataPtr = static_cast<unsigned short*>(extField.m_dataPtr); + value = *dataPtr; + sqlInteger(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Long || extType.type() == ExtType::Slong) { + long* dataPtr = static_cast<long*>(extField.m_dataPtr); + value = *dataPtr; + sqlInteger(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ulong) { + unsigned long* dataPtr = static_cast<unsigned long*>(extField.m_dataPtr); + value = *dataPtr; + sqlInteger(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Sbigint) { + SQLBIGINT* dataPtr = static_cast<SQLBIGINT*>(extField.m_dataPtr); + value = *dataPtr; + sqlInteger(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ubigint) { + SQLUBIGINT* dataPtr = static_cast<SQLUBIGINT*>(extField.m_dataPtr); + value = *dataPtr; + sqlInteger(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Float) { + float* dataPtr = static_cast<float*>(extField.m_dataPtr); + value = (SqlInteger)*dataPtr; + sqlInteger(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Double) { + double* dataPtr = static_cast<double*>(extField.m_dataPtr); + value = (SqlInteger)*dataPtr; + sqlInteger(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + } + if (sqlType.type() == SqlType::Bigint) { + SqlBigint value; + if (extType.type() == ExtType::Char) { + const char* dataPtr = static_cast<char*>(extField.m_dataPtr); + SqlBigint x; + if (! copyin_signed_char(ctx, &x, dataPtr, fieldId)) + return; + value = x; + sqlBigint(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Short || extType.type() == ExtType::Sshort) { + short* dataPtr = static_cast<short*>(extField.m_dataPtr); + value = *dataPtr; + sqlBigint(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ushort) { + unsigned short* dataPtr = static_cast<unsigned short*>(extField.m_dataPtr); + value = *dataPtr; + sqlBigint(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Long || extType.type() == ExtType::Slong) { + long* dataPtr = static_cast<long*>(extField.m_dataPtr); + value = *dataPtr; + sqlBigint(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ulong) { + unsigned long* dataPtr = static_cast<unsigned long*>(extField.m_dataPtr); + value = *dataPtr; + sqlBigint(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Sbigint) { + SQLBIGINT* dataPtr = static_cast<SQLBIGINT*>(extField.m_dataPtr); + value = *dataPtr; + sqlBigint(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ubigint) { + SQLUBIGINT* dataPtr = static_cast<SQLUBIGINT*>(extField.m_dataPtr); + value = *dataPtr; + sqlBigint(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Float) { + float* dataPtr = static_cast<float*>(extField.m_dataPtr); + value = (SqlBigint)*dataPtr; + sqlBigint(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Double) { + double* dataPtr = static_cast<double*>(extField.m_dataPtr); + value = (SqlBigint)*dataPtr; + sqlBigint(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + } + if (sqlType.type() == SqlType::Real) { + SqlReal value; + if (extType.type() == ExtType::Char) { + const char* dataPtr = static_cast<char*>(extField.m_dataPtr); + SqlDouble x; + if (! copyin_double_char(ctx, &x, dataPtr, fieldId)) + return; + value = x; + sqlReal(x); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Short || extType.type() == ExtType::Sshort) { + short* dataPtr = static_cast<short*>(extField.m_dataPtr); + value = *dataPtr; + sqlReal(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ushort) { + unsigned short* dataPtr = static_cast<unsigned short*>(extField.m_dataPtr); + value = *dataPtr; + sqlReal(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Long || extType.type() == ExtType::Slong) { + long* dataPtr = static_cast<long*>(extField.m_dataPtr); + value = *dataPtr; + sqlReal(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ulong) { + unsigned long* dataPtr = static_cast<unsigned long*>(extField.m_dataPtr); + value = *dataPtr; + sqlReal(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Sbigint) { + SQLBIGINT* dataPtr = static_cast<SQLBIGINT*>(extField.m_dataPtr); + value = *dataPtr; + sqlReal(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ubigint) { + SQLUBIGINT* dataPtr = static_cast<SQLUBIGINT*>(extField.m_dataPtr); + value = *dataPtr; + sqlReal(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Float) { + float* dataPtr = static_cast<float*>(extField.m_dataPtr); + value = *dataPtr; + sqlReal(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Double) { + double* dataPtr = static_cast<double*>(extField.m_dataPtr); + value = *dataPtr; + sqlReal(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + } + if (sqlType.type() == SqlType::Double) { + SqlDouble value; + if (extType.type() == ExtType::Char) { + const char* dataPtr = static_cast<char*>(extField.m_dataPtr); + SqlDouble x; + if (! copyin_double_char(ctx, &x, dataPtr, fieldId)) + return; + value = x; + sqlDouble(x); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Short || extType.type() == ExtType::Sshort) { + short* dataPtr = static_cast<short*>(extField.m_dataPtr); + value = *dataPtr; + sqlDouble(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ushort) { + unsigned short* dataPtr = static_cast<unsigned short*>(extField.m_dataPtr); + value = *dataPtr; + sqlDouble(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Long || extType.type() == ExtType::Slong) { + long* dataPtr = static_cast<long*>(extField.m_dataPtr); + value = *dataPtr; + sqlDouble(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ulong) { + unsigned long* dataPtr = static_cast<unsigned long*>(extField.m_dataPtr); + value = *dataPtr; + sqlDouble(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Sbigint) { + SQLBIGINT* dataPtr = static_cast<SQLBIGINT*>(extField.m_dataPtr); + value = *dataPtr; + sqlDouble(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ubigint) { + SQLUBIGINT* dataPtr = static_cast<SQLUBIGINT*>(extField.m_dataPtr); + value = *dataPtr; + sqlDouble(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Float) { + float* dataPtr = static_cast<float*>(extField.m_dataPtr); + value = *dataPtr; + sqlDouble(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Double) { + double* dataPtr = static_cast<double*>(extField.m_dataPtr); + value = *dataPtr; + sqlDouble(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + } + if (sqlType.type() == SqlType::Datetime) { + SqlDatetime value; + if (extType.type() == ExtType::Char) { + // XXX replace sscanf by manual scan or regex + const char* dataPtr = static_cast<char*>(extField.m_dataPtr); + int cc = 0; + unsigned yy = 0, mm = 0, dd = 0, HH = 0, MM = 0, SS = 0, ff = 0; + bool setdate = false; + char dummy[10]; + if (sscanf(dataPtr, "%2d%2u-%2u-%2u %2u:%2u:%2u.%4u%1s", &cc, &yy, &mm, &dd, &HH, &MM, &SS, &ff, dummy) == 8) { + ; + } else if (sscanf(dataPtr, "%2d%2u-%2u-%2u %2u:%2u:%2u%1s", &cc, &yy, &mm, &dd, &HH, &MM, &SS, dummy) == 7) { + ; + } else if (sscanf(dataPtr, "%2d%2u-%2u-%2u%1s", &cc, &yy, &mm, &dd, dummy) == 4) { + ; + } else if (sscanf(dataPtr, "%2u:%2u:%2u.%4u%1s", &HH, &MM, &SS, &ff, dummy) == 4) { + setdate = true; + } else if (sscanf(dataPtr, "%2u:%2u:%2u%1s", &HH, &MM, &SS, dummy) == 3) { + setdate = true; + } else { + ctx.pushStatus(Sqlstate::_22008, Error::Gen, "invalid timestamp format '%s'", dataPtr); + return; + } + if (setdate) { + time_t clock = time(0); + struct tm* t = localtime(&clock); + cc = (1900 + t->tm_year) / 100; + yy = (1900 + t->tm_year) % 100; + mm = 1 + t->tm_mon; + dd = t->tm_mday; + } + value.cc(cc); + value.yy(yy); + value.mm(mm); + value.dd(dd); + value.HH(HH); + value.MM(MM); + value.SS(SS); + value.ff(ff); + // XXX write date routines later + if (! value.valid()) { + ctx.pushStatus(Sqlstate::_22008, Error::Gen, "invalid timestamp values '%s'", dataPtr); + return; + } + sqlDatetime(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Timestamp) { + SQL_TIMESTAMP_STRUCT* dataPtr = static_cast<SQL_TIMESTAMP_STRUCT*>(extField.m_dataPtr); + // XXX assume same datatype + value.cc(dataPtr->year / 100); + value.yy(dataPtr->year / 100); + value.mm(dataPtr->month); + value.dd(dataPtr->day); + value.HH(dataPtr->hour); + value.MM(dataPtr->minute); + value.SS(dataPtr->second); + value.ff(dataPtr->fraction); + if (! value.valid()) { + ctx.pushStatus(Sqlstate::_22008, Error::Gen, "invalid timestamp struct"); + return; + } + sqlDatetime(value); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + } + ctx_assert(false); // SqlType::Null not applicable +} + +// copy to external + +static bool +copyout_char_char(Ctx& ctx, const char* value, unsigned n, char* ptr, unsigned len, SQLINTEGER* ind, int* off) +{ + unsigned n2 = n; + if (off != 0 && *off >= 0) { + ctx_assert((unsigned)*off <= n2); + value += *off; + n2 -= *off; + if (len < n2 + 1) { + ctx.pushStatus(Sqlstate::_01004, Error::Gen, "more data at offset %d, current fetch %u, available %u", *off, len, n2); + n2 = len - 1; + } + } else { + if (len < n + 1) { // room for null byte + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "char value '%.*s' overflow (%u < %u)", (int)n, value, (unsigned)len, (unsigned)(len + 1)); + return false; + } + } + memcpy(ptr, value, n2); + ptr[n2] = 0; + if (off != 0 && *off >= 0) { + if (ind != 0) + *ind = n - *off; + *off += n2; + } else { + if (ind != 0) + *ind = n; + } + return true; +} + +static bool +copyout_binary_binary(Ctx& ctx, const char* value, unsigned n, char* ptr, unsigned len, SQLINTEGER* ind, int* off) +{ + unsigned n2 = n; + if (off != 0 && *off >= 0) { + ctx_assert((unsigned)*off <= n2); + value += *off; + n2 -= *off; + if (len < n2 + 1) { + ctx.pushStatus(Sqlstate::_01004, Error::Gen, "more data at offset %d, current fetch %u, available %u", *off, len, n2); + n2 = len - 1; + } + } else { + if (len < n) { // no room for null byte + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "binary value '%.*s' overflow (%u < %u)", (int)n, value, (unsigned)len, (unsigned)n); + return false; + } + } + memcpy(ptr, value, n2); + ptr[n2] = 0; + if (off != 0 && *off >= 0) { + if (ind != 0) + *ind = n - *off; + *off += n2; + } else { + if (ind != 0) + *ind = n; + } + return true; +} + +static bool +copyout_char_signed(Ctx& ctx, const char* value, unsigned n, long* ptr) +{ + while (n > 0 && value[0] == 0x20) { + value++; + n--; + } + char buf[200]; + if (n >= 200) + n = 200 - 1; + memcpy(buf, value, n); + buf[n] = 0; + errno = 0; + char* endptr = 0; + long x = strtol(buf, &endptr, 10); + if (endptr == 0 || *endptr != 0) { + errno = 0; + endptr = 0; + double y = strtod(buf, &endptr); + if (endptr == 0 || *endptr != 0) { + ctx.pushStatus(Sqlstate::_22005, Error::Gen, "value %s not numeric", buf); + return false; + } else if (errno != 0) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value %s overflow", buf); + return false; + } + // XXX should handle 123.000 + ctx.pushStatus(Sqlstate::_01004, Error::Gen, "value %s truncated", buf); + x = static_cast<long>(y); + } else if (errno != 0) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value %s overflow", buf); + return false; + } + *ptr = x; + return true; +} + +static bool +copyout_char_bigsigned(Ctx& ctx, const char* value, unsigned n, SQLBIGINT* ptr) +{ + while (n > 0 && value[0] == 0x20) { + value++; + n--; + } + char buf[200]; + if (n >= 200) + n = 200 - 1; + memcpy(buf, value, n); + buf[n] = 0; + errno = 0; + char* endptr = 0; + SQLBIGINT x = strtoll(buf, &endptr, 10); + if (endptr == 0 || *endptr != 0) { + errno = 0; + endptr = 0; + double y = strtod(buf, &endptr); + if (endptr == 0 || *endptr != 0) { + ctx.pushStatus(Sqlstate::_22005, Error::Gen, "value %s not numeric", buf); + return false; + } else if (errno != 0) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value %s overflow", buf); + return false; + } + // XXX should handle 123.000 + ctx.pushStatus(Sqlstate::_01004, Error::Gen, "value %s truncated", buf); + x = static_cast<long>(y); + } else if (errno != 0) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value %s overflow", buf); + return false; + } + *ptr = x; + return true; +} + +static bool +copyout_char_unsigned(Ctx& ctx, const char* value, unsigned n, unsigned long* ptr) +{ + while (n > 0 && value[0] == 0x20) { + value++; + n--; + } + char buf[200]; + if (n >= 200) + n = 200 - 1; + memcpy(buf, value, n); + buf[n] = 0; + errno = 0; + char* endptr = 0; + unsigned long x = strtoul(buf, &endptr, 10); + if (endptr == 0 || *endptr != 0) { + errno = 0; + endptr = 0; + double y = strtod(buf, &endptr); + if (endptr == 0 || *endptr != 0) { + ctx.pushStatus(Sqlstate::_22005, Error::Gen, "value %s not numeric", buf); + return false; + } else if (errno != 0) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value %s overflow", buf); + return false; + } + // XXX should handle 123.000 + ctx.pushStatus(Sqlstate::_01004, Error::Gen, "value %s truncated", buf); + x = static_cast<unsigned long>(y); + } else if (errno != 0) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value %s overflow", buf); + return false; + } + *ptr = x; + return true; +} + +static bool +copyout_char_bigunsigned(Ctx& ctx, const char* value, unsigned n, SQLUBIGINT* ptr) +{ + while (n > 0 && value[0] == 0x20) { + value++; + n--; + } + char buf[200]; + if (n >= 200) + n = 200 - 1; + memcpy(buf, value, n); + buf[n] = 0; + errno = 0; + char* endptr = 0; + SQLUBIGINT x = strtoull(buf, &endptr, 10); + if (endptr == 0 || *endptr != 0) { + errno = 0; + endptr = 0; + double y = strtod(buf, &endptr); + if (endptr == 0 || *endptr != 0) { + ctx.pushStatus(Sqlstate::_22005, Error::Gen, "value %s not numeric", buf); + return false; + } else if (errno != 0) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value %s overflow", buf); + return false; + } + // XXX should handle 123.000 + ctx.pushStatus(Sqlstate::_01004, Error::Gen, "value %s truncated", buf); + x = static_cast<unsigned long>(y); + } else if (errno != 0) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value %s overflow", buf); + return false; + } + *ptr = x; + return true; +} + +static bool +copyout_char_double(Ctx& ctx, const char* value, unsigned n, double* ptr) +{ + while (n > 0 && value[0] == 0x20) { + value++; + n--; + } + char buf[200]; + if (n >= 200) + n = 200 - 1; + memcpy(buf, value, n); + buf[n] = 0; + errno = 0; + char* endptr = 0; + double x = strtod(value, &endptr); + if (endptr == 0 || *endptr != 0) { + ctx.pushStatus(Sqlstate::_22005, Error::Gen, "value %s not numeric", value); + return false; + } else if (errno != 0) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value %s overflow", value); + return false; + } + *ptr = x; + return true; +} + +static bool +copyout_signed_char(Ctx& ctx, Int64 value, char* ptr, int len, SQLINTEGER* ind) +{ + char buf[100]; + sprintf(buf, FMT_I64, value); + unsigned n = strlen(buf); + if (len <= 0) { + ctx.pushStatus(Sqlstate::_HY090, Error::Gen, "invalid output buffer length %d", len); + return false; + } + if ((unsigned)len < n + 1) { // room for null byte + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value %s overflow", buf); + return false; + } + strcpy(ptr, buf); + if (ind != 0) + *ind = n; + return true; +} + +static bool +copyout_unsigned_char(Ctx& ctx, Uint64 uvalue, char* ptr, int len, SQLINTEGER* ind) +{ + char buf[100]; + sprintf(buf, FMT_U64, uvalue); + unsigned n = strlen(buf); + if (len <= 0) { + ctx.pushStatus(Sqlstate::_HY090, Error::Gen, "invalid output buffer length %d", len); + return false; + } + if ((unsigned)len < n + 1) { // room for null byte + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value %s overflow", buf); + return false; + } + strcpy(ptr, buf); + if (ind != 0) + *ind = n; + return true; +} + +static bool +copyout_double_char(Ctx& ctx, double value, unsigned prec, char* ptr, int len, SQLINTEGER* ind) +{ + char buf[100]; + sprintf(buf, "%.*f", (int)prec, value); + char* p = buf + strlen(buf); + while (p > buf + prec) + *--p = 0; + while (p > buf && *(p - 1) == '0') + *--p = 0; + if (p > buf && *(p - 1) == '.') { + *p++ = '0'; + *p = 0; + } + unsigned n = strlen(buf); + if (len <= 0) { + ctx.pushStatus(Sqlstate::_HY090, Error::Gen, "invalid output buffer length %d", len); + return false; + } + if ((unsigned)len < n + 1) { // room for null byte + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value %s overflow", buf); + return false; + } + strcpy(ptr, buf); + if (ind != 0) + *ind = n; + return true; +} + +void +SqlField::copyout(Ctx& ctx, ExtField& extField) const +{ + if (extField.extSpec().extType().type() == ExtType::Unbound) { + return; // output buffer may be unbound + } + if (sqlSpec().store() == SqlSpec::Reference) { + ctx_assert(u_data.m_sqlField != 0); + u_data.m_sqlField->copyout(ctx, extField); + return; + } + SQLINTEGER* indPtr = extField.m_indPtr; + if (u_null.m_nullFlag) { + if (extField.m_pos > 0) { // second time from SQLGetData + ctx.setCode(SQL_NO_DATA); + return; + } + if (indPtr == 0) { + ctx.pushStatus(Sqlstate::_22002, Error::Gen, "indicator variable required"); + return; + } + *indPtr = SQL_NULL_DATA; + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + const SqlType& sqlType = sqlSpec().sqlType(); + const ExtType& extType = extField.extSpec().extType(); + if (sqlType.type() == SqlType::Char || sqlType.type() == SqlType::Varchar) { + unsigned n = 0; + const char* value = 0; + if (sqlType.type() == SqlType::Char) { + n = sqlType.length(); + value = reinterpret_cast<const char*>(sqlChar()); + } else { + value = reinterpret_cast<const char*>(sqlVarchar(&n)); + } + if (extType.type() == ExtType::Char) { + char* dataPtr = static_cast<char*>(extField.m_dataPtr); + if (extField.m_dataLen <= 0) { + ctx.pushStatus(Sqlstate::_HY090, Error::Gen, "invalid output buffer length %d", (int)extField.m_dataLen); + return; + } + int* off = 0; + if (extField.m_pos >= 0) { + off = &extField.m_pos; + if ((unsigned)*off >= n) { + ctx.setCode(SQL_NO_DATA); + return; + } + } + if (! copyout_char_char(ctx, value, n, dataPtr, extField.m_dataLen, indPtr, off)) + return; + return; + } + if (extType.type() == ExtType::Short || extType.type() == ExtType::Sshort) { + if (extField.m_pos > 0) { + ctx.setCode(SQL_NO_DATA); + return; + } + short* dataPtr = static_cast<short*>(extField.m_dataPtr); + long x; + if (! copyout_char_signed(ctx, value, n, &x)) + return; + if (x < SHRT_MIN || x > SHRT_MAX) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value %s overflow", value); + return; + } + *dataPtr = static_cast<short>(x); + if (indPtr != 0) + *indPtr = sizeof(short); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ushort) { + if (extField.m_pos > 0) { + ctx.setCode(SQL_NO_DATA); + return; + } + unsigned short* dataPtr = static_cast<unsigned short*>(extField.m_dataPtr); + unsigned long x; + if (! copyout_char_unsigned(ctx, value, n, &x)) + return; + if (x > USHRT_MAX) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value %s overflow", value); + return; + } + *dataPtr = static_cast<unsigned short>(x); + if (indPtr != 0) + *indPtr = sizeof(unsigned short); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Long || extType.type() == ExtType::Slong) { + if (extField.m_pos > 0) { + ctx.setCode(SQL_NO_DATA); + return; + } + long* dataPtr = static_cast<long*>(extField.m_dataPtr); + if (! copyout_char_signed(ctx, value, n, dataPtr)) + return; + if (indPtr != 0) + *indPtr = sizeof(long); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ulong) { + if (extField.m_pos > 0) { + ctx.setCode(SQL_NO_DATA); + return; + } + unsigned long* dataPtr = static_cast<unsigned long*>(extField.m_dataPtr); + if (! copyout_char_unsigned(ctx, value, n, dataPtr)) + return; + if (indPtr != 0) + *indPtr = sizeof(unsigned long); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Sbigint) { + if (extField.m_pos > 0) { + ctx.setCode(SQL_NO_DATA); + return; + } + SQLBIGINT* dataPtr = static_cast<SQLBIGINT*>(extField.m_dataPtr); + if (! copyout_char_bigsigned(ctx, value, n, dataPtr)) + return; + if (indPtr != 0) + *indPtr = sizeof(SQLBIGINT); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ubigint) { + if (extField.m_pos > 0) { + ctx.setCode(SQL_NO_DATA); + return; + } + SQLUBIGINT* dataPtr = static_cast<SQLUBIGINT*>(extField.m_dataPtr); + if (! copyout_char_bigunsigned(ctx, value, n, dataPtr)) + return; + if (indPtr != 0) + *indPtr = sizeof(SQLUBIGINT); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Float) { + if (extField.m_pos > 0) { + ctx.setCode(SQL_NO_DATA); + return; + } + float* dataPtr = static_cast<float*>(extField.m_dataPtr); + double x; + if (! copyout_char_double(ctx, value, n, &x)) + return; + if (fabs(x) < FLT_MIN || fabs(x) > FLT_MAX) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value %s overflow", value); + return; + } + *dataPtr = static_cast<float>(x); + if (indPtr != 0) + *indPtr = sizeof(float); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Double) { + if (extField.m_pos > 0) { + ctx.setCode(SQL_NO_DATA); + return; + } + double* dataPtr = static_cast<double*>(extField.m_dataPtr); + double x; + if (! copyout_char_double(ctx, value, n, &x)) + return; + *dataPtr = static_cast<double>(x); + if (indPtr != 0) + *indPtr = sizeof(double); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + } + if (sqlType.type() == SqlType::Binary || sqlType.type() == SqlType::Varbinary) { + unsigned n = 0; + const char* value = 0; + if (sqlType.type() == SqlType::Binary) { + n = sqlType.length(); + value = reinterpret_cast<const char*>(sqlBinary()); + } else { + value = reinterpret_cast<const char*>(sqlVarbinary(&n)); + } + if (extType.type() == ExtType::Binary) { + char* dataPtr = static_cast<char*>(extField.m_dataPtr); + if (extField.m_dataLen <= 0) { + ctx.pushStatus(Sqlstate::_HY090, Error::Gen, "invalid output buffer length %d", (int)extField.m_dataLen); + return; + } + int* off = 0; + if (extField.m_pos >= 0) { + off = &extField.m_pos; + if ((unsigned)*off >= n) { + ctx.setCode(SQL_NO_DATA); + return; + } + } + if (! copyout_binary_binary(ctx, value, n, dataPtr, extField.m_dataLen, indPtr, off)) + return; + return; + } + } + if (sqlType.type() == SqlType::Smallint) { + if (extField.m_pos > 0) { + ctx.setCode(SQL_NO_DATA); + return; + } + const SqlSmallint value = sqlSmallint(); + const SqlUsmallint uvalue = value; + if (extType.type() == ExtType::Char) { + char* dataPtr = static_cast<char*>(extField.m_dataPtr); + if (! sqlType.unSigned()) { + if (! copyout_signed_char(ctx, value, dataPtr, extField.m_dataLen, indPtr)) + return; + } else { + if (! copyout_unsigned_char(ctx, uvalue, dataPtr, extField.m_dataLen, indPtr)) + return; + } + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Short || extType.type() == ExtType::Sshort) { + short* dataPtr = static_cast<short*>(extField.m_dataPtr); + *dataPtr = static_cast<short>(value); // big enough + if (indPtr != 0) + *indPtr = sizeof(short); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ushort) { + unsigned short* dataPtr = static_cast<unsigned short*>(extField.m_dataPtr); + *dataPtr = static_cast<unsigned short>(uvalue); + if (indPtr != 0) + *indPtr = sizeof(unsigned short); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Long || extType.type() == ExtType::Slong) { + long* dataPtr = static_cast<long*>(extField.m_dataPtr); + *dataPtr = static_cast<long>(value); // big enough + if (indPtr != 0) + *indPtr = sizeof(long); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ulong) { + unsigned long* dataPtr = static_cast<unsigned long*>(extField.m_dataPtr); + *dataPtr = static_cast<unsigned long>(uvalue); + if (indPtr != 0) + *indPtr = sizeof(unsigned long); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Sbigint) { + SQLBIGINT* dataPtr = static_cast<SQLBIGINT*>(extField.m_dataPtr); + *dataPtr = static_cast<SQLBIGINT>(value); // big enough + if (indPtr != 0) + *indPtr = sizeof(SQLBIGINT); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ubigint) { + SQLUBIGINT* dataPtr = static_cast<SQLUBIGINT*>(extField.m_dataPtr); + *dataPtr = static_cast<SQLUBIGINT>(uvalue); + if (indPtr != 0) + *indPtr = sizeof(SQLUBIGINT); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Float) { + float* dataPtr = static_cast<float*>(extField.m_dataPtr); + *dataPtr = static_cast<float>(value); // big enough + if (indPtr != 0) + *indPtr = sizeof(float); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Double) { + double* dataPtr = static_cast<double*>(extField.m_dataPtr); + *dataPtr = static_cast<double>(value); // big enough + if (indPtr != 0) + *indPtr = sizeof(double); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + } + if (sqlType.type() == SqlType::Integer) { + if (extField.m_pos > 0) { + ctx.setCode(SQL_NO_DATA); + return; + } + const SqlInteger value = sqlInteger(); + const SqlUinteger uvalue = value; + if (extType.type() == ExtType::Char) { + char* dataPtr = static_cast<char*>(extField.m_dataPtr); + if (! sqlType.unSigned()) { + if (! copyout_signed_char(ctx, value, dataPtr, extField.m_dataLen, indPtr)) + return; + } else { + if (! copyout_unsigned_char(ctx, uvalue, dataPtr, extField.m_dataLen, indPtr)) + return; + } + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Short || extType.type() == ExtType::Sshort) { + short* dataPtr = static_cast<short*>(extField.m_dataPtr); + if (value < SHRT_MIN || value > SHRT_MAX) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value %d overflow", (int)value); + return; + } + *dataPtr = static_cast<short>(value); + if (indPtr != 0) + *indPtr = sizeof(short); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ushort) { + unsigned short* dataPtr = static_cast<unsigned short*>(extField.m_dataPtr); + if (uvalue > USHRT_MAX) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value %u overflow", uvalue); + return; + } + *dataPtr = static_cast<unsigned short>(value); + if (indPtr != 0) + *indPtr = sizeof(unsigned short); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Long || extType.type() == ExtType::Slong) { + long* dataPtr = static_cast<long*>(extField.m_dataPtr); + *dataPtr = static_cast<long>(value); // big enough + if (indPtr != 0) + *indPtr = sizeof(long); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ulong) { + unsigned long* dataPtr = static_cast<unsigned long*>(extField.m_dataPtr); + *dataPtr = static_cast<unsigned long>(uvalue); + if (indPtr != 0) + *indPtr = sizeof(unsigned long); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Sbigint) { + SQLBIGINT* dataPtr = static_cast<SQLBIGINT*>(extField.m_dataPtr); + *dataPtr = static_cast<SQLBIGINT>(value); // big enough + if (indPtr != 0) + *indPtr = sizeof(SQLBIGINT); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ubigint) { + SQLUBIGINT* dataPtr = static_cast<SQLUBIGINT*>(extField.m_dataPtr); + *dataPtr = static_cast<SQLUBIGINT>(uvalue); + if (indPtr != 0) + *indPtr = sizeof(SQLUBIGINT); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Float) { + float* dataPtr = static_cast<float*>(extField.m_dataPtr); + *dataPtr = static_cast<float>(value); // big enough + if (indPtr != 0) + *indPtr = sizeof(float); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Double) { + double* dataPtr = static_cast<double*>(extField.m_dataPtr); + *dataPtr = static_cast<double>(value); // big enough + if (indPtr != 0) + *indPtr = sizeof(double); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + } + if (sqlType.type() == SqlType::Bigint) { + if (extField.m_pos > 0) { + ctx.setCode(SQL_NO_DATA); + return; + } + const SqlBigint value = sqlBigint(); + const SqlUbigint uvalue = value; + if (extType.type() == ExtType::Char) { + char* dataPtr = static_cast<char*>(extField.m_dataPtr); + if (! sqlType.unSigned()) { + if (! copyout_signed_char(ctx, value, dataPtr, extField.m_dataLen, indPtr)) + return; + } else { + if (! copyout_unsigned_char(ctx, uvalue, dataPtr, extField.m_dataLen, indPtr)) + return; + } + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Short || extType.type() == ExtType::Sshort) { + short* dataPtr = static_cast<short*>(extField.m_dataPtr); + if (value < SHRT_MIN || value > SHRT_MAX) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value " FMT_I64 " overflow", (Int64)value); + return; + } + *dataPtr = static_cast<short>(value); + if (indPtr != 0) + *indPtr = sizeof(short); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ushort) { + unsigned short* dataPtr = static_cast<unsigned short*>(extField.m_dataPtr); + if (uvalue > USHRT_MAX) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value " FMT_U64 " overflow", (Uint64)uvalue); + return; + } + *dataPtr = static_cast<short>(value); + if (indPtr != 0) + *indPtr = sizeof(unsigned short); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Long || extType.type() == ExtType::Slong) { + long* dataPtr = static_cast<long*>(extField.m_dataPtr); + if (value < INT_MIN || value > INT_MAX) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value " FMT_I64 " overflow", (Int64)value); + return; + } + *dataPtr = static_cast<long>(value); + if (indPtr != 0) + *indPtr = sizeof(long); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ulong) { + unsigned long* dataPtr = static_cast<unsigned long*>(extField.m_dataPtr); + if (uvalue > UINT_MAX) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value " FMT_U64 " overflow", (Uint64)uvalue); + return; + } + *dataPtr = static_cast<unsigned long>(uvalue); + if (indPtr != 0) + *indPtr = sizeof(unsigned long); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Sbigint) { + SQLBIGINT* dataPtr = static_cast<SQLBIGINT*>(extField.m_dataPtr); + *dataPtr = static_cast<SQLBIGINT>(value); // big enough + if (indPtr != 0) + *indPtr = sizeof(SQLBIGINT); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ubigint) { + SQLUBIGINT* dataPtr = static_cast<SQLUBIGINT*>(extField.m_dataPtr); + *dataPtr = static_cast<SQLUBIGINT>(uvalue); + if (indPtr != 0) + *indPtr = sizeof(SQLUBIGINT); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Float) { + float* dataPtr = static_cast<float*>(extField.m_dataPtr); + *dataPtr = static_cast<float>(value); // big enough + if (indPtr != 0) + *indPtr = sizeof(float); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Double) { + double* dataPtr = static_cast<double*>(extField.m_dataPtr); + *dataPtr = static_cast<double>(value); // big enough + if (indPtr != 0) + *indPtr = sizeof(double); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + } + if (sqlType.type() == SqlType::Real) { + if (extField.m_pos > 0) { + ctx.setCode(SQL_NO_DATA); + return; + } + const SqlReal value = sqlReal(); + if (extType.type() == ExtType::Char) { + char* dataPtr = static_cast<char*>(extField.m_dataPtr); + if (! copyout_double_char(ctx, value, 7, dataPtr, extField.m_dataLen, indPtr)) + return; + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Short || extType.type() == ExtType::Sshort) { + short* dataPtr = static_cast<short*>(extField.m_dataPtr); + *dataPtr = static_cast<short>(value); // XXX todo + if (indPtr != 0) + *indPtr = sizeof(short); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ushort) { + unsigned short* dataPtr = static_cast<unsigned short*>(extField.m_dataPtr); + if (value < 0 || value > USHRT_MAX) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value %g overflow", (double)value); + return; + } + *dataPtr = static_cast<short>(value); + if (indPtr != 0) + *indPtr = sizeof(unsigned short); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Long || extType.type() == ExtType::Slong) { + long* dataPtr = static_cast<long*>(extField.m_dataPtr); + *dataPtr = static_cast<long>(value); // big enough + if (indPtr != 0) + *indPtr = sizeof(long); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ulong) { + unsigned long* dataPtr = static_cast<unsigned long*>(extField.m_dataPtr); + *dataPtr = static_cast<unsigned long>(value); // XXX todo + if (indPtr != 0) + *indPtr = sizeof(unsigned long); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Sbigint) { + SQLBIGINT* dataPtr = static_cast<SQLBIGINT*>(extField.m_dataPtr); + *dataPtr = static_cast<SQLBIGINT>(value); // big enough + if (indPtr != 0) + *indPtr = sizeof(SQLBIGINT); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ubigint) { + SQLUBIGINT* dataPtr = static_cast<SQLUBIGINT*>(extField.m_dataPtr); + *dataPtr = static_cast<SQLUBIGINT>(value); + if (indPtr != 0) + *indPtr = sizeof(SQLUBIGINT); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Float) { + float* dataPtr = static_cast<float*>(extField.m_dataPtr); + *dataPtr = static_cast<float>(value); // big enough + if (indPtr != 0) + *indPtr = sizeof(float); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Double) { + double* dataPtr = static_cast<double*>(extField.m_dataPtr); + *dataPtr = static_cast<double>(value); // big enough + if (indPtr != 0) + *indPtr = sizeof(double); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + } + if (sqlType.type() == SqlType::Double) { + if (extField.m_pos > 0) { + ctx.setCode(SQL_NO_DATA); + return; + } + SqlDouble value = sqlDouble(); + if (extType.type() == ExtType::Char) { + char* dataPtr = static_cast<char*>(extField.m_dataPtr); + if (! copyout_double_char(ctx, value, 14, dataPtr, extField.m_dataLen, indPtr)) + return; + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Short || extType.type() == ExtType::Sshort) { + short* dataPtr = static_cast<short*>(extField.m_dataPtr); + *dataPtr = static_cast<short>(value); // XXX todo + if (indPtr != 0) + *indPtr = sizeof(short); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ushort) { + unsigned short* dataPtr = static_cast<unsigned short*>(extField.m_dataPtr); + if (value < 0 || value > USHRT_MAX) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "value %g overflow", (double)value); + return; + } + *dataPtr = static_cast<short>(value); + if (indPtr != 0) + *indPtr = sizeof(unsigned short); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Long || extType.type() == ExtType::Slong) { + long* dataPtr = static_cast<long*>(extField.m_dataPtr); + *dataPtr = static_cast<long>(value); // big enough + if (indPtr != 0) + *indPtr = sizeof(long); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ulong) { + unsigned long* dataPtr = static_cast<unsigned long*>(extField.m_dataPtr); + *dataPtr = static_cast<unsigned long>(value); // XXX todo + if (indPtr != 0) + *indPtr = sizeof(unsigned long); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Sbigint) { + SQLBIGINT* dataPtr = static_cast<SQLBIGINT*>(extField.m_dataPtr); + *dataPtr = static_cast<SQLBIGINT>(value); // big enough + if (indPtr != 0) + *indPtr = sizeof(SQLBIGINT); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Ubigint) { + SQLUBIGINT* dataPtr = static_cast<SQLUBIGINT*>(extField.m_dataPtr); + *dataPtr = static_cast<SQLUBIGINT>(value); + if (indPtr != 0) + *indPtr = sizeof(SQLUBIGINT); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Float) { + float* dataPtr = static_cast<float*>(extField.m_dataPtr); + *dataPtr = static_cast<float>(value); // big enough + if (indPtr != 0) + *indPtr = sizeof(float); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Double) { + double* dataPtr = static_cast<double*>(extField.m_dataPtr); + *dataPtr = static_cast<double>(value); + if (indPtr != 0) + *indPtr = sizeof(double); + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + } + if (sqlType.type() == SqlType::Datetime) { + if (extField.m_pos > 0) { + ctx.setCode(SQL_NO_DATA); + return; + } + SqlDatetime value = sqlDatetime(); + if (extType.type() == ExtType::Char) { + char* dataPtr = static_cast<char*>(extField.m_dataPtr); + char buf[100]; + sprintf(buf, "%02d%02u-%02u-%02u\040%02u:%02u:%02u.%09u", value.cc(), value.yy(), value.mm(), value.dd(), value.HH(), value.MM(), value.SS(), value.ff()); + int n = strlen(buf); + if (extField.m_dataLen < 20) { + ctx.pushStatus(Sqlstate::_22003, Error::Gen, "buffer too small for timestamp %s", buf); + return; + } + if (extField.m_dataLen < n) { + ctx.pushStatus(Sqlstate::_01004, Error::Gen, "truncating fractional part of timestamp %s", buf); + n = extField.m_dataLen; + } + if (! copyout_char_char(ctx, buf, n, dataPtr, extField.m_dataLen, indPtr, 0)) + return; + if (extField.m_pos >= 0) + extField.m_pos = 1; + return; + } + if (extType.type() == ExtType::Timestamp) { + SQL_TIMESTAMP_STRUCT* dataPtr = static_cast<SQL_TIMESTAMP_STRUCT*>(extField.m_dataPtr); + // XXX assume same datatype + dataPtr->year = value.cc() * 100 + value.yy(); + dataPtr->month = value.mm(); + dataPtr->day = value.dd(); + dataPtr->hour = value.HH(); + dataPtr->minute = value.MM(); + dataPtr->second = value.SS(); + dataPtr->fraction = value.ff(); + return; + } + } + ctx_assert(false); // SqlType::Null not applicable +} + +void +SqlField::print(char* buf, unsigned size) const +{ + Ctx ctx; + unsigned n = sqlSpec().sqlType().displaySize(); + SQLINTEGER ind = 0; + ExtType extType(ExtType::Char); + ExtSpec extSpec(extType); + ExtField extField(extSpec, (SQLPOINTER)buf, size, &ind); + buf[0] = 0; + copyout(ctx, extField); + if (ind == SQL_NULL_DATA) + snprintf(buf, size, "NULL"); +} |