diff options
Diffstat (limited to 'storage/ndb/src/old_files/client/odbc/common')
31 files changed, 8459 insertions, 0 deletions
diff --git a/storage/ndb/src/old_files/client/odbc/common/AttrArea.cpp b/storage/ndb/src/old_files/client/odbc/common/AttrArea.cpp new file mode 100644 index 00000000000..ff9e085a7f6 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/AttrArea.cpp @@ -0,0 +1,91 @@ +/* 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 "AttrArea.hpp" + +// AttrSpec + +// AttrField + +// AttrArea + +AttrArea::AttrArea(const AttrSpec* specList) : + m_specList(specList) +{ +} + +AttrArea::~AttrArea() +{ +} + +const AttrSpec& +AttrArea::findSpec(int id) const +{ + const AttrSpec* p; + for (p = m_specList; p->m_mode != Attr_mode_undef; p++) { + if (p->m_id == id) + break; + } + return *p; +} + +void +AttrArea::setAttr(Ctx& ctx, int id, const OdbcData& data) +{ + const AttrSpec& spec = findSpec(id); + if (spec.m_mode == Attr_mode_undef) { + ctx.pushStatus(Sqlstate::_HY092, Error::Gen, "undefined attribute id %d", id); + return; + } + ctx_assert(spec.m_type == data.type()); + ctx_assert(spec.m_set != 0); + spec.m_set(ctx, m_handle, data); + if (! ctx.ok()) + return; + Fields::iterator iter; + if (ctx.logLevel() >= 3) { + char buf[100]; + data.print(buf, sizeof(buf)); + ctx_log3(("attr handle 0x%x set id %d = %s", (unsigned)m_handle, id, buf)); + } + iter = m_fields.find(id); + if (iter != m_fields.end()) { + AttrField& field = (*iter).second; + field.setData(data); + return; + } + AttrField field(spec, data); + m_fields.insert(Fields::value_type(id, field)); +} + +void +AttrArea::getAttr(Ctx& ctx, int id, OdbcData& data) +{ + const AttrSpec& spec = findSpec(id); + if (spec.m_mode == Attr_mode_undef) { + ctx.pushStatus(Sqlstate::_HY092, Error::Gen, "undefined attribute id %d", id); + return; + } + Fields::iterator iter; + iter = m_fields.find(id); + if (iter != m_fields.end()) { + AttrField& field = (*iter).second; + data.setValue(field.getData()); + return; + } + ctx_assert(spec.m_default != 0); + spec.m_default(ctx, m_handle, data); +} diff --git a/storage/ndb/src/old_files/client/odbc/common/AttrArea.hpp b/storage/ndb/src/old_files/client/odbc/common/AttrArea.hpp new file mode 100644 index 00000000000..050cce719bf --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/AttrArea.hpp @@ -0,0 +1,135 @@ +/* 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 */ + +#ifndef ODBC_HANDLES_AttrArea_hpp +#define ODBC_HANDLES_AttrArea_hpp + +#include <map> +#include <common/common.hpp> +#include "OdbcData.hpp" + +class HandleBase; + +enum AttrMode { + Attr_mode_undef, + Attr_mode_readonly, + Attr_mode_writeonly, + Attr_mode_readwrite +}; + +/** + * @struct AttrSpec + * @brief Attribute specifier + * + * Each handle class has a list of attribute specifiers. + */ +struct AttrSpec { + int m_id; // SQL_ATTR_ identifier + OdbcData::Type m_type; // data type + AttrMode m_mode; // access mode, undef indicates end of list + /** + * Callback for checks and side effects. Called before the + * attribute is stored. May set error status. + */ + typedef void CallbackSet(Ctx& ctx, HandleBase* self, const OdbcData& data); + CallbackSet* m_set; + /** + * Callback to set default value. May set error status. + */ + typedef void CallbackDefault(Ctx& ctx, HandleBase* self, OdbcData& data); + CallbackDefault* m_default; +}; + +/** + * @class AttrField + * @brief Attribute value (stored as OdbcData) + */ +class AttrField { +public: + AttrField(const AttrSpec& attrSpec, const OdbcData& data); + AttrField(const AttrField& field); + ~AttrField(); + void setData(const OdbcData& data); + const OdbcData& getData(); +private: + const AttrSpec& m_spec; + OdbcData m_data; +}; + +inline +AttrField::AttrField(const AttrSpec& spec, const OdbcData& data) : + m_spec(spec), + m_data(data) +{ +} + +inline +AttrField::AttrField(const AttrField& field) : + m_spec(field.m_spec), + m_data(field.m_data) +{ +} + +inline +AttrField::~AttrField() +{ +} + +inline void +AttrField::setData(const OdbcData& data) +{ + ctx_assert(m_spec.m_type == data.type()); + m_data.setValue(data); +} + +inline const OdbcData& +AttrField::getData() +{ + ctx_assert(m_data.type() != OdbcData::Undef); + return m_data; +} + +/** + * @class AttrArea + * @brief Handle attributes + * + * Each handle instance has a list of attribute values stored + * under an AttrArea. Callbacks to handle code provide for + * default values, extra checks, and side-effects. + */ +class AttrArea { +public: + AttrArea(const AttrSpec* specList); + ~AttrArea(); + void setHandle(HandleBase* handle); + const AttrSpec& findSpec(int id) const; + void setAttr(Ctx& ctx, int id, const OdbcData& data); + void getAttr(Ctx& ctx, int id, OdbcData& data); +private: + HandleBase* m_handle; + const AttrSpec* const m_specList; + typedef std::map<int, AttrField> Fields; + Fields m_fields; +}; + +inline void +AttrArea::setHandle(HandleBase* handle) +{ + ctx_assert(handle != 0); + m_handle = handle; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/common/CodeTree.cpp b/storage/ndb/src/old_files/client/odbc/common/CodeTree.cpp new file mode 100644 index 00000000000..ebe4840c5f6 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/CodeTree.cpp @@ -0,0 +1,37 @@ +/* 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 "CodeTree.hpp" + +// PlanTree + +PlanTree::~PlanTree() +{ +} + +// ExecTree + +ExecTree::Code::~Code() +{ +} + +ExecTree::Data::~Data() +{ +} + +ExecTree::~ExecTree() +{ +} diff --git a/storage/ndb/src/old_files/client/odbc/common/CodeTree.hpp b/storage/ndb/src/old_files/client/odbc/common/CodeTree.hpp new file mode 100644 index 00000000000..1b0ae3199af --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/CodeTree.hpp @@ -0,0 +1,49 @@ +/* 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 */ + +#ifndef ODBC_CODEGEN_CodeTree_hpp +#define ODBC_CODEGEN_CodeTree_hpp + +#include <common/common.hpp> + +/* + * Intermediary statement evalution plan. Starts as parse tree. Final + * format maps directly to ExecTree. + */ +class PlanTree { +public: + virtual ~PlanTree() = 0; +}; + +/* + * Executable code and runtime data. Currently looks like PlanTree. + * Later may change code format to linear "byte code" and move execution + * to a SQL block in NDB kernel. + */ +class ExecTree { +public: + class Code { + public: + virtual ~Code() = 0; + }; + class Data { + public: + virtual ~Data() = 0; + }; + virtual ~ExecTree() = 0; +}; + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/common/ConnArea.cpp b/storage/ndb/src/old_files/client/odbc/common/ConnArea.cpp new file mode 100644 index 00000000000..d4d3be52a3c --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/ConnArea.cpp @@ -0,0 +1,109 @@ +/* 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 <NdbApi.hpp> +#include <dictionary/DictCatalog.hpp> +#include <dictionary/DictSchema.hpp> +#include "ConnArea.hpp" + +ConnArea::ConnArea() : + m_state(Free), + m_ndbObject(0), + m_ndbSchemaCon(0), + m_ndbConnection(0), + m_useSchemaCon(0), + m_useConnection(0), + m_autocommit(true), + m_uncommitted(false) +{ + // initialize connection catalog + m_catalog = new DictCatalog(*this); + m_schema = new DictSchema(*this, "NDB"); + m_catalog->addSchema(m_schema); +} + +ConnArea::~ConnArea() +{ + delete m_catalog; +} + +bool +ConnArea::useSchemaCon(Ctx& ctx, bool use) +{ + if (m_state == Free) { + ctx.pushStatus(Sqlstate::_HY010, Error::Gen, "not connected"); + return false; + } + Ndb* ndb = m_ndbObject; + ctx_assert(ndb != 0); + NdbSchemaCon* scon = m_ndbSchemaCon; + if (use) { + if (scon == 0) { + ctx_assert(m_useSchemaCon == 0); + scon = ndb->startSchemaTransaction(); + if (scon == 0) { + ctx.pushStatus(ndb, scon, 0, "startSchemaTransaction"); + return false; + } + m_ndbSchemaCon = scon; + } + m_useSchemaCon++; + } else { + ctx_assert(scon != 0 && m_useSchemaCon != 0); + if (--m_useSchemaCon == 0) { + ndb->closeSchemaTransaction(scon); + m_ndbSchemaCon = 0; + } + } + return true; +} + +bool +ConnArea::useConnection(Ctx& ctx, bool use) +{ + ctx_log3(("useConnection: count before=%u on-off=%d", m_useConnection, (int)use)); + if (m_state == Free) { + ctx.pushStatus(Sqlstate::_HY010, Error::Gen, "not connected"); + return false; + } + Ndb* ndb = m_ndbObject; + ctx_assert(ndb != 0); + NdbConnection* tcon = m_ndbConnection; + if (use) { + if (tcon == 0) { + ctx_assert(m_useConnection == 0); + tcon = ndb->startTransaction(); + if (tcon == 0) { + ctx.pushStatus(ndb, tcon, 0, "startTransaction"); + return false; + } + m_ndbConnection = tcon; + m_state = Transacting; + ctx_log2(("transaction opened")); + } + m_useConnection++; + } else { + ctx_assert(tcon != 0 && m_useConnection != 0); + if (--m_useConnection == 0) { + ndb->closeTransaction(tcon); + m_ndbConnection = 0; + m_uncommitted = false; + m_state = Connected; + ctx_log2(("transaction closed")); + } + } + return true; +} diff --git a/storage/ndb/src/old_files/client/odbc/common/ConnArea.hpp b/storage/ndb/src/old_files/client/odbc/common/ConnArea.hpp new file mode 100644 index 00000000000..36367a39bae --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/ConnArea.hpp @@ -0,0 +1,135 @@ +/* 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 */ + +#ifndef ODBC_COMMON_ConnArea_hpp +#define ODBC_COMMON_ConnArea_hpp + +#include <common/common.hpp> + +class Ctx; +class Ndb; +class NdbSchemaCon; +class NdbConnection; +class DictCatalog; +class DictSchema; + +/** + * @class ConnArea + * @brief Public part of connection handle + */ +class ConnArea { +public: + // state between ODBC function calls + enum State { + Free = 1, // not in use, no Ndb object + Connected = 2, // has Ndb object but no Ndb connection + Transacting = 3 // has Ndb connection + }; + State getState() const; + DictCatalog& dictCatalog() const; + DictSchema& dictSchema() const; + Ndb* ndbObject() const; + NdbSchemaCon* ndbSchemaCon() const; + NdbConnection* ndbConnection() const; + // called from StmtArea + bool useSchemaCon(Ctx& ctx, bool use); + bool useConnection(Ctx& ctx, bool use); + // these just get and set the flag - no semantics + bool autocommit() const; + void autocommit(bool flag); + bool uncommitted() const; + void uncommitted(bool flag); +protected: + ConnArea(); + ~ConnArea(); + State m_state; + DictCatalog* m_catalog; + DictSchema* m_schema; + Ndb* m_ndbObject; + NdbSchemaCon* m_ndbSchemaCon; + NdbConnection* m_ndbConnection; + unsigned m_useSchemaCon; + unsigned m_useConnection; + bool m_autocommit; + bool m_uncommitted; // has uncommitted changes +}; + +inline ConnArea::State +ConnArea::getState() const +{ + return m_state; +} + +inline DictCatalog& +ConnArea::dictCatalog() const +{ + ctx_assert(m_catalog != 0); + return *m_catalog; +} + +inline DictSchema& +ConnArea::dictSchema() const +{ + ctx_assert(m_schema != 0); + return *m_schema; +} + +inline Ndb* +ConnArea::ndbObject() const +{ + ctx_assert(m_ndbObject != 0); + return m_ndbObject; +} + +inline NdbSchemaCon* +ConnArea::ndbSchemaCon() const +{ + ctx_assert(m_ndbSchemaCon != 0); + return m_ndbSchemaCon; +} + +inline NdbConnection* +ConnArea::ndbConnection() const +{ + ctx_assert(m_ndbConnection != 0); + return m_ndbConnection; +} + +inline bool +ConnArea::autocommit() const +{ + return m_autocommit; +} + +inline void +ConnArea::autocommit(bool flag) +{ + m_autocommit = flag; +} + +inline bool +ConnArea::uncommitted() const +{ + return m_uncommitted; +} + +inline void +ConnArea::uncommitted(bool flag) +{ + m_uncommitted = flag; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/common/Ctx.cpp b/storage/ndb/src/old_files/client/odbc/common/Ctx.cpp new file mode 100644 index 00000000000..d6faa5cba77 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/Ctx.cpp @@ -0,0 +1,355 @@ +/* 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 <NdbApi.hpp> +#include <common/common.hpp> +#include "DiagArea.hpp" + +// ctor + +Ctx::Ctx() : + m_diagArea(0) // create on demand +{ + const char* p; + if ((p = getenv("NDB_ODBC_TRACE")) != 0) + m_logLevel = atoi(p); + if ((p = getenv("NDB_ODBC_TRACE_FILE")) != 0 && *p != 0) + strcpy(m_szTraceFile, p); +} + +Ctx::~Ctx() +{ + delete m_diagArea; + m_diagArea = 0; +} + +// handle exceptions + +CtxAssert::CtxAssert(const char* file, int line) : + m_file(file), + m_line(line) +{ + const char* p; + if ((p = getenv("NDB_ODBC_DEBUG")) != 0 && atoi(p) != 0) { + char buf[200]; + snprintf(buf, sizeof(buf), "%s, line %d: assert failed\n", m_file, m_line); + if ((p = getenv("NDB_ODBC_TRACE_FILE")) != 0 && *p != 0) { + FILE* pFile = fopen(p, "a"); + fprintf(pFile, buf); + fflush(pFile); + fclose(pFile); + } else { + fprintf(stderr, buf); + fflush(stderr); + } + abort(); + exit(1); + } +} + +void +Ctx::handleEx(CtxAssert& ctxAssert) +{ + pushStatus(Sqlstate::_IM001, Error::Gen, "exception at %s line %d", ctxAssert.m_file, ctxAssert.m_line); +} + +// logging methods + +int Ctx::m_logLevel = 0; +char Ctx::m_szTraceFile[MAX_PATH]; + +void +Ctx::log(const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (m_szTraceFile[0]) { + FILE* pFile = fopen(m_szTraceFile, "a"); + fprintf(pFile, "[NdbOdbc] "); + vfprintf(pFile, fmt, ap); + fprintf(pFile, "\n"); + fflush(pFile); + fclose(pFile); + } else { + printf("[NdbOdbc] "); + vprintf(fmt, ap); + printf("\n"); + fflush(stdout); + } + va_end(ap); +} + +void +Ctx::logSqlEnter(const char* sqlFunction) +{ + Ctx& ctx = *this; + snprintf(m_sqlFunction, sizeof(m_sqlFunction), "%s", sqlFunction); + ctx_log3(("%s", m_sqlFunction)); +} + +void +Ctx::logSqlExit() +{ + Ctx& ctx = *this; + if (m_diagArea == 0) { + ctx_log3(("%s ret=%d", m_sqlFunction, getCode())); + return; + } + int logLevel = diagArea().numStatus() != 0 ? 2 : 3; + ctx_logN(logLevel, ("%s ret=%d diag=%d", m_sqlFunction, diagArea().getCode(), diagArea().numStatus())); + for (unsigned i = 1; i <= diagArea().numStatus(); i++) { + OdbcData state; + OdbcData message; + diagArea().getRecord(ctx, i, SQL_DIAG_SQLSTATE, state); + diagArea().getRecord(ctx, i, SQL_DIAG_MESSAGE_TEXT, message); + ctx_logN(logLevel, ("diag %u: %s - %s", i, state.sqlstate().state(), message.sqlchar())); + } +} + +void +Ctx::print(const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (m_szTraceFile[0]) { + FILE* pFile = fopen(m_szTraceFile, "a"); + vfprintf(pFile, fmt, ap); + unsigned n = strlen(fmt); + if (n > 0 && fmt[n-1] == '\n') + fflush(pFile); + fclose(pFile); + } else { + vprintf(fmt, ap); + unsigned n = strlen(fmt); + if (n > 0 && fmt[n-1] == '\n') + fflush(stdout); + } + va_end(ap); +} + +void +Ctx::print(int level, const char* fmt, ...) +{ + if (level > m_logLevel) + return; + va_list ap; + va_start(ap, fmt); + if (m_szTraceFile[0]) { + FILE* pFile = fopen(m_szTraceFile, "a"); + vfprintf(pFile, fmt, ap); + unsigned n = strlen(fmt); + if (n > 0 && fmt[n-1] == '\n') + fflush(pFile); + fclose(pFile); + } else { + vprintf(fmt, ap); + unsigned n = strlen(fmt); + if (n > 0 && fmt[n-1] == '\n') + fflush(stdout); + } + va_end(ap); +} + +// diagnostics + +static const unsigned MessageSize = 512; + +DiagArea& +Ctx::diagArea() const +{ + ctx_assert(m_diagArea != 0); + return *m_diagArea; +} + +DiagArea& +Ctx::diagArea() +{ + if (m_diagArea == 0) + m_diagArea = new DiagArea; + return *m_diagArea; +} + +SQLRETURN +Ctx::getCode() const +{ + if (m_diagArea == 0) + return SQL_SUCCESS; + return diagArea().getCode(); +} + +void +Ctx::setCode(SQLRETURN ret) +{ + diagArea().setCode(ret); +} + +void +Ctx::pushStatus(const Sqlstate& state, SQLINTEGER code, const char* fmt, ...) +{ + char message[MessageSize]; + va_list ap; + va_start(ap, fmt); + vsnprintf(message, sizeof(message), fmt, ap); + va_end(ap); + Error error(state); + error.m_status = NdbError::PermanentError; + error.m_classification = NdbError::ApplicationError; + error.m_code = code; + error.m_message = message; + error.m_sqlFunction = m_sqlFunction; + diagArea().pushStatus(error); +} + +void +Ctx::pushStatus(SQLINTEGER code, const char* fmt, ...) +{ + char message[MessageSize]; + va_list ap; + va_start(ap, fmt); + vsnprintf(message, sizeof(message), fmt, ap); + va_end(ap); + Error error(Sqlstate::_IM000); + error.m_status = NdbError::PermanentError; + error.m_classification = NdbError::ApplicationError; + error.m_code = code; + error.m_message = message; + error.m_sqlFunction = m_sqlFunction; + diagArea().pushStatus(error); +} + +void +Ctx::pushStatus(const NdbError& ndbError, const char* fmt, ...) +{ + char message[MessageSize]; + va_list ap; + va_start(ap, fmt); + snprintf(message, sizeof(message), "%s", ndbError.message); + snprintf(message + strlen(message), sizeof(message) - strlen(message), "%s", " - at "); + vsnprintf(message + strlen(message), sizeof(message) - strlen(message), fmt, ap); + va_end(ap); + Error error(Sqlstate::_IM000); + error.m_status = ndbError.status; + error.m_classification = ndbError.classification; + error.m_code = ndbError.code; + error.m_message = message; + error.m_sqlFunction = m_sqlFunction; + diagArea().pushStatus(error); +} + +void +Ctx::pushStatus(const Ndb* ndb, const char* fmt, ...) +{ + char message[MessageSize]; + va_list ap; + va_start(ap, fmt); + vsnprintf(message, sizeof(message), fmt, ap); + va_end(ap); + bool found = false; + if (ndb != 0) { + const NdbError& ndbError = ndb->getNdbError(); + if (ndbError.code != 0) { + pushStatus(ndbError, "%s", message); + found = true; + } + } + if (! found) { + pushStatus(Error::Gen, "unknown NDB error"); + } +} + +void +Ctx::pushStatus(const Ndb* ndb, const NdbConnection* tcon, const NdbOperation* op, const char* fmt, ...) +{ + char message[MessageSize]; + va_list ap; + va_start(ap, fmt); + vsnprintf(message, sizeof(message), fmt, ap); + va_end(ap); + bool found = false; + if (op != 0) { + const NdbError& ndbError = op->getNdbError(); + if (ndbError.code != 0) { + pushStatus(ndbError, "%s", message); + found = true; + } + } + if (tcon != 0) { + const NdbError& ndbError = tcon->getNdbError(); + if (ndbError.code != 0) { + pushStatus(ndbError, "%s", message); + found = true; + } + } + if (ndb != 0) { + const NdbError& ndbError = ndb->getNdbError(); + if (ndbError.code != 0) { + pushStatus(ndbError, "%s", message); + found = true; + } + } + if (! found) { + pushStatus(Error::Gen, "unknown NDB error"); + } +} + +void +Ctx::pushStatus(const Ndb* ndb, const NdbSchemaCon* scon, const NdbSchemaOp* op, const char* fmt, ...) +{ + char message[MessageSize]; + va_list ap; + va_start(ap, fmt); + vsnprintf(message, sizeof(message), fmt, ap); + va_end(ap); + bool found = false; + if (op != 0) { + const NdbError& ndbError = op->getNdbError(); + if (ndbError.code != 0) { + pushStatus(ndbError, "%s", message); + found = true; + } + } + if (scon != 0) { + const NdbError& ndbError = scon->getNdbError(); + if (ndbError.code != 0) { + pushStatus(ndbError, "%s", message); + found = true; + } + } + if (ndb != 0) { + const NdbError& ndbError = ndb->getNdbError(); + if (ndbError.code != 0) { + pushStatus(ndbError, "%s", message); + found = true; + } + } + if (! found) { + pushStatus(Error::Gen, "unknown NDB error"); + } +} + +// check for error + +bool +Ctx::ok() +{ + if (m_diagArea == 0) + return true; + if (diagArea().getCode() == SQL_SUCCESS) + return true; + if (diagArea().getCode() == SQL_SUCCESS_WITH_INFO) + return true; + return false; +} diff --git a/storage/ndb/src/old_files/client/odbc/common/Ctx.hpp b/storage/ndb/src/old_files/client/odbc/common/Ctx.hpp new file mode 100644 index 00000000000..d25d45ff0c7 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/Ctx.hpp @@ -0,0 +1,182 @@ +/* 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 */ + +#ifndef ODBC_COMMON_Ctx_hpp +#define ODBC_COMMON_Ctx_hpp + +#include <NdbDictionary.hpp> + +class Ndb; +class NdbConnection; +class NdbOperation; +class NdbSchemaCon; +class NdbSchemaOp; +class NdbError; + +class Sqlstate; +class DiagArea; +class CtxOwner; + +#ifndef MAX_PATH +#define MAX_PATH 1024 +#endif + +/** + * @class Error + * @brief Sql state, error codes, and message + */ +struct Error { + enum { + Gen = NDB_ODBC_ERROR_MIN + 1 // unclassified + }; + explicit Error(const Sqlstate& sqlstate); + const Sqlstate& m_sqlstate; + int m_status; + int m_classification; + int m_code; + const char* m_message; + const char* m_sqlFunction; + bool driverError() const; +}; + +inline +Error::Error(const Sqlstate& sqlstate) : + m_sqlstate(sqlstate), + m_status(0), + m_classification(0), + m_code(0), + m_sqlFunction(0) +{ +} + +inline bool +Error::driverError() const +{ + return NDB_ODBC_ERROR_MIN <= m_code && m_code < NDB_ODBC_ERROR_MAX; +} + +#define ctx_assert(x) \ + do { if (x) break; throw CtxAssert(__FILE__, __LINE__); } while (0) + +/** + * @class Assert + * @brief Assert thrown + */ +class CtxAssert { +public: + CtxAssert(const char* file, int line); + const char* const m_file; + const int m_line; +}; + +/** + * @class Ctx + * @brief Context for one ODBC SQL function + * + * Local to the function (not member of the handle) because methods on + * a handle can call methods on other handles. Created in driver/ + * before method calls and saved under the handle on return. Contains + * diag area for the function. Also used as logger. + */ +class Ctx { +public: + Ctx(); + ~Ctx(); + // handle exceptions + void handleEx(CtxAssert& ctxAssert); + // logging methods + int logLevel() const; + void log(const char* fmt, ...) PRINTFLIKE(2,3); + void logSqlEnter(const char* sqlFunction); + void logSqlExit(); + const char* sqlFunction() const; + void print(const char* fmt, ...) PRINTFLIKE(2,3); + void print(int level, const char* fmt, ...) PRINTFLIKE(3,4); + // diagnostics area. + DiagArea& diagArea() const; + DiagArea& diagArea(); + SQLRETURN getCode() const; + void setCode(SQLRETURN ret); + // push diagnostic record + void pushStatus(const Sqlstate& state, SQLINTEGER code, const char* fmt, ...) PRINTFLIKE(4,5); + void pushStatus(SQLINTEGER code, const char* fmt, ...) PRINTFLIKE(3,4); + void pushStatus(const NdbError& ndbError, const char* fmt, ...) PRINTFLIKE(3,4); + void pushStatus(const Ndb* ndb, const char* fmt, ...) PRINTFLIKE(3,4); + void pushStatus(const Ndb* ndb, const NdbConnection* tcon, const NdbOperation* op, const char* fmt, ...) PRINTFLIKE(5,6); + void pushStatus(const Ndb* ndb, const NdbSchemaCon* scon, const NdbSchemaOp* op, const char* fmt, ...) PRINTFLIKE(5,6); + // check if we should continue executing. + bool ok(); +private: + static int m_logLevel; + static char m_szTraceFile[MAX_PATH]; + char m_sqlFunction[32]; // max needed is 20 + DiagArea* m_diagArea; +}; + +inline int +Ctx::logLevel() const +{ + return m_logLevel; +} + +inline const char* +Ctx::sqlFunction() const +{ + return m_sqlFunction; +} + +// logging macros can be used only when ctx is in scope + +#define ctx_logN(n, x) \ + do { if (ctx.logLevel() < (n)) break; ctx.log x; } while (0) + +#if NDB_ODBC_MAX_LOG_LEVEL >= 0 +#define ctx_log0(x) ctx_logN(0, x) +#else +#define ctx_log0(x) +#endif + +#if NDB_ODBC_MAX_LOG_LEVEL >= 1 +#define ctx_log1(x) ctx_logN(1, x) +#else +#define ctx_log1(x) +#endif + +#if NDB_ODBC_MAX_LOG_LEVEL >= 2 +#define ctx_log2(x) ctx_logN(2, x) +#else +#define ctx_log2(x) +#endif + +#if NDB_ODBC_MAX_LOG_LEVEL >= 3 +#define ctx_log3(x) ctx_logN(3, x) +#else +#define ctx_log3(x) +#endif + +#if NDB_ODBC_MAX_LOG_LEVEL >= 4 +#define ctx_log4(x) ctx_logN(4, x) +#else +#define ctx_log4(x) +#endif + +#if NDB_ODBC_MAX_LOG_LEVEL >= 5 +#define ctx_log5(x) ctx_logN(5, x) +#else +#define ctx_log5(x) +#endif + +#endif 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"); +} diff --git a/storage/ndb/src/old_files/client/odbc/common/DataField.hpp b/storage/ndb/src/old_files/client/odbc/common/DataField.hpp new file mode 100644 index 00000000000..65138df25f1 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/DataField.hpp @@ -0,0 +1,446 @@ +/* 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 */ + +#ifndef ODBC_COMMON_DataField_hpp +#define ODBC_COMMON_DataField_hpp + +#include <NdbApi.hpp> +#include <common/common.hpp> +#include "DataType.hpp" + +/** + * @class SqlSpec + * @brief Specification of data in SQL format + */ +class SqlSpec { +public: + enum Store { + Undef = 0, + Reference = 1, // reference to read-only SqlField of same type + Physical = 2 // stored within or in allocated storage + }; + SqlSpec(); + SqlSpec(const SqlType& sqlType, Store store); + SqlSpec(const SqlSpec& sqlSpec); + SqlSpec(const SqlSpec& sqlSpec, Store store); + const SqlType& sqlType() const; + const Store store() const; + unsigned size() const; +private: + //SqlSpec& operator=(const SqlSpec& sqlSpec); // disallowed + SqlType m_sqlType; + Store m_store; +}; + +/** + * @class ExtSpec + * @brief Specification of data in external format + */ +class ExtSpec { +public: + ExtSpec(); + ExtSpec(const ExtType& extType); + ExtSpec(const ExtSpec& extSpec); + const ExtType& extType() const; + unsigned size() const; + void setValue(const ExtType& extType); +private: + ExtType m_extType; +}; + +/** + * @class LexSpec + * @brief Specification of lexical data + * + * Used only for converting lexical data to SQL data. + */ +class LexSpec { +public: + LexSpec(); + LexSpec(const LexType& lexType); + /** + * Lexical data is represented as string. Following + * converts it to SQL data. + */ + void convert(Ctx& ctx, const BaseString& value, class SqlField& out); +private: + LexType m_lexType; +}; + +// SqlSpec + +inline +SqlSpec::SqlSpec() : + m_store(Undef) +{ +} + +inline +SqlSpec::SqlSpec(const SqlType& sqlType, Store store) : + m_sqlType(sqlType), + m_store(store) +{ +} + +inline +SqlSpec::SqlSpec(const SqlSpec& sqlSpec) : + m_sqlType(sqlSpec.m_sqlType), + m_store(sqlSpec.m_store) +{ +} + +inline +SqlSpec::SqlSpec(const SqlSpec& sqlSpec, Store store) : + m_sqlType(sqlSpec.m_sqlType), + m_store(store) +{ +} + +inline const SqlType& +SqlSpec::sqlType() const +{ + return m_sqlType; +} + +inline const SqlSpec::Store +SqlSpec::store() const +{ + return m_store; +} + +inline unsigned +SqlSpec::size() const +{ + return sqlType().size(); +} + +// ExtSpec + +inline +ExtSpec::ExtSpec() +{ +} + +inline +ExtSpec::ExtSpec(const ExtType& extType) : + m_extType(extType) +{ +} + +inline +ExtSpec::ExtSpec(const ExtSpec& extSpec) : + m_extType(extSpec.m_extType) +{ +} + +inline const ExtType& +ExtSpec::extType() const +{ + return m_extType; +} + +inline unsigned +ExtSpec::size() const +{ + return m_extType.size(); +} + +inline void +ExtSpec::setValue(const ExtType& extType) +{ + m_extType = extType; +} + +// LexSpec + +inline +LexSpec::LexSpec(const LexType& lexType) : + m_lexType(lexType) +{ +} + +/** + * @class SqlField + * @brief Sql data field accessor + */ +class SqlField { +public: + SqlField(); + SqlField(const SqlSpec& sqlSpec); + SqlField(const SqlSpec& sqlSpec, const SqlField* sqlField); + SqlField(const SqlField& sqlField); + ~SqlField(); + const SqlSpec& sqlSpec() const; + const void* addr() const; // address of data + void* addr(); + unsigned allocSize() const; + const SqlChar* sqlChar() const; // get + const SqlChar* sqlVarchar(unsigned* length) const; + const SqlChar* sqlBinary() const; + const SqlChar* sqlVarbinary(unsigned* length) const; + SqlSmallint sqlSmallint() const; + SqlInteger sqlInteger() const; + SqlBigint sqlBigint() const; + SqlReal sqlReal() const; + SqlDouble sqlDouble() const; + SqlDatetime sqlDatetime() const; + void sqlChar(const char* value, int length); // set + void sqlChar(const SqlChar* value, int length); + void sqlVarchar(const char* value, int length); + void sqlVarchar(const SqlChar* value, int length); + void sqlBinary(const char* value, int length); + void sqlBinary(const SqlChar* value, int length); + void sqlVarbinary(const char* value, int length); + void sqlVarbinary(const SqlChar* value, int length); + void sqlSmallint(SqlSmallint value); + void sqlInteger(SqlInteger value); + void sqlBigint(SqlBigint value); + void sqlReal(SqlReal value); + void sqlDouble(SqlDouble value); + void sqlDatetime(SqlDatetime value); + bool sqlNull() const; // get and set null + void sqlNull(bool value); + unsigned trim() const; // right trimmed length + void copy(Ctx& ctx, SqlField& out) const; + bool cast(Ctx& ctx, SqlField& out) const; + bool less(const SqlField& sqlField) const; + // application input and output + void copyin(Ctx& ctx, class ExtField& extField); + void copyout(Ctx& ctx, class ExtField& extField) const; + // print for debugging + void print(char* buf, unsigned size) const; + // public for forte6 + //enum { CharSmall = 20 }; +#define SqlField_CharSmall 20 // redhat-6.2 (egcs-2.91.66) +private: + friend class LexSpec; + friend class SqlRow; + void alloc(); // allocate Physical + void alloc(const SqlField& sqlField); + void free(); // free Physical + SqlSpec m_sqlSpec; + union Data { + Data(); + Data(const SqlField* sqlField); + const SqlField* m_sqlField; + // Physical + SqlChar* m_sqlChar; // all char types + SqlChar m_sqlCharSmall[SqlField_CharSmall]; + SqlSmallint m_sqlSmallint; + SqlInteger m_sqlInteger; + SqlBigint m_sqlBigint; + SqlReal m_sqlReal; + SqlDouble m_sqlDouble; + SqlDatetime m_sqlDatetime; + } u_data; + union Null { + Null(); + bool m_nullFlag; + } u_null; +}; + +/** + * @class ExtField + * @brief External data field accessor + */ +class ExtField { +public: + ExtField(); + ExtField(const ExtSpec& extSpec, int fieldId = 0); + ExtField(const ExtSpec& extSpec, SQLPOINTER dataPtr, SQLINTEGER dataLen, SQLINTEGER* indPtr, int fieldId = 0); + ~ExtField(); + const ExtSpec& extSpec() const; + void setValue(SQLPOINTER dataPtr, SQLINTEGER dataLen); + void setValue(const ExtSpec& extSpec, SQLPOINTER dataPtr, SQLINTEGER dataLen, SQLINTEGER* indPtr); + int fieldId() const; + void setPos(int pos); + int getPos() const; +private: + friend class SqlField; + friend class Exec_root; + ExtSpec m_extSpec; + SQLPOINTER m_dataPtr; // data buffer + SQLINTEGER m_dataLen; // data buffer length + SQLINTEGER* m_indPtr; // null indicator or length + int m_fieldId; // field id > 0 for error messages + int m_pos; // output position for SQLGetData (if != -1) +}; + +inline int +ExtField::fieldId() const +{ + return m_fieldId; +} + +inline void +ExtField::setPos(int pos) +{ + m_pos = pos; +} + +inline int +ExtField::getPos() const +{ + return m_pos; +} + +// SqlField + +inline +SqlField::SqlField() +{ +} + +inline +SqlField::SqlField(const SqlSpec& sqlSpec) : + m_sqlSpec(sqlSpec) +{ + if (m_sqlSpec.store() == SqlSpec::Physical) + alloc(); +} + +inline +SqlField::SqlField(const SqlSpec& sqlSpec, const SqlField* sqlField) : + m_sqlSpec(sqlSpec), + u_data(sqlField) +{ + ctx_assert(m_sqlSpec.store() == SqlSpec::Reference); +} + +inline +SqlField::SqlField(const SqlField& sqlField) : + m_sqlSpec(sqlField.m_sqlSpec), + u_data(sqlField.u_data), + u_null(sqlField.u_null) +{ + if (m_sqlSpec.store() == SqlSpec::Physical) + alloc(sqlField); +} + +inline +SqlField::Data::Data() +{ +} + +inline +SqlField::Data::Data(const SqlField* sqlField) +{ + m_sqlField = sqlField; +} + +inline +SqlField::Null::Null() +{ +} + +inline +SqlField::~SqlField() +{ + if (m_sqlSpec.store() == SqlSpec::Physical) + free(); +} + +inline const SqlSpec& +SqlField::sqlSpec() const +{ + return m_sqlSpec; +} + +inline void +SqlField::sqlChar(const char* value, int length) +{ + sqlChar(reinterpret_cast<const SqlChar*>(value), length); +} + +inline void +SqlField::sqlVarchar(const char* value, int length) +{ + sqlVarchar(reinterpret_cast<const SqlChar*>(value), length); +} + +inline void +SqlField::sqlBinary(const char* value, int length) +{ + sqlBinary(reinterpret_cast<const SqlChar*>(value), length); +} + +inline void +SqlField::sqlVarbinary(const char* value, int length) +{ + sqlVarbinary(reinterpret_cast<const SqlChar*>(value), length); +} + +// ExtField + +inline +ExtField::ExtField() : + m_dataPtr(0), + m_dataLen(0), + m_indPtr(0), + m_pos(-1) +{ +} + +inline +ExtField::ExtField(const ExtSpec& extSpec, int fieldId) : + m_extSpec(extSpec), + m_dataPtr(0), + m_dataLen(0), + m_indPtr(0), + m_fieldId(fieldId), + m_pos(-1) +{ +} + +inline +ExtField::ExtField(const ExtSpec& extSpec, SQLPOINTER dataPtr, SQLINTEGER dataLen, SQLINTEGER* indPtr, int fieldId) : + m_extSpec(extSpec), + m_dataPtr(dataPtr), + m_dataLen(dataLen), + m_indPtr(indPtr), + m_fieldId(fieldId), + m_pos(-1) +{ +} + +inline +ExtField::~ExtField() +{ +} + +inline const ExtSpec& +ExtField::extSpec() const +{ + return m_extSpec; +} + +inline void +ExtField::setValue(SQLPOINTER dataPtr, SQLINTEGER dataLen) +{ + m_dataPtr = dataPtr; + m_dataLen = dataLen; +} + +inline void +ExtField::setValue(const ExtSpec& extSpec, SQLPOINTER dataPtr, SQLINTEGER dataLen, SQLINTEGER* indPtr) +{ + m_extSpec.setValue(extSpec.extType()); + m_dataPtr = dataPtr; + m_dataLen = dataLen; + m_indPtr = indPtr; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/common/DataRow.cpp b/storage/ndb/src/old_files/client/odbc/common/DataRow.cpp new file mode 100644 index 00000000000..509f2673e0d --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/DataRow.cpp @@ -0,0 +1,140 @@ +/* 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 "DataRow.hpp" + +// SqlSpecs + +SqlSpecs::SqlSpecs(unsigned count) : + m_count(count) +{ + m_sqlSpec = new SqlSpec[1 + count]; +} + +SqlSpecs::SqlSpecs(const SqlSpecs& sqlSpecs) : + m_count(sqlSpecs.m_count) +{ + m_sqlSpec = new SqlSpec[1 + m_count]; + for (unsigned i = 1; i <= m_count; i++) { + void* place = static_cast<void*>(&m_sqlSpec[i]); + new (place) SqlSpec(sqlSpecs.m_sqlSpec[i]); + } +} + +SqlSpecs::~SqlSpecs() +{ + delete[] m_sqlSpec; +} + +// ExtSpecs + +ExtSpecs::ExtSpecs(unsigned count) : + m_count(count) +{ + m_extSpec = new ExtSpec[1 + count]; +} + +ExtSpecs::ExtSpecs(const ExtSpecs& extSpecs) : + m_count(extSpecs.m_count) +{ + m_extSpec = new ExtSpec[1 + m_count]; + for (unsigned i = 1; i <= m_count; i++) { + void* place = static_cast<void*>(&m_extSpec[i]); + new (place) ExtSpec(extSpecs.m_extSpec[i]); + } +} + +ExtSpecs::~ExtSpecs() +{ + delete[] m_extSpec; +} + +// SqlRow + +SqlRow::SqlRow(const SqlSpecs& sqlSpecs) : + m_sqlSpecs(sqlSpecs) +{ + m_sqlField = new SqlField[1 + count()]; + for (unsigned i = 1; i <= count(); i++) { + SqlField sqlField(m_sqlSpecs.getEntry(i)); + setEntry(i, sqlField); + } +} + +SqlRow::SqlRow(const SqlRow& sqlRow) : + m_sqlSpecs(sqlRow.m_sqlSpecs) +{ + m_sqlField = new SqlField[1 + count()]; + for (unsigned i = 1; i <= count(); i++) { + void* place = static_cast<void*>(&m_sqlField[i]); + new (place) SqlField(sqlRow.getEntry(i)); + } +} + +SqlRow::~SqlRow() +{ + for (unsigned i = 1; i <= count(); i++) { + m_sqlField[i].~SqlField(); + } + delete[] m_sqlField; +} + +SqlRow* +SqlRow::copy() const +{ + SqlRow* copyRow = new SqlRow(m_sqlSpecs); + for (unsigned i = 1; i <= count(); i++) { + const SqlField* sqlField = &m_sqlField[i]; + while (sqlField->sqlSpec().store() == SqlSpec::Reference) { + sqlField = sqlField->u_data.m_sqlField; + } + copyRow->setEntry(i, *sqlField); + } + return copyRow; +} + +void +SqlRow::copyout(Ctx& ctx, class ExtRow& extRow) const +{ + for (unsigned i = 1; i <= count(); i++) { + const SqlField& sqlField = getEntry(i); + ExtField& extField = extRow.getEntry(i); + sqlField.copyout(ctx, extField); + } +} + +// ExtRow + +ExtRow::ExtRow(const ExtSpecs& extSpecs) : + m_extSpecs(extSpecs) +{ + m_extField = new ExtField[1 + count()]; +} + +ExtRow::ExtRow(const ExtRow& extRow) : + m_extSpecs(extRow.m_extSpecs) +{ + m_extField = new ExtField[1 + count()]; + for (unsigned i = 1; i <= count(); i++) { + void* place = static_cast<void*>(&m_extField[i]); + new (place) ExtField(extRow.getEntry(i)); + } +} + +ExtRow::~ExtRow() +{ + delete[] m_extField; +} diff --git a/storage/ndb/src/old_files/client/odbc/common/DataRow.hpp b/storage/ndb/src/old_files/client/odbc/common/DataRow.hpp new file mode 100644 index 00000000000..4a5a1e905b9 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/DataRow.hpp @@ -0,0 +1,185 @@ +/* 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 */ + +#ifndef ODBC_COMMON_DataRow_hpp +#define ODBC_COMMON_DataRow_hpp + +#include <new> +#include <common/common.hpp> +#include "DataField.hpp" + +class Ctx; + +/** + * @class SqlSpecs + * @brief Specification of row of SQL data + */ +class SqlSpecs { +public: + SqlSpecs(unsigned count); + SqlSpecs(const SqlSpecs& sqlSpecs); + ~SqlSpecs(); + unsigned count() const; + void setEntry(unsigned i, const SqlSpec& sqlSpec); + const SqlSpec& getEntry(unsigned i) const; +private: + SqlSpecs& operator=(const SqlSpecs& sqlSpecs); // disallowed + const unsigned m_count; + SqlSpec* m_sqlSpec; +}; + +inline unsigned +SqlSpecs::count() const +{ + return m_count; +} + +inline void +SqlSpecs::setEntry(unsigned i, const SqlSpec& sqlSpec) +{ + ctx_assert(m_sqlSpec != 0 && 1 <= i && i <= m_count); + void* place = static_cast<void*>(&m_sqlSpec[i]); + new (place) SqlSpec(sqlSpec); +} + +inline const SqlSpec& +SqlSpecs::getEntry(unsigned i) const +{ + ctx_assert(m_sqlSpec != 0 && 1 <= i && i <= m_count); + return m_sqlSpec[i]; +} + +/** + * @class ExtSpecs + * @brief Specification of row of external data + */ +class ExtSpecs { +public: + ExtSpecs(unsigned count); + ExtSpecs(const ExtSpecs& extSpecs); + ~ExtSpecs(); + unsigned count() const; + void setEntry(unsigned i, const ExtSpec& extSpec); + const ExtSpec& getEntry(unsigned i) const; +private: + ExtSpecs& operator=(const ExtSpecs& extSpecs); // disallowed + const unsigned m_count; + ExtSpec* m_extSpec; +}; + +inline unsigned +ExtSpecs::count() const +{ + return m_count; +} + +inline void +ExtSpecs::setEntry(unsigned i, const ExtSpec& extSpec) +{ + ctx_assert(m_extSpec != 0 && 1 <= i && i <= m_count); + void* place = static_cast<void*>(&m_extSpec[i]); + new (place) ExtSpec(extSpec); +} + +inline const ExtSpec& +ExtSpecs::getEntry(unsigned i) const +{ + ctx_assert(m_extSpec != 0 && 1 <= i && i <= m_count); + return m_extSpec[i]; +} + +/** + * @class SqlRow + * @brief Sql data row + */ +class SqlRow { +public: + SqlRow(const SqlSpecs& sqlSpecs); + SqlRow(const SqlRow& sqlRow); + ~SqlRow(); + unsigned count() const; + void setEntry(unsigned i, const SqlField& sqlField); + SqlField& getEntry(unsigned i) const; + SqlRow* copy() const; + void copyout(Ctx& ctx, class ExtRow& extRow) const; +private: + SqlRow& operator=(const SqlRow& sqlRow); // disallowed + SqlSpecs m_sqlSpecs; + SqlField* m_sqlField; +}; + +inline unsigned +SqlRow::count() const +{ + return m_sqlSpecs.count(); +} + +inline void +SqlRow::setEntry(unsigned i, const SqlField& sqlField) +{ + ctx_assert(1 <= i && i <= count() && m_sqlField != 0); + m_sqlField[i].~SqlField(); + void* place = static_cast<void*>(&m_sqlField[i]); + new (place) SqlField(sqlField); +} + +inline SqlField& +SqlRow::getEntry(unsigned i) const +{ + ctx_assert(1 <= i && i <= count() && m_sqlField != 0); + return m_sqlField[i]; +} + +/** + * @class ExtRow + * @brief External data row + */ +class ExtRow { +public: + ExtRow(const ExtSpecs& extSpecs); + ExtRow(const ExtRow& extRow); + ~ExtRow(); + unsigned count() const; + void setEntry(unsigned i, const ExtField& extField); + ExtField& getEntry(unsigned i) const; +private: + ExtRow& operator=(const ExtRow& extRow); // disallowed + ExtSpecs m_extSpecs; + ExtField* m_extField; +}; + +inline unsigned +ExtRow::count() const +{ + return m_extSpecs.count(); +} + +inline void +ExtRow::setEntry(unsigned i, const ExtField& extField) +{ + ctx_assert(1 <= i && i <= count() && m_extField != 0); + void* place = static_cast<void*>(&m_extField[i]); + new (place) ExtField(extField); +} + +inline ExtField& +ExtRow::getEntry(unsigned i) const +{ + ctx_assert(1 <= i && i <= count() && m_extField != 0); + return m_extField[i]; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/common/DataType.cpp b/storage/ndb/src/old_files/client/odbc/common/DataType.cpp new file mode 100644 index 00000000000..96f6a6e0877 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/DataType.cpp @@ -0,0 +1,551 @@ +/* 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 "DataType.hpp" + +// SqlType + +SqlType::SqlType() : + m_type(Undef) +{ +} + +SqlType::SqlType(Type type, bool nullable) +{ + Ctx ctx; + setType(ctx, type, nullable); + ctx_assert(ctx.ok()); +} + +SqlType::SqlType(Type type, unsigned length, bool nullable) +{ + Ctx ctx; + setType(ctx, type, length, nullable); + ctx_assert(ctx.ok()); +} + +SqlType::SqlType(Type type, unsigned precision, unsigned scale, bool nullable) +{ + Ctx ctx; + setType(ctx, type, precision, scale, nullable); + ctx_assert(ctx.ok()); +} + +SqlType::SqlType(Ctx& ctx, Type type, bool nullable) +{ + setType(ctx, type, nullable); +} + +SqlType::SqlType(Ctx& ctx, Type type, unsigned length, bool nullable) +{ + setType(ctx, type, length, nullable); +} + +SqlType::SqlType(Ctx& ctx, Type type, unsigned precision, unsigned scale, bool nullable) +{ + setType(ctx, type, precision, scale, nullable); +} + +SqlType::SqlType(Ctx& ctx, const NdbDictionary::Column* ndbColumn) +{ + setType(ctx, ndbColumn); +} + +void +SqlType::setType(Ctx& ctx, Type type, bool nullable) +{ + switch (type) { + case Smallint: + case Integer: + case Bigint: + case Real: + case Double: + case Datetime: + break; + case Blob: + setType(ctx, Varbinary, FAKE_BLOB_SIZE, nullable); // XXX BLOB hack + return; + case Clob: + setType(ctx, Varchar, FAKE_BLOB_SIZE, nullable); // XXX BLOB hack + return; + case Null: + case Unbound: + break; + default: + ctx_assert(false); + break; + } + m_type = type; + m_precision = 0; + m_scale = 0; + m_length = 0; + m_nullable = nullable; + m_unSigned = false; +} + +void +SqlType::setType(Ctx& ctx, Type type, unsigned length, bool nullable) +{ + switch (type) { + case Char: + case Varchar: + case Binary: + case Varbinary: + break; + default: + ctx_assert(false); + break; + } + m_type = type; + m_precision = 0; + m_scale = 0; + m_length = length; + m_nullable = nullable; + m_unSigned = false; +} + +void +SqlType::setType(Ctx& ctx, Type type, unsigned precision, unsigned scale, bool nullable) +{ + ctx_assert(false); // not yet +} + +void +SqlType::setType(Ctx& ctx, const NdbDictionary::Column* ndbColumn) +{ + NdbDictionary::Column::Type type = ndbColumn->getType(); + unsigned length = ndbColumn->getLength(); + unsigned precision = ndbColumn->getPrecision(); + unsigned scale = ndbColumn->getScale(); + bool nullable = ndbColumn->getNullable(); + switch (type) { + case NdbDictionary::Column::Undefined: + break; + case NdbDictionary::Column::Int: + if (length == 1) + setType(ctx, Integer, nullable); + else + setType(ctx, Binary, length * sizeof(SqlInteger), nullable); + return; + case NdbDictionary::Column::Unsigned: + if (length == 1) { + setType(ctx, Integer, nullable); + unSigned(true); + } else + setType(ctx, Binary, length * sizeof(SqlUinteger), nullable); + return; + case NdbDictionary::Column::Bigint: + if (length == 1) + setType(ctx, Bigint, nullable); + else + setType(ctx, Binary, length * sizeof(SqlBigint), nullable); + return; + case NdbDictionary::Column::Bigunsigned: + if (length == 1) { + setType(ctx, Bigint, nullable); + unSigned(true); + } else + setType(ctx, Binary, length * sizeof(SqlBigint), nullable); + return; + case NdbDictionary::Column::Float: + if (length == 1) + setType(ctx, Real, nullable); + else + setType(ctx, Binary, length * sizeof(SqlReal), nullable); + return; + case NdbDictionary::Column::Double: + if (length == 1) + setType(ctx, Double, nullable); + else + setType(ctx, Binary, length * sizeof(SqlDouble), nullable); + return; + case NdbDictionary::Column::Decimal: + setType(ctx, Decimal, precision, scale, nullable); + return; + case NdbDictionary::Column::Char: + setType(ctx, Char, length, nullable); + return; + case NdbDictionary::Column::Varchar: + setType(ctx, Varchar, length, nullable); + return; + case NdbDictionary::Column::Binary: + setType(ctx, Binary, length, nullable); + return; + case NdbDictionary::Column::Varbinary: + setType(ctx, Varbinary, length, nullable); + return; + case NdbDictionary::Column::Datetime: + // XXX not yet + break; + case NdbDictionary::Column::Timespec: + setType(ctx, Datetime, nullable); + return; + case NdbDictionary::Column::Blob: + setType(ctx, Blob, nullable); + return; + case NdbDictionary::Column::Clob: + setType(ctx, Clob, nullable); + return; + default: + break; + } + ctx.pushStatus(Error::Gen, "unsupported NDB type %d", (signed)type); +} + +bool +SqlType::equal(const SqlType& sqlType) const +{ + return + m_type == sqlType.m_type && + m_precision == sqlType.m_precision && + m_scale == sqlType.m_scale && + m_length == sqlType.m_length; +} + +unsigned +SqlType::size() const +{ + switch (m_type) { + case Char: + case Varchar: + case Binary: + case Varbinary: + return m_length; + case Smallint: + return sizeof(SqlSmallint); + case Integer: + return sizeof(SqlInteger); + case Bigint: + return sizeof(SqlBigint); + case Real: + return sizeof(SqlReal); + case Double: + return sizeof(SqlDouble); + case Datetime: + return sizeof(SqlDatetime); + case Null: + return 0; + default: + break; + } + ctx_assert(false); + return 0; +} + +unsigned +SqlType::displaySize() const +{ + switch (m_type) { + case Char: + case Varchar: + return m_length; + case Binary: + case Varbinary: + return m_length; + case Smallint: + return m_unSigned ? 5 : 6; + case Integer: + return m_unSigned ? 10 : 11; + case Bigint: + return m_unSigned ? 20 : 21; + case Real: + return 10; + case Double: + return 20; + case Datetime: + return 30; + case Null: + return 0; + default: + break; + } + ctx_assert(false); + return 0; +} + +void +SqlType::getType(Ctx& ctx, NdbDictionary::Column* ndbColumn) const +{ + switch (m_type) { + case Char: + ndbColumn->setType(NdbDictionary::Column::Char); + ndbColumn->setLength(m_length); + break; + case Varchar: + ndbColumn->setType(NdbDictionary::Column::Varchar); + ndbColumn->setLength(m_length); + break; + case Binary: + ndbColumn->setType(NdbDictionary::Column::Binary); + ndbColumn->setLength(m_length); + break; + case Varbinary: + ndbColumn->setType(NdbDictionary::Column::Varbinary); + ndbColumn->setLength(m_length); + break; + case Smallint: + break; // XXX + case Integer: + if (! m_unSigned) + ndbColumn->setType(NdbDictionary::Column::Int); + else + ndbColumn->setType(NdbDictionary::Column::Unsigned); + ndbColumn->setLength(1); + break; + case Bigint: + if (! m_unSigned) + ndbColumn->setType(NdbDictionary::Column::Bigint); + else + ndbColumn->setType(NdbDictionary::Column::Bigunsigned); + ndbColumn->setLength(1); + break; + case Real: + ndbColumn->setType(NdbDictionary::Column::Float); + ndbColumn->setLength(1); + break; + case Double: + ndbColumn->setType(NdbDictionary::Column::Double); + ndbColumn->setLength(1); + break; + case Datetime: + ndbColumn->setType(NdbDictionary::Column::Timespec); + ndbColumn->setLength(1); + break; + default: + ctx_assert(false); + break; + } + ndbColumn->setNullable(m_nullable); +} + +const char* +SqlType::typeName() const +{ + switch (m_type) { + case Char: + return "CHAR"; + case Varchar: + return "VARCHAR"; + case Binary: + return "BINARY"; + case Varbinary: + return "VARBINARY"; + case Smallint: + return "SMALLINT"; + case Integer: + return "INTEGER"; + case Bigint: + return "BIGINT"; + case Real: + return "REAL"; + case Double: + return "FLOAT"; + case Datetime: + return "DATETIME"; + default: + break; + } + return "UNKNOWN"; +} + +void +SqlType::print(char* buf, unsigned size) const +{ + switch (m_type) { + case Char: + snprintf(buf, size, "char(%d)", m_length); + break; + case Varchar: + snprintf(buf, size, "varchar(%d)", m_length); + break; + case Binary: + snprintf(buf, size, "binary(%d)", m_length); + break; + case Varbinary: + snprintf(buf, size, "varbinary(%d)", m_length); + break; + case Smallint: + snprintf(buf, size, "smallint%s", m_unSigned ? " unsigned" : ""); + break; + case Integer: + snprintf(buf, size, "integer%s", m_unSigned ? " unsigned" : ""); + break; + case Bigint: + snprintf(buf, size, "bigint%s", m_unSigned ? " unsigned" : ""); + break; + case Real: + snprintf(buf, size, "real"); + break; + case Double: + snprintf(buf, size, "double"); + break; + case Datetime: + snprintf(buf, size, "datetime"); + break; + case Null: + snprintf(buf, size, "null"); + break; + case Unbound: + snprintf(buf, size, "unbound"); + break; + default: + snprintf(buf, size, "sqltype(%d)", (int)m_type); + break; + } +} + +// ExtType + +ExtType::ExtType() : + m_type(Undef) +{ +} + +ExtType::ExtType(Type type) +{ + Ctx ctx; + setType(ctx, type); + ctx_assert(ctx.ok()); +} + +ExtType::ExtType(Ctx& ctx, Type type) +{ + setType(ctx, type); +} + +void +ExtType::setType(Ctx& ctx, Type type) +{ + switch (type) { + case Char: + case Short: + case Sshort: + case Ushort: + case Long: + case Slong: + case Ulong: + case Sbigint: + case Ubigint: + case Float: + case Double: + case Timestamp: + case Binary: // XXX BLOB hack + case Unbound: + break; + default: + ctx.pushStatus(Error::Gen, "unsupported external type %d", (int)type); + return; + } + m_type = type; +} + +unsigned +ExtType::size() const +{ + ctx_assert(false); + return 0; +} + +// LexType + +LexType::LexType() : + m_type(Undef) +{ +} + +LexType::LexType(Type type) +{ + Ctx ctx; + setType(ctx, type); + ctx_assert(ctx.ok()); +} + +LexType::LexType(Ctx& ctx, Type type) +{ + setType(ctx, type); +} + +void +LexType::setType(Ctx& ctx, Type type) +{ + switch (type) { + case Char: + case Integer: + case Float: + case Null: + break; + default: + ctx_assert(false); + break; + } + m_type = type; +} + +// convert types + +SQLSMALLINT +SqlType::sqlcdefault(Ctx& ctx) const +{ + switch (m_type) { + case Char: + return SQL_C_CHAR; + case Varchar: + return SQL_C_CHAR; + case Binary: + return SQL_C_BINARY; + case Varbinary: + return SQL_C_BINARY; + case Smallint: + return m_unSigned ? SQL_C_USHORT : SQL_C_SSHORT; + case Integer: + return m_unSigned ? SQL_C_ULONG : SQL_C_SLONG; + case Bigint: + return SQL_C_CHAR; + // or maybe this + return m_unSigned ? SQL_C_UBIGINT : SQL_C_SBIGINT; + case Real: + return SQL_C_FLOAT; + case Double: + return SQL_C_DOUBLE; + case Datetime: + return SQL_C_TYPE_TIMESTAMP; + default: + break; + } + return SQL_C_DEFAULT; // no default +} + +void +LexType::convert(Ctx& ctx, SqlType& out, unsigned length) const +{ + switch (m_type) { + case Char: + out.setType(ctx, SqlType::Char, length, true); + return; + case Integer: + out.setType(ctx, SqlType::Bigint, false); + return; + case Float: + out.setType(ctx, SqlType::Double, false); + return; + case Null: + out.setType(ctx, SqlType::Null, true); + return; + default: + break; + } + ctx.pushStatus(Error::Gen, "unsupported lexical to SQL type conversion"); +} diff --git a/storage/ndb/src/old_files/client/odbc/common/DataType.hpp b/storage/ndb/src/old_files/client/odbc/common/DataType.hpp new file mode 100644 index 00000000000..e03e445cf05 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/DataType.hpp @@ -0,0 +1,293 @@ +/* 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 */ + +#ifndef ODBC_COMMON_DataType_hpp +#define ODBC_COMMON_DataType_hpp + +#include <map> +#include <ndb_types.h> +#include <AttrType.hpp> +#include <NdbDictionary.hpp> +#include <common/common.hpp> + +/** + * Sql data exists in several formats: + * + * - as NDB data at the bottom + * - as SQL data during intermediary processing + * - as external data in user input and output buffers + * - as lexical constants in SQL statement text + * + * Each data format has specific types (e.g. number) and each + * type has specific attributes (e.g. precision). + */ +enum DataFormat { + Undef_format = 0, + Ndb_format = 1, // not used in NDB version >= v2.10 + Sql_format = 2, + Ext_format = 3, + Lex_format = 4 +}; + +#define UndefDataType 990 +#define NullDataType 991 +#define UnboundDataType 992 + +class SqlType; +class ExtType; +class LexType; + +/** + * @class SqlType + * @brief Sql data type + */ +class SqlType { +public: + enum Type { + Undef = UndefDataType, + Char = SQL_CHAR, + Varchar = SQL_VARCHAR, + Longvarchar = SQL_LONGVARCHAR, + Binary = SQL_BINARY, + Varbinary = SQL_VARBINARY, + Longvarbinary = SQL_LONGVARBINARY, + Decimal = SQL_DECIMAL, + Tinyint = SQL_TINYINT, + Smallint = SQL_SMALLINT, + Integer = SQL_INTEGER, + Bigint = SQL_BIGINT, + Real = SQL_REAL, + Double = SQL_DOUBLE, + Date = SQL_DATE, + Datetime = SQL_TYPE_TIMESTAMP, + Blob = SQL_BLOB, + Clob = SQL_CLOB, + Null = NullDataType, // not an ODBC SQL type + Unbound = UnboundDataType // special for placeholders + }; + SqlType(); + SqlType(Type type, bool nullable = true); + SqlType(Type type, unsigned length, bool nullable = true); + SqlType(Type type, unsigned precision, unsigned scale, bool nullable = true); + SqlType(Ctx& ctx, Type type, bool nullable = true); + SqlType(Ctx& ctx, Type type, unsigned length, bool nullable = true); + SqlType(Ctx& ctx, Type type, unsigned precision, unsigned scale, bool nullable = true); + SqlType(Ctx& ctx, const NdbDictionary::Column* ndbColumn); + Type type() const; + void setType(Ctx& ctx, Type type, bool nullable = true); + void setType(Ctx& ctx, Type type, unsigned length, bool nullable = true); + void setType(Ctx& ctx, Type type, unsigned precision, unsigned scale, bool nullable = true); + void setType(Ctx& ctx, const NdbDictionary::Column* ndbColumn); + bool equal(const SqlType& sqlType) const; + unsigned size() const; + unsigned displaySize() const; + const char* typeName() const; + unsigned length() const; + bool nullable() const; + void nullable(bool value); + bool unSigned() const; + void unSigned(bool value); + // forwards compatible + void getType(Ctx& ctx, NdbDictionary::Column* ndbColumn) const; + // type conversion + SQLSMALLINT sqlcdefault(Ctx& ctx) const; + // print for debugging + void print(char* buf, unsigned size) const; +private: + friend class LexType; + Type m_type; + unsigned m_precision; + unsigned m_scale; + unsigned m_length; + bool m_nullable; + bool m_unSigned; // qualifier instead of separate types +}; + +inline SqlType::Type +SqlType::type() const +{ + return m_type; +} + +inline unsigned +SqlType::length() const +{ + return m_length; +} + +inline bool +SqlType::nullable() const +{ + return m_nullable; +} + +inline void +SqlType::nullable(bool value) +{ + m_nullable = value; +} + +inline bool +SqlType::unSigned() const +{ + return m_unSigned; +} + +inline void +SqlType::unSigned(bool value) +{ + ctx_assert(m_type == Smallint || m_type == Integer || m_type == Bigint); + m_unSigned = value; +} + +/** + * Actual SQL datatypes. + */ +typedef unsigned char SqlChar; // Char and Varchar via pointer +typedef Int16 SqlSmallint; +typedef Int32 SqlInteger; +typedef Int64 SqlBigint; +typedef Uint16 SqlUsmallint; +typedef Uint32 SqlUinteger; +typedef Uint64 SqlUbigint; +typedef float SqlReal; +typedef double SqlDouble; + +// datetime cc yy mm dd HH MM SS 00 ff ff ff ff stored as String(12) +struct SqlDatetime { + int cc() const { return *(signed char*)&m_data[0]; } + void cc(int x) { *(signed char*)&m_data[0] = x; } + unsigned yy() const { return *(unsigned char*)&m_data[1]; } + void yy(unsigned x) { *(unsigned char*)&m_data[1] = x; } + unsigned mm() const { return *(unsigned char*)&m_data[2]; } + void mm(unsigned x) { *(unsigned char*)&m_data[2] = x; } + unsigned dd() const { return *(unsigned char*)&m_data[3]; } + void dd(unsigned x) { *(unsigned char*)&m_data[3] = x; } + unsigned HH() const { return *(unsigned char*)&m_data[4]; } + void HH(unsigned x) { *(unsigned char*)&m_data[4] = x; } + unsigned MM() const { return *(unsigned char*)&m_data[5]; } + void MM(unsigned x) { *(unsigned char*)&m_data[5] = x; } + unsigned SS() const { return *(unsigned char*)&m_data[6]; } + void SS(unsigned x) { *(unsigned char*)&m_data[6] = x; } + unsigned ff() const { + const unsigned char* p = (unsigned char*)&m_data[8]; + unsigned x = 0; + x += *p++ << 24; + x += *p++ << 16; + x += *p++ << 8; + x += *p++; + return x; + } + void ff(unsigned x) { + unsigned char* p = (unsigned char*)&m_data[8]; + *p++ = (x >> 24) & 0xff; + *p++ = (x >> 16) & 0xff; + *p++ = (x >> 8) & 0xff; + *p++ = x & 0xff; + } + bool valid() { return true; } // XXX later + bool less(const SqlDatetime t) const { + if (cc() != t.cc()) + return cc() < t.cc(); + if (yy() != t.yy()) + return yy() < t.yy(); + if (mm() != t.mm()) + return mm() < t.mm(); + if (dd() != t.dd()) + return dd() < t.dd(); + if (HH() != t.HH()) + return HH() < t.HH(); + if (MM() != t.MM()) + return MM() < t.MM(); + if (SS() != t.SS()) + return SS() < t.SS(); + if (ff() != t.ff()) + return ff() < t.ff(); + return false; + } +private: + char m_data[12]; // use array to avoid gaps +}; + +/** + * @class ExtType + * @brief External data type + */ +class ExtType { +public: + enum Type { + Undef = UndefDataType, + Char = SQL_C_CHAR, + Short = SQL_C_SHORT, + Sshort = SQL_C_SSHORT, + Ushort = SQL_C_USHORT, + Long = SQL_C_LONG, // for sun.jdbc.odbc + Slong = SQL_C_SLONG, + Ulong = SQL_C_ULONG, + Sbigint = SQL_C_SBIGINT, + Ubigint = SQL_C_UBIGINT, + Float = SQL_C_FLOAT, + Double = SQL_C_DOUBLE, + Timestamp = SQL_C_TYPE_TIMESTAMP, + Binary = SQL_C_BINARY, // XXX BLOB hack + Unbound = UnboundDataType + }; + ExtType(); + ExtType(Type type); + ExtType(Ctx& ctx, Type type); + Type type() const; + void setType(Ctx& ctx, Type type); + unsigned size() const; +private: + Type m_type; +}; + +inline ExtType::Type +ExtType::type() const +{ + return m_type; +} + +/** + * @class LexType + * @class Lexical data type + */ +class LexType { +public: + enum Type { + Undef = UndefDataType, + Char = 1, + Integer = 2, + Float = 3, + Null = 4 + }; + LexType(); + LexType(Type type); + LexType(Ctx& ctx, Type type); + Type type() const; + void setType(Ctx& ctx, Type type); + void convert(Ctx& ctx, SqlType& out, unsigned length = 0) const; +private: + Type m_type; +}; + +inline LexType::Type +LexType::type() const +{ + return m_type; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/common/DescArea.cpp b/storage/ndb/src/old_files/client/odbc/common/DescArea.cpp new file mode 100644 index 00000000000..bad9f23d3ef --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/DescArea.cpp @@ -0,0 +1,167 @@ +/* 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 <vector> +#include "DescArea.hpp" + +// DescField + +// DescRec + +void +DescRec::setField(int id, const OdbcData& data) +{ + Ctx ctx; + setField(ctx, id, data); + ctx_assert(ctx.ok()); +} + +void +DescRec::getField(int id, OdbcData& data) +{ + Ctx ctx; + getField(ctx, id, data); + ctx_assert(ctx.ok()); +} + +void +DescRec::setField(Ctx& ctx, int id, const OdbcData& data) +{ + Fields::iterator iter; + iter = m_fields.find(id); + if (ctx.logLevel() >= 3) { + char buf[100]; + data.print(buf, sizeof(buf)); + ctx_log3(("set %s rec %d id %d = %s", DescArea::nameUsage(m_area->getUsage()), m_num, id, buf)); + } + if (iter != m_fields.end()) { + DescField& field = (*iter).second; + field.setData(data); + m_area->setBound(false); // XXX could compare data values + return; + } + const DescSpec& spec = m_area->findSpec(id); + if (spec.m_pos != Desc_pos_end) { + DescField field(spec, data); + m_fields.insert(Fields::value_type(id, field)); + m_area->setBound(false); + return; + } + ctx_assert(false); +} + +void +DescRec::getField(Ctx& ctx, int id, OdbcData& data) +{ + Fields::iterator iter; + iter = m_fields.find(id); + if (iter != m_fields.end()) { + DescField& field = (*iter).second; + data.setValue(field.getData()); + return; + } + const DescSpec& spec = m_area->findSpec(id); + if (spec.m_pos != Desc_pos_end) { + data.setValue(); + return; // XXX default value + } + ctx_assert(false); +} + +// DescArea + +DescArea::DescArea(HandleBase* handle, const DescSpec* specList) : + m_handle(handle), + m_specList(specList), + m_alloc(Desc_alloc_undef), + m_usage(Desc_usage_undef), + m_bound(true) // no bind necessary since empty +{ + m_header.m_area = this; + m_header.m_num = -1; + DescRec rec; + rec.m_area = this; + rec.m_num = m_recs.size(); + m_recs.push_back(rec); // add bookmark record + SQLSMALLINT count = 0; + getHeader().setField(SQL_DESC_COUNT, count); + m_bound = true; +} + +DescArea::~DescArea() +{ +} + +const DescSpec& +DescArea::findSpec(int id) +{ + const DescSpec* p; + for (p = m_specList; p->m_pos != Desc_pos_end; p++) { + if (p->m_id == id) + break; + } + return *p; +} + +unsigned +DescArea::getCount() const +{ + ctx_assert(m_recs.size() > 0); + return m_recs.size() - 1; +} + +void +DescArea::setCount(Ctx& ctx, unsigned count) +{ + if (m_recs.size() - 1 == count) + return; + ctx_log3(("set %s count %d to %d", + DescArea::nameUsage(m_usage), + (unsigned)(m_recs.size() - 1), + count)); + m_recs.resize(1 + count); + for (unsigned i = 0; i <= count; i++) { + m_recs[i].m_area = this; + m_recs[i].m_num = i; + } + getHeader().setField(SQL_DESC_COUNT, static_cast<SQLSMALLINT>(count)); +} + +DescRec& +DescArea::pushRecord() +{ + ctx_assert(m_recs.size() > 0); + DescRec rec; + rec.m_area = this; + rec.m_num = m_recs.size(); + m_recs.push_back(rec); + SQLSMALLINT count = m_recs.size() - 1; + getHeader().setField(SQL_DESC_COUNT, count); + return m_recs.back(); +} + +DescRec& +DescArea::getHeader() +{ + return m_header; +} + +DescRec& +DescArea::getRecord(unsigned num) +{ + ctx_assert(num < m_recs.size()); + return m_recs[num]; +} diff --git a/storage/ndb/src/old_files/client/odbc/common/DescArea.hpp b/storage/ndb/src/old_files/client/odbc/common/DescArea.hpp new file mode 100644 index 00000000000..e9f552d758d --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/DescArea.hpp @@ -0,0 +1,266 @@ +/* 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 */ + +#ifndef ODBC_COMMON_DescArea_hpp +#define ODBC_COMMON_DescArea_hpp + +#include <map> +#include <vector> +#include <common/common.hpp> +#include "OdbcData.hpp" + +/** + * Descriptor records. Contains: + * -# header, not called a "record" in this context + * -# bookmark record at index position 0 + * -# descriptor records at index positions starting from 1 + * + * These classes are in common/ since the code is general. + * However each area is associated with a HandleDesc. + * + * DescField - field identified by an SQL_DESC_* constant + * DescRec - header or record, a list of fields + * DescArea - header and all records + */ + +class HandleBase; +class DescField; +class DescRec; +class DescArea; + +enum DescPos { + Desc_pos_undef = 0, + Desc_pos_header, + Desc_pos_record, + Desc_pos_end +}; + +enum DescMode { + Desc_mode_undef = 0, + Desc_mode_readonly, + Desc_mode_writeonly, + Desc_mode_readwrite, + Desc_mode_unused +}; + +struct DescSpec { + DescPos m_pos; // header or record + int m_id; // SQL_DESC_ identifier + OdbcData::Type m_type; // data type + DescMode m_mode[1+4]; // access mode IPD APD IRD ARD + // called before setting value + typedef void CallbackSet(Ctx& ctx, HandleBase* self, const OdbcData& data); + CallbackSet* m_set; + // called to get default value + typedef void CallbackDefault(Ctx& ctx, HandleBase* self, OdbcData& data); + CallbackDefault* m_default; +}; + +enum DescAlloc { + Desc_alloc_undef = 0, + Desc_alloc_auto, + Desc_alloc_user +}; + +enum DescUsage { + Desc_usage_undef = 0, + Desc_usage_IPD = 1, // these must be 1-4 + Desc_usage_IRD = 2, + Desc_usage_APD = 3, + Desc_usage_ARD = 4 +}; + +/** + * @class DescField + * @brief Field identified by an SQL_DESC_* constant + */ +class DescField { +public: + DescField(const DescSpec& spec, const OdbcData& data); + DescField(const DescField& field); + ~DescField(); +private: + friend class DescRec; + void setData(const OdbcData& data); + const OdbcData& getData(); + const DescSpec& m_spec; + OdbcData m_data; +}; + +inline +DescField::DescField(const DescSpec& spec, const OdbcData& data) : + m_spec(spec), + m_data(data) +{ +} + +inline +DescField::DescField(const DescField& field) : + m_spec(field.m_spec), + m_data(field.m_data) +{ +} + +inline +DescField::~DescField() +{ +} + +inline void +DescField::setData(const OdbcData& data) +{ + ctx_assert(m_spec.m_type == data.type()); + m_data.setValue(data); +} + +inline const OdbcData& +DescField::getData() +{ + ctx_assert(m_data.type() != OdbcData::Undef); + return m_data; +} + +/** + * @class DescRec + * @brief Descriptor record, a list of fields + */ +class DescRec { + friend class DescArea; +public: + DescRec(); + ~DescRec(); + void setField(int id, const OdbcData& data); + void getField(int id, OdbcData& data); + void setField(Ctx& ctx, int id, const OdbcData& data); + void getField(Ctx& ctx, int id, OdbcData& data); +private: + DescArea* m_area; + int m_num; // for logging only -1 = header 0 = bookmark + typedef std::map<int, DescField> Fields; + Fields m_fields; +}; + +inline +DescRec::DescRec() : + m_area(0) +{ +} + +inline +DescRec::~DescRec() +{ +} + +/** + * @class DescArea + * @brief All records, including header (record 0) + * + * Descriptor area includes a header (record 0) + * and zero or more records at position >= 1. + * Each of these describes one parameter or one column. + * + * - DescArea : Collection of records + * - DescRec : Collection of fields + * - DescField : Contains data of type OdbcData + */ +class DescArea { +public: + DescArea(HandleBase* handle, const DescSpec* specList); + ~DescArea(); + void setAlloc(DescAlloc alloc); + DescAlloc getAlloc() const; + void setUsage(DescUsage usage); + DescUsage getUsage() const; + static const char* nameUsage(DescUsage u); + // find specifier + const DescSpec& findSpec(int id); + // get or set number of records (record 0 not counted) + unsigned getCount() const; + void setCount(Ctx& ctx, unsigned count); + // paush new record (record 0 exists always) + DescRec& pushRecord(); + // get ref to header or to any record + DescRec& getHeader(); + DescRec& getRecord(unsigned num); + // modified since last bind + void setBound(bool bound); + bool isBound() const; +private: + HandleBase* m_handle; + const DescSpec* const m_specList; + DescRec m_header; + typedef std::vector<DescRec> Recs; + Recs m_recs; + DescAlloc m_alloc; + DescUsage m_usage; + bool m_bound; +}; + +inline void +DescArea::setAlloc(DescAlloc alloc) +{ + m_alloc = alloc; +} + +inline DescAlloc +DescArea::getAlloc() const +{ + return m_alloc; +} + +inline void +DescArea::setUsage(DescUsage usage) +{ + m_usage = usage; +} + +inline DescUsage +DescArea::getUsage() const +{ + return m_usage; +} + +inline const char* +DescArea::nameUsage(DescUsage u) +{ + switch (u) { + case Desc_usage_undef: + break; + case Desc_usage_IPD: + return "IPD"; + case Desc_usage_IRD: + return "IRD"; + case Desc_usage_APD: + return "APD"; + case Desc_usage_ARD: + return "ARD"; + } + return "?"; +} + +inline void +DescArea::setBound(bool bound) +{ + m_bound = bound; +} + +inline bool +DescArea::isBound() const +{ + return m_bound; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/common/DiagArea.cpp b/storage/ndb/src/old_files/client/odbc/common/DiagArea.cpp new file mode 100644 index 00000000000..06e8da89495 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/DiagArea.cpp @@ -0,0 +1,284 @@ +/* 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 <stdio.h> +#include "OdbcData.hpp" +#include "DiagArea.hpp" + +// DiagSpec + +static const DiagSpec +diag_spec_list[] = { + { Diag_pos_header, + SQL_DIAG_CURSOR_ROW_COUNT, + OdbcData::Integer, + Odbc_handle_stmt + }, + { Diag_pos_header, + SQL_DIAG_DYNAMIC_FUNCTION, + OdbcData::Sqlchar, + Odbc_handle_stmt + }, + { Diag_pos_header, + SQL_DIAG_DYNAMIC_FUNCTION_CODE, + OdbcData::Integer, + Odbc_handle_stmt + }, + { Diag_pos_header, + SQL_DIAG_NUMBER, + OdbcData::Integer, + Odbc_handle_all + }, + { Diag_pos_header, + SQL_DIAG_RETURNCODE, + OdbcData::Smallint, + Odbc_handle_all + }, + { Diag_pos_header, + SQL_DIAG_ROW_COUNT, + OdbcData::Integer, + Odbc_handle_stmt + }, + { Diag_pos_status, + SQL_DIAG_CLASS_ORIGIN, + OdbcData::Sqlchar, + Odbc_handle_all + }, + { Diag_pos_status, + SQL_DIAG_COLUMN_NUMBER, + OdbcData::Integer, + Odbc_handle_all + }, + { Diag_pos_status, + SQL_DIAG_CONNECTION_NAME, + OdbcData::Sqlchar, + Odbc_handle_all + }, + { Diag_pos_status, + SQL_DIAG_MESSAGE_TEXT, + OdbcData::Sqlchar, + Odbc_handle_all + }, + { Diag_pos_status, + SQL_DIAG_NATIVE, + OdbcData::Integer, + Odbc_handle_all + }, + { Diag_pos_status, + SQL_DIAG_ROW_NUMBER, + OdbcData::Integer, + Odbc_handle_all + }, + { Diag_pos_status, + SQL_DIAG_SERVER_NAME, + OdbcData::Sqlchar, + Odbc_handle_all + }, + { Diag_pos_status, + SQL_DIAG_SQLSTATE, + OdbcData::Sqlchar, + Odbc_handle_all + }, + { Diag_pos_status, + SQL_DIAG_SUBCLASS_ORIGIN, + OdbcData::Sqlchar, + Odbc_handle_all + }, + { Diag_pos_end, + 0, + OdbcData::Undef, + 0 + } +}; + +const DiagSpec& +DiagSpec::find(int id) +{ + const DiagSpec* p; + for (p = diag_spec_list; p->m_pos != Diag_pos_end; p++) { + if (p->m_id == id) + break; + } + return *p; +} + +// DiagField + +// DiagRec + +void +DiagRec::setField(int id, const OdbcData& data) +{ + Fields::iterator iter; + iter = m_fields.find(id); + if (iter != m_fields.end()) { + DiagField& field = (*iter).second; + field.setData(data); + return; + } + const DiagSpec& spec = DiagSpec::find(id); + if (spec.m_pos != Diag_pos_end) { + DiagField field(spec, data); + m_fields.insert(Fields::value_type(id, field)); + return; + } + ctx_assert(false); +} + +void +DiagRec::getField(Ctx& ctx, int id, OdbcData& data) +{ + Fields::iterator iter; + iter = m_fields.find(id); + if (iter != m_fields.end()) { + DiagField& field = (*iter).second; + data.setValue(field.getData()); + return; + } + const DiagSpec& spec = DiagSpec::find(id); + if (spec.m_pos != Diag_pos_end) { + // success and undefined value says the MS doc + data.setValue(); + return; + } + ctx_assert(false); +} + +// DiagArea + +DiagArea::DiagArea() : + m_recs(1), // add header + m_code(SQL_SUCCESS), + m_recNumber(0) +{ + setHeader(SQL_DIAG_NUMBER, (SQLINTEGER)0); +} + +DiagArea::~DiagArea() { +} + +unsigned +DiagArea::numStatus() +{ + ctx_assert(m_recs.size() > 0); + return m_recs.size() - 1; +} + +void +DiagArea::pushStatus() +{ + ctx_assert(m_recs.size() > 0); + DiagRec rec; + m_recs.push_back(rec); + SQLINTEGER diagNumber = m_recs.size() - 1; + setHeader(SQL_DIAG_NUMBER, diagNumber); +} + +void +DiagArea::setHeader(int id, const OdbcData& data) +{ + ctx_assert(m_recs.size() > 0); + getHeader().setField(id, data); +} + +// set status + +void +DiagArea::setStatus(int id, const OdbcData& data) +{ + getStatus().setField(id, data); +} + +void +DiagArea::setStatus(const Sqlstate& state) +{ + getStatus().setField(SQL_DIAG_SQLSTATE, state); + setCode(state.getCode(m_code)); +} + +void +DiagArea::setStatus(const Error& error) +{ + BaseString message(""); + // bracketed prefixes + message.append(NDB_ODBC_COMPONENT_VENDOR); + message.append(NDB_ODBC_COMPONENT_DRIVER); + if (! error.driverError()) + message.append(NDB_ODBC_COMPONENT_DATABASE); + // native error code + char nativeString[20]; + sprintf(nativeString, "%02d%02d%04d", + (unsigned)error.m_status % 100, + (unsigned)error.m_classification % 100, + (unsigned)error.m_code % 10000); + SQLINTEGER native = atoi(nativeString); + message.appfmt("NDB-%s", nativeString); + // message text + message.append(" "); + message.append(error.m_message); + if (error.m_sqlFunction != 0) + message.appfmt(" (in %s)", error.m_sqlFunction); + // set diag fields + setStatus(error.m_sqlstate); + setStatus(SQL_DIAG_NATIVE, native); + setStatus(SQL_DIAG_MESSAGE_TEXT, message.c_str()); +} + +// push status + +void +DiagArea::pushStatus(const Error& error) +{ + pushStatus(); + setStatus(error); +} + +// record access + +DiagRec& +DiagArea::getHeader() +{ + ctx_assert(m_recs.size() > 0); + return m_recs[0]; +} + +DiagRec& +DiagArea::getStatus() +{ + ctx_assert(m_recs.size() > 1); + return m_recs.back(); +} + +DiagRec& +DiagArea::getRecord(unsigned num) +{ + ctx_assert(num < m_recs.size()); + return m_recs[num]; +} + +void +DiagArea::getRecord(Ctx& ctx, unsigned num, int id, OdbcData& data) +{ + DiagRec& rec = getRecord(num); + rec.getField(ctx, id, data); +} + +void +DiagArea::setCode(SQLRETURN code) +{ + m_code = code; + getHeader().setField(SQL_DIAG_RETURNCODE, (SQLSMALLINT)code); +} diff --git a/storage/ndb/src/old_files/client/odbc/common/DiagArea.hpp b/storage/ndb/src/old_files/client/odbc/common/DiagArea.hpp new file mode 100644 index 00000000000..79c03de6623 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/DiagArea.hpp @@ -0,0 +1,196 @@ +/* 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 */ + +#ifndef ODBC_COMMON_DiagArea_hpp +#define ODBC_COMMON_DiagArea_hpp + +#include <map> +#include <vector> +#include <common/common.hpp> +#include "OdbcData.hpp" + +enum DiagPos { + Diag_pos_undef = 0, + Diag_pos_header, + Diag_pos_status, + Diag_pos_end +}; + +/** + * @class DiagSpec + * @brief Field specification + */ +struct DiagSpec { + DiagPos m_pos; // header or status + int m_id; // SQL_DIAG_ identifier + OdbcData::Type m_type; // data type + unsigned m_handles; // defined for these handle types + // find the spec + static const DiagSpec& find(int id); +}; + +/** + * @class DiagField + * @brief Field identified by an SQL_DIAG_* constant + */ +class DiagField { +public: + DiagField(const DiagSpec& spec, const OdbcData& data); + DiagField(const DiagField& field); + ~DiagField(); + void setData(const OdbcData& data); + const OdbcData& getData(); +private: + const DiagSpec& m_spec; + OdbcData m_data; +}; + +inline +DiagField::DiagField(const DiagSpec& spec, const OdbcData& data) : + m_spec(spec), + m_data(data) +{ +} + +inline +DiagField::DiagField(const DiagField& field) : + m_spec(field.m_spec), + m_data(field.m_data) +{ +} + +inline +DiagField::~DiagField() +{ +} + +inline void +DiagField::setData(const OdbcData& data) +{ + ctx_assert(m_spec.m_type == data.type()); + m_data.setValue(data); +} + +inline const OdbcData& +DiagField::getData() +{ + ctx_assert(m_data.type() != OdbcData::Undef); + return m_data; +} + +/** + * @class DiagRec + * @brief One diagnostic record, a list of fields + */ +class DiagRec { +public: + DiagRec(); + ~DiagRec(); + void setField(int id, const OdbcData& data); + void getField(Ctx& ctx, int id, OdbcData& data); +private: + typedef std::map<int, DiagField> Fields; + Fields m_fields; +}; + +inline +DiagRec::DiagRec() +{ +} + +inline +DiagRec::~DiagRec() +{ +} + +/** + * @class DiagArea + * @brief All records, including header (record 0) + * + * Diagnostic area includes a header (record 0) and zero or more + * status records at positions >= 1. + */ +class DiagArea { +public: + DiagArea(); + ~DiagArea(); + /** + * Get number of status records. + */ + unsigned numStatus(); + /** + * Push new status record. + */ + void pushStatus(); + /** + * Set field in header. + */ + void setHeader(int id, const OdbcData& data); + /** + * Set field in latest status record. The arguments can + * also be plain int, char*, Sqlstate. The NDB and other + * native errors set Sqlstate _IM000 automatically. + */ + void setStatus(int id, const OdbcData& data); + void setStatus(const Sqlstate& state); + void setStatus(const Error& error); + /** + * Convenience methods to push new status record and set + * some common fields in it. Sqlstate is set always. + */ + void pushStatus(const Error& error); + /** + * Get refs to various records. + */ + DiagRec& getHeader(); + DiagRec& getStatus(); + DiagRec& getRecord(unsigned num); + /** + * Get diag values. + */ + void getRecord(Ctx& ctx, unsigned num, int id, OdbcData& data); + /** + * Get or set return code. + */ + SQLRETURN getCode() const; + void setCode(SQLRETURN ret); + /** + * Get "next" record number (0 when no more). + * Used only by the deprecated SQLError function. + */ + unsigned nextRecNumber(); +private: + typedef std::vector<DiagRec> Recs; + Recs m_recs; + SQLRETURN m_code; + unsigned m_recNumber; // for SQLError +}; + +inline SQLRETURN +DiagArea::getCode() const +{ + return m_code; +} + +inline unsigned +DiagArea::nextRecNumber() +{ + if (m_recNumber >= numStatus()) + return 0; + return ++m_recNumber; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/common/Makefile b/storage/ndb/src/old_files/client/odbc/common/Makefile new file mode 100644 index 00000000000..7ee29738d86 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/Makefile @@ -0,0 +1,29 @@ +include .defs.mk + +TYPE = * + +NONPIC_ARCHIVE = N + +PIC_ARCHIVE = Y + +ARCHIVE_TARGET = odbccommon + +SOURCES = \ + common.cpp \ + Ctx.cpp \ + Sqlstate.cpp \ + OdbcData.cpp \ + DiagArea.cpp \ + AttrArea.cpp \ + DescArea.cpp \ + ConnArea.cpp \ + StmtInfo.cpp \ + StmtArea.cpp \ + CodeTree.cpp \ + ResultArea.cpp \ + DataType.cpp \ + DataField.cpp \ + DataRow.cpp + +include ../Extra.mk +include $(NDB_TOP)/Epilogue.mk diff --git a/storage/ndb/src/old_files/client/odbc/common/OdbcData.cpp b/storage/ndb/src/old_files/client/odbc/common/OdbcData.cpp new file mode 100644 index 00000000000..32400e07c7a --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/OdbcData.cpp @@ -0,0 +1,560 @@ +/* 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 "OdbcData.hpp" + +OdbcData::OdbcData() : + m_type(Undef) +{ +} + +OdbcData::OdbcData(Type type) : + m_type(type) +{ + switch (m_type) { + case Smallint: + m_smallint = 0; + break; + case Usmallint: + m_usmallint = 0; + break; + case Integer: + m_integer = 0; + break; + case Uinteger: + m_uinteger = 0; + break; + case Pointer: + m_pointer = 0; + break; + case SmallintPtr: + m_smallintPtr = 0; + break; + case UsmallintPtr: + m_usmallintPtr = 0; + break; + case IntegerPtr: + m_integerPtr = 0; + break; + case UintegerPtr: + m_uintegerPtr = 0; + break; + case PointerPtr: + m_pointerPtr = 0; + break; + case Sqlchar: + m_sqlchar = 0; + break; + case Sqlstate: + m_sqlstate = 0; + break; + default: + ctx_assert(false); + break; + }; +} + +OdbcData::OdbcData(const OdbcData& odbcData) : + m_type(odbcData.m_type) +{ + switch (m_type) { + case Smallint: + m_smallint = odbcData.m_smallint; + break; + case Usmallint: + m_usmallint = odbcData.m_usmallint; + break; + case Integer: + m_integer = odbcData.m_integer; + break; + case Uinteger: + m_uinteger = odbcData.m_uinteger; + break; + case Pointer: + m_pointer = odbcData.m_pointer; + break; + case SmallintPtr: + m_smallintPtr = odbcData.m_smallintPtr; + break; + case UsmallintPtr: + m_usmallintPtr = odbcData.m_usmallintPtr; + break; + case IntegerPtr: + m_integerPtr = odbcData.m_integerPtr; + break; + case UintegerPtr: + m_uintegerPtr = odbcData.m_uintegerPtr; + break; + case PointerPtr: + m_pointerPtr = odbcData.m_pointerPtr; + break; + case Sqlchar: { + unsigned n = strlen(odbcData.m_sqlchar); + m_sqlchar = new char[n + 1]; + memcpy(m_sqlchar, odbcData.m_sqlchar, n + 1); + break; + } + case Sqlstate: + m_sqlstate = odbcData.m_sqlstate; + break; + default: + ctx_assert(false); + break; + }; +} + +OdbcData::~OdbcData() +{ + switch (m_type) { + case Sqlchar: + delete[] m_sqlchar; + break; + default: + break; + } +} + +void +OdbcData::setValue() +{ + m_type = Undef; +} + +void +OdbcData::setValue(Type type) +{ + if (m_type == Sqlchar) { + delete[] m_sqlchar; + m_sqlchar = 0; + } + switch (m_type) { + case Smallint: + m_smallint = 0; + break; + case Usmallint: + m_usmallint = 0; + break; + case Integer: + m_integer = 0; + break; + case Uinteger: + m_uinteger = 0; + break; + case Pointer: + m_pointer = 0; + break; + case SmallintPtr: + m_smallintPtr = 0; + break; + case UsmallintPtr: + m_usmallintPtr = 0; + break; + case IntegerPtr: + m_integerPtr = 0; + break; + case UintegerPtr: + m_uintegerPtr = 0; + break; + case PointerPtr: + m_pointerPtr = 0; + break; + case Sqlchar: + m_sqlchar = 0; + break; + case Sqlstate: + m_sqlstate = 0; + break; + default: + ctx_assert(false); + break; + }; +} + +void +OdbcData::setValue(const OdbcData odbcData) +{ + if (m_type == Sqlchar) { + delete[] m_sqlchar; + m_sqlchar = 0; + } + m_type = odbcData.m_type; + switch (m_type) { + case Smallint: + m_smallint = odbcData.m_smallint; + break; + case Usmallint: + m_usmallint = odbcData.m_usmallint; + break; + case Integer: + m_integer = odbcData.m_integer; + break; + case Uinteger: + m_uinteger = odbcData.m_uinteger; + break; + case Pointer: + m_pointer = odbcData.m_pointer; + break; + case SmallintPtr: + m_smallintPtr = odbcData.m_smallintPtr; + break; + case UsmallintPtr: + m_usmallintPtr = odbcData.m_usmallintPtr; + break; + case IntegerPtr: + m_integerPtr = odbcData.m_integerPtr; + break; + case UintegerPtr: + m_uintegerPtr = odbcData.m_uintegerPtr; + break; + case PointerPtr: + m_pointerPtr = odbcData.m_pointerPtr; + break; + case Sqlchar: { + unsigned n = strlen(odbcData.m_sqlchar); + m_sqlchar = new char[n + 1]; + memcpy(m_sqlchar, odbcData.m_sqlchar, n + 1); + break; + } + case Sqlstate: + m_sqlstate = odbcData.m_sqlstate; + break; + default: + ctx_assert(false); + break; + }; +} + +// copy in from user buffer + +void +OdbcData::copyin(Ctx& ctx, Type type, SQLPOINTER buf, SQLINTEGER length) +{ + if (m_type == Sqlchar) { + delete[] m_sqlchar; + m_sqlchar = 0; + } + m_type = type; + switch (m_type) { + case Smallint: { + SQLSMALLINT val = 0; + switch (length) { + case 0: + case SQL_IS_SMALLINT: + val = (SQLSMALLINT)(SQLINTEGER)buf; + break; + case SQL_IS_USMALLINT: + val = (SQLUSMALLINT)(SQLUINTEGER)buf; + break; + case SQL_IS_INTEGER: + val = (SQLINTEGER)buf; + break; + case SQL_IS_UINTEGER: + val = (SQLUINTEGER)buf; + break; + default: + ctx.pushStatus(Error::Gen, "smallint input - invalid length %d", (int)length); + return; + } + m_smallint = val; + break; + } + case Usmallint: { + SQLUSMALLINT val = 0; + switch (length) { + case SQL_IS_SMALLINT: + val = (SQLSMALLINT)(SQLINTEGER)buf; + break; + case 0: + case SQL_IS_USMALLINT: + val = (SQLUSMALLINT)(SQLUINTEGER)buf; + break; + case SQL_IS_INTEGER: + val = (SQLINTEGER)buf; + break; + case SQL_IS_UINTEGER: + val = (SQLUINTEGER)buf; + break; + default: + ctx.pushStatus(Error::Gen, "unsigned smallint input - invalid length %d", (int)length); + return; + } + m_usmallint = val; + break; + } + case Integer: { + SQLINTEGER val = 0; + switch (length) { + case SQL_IS_SMALLINT: + val = (SQLSMALLINT)(SQLINTEGER)buf; + break; + case SQL_IS_USMALLINT: + val = (SQLUSMALLINT)(SQLUINTEGER)buf; + break; + case 0: + case SQL_IS_INTEGER: + val = (SQLINTEGER)buf; + break; + case SQL_IS_UINTEGER: + val = (SQLUINTEGER)buf; + break; + default: + ctx.pushStatus(Error::Gen, "integer input - invalid length %d", (int)length); + return; + } + m_integer = val; + break; + } + case Uinteger: { + SQLUINTEGER val = 0; + switch (length) { + case SQL_IS_SMALLINT: + val = (SQLSMALLINT)(SQLINTEGER)buf; + break; + case SQL_IS_USMALLINT: + val = (SQLUSMALLINT)(SQLUINTEGER)buf; + break; + case SQL_IS_INTEGER: + val = (SQLINTEGER)buf; + break; + case 0: + case SQL_IS_UINTEGER: + val = (SQLUINTEGER)buf; + break; + default: + ctx.pushStatus(Error::Gen, "unsigned integer input - invalid length %d", (int)length); + return; + } + m_uinteger = val; + break; + } + case Pointer: { + SQLPOINTER val = 0; + switch (length) { + case 0: + case SQL_IS_POINTER: + val = (SQLPOINTER)buf; + break; + default: + ctx.pushStatus(Error::Gen, "pointer input - invalid length %d", (int)length); + return; + } + m_pointer = val; + break; + } + case SmallintPtr: { + SQLSMALLINT* val = 0; + switch (length) { + case 0: + case SQL_IS_POINTER: + val = (SQLSMALLINT*)buf; + break; + default: + ctx.pushStatus(Error::Gen, "smallint pointer input - invalid length %d", (int)length); + return; + } + m_smallintPtr = val; + break; + } + case UsmallintPtr: { + SQLUSMALLINT* val = 0; + switch (length) { + case 0: + case SQL_IS_POINTER: + val = (SQLUSMALLINT*)buf; + break; + default: + ctx.pushStatus(Error::Gen, "unsigned smallint pointer input - invalid length %d", (int)length); + return; + } + m_usmallintPtr = val; + break; + } + case IntegerPtr: { + SQLINTEGER* val = 0; + switch (length) { + case 0: + case SQL_IS_POINTER: + val = (SQLINTEGER*)buf; + break; + default: + ctx.pushStatus(Error::Gen, "integer pointer input - invalid length %d", (int)length); + return; + } + m_integerPtr = val; + break; + } + case UintegerPtr: { + SQLUINTEGER* val = 0; + switch (length) { + case 0: + case SQL_IS_POINTER: + val = (SQLUINTEGER*)buf; + break; + default: + ctx.pushStatus(Error::Gen, "unsigned integer pointer input - invalid length %d", (int)length); + return; + } + m_uintegerPtr = val; + break; + } + case Sqlchar: { + const char* val = (char*)buf; + if (val == 0) { + ctx.pushStatus(Sqlstate::_HY009, Error::Gen, "null string input"); + return; + } + if (length < 0 && length != SQL_NTS) { + ctx.pushStatus(Error::Gen, "string input - invalid length %d", (int)length); + return; + } + if (length == SQL_NTS) { + m_sqlchar = strcpy(new char[strlen(val) + 1], val); + } else { + m_sqlchar = (char*)memcpy(new char[length + 1], val, length); + m_sqlchar[length] = 0; + } + break; + } + default: + ctx_assert(false); + break; + } +} + +// copy out to user buffer + +void +OdbcData::copyout(Ctx& ctx, SQLPOINTER buf, SQLINTEGER length, SQLINTEGER* total, SQLSMALLINT* total2) +{ + if (buf == 0) { + ctx.setCode(SQL_ERROR); + return; + } + switch (m_type) { + case Smallint: { + SQLSMALLINT* ptr = static_cast<SQLSMALLINT*>(buf); + *ptr = m_smallint; + break; + } + case Usmallint: { + SQLUSMALLINT* ptr = static_cast<SQLUSMALLINT*>(buf); + *ptr = m_usmallint; + break; + } + case Integer: { + SQLINTEGER* ptr = static_cast<SQLINTEGER*>(buf); + *ptr = m_integer; + break; + } + case Uinteger: { + SQLUINTEGER* ptr = static_cast<SQLUINTEGER*>(buf); + *ptr = m_uinteger; + break; + } + case Pointer: { + SQLPOINTER* ptr = static_cast<SQLPOINTER*>(buf); + *ptr = m_pointer; + break; + } + case Sqlchar: { + char* ptr = static_cast<char*>(buf); + if (length < 0 && length != SQL_NTS) { + ctx.setCode(SQL_ERROR); + return; + } + if (length == SQL_NTS) { + strcpy(ptr, m_sqlchar); + } else { + strncpy(ptr, m_sqlchar, length); + } + if (total != 0) + *total = strlen(m_sqlchar); + if (total2 != 0) + *total2 = strlen(m_sqlchar); + break; + } + case Sqlstate: { + char* ptr = static_cast<char*>(buf); + const char* state = m_sqlstate->state(); + if (length < 0 && length != SQL_NTS) { + ctx.setCode(SQL_ERROR); + return; + } + if (length == SQL_NTS) { + strcpy(ptr, state); + } else { + strncpy(ptr, state, length); + } + if (total != 0) + *total = strlen(state); + if (total2 != 0) + *total2 = strlen(state); + break; + } + default: + ctx_assert(false); + break; + } +} + +void +OdbcData::print(char* buf, unsigned size) const +{ + switch (m_type) { + case Undef: + snprintf(buf, size, "undef"); + break; + case Smallint: + snprintf(buf, size, "%d", (int)m_smallint); + break; + case Usmallint: + snprintf(buf, size, "%u", (unsigned)m_usmallint); + break; + case Integer: + snprintf(buf, size, "%ld", (long)m_integer); + break; + case Uinteger: + snprintf(buf, size, "%lu", (unsigned long)m_uinteger); + break; + case Pointer: + snprintf(buf, size, "0x%lx", (unsigned long)m_pointer); + break; + case SmallintPtr: + snprintf(buf, size, "0x%lx", (unsigned long)m_smallintPtr); + break; + case UsmallintPtr: + snprintf(buf, size, "0x%lx", (unsigned long)m_usmallintPtr); + break; + case IntegerPtr: + snprintf(buf, size, "0x%lx", (unsigned long)m_integerPtr); + break; + case UintegerPtr: + snprintf(buf, size, "0x%lx", (unsigned long)m_uintegerPtr); + break; + case PointerPtr: + snprintf(buf, size, "0x%lx", (unsigned long)m_pointerPtr); + break; + case Sqlchar: + snprintf(buf, size, "%s", m_sqlchar); + break; + case Sqlstate: + snprintf(buf, size, "%s", m_sqlstate->state()); + break; + default: + snprintf(buf, size, "data(%d)", (int)m_type); + break; + }; +} diff --git a/storage/ndb/src/old_files/client/odbc/common/OdbcData.hpp b/storage/ndb/src/old_files/client/odbc/common/OdbcData.hpp new file mode 100644 index 00000000000..c1884507cfe --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/OdbcData.hpp @@ -0,0 +1,283 @@ +/* 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 */ + +#ifndef ODBC_COMMON_OdbcData_hpp +#define ODBC_COMMON_OdbcData_hpp + +#include <ndb_types.h> +#include <common/common.hpp> + +/** + * @class OdbcData + * @brief Odbc data types and storage + * + * Stores diagnostics, attributes, and descriptors. Also used + * for converting to and from driver function arguments. + */ +class OdbcData { +public: + enum Type { + Undef = 0, + Smallint, + Usmallint, + Integer, + Uinteger, + Pointer, + SmallintPtr, + UsmallintPtr, + IntegerPtr, + UintegerPtr, + PointerPtr, + Sqlchar, + Sqlstate + }; + OdbcData(); + OdbcData(Type type); + OdbcData(const OdbcData& odbcData); + OdbcData(SQLSMALLINT smallint); + OdbcData(SQLUSMALLINT usmallint); + OdbcData(SQLINTEGER integer); + OdbcData(SQLUINTEGER uinteger); + OdbcData(SQLPOINTER pointer); + OdbcData(SQLSMALLINT* smallintPtr); + OdbcData(SQLUSMALLINT* usmallintPtr); + OdbcData(SQLINTEGER* integerPtr); + OdbcData(SQLUINTEGER* uintegerPtr); + OdbcData(SQLPOINTER* pointerPtr); + OdbcData(const char* sqlchar); + OdbcData(const ::Sqlstate& sqlstate); + ~OdbcData(); + Type type() const; + void setValue(); + void setValue(Type type); + void setValue(const OdbcData odbcData); + // get value + SQLSMALLINT smallint() const; + SQLUSMALLINT usmallint() const; + SQLINTEGER integer() const; + SQLUINTEGER uinteger() const; + SQLPOINTER pointer() const; + SQLSMALLINT* smallintPtr() const; + SQLUSMALLINT* usmallintPtr() const; + SQLINTEGER* integerPtr() const; + SQLUINTEGER* uintegerPtr() const; + SQLPOINTER* pointerPtr() const; + const char* sqlchar() const; + const ::Sqlstate& sqlstate() const; + // copy in from user buffer + void copyin(Ctx& ctx, Type type, SQLPOINTER buf, SQLINTEGER length); + // copy out to user buffer + void copyout(Ctx& ctx, SQLPOINTER buf, SQLINTEGER length, SQLINTEGER* total, SQLSMALLINT* total2 = 0); + // logging + void print(char* buf, unsigned size) const; +private: + OdbcData& operator=(const OdbcData& odbcData); // disallowed + Type m_type; + union { + SQLSMALLINT m_smallint; + SQLUSMALLINT m_usmallint; + SQLINTEGER m_integer; + SQLUINTEGER m_uinteger; + SQLPOINTER m_pointer; + SQLSMALLINT* m_smallintPtr; + SQLUSMALLINT* m_usmallintPtr; + SQLINTEGER* m_integerPtr; + SQLUINTEGER* m_uintegerPtr; + SQLPOINTER* m_pointerPtr; + char* m_sqlchar; + const ::Sqlstate* m_sqlstate; + }; +}; + +inline OdbcData::Type +OdbcData::type() const +{ + return m_type; +} + +inline +OdbcData::OdbcData(SQLSMALLINT smallint) : + m_type(Smallint), + m_smallint(smallint) +{ +} + +inline +OdbcData::OdbcData(SQLUSMALLINT usmallint) : + m_type(Usmallint), + m_usmallint(usmallint) +{ +} + +inline +OdbcData::OdbcData(SQLINTEGER integer) : + m_type(Integer), + m_integer(integer) +{ +} + +inline +OdbcData::OdbcData(SQLUINTEGER uinteger) : + m_type(Uinteger), + m_uinteger(uinteger) +{ +} + +inline +OdbcData::OdbcData(SQLPOINTER pointer) : + m_type(Pointer), + m_pointer(pointer) +{ +} + +inline +OdbcData::OdbcData(SQLSMALLINT* smallintPtr) : + m_type(SmallintPtr), + m_smallintPtr(smallintPtr) +{ +} + +inline +OdbcData::OdbcData(SQLUSMALLINT* usmallintPtr) : + m_type(UsmallintPtr), + m_usmallintPtr(usmallintPtr) +{ +} + +inline +OdbcData::OdbcData(SQLINTEGER* integerPtr) : + m_type(IntegerPtr), + m_integerPtr(integerPtr) +{ +} + +inline +OdbcData::OdbcData(SQLUINTEGER* uintegerPtr) : + m_type(UintegerPtr), + m_uintegerPtr(uintegerPtr) +{ +} + +inline +OdbcData::OdbcData(SQLPOINTER* pointerPtr) : + m_type(PointerPtr), + m_pointerPtr(pointerPtr) +{ +} + +inline +OdbcData::OdbcData(const char* sqlchar) : + m_type(Sqlchar) +{ + unsigned n = strlen(sqlchar); + m_sqlchar = new char[n + 1]; + strcpy(m_sqlchar, sqlchar); +} + +inline +OdbcData::OdbcData(const ::Sqlstate& sqlstate) : + m_type(Sqlstate), + m_sqlstate(&sqlstate) +{ +} + +// get value + +inline SQLSMALLINT +OdbcData::smallint() const +{ + ctx_assert(m_type == Smallint); + return m_smallint; +} + +inline SQLUSMALLINT +OdbcData::usmallint() const +{ + ctx_assert(m_type == Usmallint); + return m_usmallint; +} + +inline SQLINTEGER +OdbcData::integer() const +{ + ctx_assert(m_type == Integer); + return m_integer; +} + +inline SQLUINTEGER +OdbcData::uinteger() const +{ + ctx_assert(m_type == Uinteger); + return m_uinteger; +} + +inline SQLPOINTER +OdbcData::pointer() const +{ + ctx_assert(m_type == Pointer); + return m_pointer; +} + +inline SQLSMALLINT* +OdbcData::smallintPtr() const +{ + ctx_assert(m_type == SmallintPtr); + return m_smallintPtr; +} + +inline SQLUSMALLINT* +OdbcData::usmallintPtr() const +{ + ctx_assert(m_type == UsmallintPtr); + return m_usmallintPtr; +} + +inline SQLINTEGER* +OdbcData::integerPtr() const +{ + ctx_assert(m_type == IntegerPtr); + return m_integerPtr; +} + +inline SQLUINTEGER* +OdbcData::uintegerPtr() const +{ + ctx_assert(m_type == UintegerPtr); + return m_uintegerPtr; +} + +inline SQLPOINTER* +OdbcData::pointerPtr() const +{ + ctx_assert(m_type == PointerPtr); + return m_pointerPtr; +} + +inline const char* +OdbcData::sqlchar() const +{ + ctx_assert(m_type == Sqlchar); + return m_sqlchar; +} + +inline const ::Sqlstate& +OdbcData::sqlstate() const +{ + ctx_assert(m_type == Sqlstate); + return *m_sqlstate; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/common/ResultArea.cpp b/storage/ndb/src/old_files/client/odbc/common/ResultArea.cpp new file mode 100644 index 00000000000..79d7fb0ccc4 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/ResultArea.cpp @@ -0,0 +1,29 @@ +/* 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 "ResultArea.hpp" + +// ResultArea + +ResultArea::~ResultArea() +{ +} + +// ResultSet + +ResultSet::~ResultSet() +{ +} diff --git a/storage/ndb/src/old_files/client/odbc/common/ResultArea.hpp b/storage/ndb/src/old_files/client/odbc/common/ResultArea.hpp new file mode 100644 index 00000000000..d4890c44d99 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/ResultArea.hpp @@ -0,0 +1,162 @@ +/* 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 */ + +#ifndef ODBC_COMMON_ResultArea_hpp +#define ODBC_COMMON_ResultArea_hpp + +#include <common/common.hpp> +#include <codegen/Code_base.hpp> + +class SqlRow; + +/** + * @class ResultArea + * @brief Execution result + * + * ResultArea contains general results from executing SQL + * statements. Data rows from queries are fetched via derived + * class ResultSet. + */ +class ResultArea { +public: + ResultArea(); + virtual ~ResultArea(); + /** + * Get number of rows: + * + * - for queries: number of rows fetched so far + * - for DML statements: number of rows affected + * - for DDL and other statements: 0 + */ + CountType getCount() const; +protected: + void setCount(CountType count); + void addCount(unsigned count = 1); +private: + CountType m_count; +}; + +inline +ResultArea::ResultArea() : + m_count(0) +{ +} + +inline CountType +ResultArea::getCount() const +{ + return m_count; +} + +inline void +ResultArea::setCount(CountType count) +{ + m_count = count; +} + +inline void +ResultArea::addCount(unsigned count) +{ + m_count += count; +} + +/** + * @class ResultSet + * @brief Data rows from queries + * + * ResultSet is an interface implemented by SQL queries and + * virtual queries (such as SQLTables). It has an associated + * data row accessor SqlRow. + */ +class ResultSet : public ResultArea { +public: + ResultSet(const SqlRow& dataRow); + virtual ~ResultSet(); + enum State { + State_init = 1, // before first fetch + State_ok = 2, // last fetch succeeded + State_end = 3 // end of fetch or error + }; + void initState(); + State getState() const; + /** + * Get data accessor. Can be retrieved once and used after + * each successful ResultSet::fetch(). + */ + const SqlRow& dataRow() const; + /** + * Try to fetch one more row from this result set. + * - returns true if a row was fetched + * - returns false on end of fetch + * - returns false on error and sets error status + * It is a fatal error to call fetch after end of fetch. + */ + bool fetch(Ctx& ctx, Exec_base::Ctl& ctl); +protected: + /** + * Implementation of ResultSet::fetch() must be provided by + * each concrete subclass. + */ + virtual bool fetchImpl(Ctx& ctx, Exec_base::Ctl& ctl) = 0; + const SqlRow& m_dataRow; + State m_state; +}; + +inline +ResultSet::ResultSet(const SqlRow& dataRow) : + m_dataRow(dataRow), + m_state(State_end) // explicit initState() is required +{ +} + +inline const SqlRow& +ResultSet::dataRow() const +{ + return m_dataRow; +} + +inline void +ResultSet::initState() +{ + m_state = State_init; + setCount(0); +} + +inline ResultSet::State +ResultSet::getState() const +{ + return m_state; +} + +inline bool +ResultSet::fetch(Ctx& ctx, Exec_base::Ctl& ctl) +{ + if (! (m_state == State_init || m_state == State_ok)) { + // should not happen but return error instead of assert + ctx.pushStatus(Error::Gen, "invalid fetch state %d", (int)m_state); + m_state = State_end; + return false; + } + if (fetchImpl(ctx, ctl)) { + m_state = State_ok; + addCount(); + return true; + } + m_state = State_end; + return false; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/common/Sqlstate.cpp b/storage/ndb/src/old_files/client/odbc/common/Sqlstate.cpp new file mode 100644 index 00000000000..2d625a7c159 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/Sqlstate.cpp @@ -0,0 +1,93 @@ +/* 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 <common/common.hpp> + +// Initialize Sqlstate records statically. +// They are not used by other static initializers. + +#define make_Sqlstate(state, code) \ + const Sqlstate Sqlstate::_##state(#state, code) + +make_Sqlstate(00000, SQL_SUCCESS); +make_Sqlstate(01004, SQL_SUCCESS_WITH_INFO); +make_Sqlstate(01S02, SQL_SUCCESS_WITH_INFO); +make_Sqlstate(07009, SQL_ERROR); +make_Sqlstate(08003, SQL_ERROR); +make_Sqlstate(21S01, SQL_ERROR); +make_Sqlstate(22001, SQL_ERROR); +make_Sqlstate(22002, SQL_ERROR); +make_Sqlstate(22003, SQL_ERROR); +make_Sqlstate(22005, SQL_ERROR); +make_Sqlstate(22008, SQL_ERROR); +make_Sqlstate(22012, SQL_ERROR); +make_Sqlstate(24000, SQL_ERROR); +make_Sqlstate(25000, SQL_ERROR); +make_Sqlstate(42000, SQL_ERROR); +make_Sqlstate(42S02, SQL_ERROR); +make_Sqlstate(42S22, SQL_ERROR); +make_Sqlstate(HY004, SQL_ERROR); +make_Sqlstate(HY009, SQL_ERROR); +make_Sqlstate(HY010, SQL_ERROR); +make_Sqlstate(HY011, SQL_ERROR); +make_Sqlstate(HY012, SQL_ERROR); +make_Sqlstate(HY014, SQL_ERROR); +make_Sqlstate(HY019, SQL_ERROR); +make_Sqlstate(HY024, SQL_ERROR); +make_Sqlstate(HY090, SQL_ERROR); +make_Sqlstate(HY091, SQL_ERROR); +make_Sqlstate(HY092, SQL_ERROR); +make_Sqlstate(HY095, SQL_ERROR); +make_Sqlstate(HY096, SQL_ERROR); +make_Sqlstate(HYC00, SQL_ERROR); +make_Sqlstate(HYT00, SQL_ERROR); +make_Sqlstate(IM000, SQL_ERROR); // consider all to be errors for now +make_Sqlstate(IM001, SQL_ERROR); +make_Sqlstate(IM999, SQL_ERROR); + +SQLRETURN +Sqlstate::getCode(SQLRETURN code) const +{ + int codes[2]; + int ranks[2]; + codes[0] = code; + codes[1] = m_code; + for (int i = 0; i < 2; i++) { + switch (codes[i]) { + case SQL_SUCCESS: + ranks[i] = 0; + break; + case SQL_SUCCESS_WITH_INFO: + ranks[i] = 1; + break; + case SQL_NO_DATA: + ranks[i] = 2; + break; + case SQL_NEED_DATA: + ranks[i] = 3; + break; + case SQL_ERROR: + ranks[i] = 9; + break; + default: + ctx_assert(false); + ranks[i] = 9; + } + } + if (ranks[0] < ranks[1]) + code = m_code; + return code; +} diff --git a/storage/ndb/src/old_files/client/odbc/common/Sqlstate.hpp b/storage/ndb/src/old_files/client/odbc/common/Sqlstate.hpp new file mode 100644 index 00000000000..3b4665dc6ca --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/Sqlstate.hpp @@ -0,0 +1,85 @@ +/* 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 */ + +#ifndef ODBC_COMMON_SqlState_hpp +#define ODBC_COMMON_SqlState_hpp + +#include <string.h> + +/** + * SQL states. + */ +class Sqlstate { +public: + static const Sqlstate _00000; // no state + static const Sqlstate _01004; // data converted with truncation + static const Sqlstate _01S02; // option value changed + static const Sqlstate _07009; // invalid descriptor index + static const Sqlstate _08003; // connection not open + static const Sqlstate _21S01; // insert value list does not match column list + static const Sqlstate _22001; // string data, right truncation + static const Sqlstate _22002; // indicator variable required but not supplied + static const Sqlstate _22003; // data overflow + static const Sqlstate _22005; // data is not numeric-literal + static const Sqlstate _22008; // data value is not a valid timestamp + static const Sqlstate _22012; // division by zero + static const Sqlstate _24000; // invalid cursor state + static const Sqlstate _25000; // invalid transaction state + static const Sqlstate _42000; // syntax error or access violation + static const Sqlstate _42S02; // base table or view not found + static const Sqlstate _42S22; // column not found + static const Sqlstate _HY004; // invalid SQL data type + static const Sqlstate _HY009; // invalid use of null pointer + static const Sqlstate _HY010; // function sequence error + static const Sqlstate _HY011; // attribute cannot be set now + static const Sqlstate _HY012; // invalid transaction operation code + static const Sqlstate _HY014; // limit on number of handles exceeded + static const Sqlstate _HY019; // non-character and non-binary data sent in pieces + static const Sqlstate _HY024; // invalid attribute value + static const Sqlstate _HY090; // invalid string or buffer length + static const Sqlstate _HY091; // invalid descriptor field identifier + static const Sqlstate _HY092; // invalid attribute/option identifier + static const Sqlstate _HY095; // function type out of range + static const Sqlstate _HY096; // information type out of range + static const Sqlstate _HYC00; // optional feature not implemented + static const Sqlstate _HYT00; // timeout expired + static const Sqlstate _IM000; // implementation defined + static const Sqlstate _IM001; // driver does not support this function + static const Sqlstate _IM999; // fill in the right state please + // get the 5-char text string + const char* state() const; + // get code or "upgrade" existing code + SQLRETURN getCode(SQLRETURN code = SQL_SUCCESS) const; +private: + Sqlstate(const char* state, const SQLRETURN code); + const char* const m_state; + const SQLRETURN m_code; +}; + +inline const char* +Sqlstate::state() const +{ + return m_state; +} + +inline +Sqlstate::Sqlstate(const char* state, const SQLRETURN code) : + m_state(state), + m_code(code) +{ +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/common/StmtArea.cpp b/storage/ndb/src/old_files/client/odbc/common/StmtArea.cpp new file mode 100644 index 00000000000..5ce2d47d31a --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/StmtArea.cpp @@ -0,0 +1,112 @@ +/* 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 "DiagArea.hpp" +#include "StmtArea.hpp" +#include <codegen/CodeGen.hpp> + +StmtArea::StmtArea(ConnArea& connArea) : + m_connArea(connArea), + m_state(Free), + m_useSchemaCon(false), + m_useConnection(false), + m_planTree(0), + m_execTree(0), + m_unbound(0), + m_rowCount(0), + m_tuplesFetched(0) +{ + for (unsigned i = 0; i <= 4; i++) + m_descArea[i] = 0; +} + +StmtArea::~StmtArea() +{ +} + +void +StmtArea::free(Ctx &ctx) +{ + CodeGen codegen(*this); + codegen.close(ctx); + codegen.free(ctx); + m_sqlText.assign(""); + m_nativeText.assign(""); + useSchemaCon(ctx, false); + useConnection(ctx, false); + m_stmtInfo.free(ctx); + m_planTree = 0; + m_execTree = 0; + m_rowCount = 0; + m_tuplesFetched = 0; + m_unbound = 0; + m_state = Free; +} + +void +StmtArea::setRowCount(Ctx& ctx, CountType rowCount) +{ + m_rowCount = rowCount; + // location + DescArea& ird = descArea(Desc_usage_IRD); + OdbcData data; + ird.getHeader().getField(ctx, SQL_DESC_ROWS_PROCESSED_PTR, data); + if (data.type() != OdbcData::Undef) { + SQLUINTEGER* countPtr = data.uintegerPtr(); + if (countPtr != 0) { + *countPtr = static_cast<SQLUINTEGER>(m_rowCount); + } + } + // diagnostic + SQLINTEGER count = static_cast<SQLINTEGER>(m_rowCount); + ctx.diagArea().setHeader(SQL_DIAG_ROW_COUNT, count); +} + +void +StmtArea::setFunction(Ctx& ctx, const char* function, SQLINTEGER functionCode) +{ + m_stmtInfo.m_function = function; + m_stmtInfo.m_functionCode = functionCode; +} + +void +StmtArea::setFunction(Ctx& ctx) +{ + OdbcData function(m_stmtInfo.m_function); + ctx.diagArea().setHeader(SQL_DIAG_DYNAMIC_FUNCTION, function); + OdbcData functionCode(m_stmtInfo.m_functionCode); + ctx.diagArea().setHeader(SQL_DIAG_DYNAMIC_FUNCTION_CODE, functionCode); +} + +bool +StmtArea::useSchemaCon(Ctx& ctx, bool use) +{ + if (m_useSchemaCon != use) + if (! m_connArea.useSchemaCon(ctx, use)) + return false; + m_useSchemaCon = use; + return true; +} + +bool +StmtArea::useConnection(Ctx& ctx, bool use) +{ + if (m_useConnection != use) + if (! m_connArea.useConnection(ctx, use)) + return false; + m_useConnection = use; + return true; +} diff --git a/storage/ndb/src/old_files/client/odbc/common/StmtArea.hpp b/storage/ndb/src/old_files/client/odbc/common/StmtArea.hpp new file mode 100644 index 00000000000..a88c6d36e6d --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/StmtArea.hpp @@ -0,0 +1,157 @@ +/* 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 */ + +#ifndef ODBC_COMMON_StmtArea_hpp +#define ODBC_COMMON_StmtArea_hpp + +#include <common/common.hpp> +#include "ConnArea.hpp" +#include "StmtInfo.hpp" +#include "DescArea.hpp" + +class PlanTree; +class ExecTree; + +/** + * @class StmtArea + * @brief Public part of statement handle + */ +class StmtArea { +public: + // state between ODBC function calls + enum State { + Free = 1, // not in use + Prepared = 2, // statement prepared, maybe unbound + NeedData = 3, // executed, SQLParamData expected + Open = 4 // cursor open + }; + // connection area shared by all statements + ConnArea& connArea(); + State getState() const; + // SQL text + const BaseString& sqlText(); + BaseString& nativeText(); + // allocate or unallocate connections if necessary + bool useSchemaCon(Ctx& ctx, bool use); + bool useConnection(Ctx& ctx, bool use); + // statement info + StmtInfo& stmtInfo(); + DescArea& descArea(DescUsage u); + unsigned unbound() const; + // set row count here and in diagnostics + void setRowCount(Ctx& ctx, CountType rowCount); + CountType getRowCount() const; + // raw tuple count (tuples fetched from NDB) + void resetTuplesFetched(); + void incTuplesFetched(); + CountType getTuplesFetched() const; + // set dynamic function in StmtInfo only (at prepare) + void setFunction(Ctx& ctx, const char* function, SQLINTEGER functionCode); + // set dynamic function in diagnostics (at execute) + void setFunction(Ctx& ctx); +protected: + friend class CodeGen; + friend class Executor; + friend class Plan_root; + StmtArea(ConnArea& connArea); + ~StmtArea(); + void free(Ctx& ctx); + ConnArea& m_connArea; + State m_state; + BaseString m_sqlText; + BaseString m_nativeText; + bool m_useSchemaCon; + bool m_useConnection; + StmtInfo m_stmtInfo; + // plan tree output from parser and rewritten by analyze + PlanTree* m_planTree; + // exec tree output from analyze + ExecTree* m_execTree; + // pointers within HandleDesc allocated via HandleStmt + DescArea* m_descArea[1+4]; + // parameters with unbound SQL type + unsigned m_unbound; + CountType m_rowCount; + CountType m_tuplesFetched; +}; + +inline ConnArea& +StmtArea::connArea() +{ + return m_connArea; +} + +inline StmtArea::State +StmtArea::getState() const +{ + return m_state; +} + +inline const BaseString& +StmtArea::sqlText() { + return m_sqlText; +} + +inline BaseString& +StmtArea::nativeText() { + return m_nativeText; +} + +inline StmtInfo& +StmtArea::stmtInfo() +{ + return m_stmtInfo; +} + +inline DescArea& +StmtArea::descArea(DescUsage u) +{ + ctx_assert(1 <= u && u <= 4); + ctx_assert(m_descArea[u] != 0); + return *m_descArea[u]; +} + +inline unsigned +StmtArea::unbound() const +{ + return m_unbound; +} + +inline CountType +StmtArea::getRowCount() const +{ + return m_rowCount; +} + +inline void +StmtArea::resetTuplesFetched() +{ + m_tuplesFetched = 0; +} + +inline void +StmtArea::incTuplesFetched() +{ + m_tuplesFetched++; +} + +inline CountType +StmtArea::getTuplesFetched() const +{ + return m_tuplesFetched; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/common/StmtInfo.cpp b/storage/ndb/src/old_files/client/odbc/common/StmtInfo.cpp new file mode 100644 index 00000000000..3467fb5023e --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/StmtInfo.cpp @@ -0,0 +1,78 @@ +/* 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 "StmtInfo.hpp" + +const char* +StmtInfo::getDesc() const +{ + switch (m_name) { + case Stmt_name_select: + return "select"; + case Stmt_name_insert: + return "insert"; + case Stmt_name_update: + return "update"; + case Stmt_name_delete: + return "delete"; + case Stmt_name_create_table: + return "create table"; + case Stmt_name_create_index: + return "create index"; + case Stmt_name_drop_table: + return "drop table"; + case Stmt_name_drop_index: + return "drop index"; + default: + ctx_assert(false); + break; + } + return ""; +} + +StmtType +StmtInfo::getType() const +{ + StmtType type = Stmt_type_undef; + switch (m_name) { + case Stmt_name_select: // query + type = Stmt_type_query; + break; + case Stmt_name_insert: // DML + case Stmt_name_update: + case Stmt_name_delete: + type = Stmt_type_DML; + break; + case Stmt_name_create_table: // DDL + case Stmt_name_create_index: + case Stmt_name_drop_table: + case Stmt_name_drop_index: + type = Stmt_type_DDL; + break; + default: + ctx_assert(false); + break; + } + return type; +} + +void +StmtInfo::free(Ctx& ctx) +{ + m_name = Stmt_name_undef; + m_function = ""; + m_functionCode = SQL_DIAG_UNKNOWN_STATEMENT; +} diff --git a/storage/ndb/src/old_files/client/odbc/common/StmtInfo.hpp b/storage/ndb/src/old_files/client/odbc/common/StmtInfo.hpp new file mode 100644 index 00000000000..9cd489be6da --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/StmtInfo.hpp @@ -0,0 +1,86 @@ +/* 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 */ + +#ifndef ODBC_COMMON_StmtInfo_hpp +#define ODBC_COMMON_StmtInfo_hpp + +#include <common/common.hpp> + +// general type (determined by SQL command) +enum StmtType { + Stmt_type_undef = 0, + Stmt_type_query, // select + Stmt_type_DML, // insert, update, delete + Stmt_type_DDL, // create, drop, alter table + Stmt_type_info // virtual query +}; + +// specific SQL command (first 1-2 words) +enum StmtName { + Stmt_name_undef = 0, + Stmt_name_select, + Stmt_name_insert, + Stmt_name_update, + Stmt_name_delete, + Stmt_name_create_table, + Stmt_name_create_index, + Stmt_name_drop_table, + Stmt_name_drop_index +}; + +/** + * @class StmtInfo + * @brief Statement Info + * + * Statement info. This is a separate class which could + * be used in cases not tied to statement execution. + */ +class StmtInfo { +public: + StmtInfo(); + void setName(StmtName name); + StmtName getName() const; + const char* getDesc() const; + StmtType getType() const; + void free(Ctx& ctx); +private: + friend class StmtArea; + StmtName m_name; + const char* m_function; // not allocated + SQLINTEGER m_functionCode; +}; + +inline +StmtInfo::StmtInfo() : + m_name(Stmt_name_undef), + m_function(""), + m_functionCode(SQL_DIAG_UNKNOWN_STATEMENT) +{ +} + +inline void +StmtInfo::setName(StmtName name) +{ + m_name = name; +} + +inline StmtName +StmtInfo::getName() const +{ + return m_name; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/common/common.cpp b/storage/ndb/src/old_files/client/odbc/common/common.cpp new file mode 100644 index 00000000000..73d14c82efe --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/common.cpp @@ -0,0 +1,17 @@ +/* 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 "common.hpp" diff --git a/storage/ndb/src/old_files/client/odbc/common/common.hpp b/storage/ndb/src/old_files/client/odbc/common/common.hpp new file mode 100644 index 00000000000..d2f243b6437 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/common/common.hpp @@ -0,0 +1,124 @@ +/* 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 */ + +#ifndef ODBC_COMMON_common_hpp +#define ODBC_COMMON_common_hpp + +#define stpcpy stpcpy +#include <ndb_global.h> +#undef swap + +// misc defs + +#ifdef NDB_GCC // only for odbc +#define PRINTFLIKE(i,j) __attribute__ ((format (printf, i, j))) +#else +#define PRINTFLIKE(i,j) +#endif + +// odbc defs + +#define ODBCVER 0x0351 + +#ifdef NDB_WIN32 +#include <windows.h> +#endif + +extern "C" { +#include <sqlext.h> +} +// some types which may be missing +#ifndef SQL_BLOB +#define SQL_BLOB 30 +#endif +#ifndef SQL_BLOB_LOCATOR +#define SQL_BLOB_LOCATOR 31 +#endif +#ifndef SQL_CLOB +#define SQL_CLOB 40 +#endif +#ifndef SQL_CLOB_LOCATOR +#define SQL_CLOB_LOCATOR 41 +#endif + +// until real blobs use Varchar of this size +#define FAKE_BLOB_SIZE 2000 + +#define SQL_HANDLE_ROOT 0 // assume real handles != 0 + +enum OdbcHandle { + Odbc_handle_root = 0, // not an odbc handle + Odbc_handle_env = 1, + Odbc_handle_dbc = 2, + Odbc_handle_stmt = 4, + Odbc_handle_desc = 8, + Odbc_handle_all = (1|2|4|8) +}; + +// ndb defs + +#undef BOOL +#include <ndb_types.h> +// this info not yet on api side +#include <kernel/ndb_limits.h> +#include <ndb_version.h> + +#ifndef MAX_TAB_NAME_SIZE +#define MAX_TAB_NAME_SIZE 128 +#endif + +#ifndef MAX_ATTR_NAME_SIZE +#define MAX_ATTR_NAME_SIZE 32 +#endif + +#ifndef MAX_ATTR_DEFAULT_VALUE_SIZE +#define MAX_ATTR_DEFAULT_VALUE_SIZE 128 +#endif + +typedef Uint32 NdbAttrId; +typedef Uint64 CountType; + +// ndb odbc defs + +#define NDB_ODBC_COMPONENT_VENDOR "[MySQL]" +#define NDB_ODBC_COMPONENT_DRIVER "[ODBC driver]" +#define NDB_ODBC_COMPONENT_DATABASE "[NDB Cluster]" + +#define NDB_ODBC_VERSION_MAJOR 0 +#define NDB_ODBC_VERSION_MINOR 22 +#define NDB_ODBC_VERSION_STRING "0.22" + +// reserved error codes for non-NDB errors +#define NDB_ODBC_ERROR_MIN 5000 +#define NDB_ODBC_ERROR_MAX 5100 + +// maximum log level compiled in +#ifdef VM_TRACE +#define NDB_ODBC_MAX_LOG_LEVEL 5 +#else +#define NDB_ODBC_MAX_LOG_LEVEL 3 +#endif + +// driver specific statement attribute for number of NDB tuples fetched +#define SQL_ATTR_NDB_TUPLES_FETCHED 66601 + +#include <BaseString.hpp> +#include <common/Sqlstate.hpp> +#include <common/Ctx.hpp> + +#undef assert + +#endif |