summaryrefslogtreecommitdiff
path: root/storage/ndb/src/old_files/client/odbc/common
diff options
context:
space:
mode:
Diffstat (limited to 'storage/ndb/src/old_files/client/odbc/common')
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/AttrArea.cpp91
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/AttrArea.hpp135
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/CodeTree.cpp37
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/CodeTree.hpp49
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/ConnArea.cpp109
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/ConnArea.hpp135
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/Ctx.cpp355
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/Ctx.hpp182
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/DataField.cpp3023
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/DataField.hpp446
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/DataRow.cpp140
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/DataRow.hpp185
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/DataType.cpp551
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/DataType.hpp293
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/DescArea.cpp167
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/DescArea.hpp266
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/DiagArea.cpp284
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/DiagArea.hpp196
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/Makefile29
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/OdbcData.cpp560
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/OdbcData.hpp283
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/ResultArea.cpp29
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/ResultArea.hpp162
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/Sqlstate.cpp93
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/Sqlstate.hpp85
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/StmtArea.cpp112
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/StmtArea.hpp157
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/StmtInfo.cpp78
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/StmtInfo.hpp86
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/common.cpp17
-rw-r--r--storage/ndb/src/old_files/client/odbc/common/common.hpp124
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