diff options
Diffstat (limited to 'storage/ndb/src/old_files/client/odbc/codegen')
119 files changed, 20153 insertions, 0 deletions
diff --git a/storage/ndb/src/old_files/client/odbc/codegen/CodeGen.cpp b/storage/ndb/src/old_files/client/odbc/codegen/CodeGen.cpp new file mode 100644 index 00000000000..6be78b62bd9 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/CodeGen.cpp @@ -0,0 +1,229 @@ +/* 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/StmtArea.hpp> +#include <common/CodeTree.hpp> +#include <executor/Executor.hpp> +#include "CodeGen.hpp" +#include "Code_root.hpp" + +#include <FlexLexer.h> +#include "SimpleParser.hpp" + +void +CodeGen::prepare(Ctx& ctx) +{ + parse(ctx); + if (! ctx.ok()) + return; + analyze(ctx); + if (! ctx.ok()) + return; + describe(ctx); +} + +void +CodeGen::execute(Ctx& ctx) +{ + DescArea& ipd = m_stmtArea.descArea(Desc_usage_IPD); + if (m_stmtArea.m_unbound) { + analyze(ctx); + if (! ctx.ok()) + return; + describe(ctx); + if (! ctx.ok()) + return; + if (m_stmtArea.m_unbound) { + ctx.pushStatus(Sqlstate::_HY010, Error::Gen, "%u input parameters have unbound SQL type", m_stmtArea.m_unbound); + return; + } + ipd.setBound(true); + } + if (! ipd.isBound()) { + ctx_log2(("IPD changed between executes - reanalyze")); + // jdbc can change parameter length at each execute + analyze(ctx); + if (! ctx.ok()) + return; + describe(ctx); + if (! ctx.ok()) + return; + freeExec(ctx); + codegen(ctx); + if (! ctx.ok()) + return; + alloc(ctx); + if (! ctx.ok()) + return; + ipd.setBound(true); + } + if (m_stmtArea.m_execTree == 0) { + codegen(ctx); + if (! ctx.ok()) + return; + alloc(ctx); + if (! ctx.ok()) + return; + } + Executor executor(m_stmtArea); + executor.execute(ctx); +} + +void +CodeGen::fetch(Ctx& ctx) +{ + // XXX parameter types are not checked any more + ctx_assert(! m_stmtArea.m_unbound); + Executor executor(m_stmtArea); + executor.fetch(ctx); +} + +void +CodeGen::parse(Ctx& ctx) +{ + Plan_root* planRoot = new Plan_root(m_stmtArea); + SimpleParser simpleParser(ctx, m_stmtArea, planRoot); + simpleParser.yyparse(); + if (! ctx.ok()) + return; + planRoot->m_paramList.resize(1 + simpleParser.paramNumber()); + ctx_log2(("CodeGen: parse done - plan tree follows")); + if (ctx.logLevel() >= 2) + planRoot->print(ctx); + m_stmtArea.m_planTree = planRoot; +} + +void +CodeGen::analyze(Ctx& ctx) +{ + Plan_root* planRoot = static_cast<Plan_root*>(m_stmtArea.m_planTree); + ctx_assert(planRoot != 0); + Plan_base::Ctl ctl(0); + planRoot->analyze(ctx, ctl); // returns itself + if (! ctx.ok()) + return; + ctx_log2(("CodeGen: analyze done - plan tree follows")); + if (ctx.logLevel() >= 2) + planRoot->print(ctx); +} + +void +CodeGen::describe(Ctx& ctx) +{ + Plan_root* planRoot = static_cast<Plan_root*>(m_stmtArea.m_planTree); + ctx_assert(planRoot != 0); + planRoot->describe(ctx); + ctx_log2(("CodeGen: describe done")); +} + +void +CodeGen::codegen(Ctx& ctx) +{ + Plan_root* planRoot = static_cast<Plan_root*>(m_stmtArea.m_planTree); + ctx_assert(planRoot != 0); + Plan_base::Ctl ctl(0); + Exec_root* execRoot = static_cast<Exec_root*>(planRoot->codegen(ctx, ctl)); + if (! ctx.ok()) + return; + ctx_assert(execRoot != 0); + ctx_log2(("CodeGen: codegen done - code tree follows")); + if (ctx.logLevel() >= 2) + execRoot->print(ctx); + m_stmtArea.m_execTree = execRoot; +} + +void +CodeGen::alloc(Ctx& ctx) +{ + Exec_root* execRoot = static_cast<Exec_root*>(m_stmtArea.m_execTree); + ctx_assert(execRoot != 0); + Exec_base::Ctl ctl(0); + execRoot->alloc(ctx, ctl); + if (! ctx.ok()) + return; + ctx_log2(("CodeGen: alloc done")); +} + +void +CodeGen::close(Ctx& ctx) +{ + Exec_root* execRoot = static_cast<Exec_root*>(m_stmtArea.m_execTree); + if (execRoot != 0) { + execRoot->close(ctx); + ctx_log2(("CodeGen: close done")); + } +} + +void +CodeGen::free(Ctx& ctx) +{ + freePlan(ctx); + freeExec(ctx); +} + +void +CodeGen::freePlan(Ctx & ctx) +{ + if (m_stmtArea.m_planTree != 0) { + Plan_root* planRoot = static_cast<Plan_root*>(m_stmtArea.m_planTree); + ctx_assert(planRoot != 0); + unsigned count = 1 + planRoot->m_nodeList.size(); + planRoot->freeNodeList(); + delete planRoot; + m_stmtArea.m_planTree = 0; + ctx_log3(("CodeGen: freed %u plan tree nodes", count)); + } +} + +void +CodeGen::freeExec(Ctx & ctx) +{ + if (m_stmtArea.m_execTree != 0) { + Exec_root* execRoot = static_cast<Exec_root*>(m_stmtArea.m_execTree); + ctx_assert(execRoot != 0); + unsigned count = 1 + execRoot->m_nodeList.size(); + execRoot->freeNodeList(); + delete execRoot; + m_stmtArea.m_execTree = 0; + ctx_log3(("CodeGen: freed %u exec tree nodes", count)); + } +} + +// odbc support + +void +CodeGen::sqlGetData(Ctx& ctx, SQLUSMALLINT columnNumber, SQLSMALLINT targetType, SQLPOINTER targetValue, SQLINTEGER bufferLength, SQLINTEGER* strlen_or_Ind) +{ + Exec_root* execRoot = static_cast<Exec_root*>(m_stmtArea.m_execTree); + ctx_assert(execRoot != 0); + execRoot->sqlGetData(ctx, columnNumber, targetType, targetValue, bufferLength, strlen_or_Ind); +} + +void +CodeGen::sqlParamData(Ctx& ctx, SQLPOINTER* value) +{ + Exec_root* execRoot = static_cast<Exec_root*>(m_stmtArea.m_execTree); + ctx_assert(execRoot != 0); + execRoot->sqlParamData(ctx, value); +} + +void +CodeGen::sqlPutData(Ctx& ctx, SQLPOINTER data, SQLINTEGER strlen_or_Ind) +{ + Exec_root* execRoot = static_cast<Exec_root*>(m_stmtArea.m_execTree); + ctx_assert(execRoot != 0); + execRoot->sqlPutData(ctx, data, strlen_or_Ind); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/CodeGen.hpp b/storage/ndb/src/old_files/client/odbc/codegen/CodeGen.hpp new file mode 100644 index 00000000000..ae61dab0c2a --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/CodeGen.hpp @@ -0,0 +1,69 @@ +/* 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_CodeGen_hpp +#define ODBC_CODEGEN_CodeGen_hpp + +#include <common/common.hpp> + +class StmtArea; +class SqlField; +class ExtField; + +/** + * @class CodeGen + * @brief Compiles SQL text into ExecTree::Code + */ +class CodeGen { +public: + CodeGen(StmtArea& stmtArea); + ~CodeGen(); + // parse and analyze SQL statement + void prepare(Ctx& ctx); + // these are passed to Executor + void execute(Ctx& ctx); + void fetch(Ctx& ctx); + // close statement (mainly scan) + void close(Ctx& ctx); + // free data structures + void free(Ctx& ctx); + // odbc support + void sqlGetData(Ctx& ctx, SQLUSMALLINT columnNumber, SQLSMALLINT targetType, SQLPOINTER targetValue, SQLINTEGER bufferLength, SQLINTEGER* strlen_or_Ind); + void sqlParamData(Ctx& ctx, SQLPOINTER* value); + void sqlPutData(Ctx& ctx, SQLPOINTER data, SQLINTEGER strlen_or_Ind); +private: + void parse(Ctx& ctx); + void analyze(Ctx& ctx); + void describe(Ctx& ctx); + void codegen(Ctx& ctx); + void alloc(Ctx& ctx); + void freePlan(Ctx& ctx); + void freeExec(Ctx& ctx); + StmtArea& m_stmtArea; +}; + +inline +CodeGen::CodeGen(StmtArea& stmtArea) : + m_stmtArea(stmtArea) +{ +} + +inline +CodeGen::~CodeGen() +{ +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_base.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_base.cpp new file mode 100644 index 00000000000..dc02e071156 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_base.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 <common/StmtArea.hpp> +#include "Code_base.hpp" +#include "Code_root.hpp" + +// Plan_base + +Plan_base::~Plan_base() +{ +} + +StmtArea& +Plan_base::stmtArea() const +{ + ctx_assert(m_root != 0); + return m_root->m_stmtArea; +} + +DescArea& +Plan_base::descArea(DescUsage u) const +{ + return stmtArea().descArea(u); +} + +ConnArea& +Plan_base::connArea() const +{ + return stmtArea().connArea(); +} + +DictCatalog& +Plan_base::dictCatalog() const +{ + return connArea().dictCatalog(); +} + +DictSchema& +Plan_base::dictSchema() const +{ + return connArea().dictSchema(); +} + +Ndb* +Plan_base::ndbObject() const +{ + Ndb* ndb = connArea().ndbObject(); + ctx_assert(ndb != 0); + return ndb; +} + +NdbSchemaCon* +Plan_base::ndbSchemaCon() const +{ + NdbSchemaCon* ndbSchemaCon = connArea().ndbSchemaCon(); + ctx_assert(ndbSchemaCon != 0); + return ndbSchemaCon; +} + +NdbConnection* +Plan_base::ndbConnection() const +{ + NdbConnection* ndbConnection = connArea().ndbConnection(); + ctx_assert(ndbConnection != 0); + return ndbConnection; +} + +void +Plan_base::printList(Ctx& ctx, Plan_base* a[], unsigned n) +{ + for (unsigned i = 0; i < n; i++) { + if (a[i] == 0) + ctx.print(" -"); + else + a[i]->print(ctx); + } +} + +// Exec_base + +Exec_base::Code::~Code() +{ +} + +Exec_base::Data::~Data() +{ +} + +Exec_base::~Exec_base() +{ + delete m_code; // remove when code becomes shared + m_code = 0; + delete m_data; + m_data = 0; +} + +StmtArea& +Exec_base::stmtArea() const +{ + ctx_assert(m_root != 0); + return m_root->m_stmtArea; +} + +DescArea& +Exec_base::descArea(DescUsage u) const +{ + return stmtArea().descArea(u); +} + +ConnArea& +Exec_base::connArea() const +{ + return stmtArea().connArea(); +} + +DictSchema& +Exec_base::dictSchema() const +{ + return connArea().dictSchema(); +} + +Ndb* +Exec_base::ndbObject() const +{ + Ndb* ndb = connArea().ndbObject(); + ctx_assert(ndb != 0); + return ndb; +} + +NdbSchemaCon* +Exec_base::ndbSchemaCon() const +{ + NdbSchemaCon* ndbSchemaCon = connArea().ndbSchemaCon(); + ctx_assert(ndbSchemaCon != 0); + return ndbSchemaCon; +} + +NdbConnection* +Exec_base::ndbConnection() const +{ + NdbConnection* ndbConnection = connArea().ndbConnection(); + ctx_assert(ndbConnection != 0); + return ndbConnection; +} + +void +Exec_base::printList(Ctx& ctx, Exec_base* a[], unsigned n) +{ + for (unsigned i = 0; i < n; i++) { + ctx_assert(a[i] != 0); + a[i]->print(ctx); + } +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_base.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_base.hpp new file mode 100644 index 00000000000..c67c0ca7adb --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_base.hpp @@ -0,0 +1,237 @@ +/* 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_Code_base_hpp +#define ODBC_CODEGEN_Code_base_hpp + +#include <set> +#include <list> +#include <vector> +#include <common/common.hpp> +#include <common/CodeTree.hpp> +#include <common/DescArea.hpp> + +class Ctx; +class ConnArea; +class StmtArea; +class DescArea; +class DictCatalog; +class DictSchema; +class ResultArea; +class ResultSet; +class SpecRow; +class Ndb; +class NdbSchemaCon; +class NdbConnection; +class NdbOperation; +class NdbScanFilter; + +class Plan_root; +class Plan_table; +class Plan_column; +class Plan_expr; +class Plan_expr_param; +class Plan_pred; +class Plan_dml_row; +class Plan_dml_column; +class Plan_ddl_column; +class Plan_ddl_constr; +class Plan_idx_column; +class Exec_root; +class Exec_base; +class Exec_query; +class Exec_expr; +class Exec_expr_row; +class Exec_expr_param; + +/** + * @class Plan_base + * @brief Base class for plan trees + */ +class Plan_base : public PlanTree { +public: + Plan_base(Plan_root* root); + virtual ~Plan_base() = 0; + // get references to StmtArea via Plan_root + StmtArea& stmtArea() const; + DescArea& descArea(DescUsage u) const; + ConnArea& connArea() const; + // catalogs + DictCatalog& dictCatalog() const; + DictSchema& dictSchema() const; + // ndb + Ndb* ndbObject() const; + NdbSchemaCon* ndbSchemaCon() const; + NdbConnection* ndbConnection() const; + // containers for Plan classes + typedef std::vector<Plan_table*> TableVector; + typedef std::vector<Plan_column*> ColumnVector; + typedef std::vector<Plan_dml_column*> DmlColumnVector; + typedef std::vector<Plan_ddl_column*> DdlColumnVector; + typedef std::vector<Plan_ddl_constr*> DdlConstrVector; + typedef std::vector<Plan_idx_column*> IdxColumnVector; + typedef std::vector<Plan_expr*> ExprVector; + typedef std::list<Plan_expr*> ExprList; + typedef std::vector<ExprList> ExprListVector; + typedef std::list<Plan_pred*> PredList; + typedef std::set<Plan_table*> TableSet; + typedef std::vector<Plan_expr_param*> ParamVector; + // control area on the stack XXX needs to be designed + struct Ctl { + Ctl(Ctl* up); + Ctl* m_up; // up the stack + // analyze + TableVector m_tableList; // resolve column names + bool m_topand; // in top-level where clause + bool m_extra; // anything but single pk=expr + bool m_aggrok; // aggregate allowed + bool m_aggrin; // within aggregate args + bool m_const; // only constants in set clause + PredList m_topcomp; // top level comparisons + Plan_dml_row *m_dmlRow; // row type to convert to + Plan_table* m_topTable; // top level table for interpreted progs + bool m_having; // in having-predicate + // codegen + Exec_root* m_execRoot; // root of Exec tree + const Exec_query* m_execQuery; // pass to column + }; + // semantic analysis and optimization + virtual Plan_base* analyze(Ctx& ctx, Ctl& ctl) = 0; + // generate "executable" code + virtual Exec_base* codegen(Ctx& ctx, Ctl& ctl) = 0; + // misc + virtual void print(Ctx& ctx) = 0; +protected: + Plan_root* m_root; + void printList(Ctx& ctx, Plan_base* a[], unsigned n); +}; + +inline +Plan_base::Plan_base(Plan_root* root) : + m_root(root) +{ + ctx_assert(m_root != 0); +} + +inline +Plan_base::Ctl::Ctl(Ctl* up) : + m_up(up), + m_tableList(1), // 1-based + m_topand(false), + m_extra(false), + m_aggrok(false), + m_aggrin(false), + m_dmlRow(0), + m_topTable(0), + m_having(false), + m_execRoot(0), + m_execQuery(0) +{ +} + +/** + * @class Exec_base + * @brief Base class for exec trees + */ +class Exec_base : public ExecTree { +public: + class Code : public ExecTree::Code { + public: + virtual ~Code() = 0; + }; + class Data : public ExecTree::Data { + public: + virtual ~Data() = 0; + }; + Exec_base(Exec_root* root); + virtual ~Exec_base() = 0; + // get references to StmtArea via Exec_root + virtual StmtArea& stmtArea() const; + DescArea& descArea(DescUsage u) const; + ConnArea& connArea() const; + // catalogs + DictSchema& dictSchema() const; + // ndb + Ndb* ndbObject() const; + NdbSchemaCon* ndbSchemaCon() const; + NdbConnection* ndbConnection() const; + // containers for Exec classes + typedef std::vector<Exec_expr*> ExprVector; + typedef std::vector<Exec_expr_param*> ParamVector; + // control area on the stack + struct Ctl { + Ctl(Ctl* up); + Ctl* m_up; // up the stack + const Exec_query* m_query; // pass Data + ExprVector m_exprList; // pass Data + NdbOperation* m_scanOp; // scan operation + bool m_postEval; // for rownum + unsigned m_groupIndex; // for group by + bool m_groupInit; // first in group + Exec_expr_row* m_sortRow; // from sort to group by + NdbScanFilter* m_scanFilter; // scan filter + }; + // allocate and deallocate Data instances + virtual void alloc(Ctx& ctx, Ctl& ctl) = 0; + virtual void close(Ctx& ctx) = 0; + // set Code and Data + void setCode(const Code& code); + void setData(Data& data); + // misc + virtual void print(Ctx& ctx) = 0; +protected: + const Code* m_code; + Data* m_data; + Exec_root* m_root; + void printList(Ctx& ctx, Exec_base* a[], unsigned n); +}; + +inline +Exec_base::Exec_base(Exec_root* root) : + m_code(0), + m_data(0), + m_root(root) +{ + ctx_assert(m_root != 0); +} + +inline void +Exec_base::setCode(const Code& code) +{ + ctx_assert(m_code == 0); + m_code = &code; +} + +inline void +Exec_base::setData(Data& data) +{ + ctx_assert(m_data == 0); + m_data = &data; +} + +inline +Exec_base::Ctl::Ctl(Ctl* up) : + m_up(up), + m_scanOp(0), + m_postEval(false), + m_groupIndex(0), + m_groupInit(false), + m_sortRow(0), + m_scanFilter(0) +{ +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_column.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_column.cpp new file mode 100644 index 00000000000..c4c0480a5e7 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_column.cpp @@ -0,0 +1,72 @@ +/* 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/StmtArea.hpp> +#include <dictionary/DictSchema.hpp> +#include <dictionary/DictColumn.hpp> +#include "Code_column.hpp" +#include "Code_table_list.hpp" +#include "Code_table.hpp" + +// Plan_column + +Plan_column::~Plan_column() +{ +} + +void +Plan_column::analyzeColumn(Ctx& ctx, Plan_base::Ctl& ctl) +{ + if (m_resTable != 0) // done on previous pass + return; + if (! (ctl.m_tableList.size() > 1)) { + ctx.pushStatus(Sqlstate::_42000, Error::Gen, "column %s not allowed here", getPrintName()); + return; + } + unsigned resCount = 0; + for (unsigned i = 1; i < ctl.m_tableList.size(); i++) { + Plan_table* table = ctl.m_tableList[i]; + ctx_assert(table != 0); + int ret = table->resolveColumn(ctx, this); + if (ret < 0) + return; + if (ret) + resCount++; + } + if (resCount == 0) { + // XXX try to strip "schema name" from table name + for (unsigned i = 1; i < ctl.m_tableList.size(); i++) { + Plan_table* table = ctl.m_tableList[i]; + ctx_assert(table != 0); + int ret = table->resolveColumn(ctx, this, true); + if (ret < 0) + return; + if (ret) + resCount++; + } + } + if (resCount == 0) { + ctx.pushStatus(Sqlstate::_42S22, Error::Gen, "column %s not found", getPrintName()); + return; + } + if (resCount > 1) { + ctx.pushStatus(Error::Gen, "column %s is ambiguous", getPrintName()); + return; + } + // copy SQL type + m_sqlType = dictColumn().sqlType(); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_column.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_column.hpp new file mode 100644 index 00000000000..af0dcea690d --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_column.hpp @@ -0,0 +1,122 @@ +/* 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_Code_column_hpp +#define ODBC_CODEGEN_Code_column_hpp + +#include <common/common.hpp> +#include <common/DataType.hpp> +#include "Code_base.hpp" + +class DictColumn; +class Plan_table; + +/** + * @class Plan_column + * @brief Abstract base class for columns + */ +class Plan_column { +public: + enum Type { + Type_expr = 1, + Type_dml = 2, + Type_ddl = 3, // new columns in create table + Type_idx = 4 // old columns in create index + }; + Plan_column(Type type, const BaseString& name); + virtual ~Plan_column() = 0; + void analyzeColumn(Ctx& ctx, Plan_base::Ctl& ctl); + // attributes + const BaseString& getName() const; + const BaseString& getCname() const; + const char* getPrintName() const; + void setCname(const BaseString& cname); + const DictColumn& dictColumn() const; + const SqlType& sqlType() const; +protected: + friend class Plan_table; + friend class Plan_comp_op; + Type m_type; + BaseString m_name; + BaseString m_cname; + BaseString m_printName; + DictColumn* m_dictColumn; + /** + * Resolve to table and operational position (for example + * column number in scan query). + */ + Plan_table* m_resTable; + unsigned m_resPos; + SqlType m_sqlType; +}; + +inline +Plan_column::Plan_column(Type type, const BaseString& name) : + m_type(type), + m_name(name), + m_printName(name), + m_dictColumn(0), + m_resTable(0), + m_resPos(0) +{ +} + +inline const BaseString& +Plan_column::getName() const +{ + return m_name; +} + +inline const BaseString& +Plan_column::getCname() const +{ + return m_cname; +} + +inline const char* +Plan_column::getPrintName() const +{ + return m_printName.c_str(); +} + +inline void +Plan_column::setCname(const BaseString& cname) +{ + m_cname.assign(cname); + if (m_cname.empty()) + m_printName.assign(m_name); + else { + m_printName.assign(m_cname); + m_printName.append("."); + m_printName.append(m_name); + } +} + +inline const DictColumn& +Plan_column::dictColumn() const +{ + ctx_assert(m_dictColumn != 0); + return *m_dictColumn; +} + +inline const SqlType& +Plan_column::sqlType() const +{ + ctx_assert(m_sqlType.type() != SqlType::Undef); + return m_sqlType; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_comp_op.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_comp_op.cpp new file mode 100644 index 00000000000..7782ed1ea2a --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_comp_op.cpp @@ -0,0 +1,485 @@ +/* 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 <dictionary/DictColumn.hpp> +#include "Code_pred.hpp" +#include "Code_comp_op.hpp" +#include "Code_expr_conv.hpp" +#include "Code_expr_column.hpp" +#include "Code_table.hpp" +#include "Code_root.hpp" + +// Comp_op + +const char* +Comp_op::name() const +{ + switch (m_opcode) { + case Eq: + return "="; + case Noteq: + return "!="; + case Lt: + return "<"; + case Lteq: + return "<="; + case Gt: + return ">"; + case Gteq: + return ">="; + case Like: + return "like"; + case Notlike: + return "not like"; + case Isnull: + return "is null"; + case Isnotnull: + return "is not null"; + } + ctx_assert(false); + return ""; +} + +unsigned +Comp_op::arity() const +{ + switch (m_opcode) { + case Eq: + case Noteq: + case Lt: + case Lteq: + case Gt: + case Gteq: + case Like: + case Notlike: + return 2; + case Isnull: + case Isnotnull: + return 1; + } + ctx_assert(false); + return 0; +} + +// Plan_comp_op + +Plan_comp_op::~Plan_comp_op() +{ +} + +Plan_base* +Plan_comp_op::analyze(Ctx& ctx, Ctl& ctl) +{ + m_exec = 0; + const unsigned arity = m_op.arity(); + // analyze operands + for (unsigned i = 1; i <= arity; i++) { + ctx_assert(m_expr[i] != 0); + m_expr[i]->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + } + // for each operand, find type to convert to + SqlType con[1 + 2]; + if (arity == 1) { + const SqlType& t1 = m_expr[1]->sqlType(); + switch (t1.type()) { + case SqlType::Char: + case SqlType::Varchar: + case SqlType::Smallint: + case SqlType::Integer: + case SqlType::Bigint: + case SqlType::Real: + case SqlType::Double: + case SqlType::Datetime: + case SqlType::Null: + case SqlType::Unbound: + con[1] = t1; + break; + default: + break; + } + if (con[1].type() == SqlType::Undef) { + char b1[40]; + t1.print(b1, sizeof(b1)); + ctx.pushStatus(Error::Gen, "type mismatch in comparison: %s %s", b1, m_op.name()); + return 0; + } + } else if (arity == 2) { + const SqlType& t1 = m_expr[1]->sqlType(); + const SqlType& t2 = m_expr[2]->sqlType(); + switch (t1.type()) { + case SqlType::Char: + switch (t2.type()) { + case SqlType::Char: + case SqlType::Varchar: + case SqlType::Null: + con[1] = t1; + con[2] = t2; + break; + case SqlType::Unbound: + con[1] = con[2] = t2; + break; + default: + break; + } + break; + case SqlType::Varchar: + switch (t2.type()) { + case SqlType::Char: + case SqlType::Varchar: + case SqlType::Null: + con[1] = t1; + con[2] = t2; + break; + case SqlType::Unbound: + con[1] = con[2] = t2; + break; + default: + break; + } + break; + case SqlType::Smallint: + case SqlType::Integer: + case SqlType::Bigint: + switch (t2.type()) { + case SqlType::Smallint: + case SqlType::Integer: + case SqlType::Bigint: + // conversion would mask primary key optimization + con[1] = t1; + con[2] = t2; + break; + case SqlType::Real: + case SqlType::Double: + con[1].setType(ctx, SqlType::Double); + con[2] = con[1]; + break; + case SqlType::Null: + con[1] = t1; + con[2] = t2; + break; + case SqlType::Unbound: + con[1] = con[2] = t2; + break; + default: + break; + } + break; + case SqlType::Real: + case SqlType::Double: + switch (t2.type()) { + case SqlType::Smallint: + case SqlType::Integer: + case SqlType::Bigint: + case SqlType::Real: + case SqlType::Double: + con[1].setType(ctx, SqlType::Double); + con[2] = con[1]; + break; + case SqlType::Null: + con[1] = t1; + con[2] = t2; + break; + case SqlType::Unbound: + con[1] = con[2] = t2; + break; + default: + break; + } + break; + case SqlType::Datetime: + switch (t2.type()) { + case SqlType::Datetime: + con[1] = t1; + con[2] = t2; + break; + case SqlType::Unbound: + con[1] = con[2] = t2; + break; + default: + break; + } + break; + case SqlType::Null: + switch (t2.type()) { + case SqlType::Char: + case SqlType::Varchar: + case SqlType::Smallint: + case SqlType::Integer: + case SqlType::Bigint: + case SqlType::Real: + case SqlType::Double: + case SqlType::Datetime: + con[1] = t1; + con[2] = t2; + break; + case SqlType::Unbound: + con[1] = con[2] = t2; + break; + default: + break; + } + break; + case SqlType::Unbound: + con[1] = con[2] = t1; + break; + default: + break; + } + if (con[1].type() == SqlType::Undef || con[2].type() == SqlType::Undef) { + char b1[40], b2[40]; + t1.print(b1, sizeof(b1)); + t2.print(b2, sizeof(b2)); + ctx.pushStatus(Error::Gen, "type mismatch in comparison: %s %s %s", b1, m_op.name(), b2); + return 0; + } + } else { + ctx_assert(false); + return 0; + } + if (! ctx.ok()) + return 0; + // insert required conversions + for (unsigned i = 1; i <= arity; i++) { + if (con[i].type() == SqlType::Unbound) { + continue; + } + Plan_expr_conv* exprConv = new Plan_expr_conv(m_root, con[i]); + m_root->saveNode(exprConv); + exprConv->setExpr(m_expr[i]); + m_expr[i] = static_cast<Plan_expr*>(exprConv->analyze(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(m_expr[i] != 0); + } + // look for column=expr + if (ctl.m_topand && m_op.m_opcode == Comp_op::Eq) { + ctx_assert(arity == 2); + for (unsigned i = 1, j = 2; i <= 2; i++, j--) { + if (m_expr[i]->type() != Plan_expr::TypeColumn) + continue; + Plan_expr_column* column = static_cast<Plan_expr_column*>(m_expr[i]); + if (! column->resolveEq(ctx, m_expr[j])) + ctl.m_extra = true; + } + } else { + ctl.m_extra = true; + } + // save top level comparison on list + if (ctl.m_topand) { + ctl.m_topcomp.push_back(this); + } + // table dependencies are union from operands + m_tableSet.clear(); + for (unsigned i = 1; i <= arity; i++) { + const TableSet& ts = m_expr[i]->tableSet(); + m_tableSet.insert(ts.begin(), ts.end()); + } + // set of tables for which interpreter cannot be used + m_noInterp.clear(); + // convenient +#undef ustype +#define ustype(b, n) (((b) ? 1 : 0) * 100 + (n)) + if (arity == 1) { + for (unsigned i = 1; i <= 1; i++) { + const SqlType t1 = m_expr[i]->sqlType(); + switch (m_op.m_opcode) { + case Comp_op::Isnull: + case Comp_op::Isnotnull: + if (m_expr[i]->type() == Plan_expr::TypeColumn) { + switch (ustype(t1.unSigned(), t1.type())) { + // all types accepted now + default: + { + Plan_expr_column* column = static_cast<Plan_expr_column*>(m_expr[i]); + ctx_assert(column->m_resTable != 0); + m_interpColumn[i] = column; + continue; // ok + } + break; + } + } + break; + default: + break; + } + const TableSet& ts = m_expr[i]->tableSet(); + m_noInterp.insert(ts.begin(), ts.end()); + } + } else if (arity == 2) { + for (unsigned i = 1, j = 2; i <= 2; i++, j--) { + const SqlType t1 = m_expr[i]->sqlType(); + switch (m_op.m_opcode) { + case Comp_op::Like: + case Comp_op::Notlike: + if (i == 2) // col like val but not val like col + break; + /*FALLTHRU*/ + case Comp_op::Eq: + case Comp_op::Noteq: + case Comp_op::Lt: + case Comp_op::Lteq: + case Comp_op::Gt: + case Comp_op::Gteq: + if (m_expr[i]->type() == Plan_expr::TypeColumn) { + switch (ustype(t1.unSigned(), t1.type())) { + case ustype(false, SqlType::Char): + case ustype(false, SqlType::Varchar): + case ustype(true, SqlType::Smallint): + case ustype(true, SqlType::Integer): + case ustype(true, SqlType::Bigint): + { + Plan_expr_column* column = static_cast<Plan_expr_column*>(m_expr[i]); + ctx_assert(column->m_resTable != 0); + const TableSet& ts = m_expr[j]->tableSet(); + if (ts.find(column->m_resTable) == ts.end()) { + // candidate for column=const + m_interpColumn[i] = column; + continue; // ok + } + } + break; + default: + break; + } + } + break; + default: + break; + } + const TableSet& ts = m_expr[i]->tableSet(); + m_noInterp.insert(ts.begin(), ts.end()); + } + } else { + ctx_assert(false); + return 0; + } +#undef ustype + return this; +} + +Exec_base* +Plan_comp_op::codegen(Ctx& ctx, Ctl& ctl) +{ + if (m_exec != 0) + return m_exec; + const unsigned arity = m_op.arity(); + Exec_comp_op* exec = new Exec_comp_op(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + // create code for operands + for (unsigned i = 1; i <= arity; i++) { + ctx_assert(m_expr[i] != 0); + Exec_expr* execExpr = static_cast<Exec_expr*>(m_expr[i]->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execExpr != 0); + exec->setExpr(i, execExpr); + } + // create the code + Exec_comp_op::Code& code = *new Exec_comp_op::Code(m_op); + // interpreted column=const + if (! ctl.m_having) { + ctx_assert(ctl.m_topTable != 0); + for (unsigned i = 1; i <= arity; i++) { + Plan_expr_column* column = m_interpColumn[i]; + if (column == 0) + continue; + ctx_assert(column->m_resTable != 0); + if (column->m_resTable != ctl.m_topTable) + continue; + ctx_assert(code.m_interpColumn == 0); + code.m_interpColumn = i; + code.m_interpAttrId = column->dictColumn().getAttrId(); + ctx_log2(("can use interpreter on %s", column->getPrintName())); + } + } + exec->setCode(code); + m_exec = exec; + return exec; +} + +void +Plan_comp_op::print(Ctx& ctx) +{ + ctx.print(" [%s", m_op.name()); + Plan_base* a[] = { m_expr[1], m_expr[2] }; + printList(ctx, a, m_op.arity()); + ctx.print("]"); +} + +bool +Plan_comp_op::isGroupBy(const Plan_expr_row* row) const +{ + const unsigned arity = m_op.arity(); + for (unsigned i = 1; i <= arity; i++) { + ctx_assert(m_expr[i] != 0); + if (! m_expr[i]->isGroupBy(row)) + return false; + } + return true; +} + +// Code_comp_op + +Exec_comp_op::Code::~Code() +{ +} + +Exec_comp_op::Data::~Data() +{ +} + +Exec_comp_op::~Exec_comp_op() +{ +} + +void +Exec_comp_op::alloc(Ctx& ctx, Ctl& ctl) +{ + const Code& code = getCode(); + // allocate subexpressions + unsigned arity = code.m_op.arity(); + for (unsigned i = 1; i <= arity; i++) { + ctx_assert(m_expr[i] != 0); + m_expr[i]->alloc(ctx, ctl); + if (! ctx.ok()) + return; + } + Data& data = *new Data; + setData(data); +} + +void +Exec_comp_op::close(Ctx& ctx) +{ + const Code& code = getCode(); + unsigned arity = code.m_op.arity(); + for (unsigned i = 1; i <= arity; i++) { + ctx_assert(m_expr[i] != 0); + m_expr[i]->close(ctx); + } +} + +void +Exec_comp_op::print(Ctx& ctx) +{ + const Code& code = getCode(); + ctx.print(" [%s", code.m_op.name()); + Exec_base* a[] = { m_expr[1], m_expr[2] }; + printList(ctx, a, code.m_op.arity()); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_comp_op.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_comp_op.hpp new file mode 100644 index 00000000000..0585ab1dabf --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_comp_op.hpp @@ -0,0 +1,172 @@ +/* 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_Code_comp_op_hpp +#define ODBC_CODEGEN_Code_comp_op_hpp + +#include <common/common.hpp> +#include <common/DataField.hpp> +#include "Code_pred.hpp" +#include "Code_expr.hpp" +#include "Code_expr_column.hpp" + +/** + * @class Comp_op + * @brief Comparison operations + */ +struct Comp_op { + enum Opcode { + Eq = 1, // binary + Noteq, + Lt, + Lteq, + Gt, + Gteq, + Like, + Notlike, + Isnull, // unary + Isnotnull + }; + Comp_op(Opcode opcode); + const char* name() const; + unsigned arity() const; + Opcode m_opcode; +}; + +inline +Comp_op::Comp_op(Opcode opcode) : + m_opcode(opcode) +{ +} + +/** + * @class Plan_comp_op + * @brief Comparison operator node in PlanTree + */ +class Plan_comp_op : public Plan_pred { +public: + Plan_comp_op(Plan_root* root, Comp_op op); + virtual ~Plan_comp_op(); + void setExpr(unsigned i, Plan_expr* expr); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + virtual bool isGroupBy(const Plan_expr_row* row) const; +protected: + Comp_op m_op; + Plan_expr* m_expr[1 + 2]; + Plan_expr_column* m_interpColumn[1 + 2]; // candidates +}; + +inline +Plan_comp_op::Plan_comp_op(Plan_root* root, Comp_op op) : + Plan_pred(root, TypeComp), + m_op(op) +{ + m_expr[0] = m_expr[1] = m_expr[2] = 0; + m_interpColumn[0] = m_interpColumn[1] = m_interpColumn[2] = 0; +} + +inline void +Plan_comp_op::setExpr(unsigned i, Plan_expr* expr) +{ + ctx_assert(1 <= i && i <= 2); + m_expr[i] = expr; +} + +/** + * @class Exec_comp_op + * @brief Comparison operator node in ExecTree + */ +class Exec_comp_op : public Exec_pred { +public: + class Code : public Exec_pred::Code { + public: + Code(Comp_op op); + virtual ~Code(); + protected: + friend class Plan_comp_op; + friend class Exec_comp_op; + Comp_op m_op; + unsigned m_interpColumn; // 1 or 2 if interpreted column, 0 if both constant + NdbAttrId m_interpAttrId; + }; + class Data : public Exec_pred::Data { + public: + Data(); + virtual ~Data(); + protected: + friend class Exec_comp_op; + }; + Exec_comp_op(Exec_root* root); + virtual ~Exec_comp_op(); + void alloc(Ctx& ctx, Ctl& ctl); + void execInterp(Ctx& ctx, Ctl& ctl); + void evaluate(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setExpr(unsigned i, Exec_expr* expr); +protected: + Exec_expr* m_expr[1 + 2]; +}; + +inline +Exec_comp_op::Code::Code(Comp_op op) : + m_op(op), + m_interpColumn(0), + m_interpAttrId((NdbAttrId)-1) +{ +} + +inline +Exec_comp_op::Data::Data() +{ +} + +inline +Exec_comp_op::Exec_comp_op(Exec_root* root) : + Exec_pred(root) +{ + m_expr[0] = m_expr[1] = m_expr[2] = 0; +} + +// children + +inline const Exec_comp_op::Code& +Exec_comp_op::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_comp_op::Data& +Exec_comp_op::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_comp_op::setExpr(unsigned i, Exec_expr* expr) +{ + ctx_assert(1 <= i && i <= 2 && m_expr[i] == 0); + m_expr[i] = expr; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_create_index.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_create_index.cpp new file mode 100644 index 00000000000..84f319338a4 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_create_index.cpp @@ -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 */ + +#include <common/StmtArea.hpp> +#include "Code_create_index.hpp" +#include "Code_root.hpp" + +// Plan_create_index + +Plan_create_index::~Plan_create_index() +{ +} + +Plan_base* +Plan_create_index::analyze(Ctx& ctx, Ctl& ctl) +{ + stmtArea().stmtInfo().setName(Stmt_name_create_index); + // analyze the table + ctx_assert(m_table != 0); + m_table->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + // analyze the columns + ctl.m_tableList.resize(1 + 1); // indexed from 1 + ctl.m_tableList[1] = m_table; + for (unsigned i = 1, n = countColumn(); i <= n; i++) { + Plan_idx_column* column = getColumn(i); + column->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + } + return this; +} + +void +Plan_create_index::describe(Ctx& ctx) +{ + stmtArea().setFunction(ctx, "CREATE INDEX", SQL_DIAG_CREATE_INDEX); +} + +Exec_base* +Plan_create_index::codegen(Ctx& ctx, Ctl& ctl) +{ + Exec_create_index* exec = new Exec_create_index(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + const unsigned count = countColumn(); + const char** attrList = new const char* [1 + count]; + attrList[0] = 0; // unused + for (unsigned i = 1; i <= count; i++) { + Plan_idx_column* column = getColumn(i); + const char* cname = column->getName().c_str(); + attrList[i] = strcpy(new char[strlen(cname) + 1], cname); + } + Exec_create_index::Code& code = *new Exec_create_index::Code(m_name, m_table->getName(), m_type, count, attrList); + exec->setCode(code); + code.m_fragmentType = m_fragmentType; + code.m_logging = m_logging; + return exec; +} + +void +Plan_create_index::print(Ctx& ctx) +{ + ctx.print(" [create_index name=%s table=%s type=%d", m_name.c_str(), m_table->getName().c_str(), (int)m_type); + ctx.print(" ["); + for (unsigned i = 1; i <= countColumn(); i++) { + Plan_idx_column* column = getColumn(i); + if (i > 1) + ctx.print(" "); + column->print(ctx); + } + ctx.print("]"); +} + +// Exec_create_index + +Exec_create_index::Code::~Code() +{ + for (unsigned i = 1; i <= m_attrCount; i++) { + delete[] m_attrList[i]; + m_attrList[i] = 0; + } + delete[] m_attrList; +} + +Exec_create_index::Data::~Data() +{ +} + +Exec_create_index::~Exec_create_index() +{ +} + +void +Exec_create_index::alloc(Ctx& ctx, Ctl& ctl) +{ + Data& data = *new Data; + setData(data); +} + +void +Exec_create_index::close(Ctx& ctx) +{ +} + +void +Exec_create_index::print(Ctx& ctx) +{ + const Code& code = getCode(); + ctx.print(" [create_index %s]", code.m_tableName.c_str()); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_create_index.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_create_index.hpp new file mode 100644 index 00000000000..ebd757e1118 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_create_index.hpp @@ -0,0 +1,203 @@ +/* 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_Code_create_index_hpp +#define ODBC_CODEGEN_Code_create_index_hpp + +#include <vector> +#include <NdbApi.hpp> +#include <common/common.hpp> +#include "Code_ddl.hpp" +#include "Code_table.hpp" +#include "Code_idx_column.hpp" + +class DictTable; +class DictColumn; + +/** + * @class Plan_create_index + * @brief Create table in PlanTree + */ +class Plan_create_index : public Plan_ddl { +public: + Plan_create_index(Plan_root* root, const BaseString& name); + virtual ~Plan_create_index(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void describe(Ctx & ctx); + void print(Ctx& ctx); + // attributes + const BaseString& getName() const; + // children + void setType(NdbDictionary::Object::Type type); + void setTable(Plan_table* table); + unsigned countColumn() const; + void addColumn(Plan_idx_column* column); + Plan_idx_column* getColumn(unsigned i) const; + void setFragmentType(NdbDictionary::Object::FragmentType fragmentType); + void setLogging(bool logging); +protected: + BaseString m_name; + NdbDictionary::Object::Type m_type; + Plan_table* m_table; + IdxColumnVector m_columnList; + NdbDictionary::Object::FragmentType m_fragmentType; + bool m_logging; +}; + +inline +Plan_create_index::Plan_create_index(Plan_root* root, const BaseString& name) : + Plan_ddl(root), + m_name(name), + m_type(NdbDictionary::Object::TypeUndefined), + m_columnList(1), + m_fragmentType(NdbDictionary::Object::FragUndefined), + m_logging(true) +{ +} + +inline const BaseString& +Plan_create_index::getName() const +{ + return m_name; +} + +// children + +inline void +Plan_create_index::setType(NdbDictionary::Object::Type type) +{ + m_type = type; +} + +inline void +Plan_create_index::setTable(Plan_table* table) +{ + ctx_assert(table != 0); + m_table = table; +} + +inline unsigned +Plan_create_index::countColumn() const +{ + return m_columnList.size() - 1; +} + +inline void +Plan_create_index::addColumn(Plan_idx_column* column) +{ + ctx_assert(column != 0); + m_columnList.push_back(column); +} + +inline Plan_idx_column* +Plan_create_index::getColumn(unsigned i) const +{ + ctx_assert(1 <= i && i <= countColumn() && m_columnList[i] != 0); + return m_columnList[i]; +} + +inline void +Plan_create_index::setFragmentType(NdbDictionary::Object::FragmentType fragmentType) +{ + m_fragmentType = fragmentType; +} + +inline void +Plan_create_index::setLogging(bool logging) +{ + m_logging = logging; +} + +/** + * @class Exec_create_index + * @brief Create table in ExecTree + */ +class Exec_create_index : public Exec_ddl { +public: + class Code : public Exec_ddl::Code { + public: + Code(const BaseString& indexName, const BaseString& tableName, NdbDictionary::Object::Type type, unsigned attrCount, const char** attrList); + virtual ~Code(); + protected: + friend class Plan_create_index; + friend class Exec_create_index; + const BaseString m_indexName; + const BaseString m_tableName; + NdbDictionary::Object::Type m_type; + const unsigned m_attrCount; + const char** m_attrList; + NdbDictionary::Object::FragmentType m_fragmentType; + bool m_logging; + }; + class Data : public Exec_ddl::Data { + public: + Data(); + virtual ~Data(); + protected: + friend class Exec_create_index; + }; + Exec_create_index(Exec_root* root); + virtual ~Exec_create_index(); + void alloc(Ctx& ctx, Ctl& ctl); + void execute(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; +}; + +inline +Exec_create_index::Code::Code(const BaseString& indexName, const BaseString& tableName, NdbDictionary::Object::Type type, unsigned attrCount, const char** attrList) : + m_indexName(indexName), + m_tableName(tableName), + m_type(type), + m_attrCount(attrCount), + m_attrList(attrList), + m_fragmentType(NdbDictionary::Object::FragUndefined), + m_logging(true) +{ +} + +inline +Exec_create_index::Data::Data() +{ +} + +inline +Exec_create_index::Exec_create_index(Exec_root* root) : + Exec_ddl(root) +{ +} + +// children + +inline const Exec_create_index::Code& +Exec_create_index::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_create_index::Data& +Exec_create_index::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_create_row.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_create_row.cpp new file mode 100644 index 00000000000..5b90b658ed7 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_create_row.cpp @@ -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 */ + +#include "Code_create_row.hpp" +#include "Code_root.hpp" + +Plan_create_row::~Plan_create_row() +{ +} + +Plan_base* +Plan_create_row::analyze(Ctx& ctx, Ctl& ctl) +{ + // check for duplicate column name + for (unsigned i = 1, n = countColumn(); i < n; i++) { + const BaseString& a = getColumn(i)->getName(); + for (unsigned i2 = i + 1; i2 <= n; i2++) { + const BaseString& a2 = getColumn(i2)->getName(); + if (strcmp(a.c_str(), a2.c_str()) == 0) { + ctx.pushStatus(Error::Gen, "duplicate column %s", a.c_str()); + return 0; + } + } + } + // move single-column primary key constraint to constraint list + for (unsigned i = 1, n = countColumn(); i <= n; i++) { + Plan_ddl_column* column = getColumn(i); + if (column->m_primaryKey) { + Plan_ddl_row* ddlRow = new Plan_ddl_row(m_root); + m_root->saveNode(ddlRow); + ddlRow->addColumn(column); + Plan_ddl_constr* constr = new Plan_ddl_constr(m_root); + m_root->saveNode(constr); + constr->setRow(ddlRow); + addConstr(constr); + column->m_primaryKey = false; // will be set again + } + } + // check primary key constraints + if (countConstr() < 1) { + ctx.pushStatus(Error::Gen, "table must have a primary key"); + return 0; + } + if (countConstr() > 1) { + ctx.pushStatus(Error::Gen, "table can have only one primary key"); + return 0; + } + Plan_ddl_row* ddlRow = getConstr(1)->getRow(); + for (unsigned i = 1, n = ddlRow->countColumn(); i <= n; i++) { + Plan_ddl_column* column = ddlRow->getColumn(i); + const BaseString& a = column->getName(); + bool found = false; + for (unsigned i2 = 1, n2 = countColumn(); i2 <= n2; i2++) { + Plan_ddl_column* column2 = getColumn(i2); + const BaseString& a2 = column2->getName(); + if (strcmp(a.c_str(), a2.c_str()) != 0) + continue; + if (column2->getPrimaryKey()) { + ctx.pushStatus(Error::Gen, "duplicate primary key constraint on %s", a.c_str()); + return 0; + } + column2->setPrimaryKey(); + found = true; + break; + } + if (! found) { + ctx.pushStatus(Error::Gen, "undefined primary key column %s", a.c_str()); + return 0; + } + } + // analyze column types + for (unsigned i = 1, n = countColumn(); i <= n; i++) { + getColumn(i)->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + } + // check TupleId + unsigned tupleId = 0; + for (unsigned i = 1, n = countColumn(); i <= n; i++) { + Plan_ddl_column* column = getColumn(i); + if (! column->getTupleId()) + continue; + if (i != 1) { + ctx.pushStatus(Error::Gen, "tuple id column %u is not first column", i); + return 0; + } + if (tupleId != 0) { // cannot happen now since attr name is fixed + ctx.pushStatus(Error::Gen, "duplicate tuple id column %u", i); + return 0; + } + tupleId = i; + } + if (tupleId != 0) { + for (unsigned i = 1, n = countColumn(); i <= n; i++) { + Plan_ddl_column* column = getColumn(i); + if (i == tupleId) + continue; + if (! column->getPrimaryKey()) + continue; + ctx.pushStatus(Error::Gen, "cannot have both tuple id and other primary key column %u", i); + return 0; + } + } + // check auto-increment + unsigned autoIncrement = 0; + for (unsigned i = 1, n = countColumn(); i <= n; i++) { + Plan_ddl_column* column = getColumn(i); + if (! column->getAutoIncrement()) + continue; + if (autoIncrement != 0) { + ctx.pushStatus(Error::Gen, "duplicate auto-increment column %u", i); + return 0; + } + autoIncrement = i; + } + if (autoIncrement != 0) { + for (unsigned i = 1, n = countColumn(); i <= n; i++) { + Plan_ddl_column* column = getColumn(i); + if (i == autoIncrement) + continue; + if (! column->getPrimaryKey()) + continue; + ctx.pushStatus(Error::Gen, "cannot have both auto-increment column and other primary key column %u", i); + return 0; + } + } + return this; +} + +Exec_base* +Plan_create_row::codegen(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(false); + return 0; +} + +void +Plan_create_row::print(Ctx& ctx) +{ + ctx.print(" [create_row"); + for (unsigned i = 1; i <= countColumn(); i++) { + Plan_base* a = m_columnList[i]; + printList(ctx, &a, 1); + } + for (unsigned i = 1; i <= countConstr(); i++) { + Plan_base* a = m_constrList[i]; + printList(ctx, &a, 1); + } +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_create_row.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_create_row.hpp new file mode 100644 index 00000000000..f03455ff28e --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_create_row.hpp @@ -0,0 +1,99 @@ +/* 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_Code_create_row_hpp +#define ODBC_CODEGEN_Code_create_row_hpp + +#include <vector> +#include <common/common.hpp> +#include "Code_base.hpp" +#include "Code_ddl_column.hpp" +#include "Code_ddl_constr.hpp" + +/** + * @class Plan_create_row + * @brief Row of columns and constraints in create statement + */ +class Plan_create_row : public Plan_base { +public: + Plan_create_row(Plan_root* root); + virtual ~Plan_create_row(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + unsigned countColumn() const; + void addColumn(Plan_ddl_column* column); + Plan_ddl_column* getColumn(unsigned i) const; + unsigned countConstr() const; + void addConstr(Plan_ddl_constr* constr); + Plan_ddl_constr* getConstr(unsigned i) const; +protected: + DdlColumnVector m_columnList; + DdlConstrVector m_constrList; +}; + +inline +Plan_create_row::Plan_create_row(Plan_root* root) : + Plan_base(root), + m_columnList(1), + m_constrList(1) +{ +} + +// children + +inline unsigned +Plan_create_row::countColumn() const +{ + return m_columnList.size() - 1; +} + +inline void +Plan_create_row::addColumn(Plan_ddl_column* column) +{ + ctx_assert(column != 0); + m_columnList.push_back(column); +} + +inline Plan_ddl_column* +Plan_create_row::getColumn(unsigned i) const +{ + ctx_assert(1 <= i && i <= m_columnList.size() && m_columnList[i] != 0); + return m_columnList[i]; +} + +inline unsigned +Plan_create_row::countConstr() const +{ + return m_constrList.size() - 1; +} + +inline void +Plan_create_row::addConstr(Plan_ddl_constr* constr) +{ + ctx_assert(constr != 0); + m_constrList.push_back(constr); +} + +inline Plan_ddl_constr* +Plan_create_row::getConstr(unsigned i) const +{ + ctx_assert(1 <= i && i <= m_constrList.size() && m_constrList[i] != 0); + return m_constrList[i]; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_create_table.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_create_table.cpp new file mode 100644 index 00000000000..14e4abbd7fe --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_create_table.cpp @@ -0,0 +1,137 @@ +/* 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/StmtArea.hpp> +#include "Code_create_table.hpp" +#include "Code_root.hpp" + +// Plan_create_table + +Plan_create_table::~Plan_create_table() +{ +} + +Plan_base* +Plan_create_table::analyze(Ctx& ctx, Ctl& ctl) +{ + stmtArea().stmtInfo().setName(Stmt_name_create_table); + // analyze the create row + ctx_assert(m_createRow != 0); + m_createRow->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + return this; +} + +void +Plan_create_table::describe(Ctx& ctx) +{ + stmtArea().setFunction(ctx, "CREATE TABLE", SQL_DIAG_CREATE_TABLE); +} + +Exec_base* +Plan_create_table::codegen(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_createRow != 0); + Exec_create_table* exec = new Exec_create_table(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + const unsigned count = m_createRow->countColumn(); + Exec_create_table::Code::Attr* attrList = new Exec_create_table::Code::Attr[1 + count]; + unsigned tupleId = 0; + unsigned autoIncrement = 0; + for (unsigned i = 1; i <= count; i++) { + Plan_ddl_column* column = m_createRow->getColumn(i); + Exec_create_table::Code::Attr& attr = attrList[i]; + attr.m_attrName.assign(column->getName()); + attr.m_sqlType = column->sqlType(); + attr.m_tupleKey = column->getPrimaryKey(); + attr.m_tupleId = column->getTupleId(); + attr.m_autoIncrement = column->getAutoIncrement(); + if (attr.m_tupleId) + tupleId = i; + if (attr.m_autoIncrement) + autoIncrement = i; + attr.m_defaultValue = 0; + Plan_expr* expr; + if ((expr = column->getDefaultValue()) != 0) { + Exec_expr* execExpr = static_cast<Exec_expr*>(expr->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execExpr != 0); + attr.m_defaultValue = execExpr; + } + } + Exec_create_table::Code& code = *new Exec_create_table::Code(m_name, count, attrList, tupleId, autoIncrement); + exec->setCode(code); + code.m_fragmentType = m_fragmentType; + code.m_logging = m_logging; + return exec; +} + +void +Plan_create_table::print(Ctx& ctx) +{ + ctx.print(" [create_table '%s'", m_name.c_str()); + Plan_base* a[] = { m_createRow }; + printList(ctx, a, 1); + ctx.print("]"); +} + +// Exec_create_table + +Exec_create_table::Code::~Code() +{ + delete[] m_attrList; +} + +Exec_create_table::Data::~Data() +{ +} + +Exec_create_table::~Exec_create_table() +{ +} + +void +Exec_create_table::alloc(Ctx& ctx, Ctl& ctl) +{ + const Code& code = getCode(); + for (unsigned i = 1; i <= code.m_attrCount; i++) { + const Code::Attr& attr = code.m_attrList[i]; + if (attr.m_defaultValue != 0) + attr.m_defaultValue->alloc(ctx, ctl); + } + Data& data = *new Data; + setData(data); +} + +void +Exec_create_table::close(Ctx& ctx) +{ + const Code& code = getCode(); + for (unsigned i = 1; i <= code.m_attrCount; i++) { + const Code::Attr& attr = code.m_attrList[i]; + if (attr.m_defaultValue != 0) + attr.m_defaultValue->close(ctx); + } +} + +void +Exec_create_table::print(Ctx& ctx) +{ + const Code& code = getCode(); + ctx.print(" [create_table %s]", code.m_tableName.c_str()); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_create_table.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_create_table.hpp new file mode 100644 index 00000000000..cbb2189d8ce --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_create_table.hpp @@ -0,0 +1,178 @@ +/* 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_Code_create_table_hpp +#define ODBC_CODEGEN_Code_create_table_hpp + +#include <vector> +#include <common/common.hpp> +#include "Code_ddl.hpp" +#include "Code_ddl_row.hpp" +#include "Code_create_row.hpp" + +class DictTable; +class DictColumn; + +/** + * @class Plan_create_table + * @brief Create table in PlanTree + */ +class Plan_create_table : public Plan_ddl { +public: + Plan_create_table(Plan_root* root, const BaseString& name); + virtual ~Plan_create_table(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void describe(Ctx & ctx); + void print(Ctx& ctx); + // attributes + const BaseString& getName() const; + // children + void setCreateRow(Plan_create_row* createRow); + void setFragmentType(NdbDictionary::Object::FragmentType fragmentType); + void setLogging(bool logging); +protected: + BaseString m_name; + Plan_create_row* m_createRow; + NdbDictionary::Object::FragmentType m_fragmentType; + bool m_logging; +}; + +inline +Plan_create_table::Plan_create_table(Plan_root* root, const BaseString& name) : + Plan_ddl(root), + m_name(name), + m_createRow(0), + m_fragmentType(NdbDictionary::Object::FragUndefined), + m_logging(true) +{ +} + +inline const BaseString& +Plan_create_table::getName() const +{ + return m_name; +} + +// children + +inline void +Plan_create_table::setCreateRow(Plan_create_row* createRow) +{ + ctx_assert(createRow != 0); + m_createRow = createRow; +} + +inline void +Plan_create_table::setFragmentType(NdbDictionary::Object::FragmentType fragmentType) +{ + m_fragmentType = fragmentType; +} + +inline void +Plan_create_table::setLogging(bool logging) +{ + m_logging = logging; +} + +/** + * @class Exec_create_table + * @brief Create table in ExecTree + */ +class Exec_create_table : public Exec_ddl { +public: + class Code : public Exec_ddl::Code { + public: + struct Attr { + Attr() : m_defaultValue(0) {} + BaseString m_attrName; + SqlType m_sqlType; + bool m_tupleKey; + bool m_tupleId; + bool m_autoIncrement; + Exec_expr* m_defaultValue; + }; + Code(const BaseString& tableName, unsigned attrCount, const Attr* attrList, unsigned tupleId, unsigned autoIncrement); + virtual ~Code(); + protected: + friend class Plan_create_table; + friend class Exec_create_table; + const BaseString m_tableName; + const unsigned m_attrCount; + const Attr* const m_attrList; + unsigned m_tupleId; + unsigned m_autoIncrement; + NdbDictionary::Object::FragmentType m_fragmentType; + bool m_logging; + }; + class Data : public Exec_ddl::Data { + public: + Data(); + virtual ~Data(); + protected: + friend class Exec_create_table; + }; + Exec_create_table(Exec_root* root); + virtual ~Exec_create_table(); + void alloc(Ctx& ctx, Ctl& ctl); + void execute(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; +}; + +inline +Exec_create_table::Code::Code(const BaseString& tableName, unsigned attrCount, const Attr* attrList, unsigned tupleId, unsigned autoIncrement) : + m_tableName(tableName), + m_attrCount(attrCount), + m_attrList(attrList), + m_tupleId(tupleId), + m_autoIncrement(autoIncrement), + m_fragmentType(NdbDictionary::Object::FragUndefined), + m_logging(true) +{ +} + +inline +Exec_create_table::Data::Data() +{ +} + +inline +Exec_create_table::Exec_create_table(Exec_root* root) : + Exec_ddl(root) +{ +} + +// children + +inline const Exec_create_table::Code& +Exec_create_table::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_create_table::Data& +Exec_create_table::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_data_type.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_data_type.cpp new file mode 100644 index 00000000000..1ff0fcebcbe --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_data_type.cpp @@ -0,0 +1,44 @@ +/* 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/StmtArea.hpp> +#include "Code_data_type.hpp" + +// Plan_data_type + +Plan_data_type::~Plan_data_type() +{ +} + +Plan_base* +Plan_data_type::analyze(Ctx& ctx, Ctl& ctl) +{ + return this; +} + +Exec_base* +Plan_data_type::codegen(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(false); + return 0; +} + +void +Plan_data_type::print(Ctx& ctx) +{ + ctx.print(" [data_type]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_data_type.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_data_type.hpp new file mode 100644 index 00000000000..735dc05014f --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_data_type.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_Code_data_type_hpp +#define ODBC_CODEGEN_Code_data_type_hpp + +#include <common/common.hpp> +#include <common/DataType.hpp> +#include "Code_base.hpp" + +/** + * @class Plan_data_type + * @brief Data type in DDL statement + * + * This is pure plan node. + */ +class Plan_data_type : public Plan_base { +public: + Plan_data_type(Plan_root* root, const SqlType& sqlType); + virtual ~Plan_data_type(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); +private: + friend class Plan_ddl_column; + SqlType m_sqlType; +}; + +inline +Plan_data_type::Plan_data_type(Plan_root* root, const SqlType& sqlType) : + Plan_base(root), + m_sqlType(sqlType) +{ +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl.cpp new file mode 100644 index 00000000000..2ba4291a0e8 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl.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 "Code_ddl.hpp" + +// Plan_ddl + +Plan_ddl::~Plan_ddl() +{ +} + +// Exec_ddl + +Exec_ddl::Code::~Code() +{ +} + +Exec_ddl::Data::~Data() +{ +} + +Exec_ddl::~Exec_ddl() +{ +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl.hpp new file mode 100644 index 00000000000..1ceca62d55d --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl.hpp @@ -0,0 +1,63 @@ +/* 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_Code_ddl_hpp +#define ODBC_CODEGEN_Code_ddl_hpp + +#include <common/common.hpp> +#include "Code_stmt.hpp" + +/** + * @class Plan_ddl + * @brief Base class for DDL statements in PlanTree + */ +class Plan_ddl : public Plan_stmt { +public: + Plan_ddl(Plan_root* root); + virtual ~Plan_ddl() = 0; +}; + +inline +Plan_ddl::Plan_ddl(Plan_root* root) : + Plan_stmt(root) +{ +} + +/** + * @class Exec_ddl + * @brief Base class for DDL statements in ExecTree + */ +class Exec_ddl : public Exec_stmt { +public: + class Code : public Exec_stmt::Code { + public: + virtual ~Code() = 0; + }; + class Data : public Exec_stmt::Data { + public: + virtual ~Data() = 0; + }; + Exec_ddl(Exec_root* root); + virtual ~Exec_ddl() = 0; +}; + +inline +Exec_ddl::Exec_ddl(Exec_root* root) : + Exec_stmt(root) +{ +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl_column.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl_column.cpp new file mode 100644 index 00000000000..ee037e54c1f --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl_column.cpp @@ -0,0 +1,104 @@ +/* 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/StmtArea.hpp> +#include "Code_ddl_column.hpp" +#include "Code_expr_conv.hpp" +#include "Code_root.hpp" + +// Plan_ddl_column + +Plan_ddl_column::~Plan_ddl_column() +{ +} + +Plan_base* +Plan_ddl_column::analyze(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_type != 0); + if (! m_type->m_sqlType.nullable()) { + m_nullable = false; + } + m_sqlType = m_type->m_sqlType; + m_sqlType.nullable(m_nullable); + const BaseString& name = getName(); + if (m_unSigned) { + switch (m_sqlType.type()) { + case SqlType::Smallint: + case SqlType::Integer: + case SqlType::Bigint: + break; + default: + ctx.pushStatus(Error::Gen, "invalid unsigned qualifier on column %s", name.c_str()); + return 0; + } + m_sqlType.unSigned(true); + } + if (strcmp(name.c_str(), "NDB$TID") == 0) { + if (! m_primaryKey) { + ctx.pushStatus(Error::Gen, "column %s must be a primary key", name.c_str()); + return 0; + } + if (sqlType().type() != SqlType::Bigint || ! sqlType().unSigned()) { + ctx.pushStatus(Error::Gen, "tuple id %s must have type BIGINT UNSIGNED", name.c_str()); + return 0; + } + setTupleId(); + } + if (m_autoIncrement) { + if (! m_primaryKey) { + ctx.pushStatus(Error::Gen, "auto-increment column %s must be a primary key", name.c_str()); + return 0; + } + if (sqlType().type() != SqlType::Smallint && sqlType().type() != SqlType::Integer && sqlType().type() != SqlType::Bigint) { + ctx.pushStatus(Error::Gen, "auto-increment column %s must have an integral type", name.c_str()); + return 0; + } + } + if (m_defaultValue != 0) { + if (m_primaryKey) { + ctx.pushStatus(Sqlstate::_42000, Error::Gen, "default value not allowed on primary key column %s", name.c_str()); + return 0; + } + m_defaultValue->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + // insert conversion node + Plan_expr_conv* exprConv = new Plan_expr_conv(m_root, sqlType()); + m_root->saveNode(exprConv); + exprConv->setExpr(m_defaultValue); + Plan_expr* expr = static_cast<Plan_expr*>(exprConv->analyze(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(expr != 0); + m_defaultValue = expr; + } + return this; +} + +Exec_base* +Plan_ddl_column::codegen(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(false); + return 0; +} + +void +Plan_ddl_column::print(Ctx& ctx) +{ + ctx.print(" [ddl_column %s key=%d id=%d]", getPrintName(), m_primaryKey, m_tupleId); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl_column.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl_column.hpp new file mode 100644 index 00000000000..7d089d37440 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl_column.hpp @@ -0,0 +1,150 @@ +/* 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_Code_ddl_column_hpp +#define ODBC_CODEGEN_Code_ddl_column_hpp + +#include <common/common.hpp> +#include "Code_column.hpp" +#include "Code_data_type.hpp" +#include "Code_expr.hpp" + +class DictColumn; +class Plan_table; + +/** + * @class Plan_ddl_column + * @brief Column in DDL statement + */ +class Plan_ddl_column : public Plan_base, public Plan_column { +public: + Plan_ddl_column(Plan_root* root, const BaseString& name); + virtual ~Plan_ddl_column(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // attributes + void setNotNull(); + void setUnSigned(); + void setPrimaryKey(); + bool getPrimaryKey() const; + void setTupleId(); + bool getTupleId() const; + void setAutoIncrement(); + bool getAutoIncrement() const; + // children + void setType(Plan_data_type* type); + void setDefaultValue(Plan_expr* defaultValue); + Plan_expr* getDefaultValue() const; +protected: + friend class Plan_create_row; + Plan_data_type* m_type; + Plan_expr* m_defaultValue; + bool m_nullable; + bool m_unSigned; + bool m_primaryKey; + bool m_tupleId; + bool m_autoIncrement; +}; + +inline +Plan_ddl_column::Plan_ddl_column(Plan_root* root, const BaseString& name) : + Plan_base(root), + Plan_column(Type_ddl, name), + m_type(0), + m_defaultValue(0), + m_nullable(true), + m_unSigned(false), + m_primaryKey(false), + m_tupleId(false), + m_autoIncrement(false) +{ +} + +inline void +Plan_ddl_column::setNotNull() +{ + m_nullable = false; +} + +inline void +Plan_ddl_column::setUnSigned() +{ + m_unSigned = true; +} + +inline void +Plan_ddl_column::setPrimaryKey() +{ + m_nullable = false; + m_primaryKey = true; +} + +inline bool +Plan_ddl_column::getPrimaryKey() const +{ + return m_primaryKey; +} + +inline void +Plan_ddl_column::setTupleId() +{ + m_nullable = false; + m_tupleId = true; +} + +inline bool +Plan_ddl_column::getTupleId() const +{ + return m_tupleId; +} + +inline void +Plan_ddl_column::setAutoIncrement() +{ + m_nullable = false; + m_autoIncrement = true; +} + +inline bool +Plan_ddl_column::getAutoIncrement() const +{ + return m_autoIncrement; +} + +// children + +inline void +Plan_ddl_column::setType(Plan_data_type* type) +{ + ctx_assert(type != 0); + m_type = type; +} + +inline void +Plan_ddl_column::setDefaultValue(Plan_expr* defaultValue) +{ + ctx_assert(defaultValue != 0); + m_defaultValue = defaultValue; +} + +inline Plan_expr* +Plan_ddl_column::getDefaultValue() const +{ + return m_defaultValue; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl_constr.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl_constr.cpp new file mode 100644 index 00000000000..78c23e38d97 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl_constr.cpp @@ -0,0 +1,51 @@ +/* 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/StmtArea.hpp> +#include "Code_ddl_constr.hpp" + +// Plan_ddl_constr + +Plan_ddl_constr::~Plan_ddl_constr() +{ +} + +Plan_base* +Plan_ddl_constr::analyze(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_ddlRow != 0); + m_ddlRow->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + return this; +} + +Exec_base* +Plan_ddl_constr::codegen(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(false); + return 0; +} + +void +Plan_ddl_constr::print(Ctx& ctx) +{ + ctx.print(" [ddl_constr"); + Plan_base* a[] = { m_ddlRow }; + printList(ctx, a, 1); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl_constr.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl_constr.hpp new file mode 100644 index 00000000000..ea7808b37cb --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl_constr.hpp @@ -0,0 +1,65 @@ +/* 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_Code_ddl_constr_hpp +#define ODBC_CODEGEN_Code_ddl_constr_hpp + +#include <common/common.hpp> +#include "Code_ddl_row.hpp" + +/** + * @class Plan_ddl_constr + * @brief Constraint in DDL statement + * + * Only unnamed primary key constraint exists. + */ +class Plan_ddl_constr : public Plan_base { +public: + Plan_ddl_constr(Plan_root* root); + virtual ~Plan_ddl_constr(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setRow(Plan_ddl_row* ddlRow); + Plan_ddl_row* getRow() const; +protected: + Plan_ddl_row* m_ddlRow; +}; + +inline +Plan_ddl_constr::Plan_ddl_constr(Plan_root* root) : + Plan_base(root) +{ +} + +// children + +inline void +Plan_ddl_constr::setRow(Plan_ddl_row* ddlRow) +{ + ctx_assert(ddlRow != 0); + m_ddlRow = ddlRow; +} + +inline Plan_ddl_row* +Plan_ddl_constr::getRow() const +{ + ctx_assert(m_ddlRow != 0); + return m_ddlRow; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl_row.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl_row.cpp new file mode 100644 index 00000000000..87589ebbaa0 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl_row.cpp @@ -0,0 +1,54 @@ +/* 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 "Code_ddl_row.hpp" +#include "Code_ddl_column.hpp" +#include "Code_ddl_constr.hpp" + +Plan_ddl_row::~Plan_ddl_row() +{ +} + +Plan_base* +Plan_ddl_row::analyze(Ctx& ctx, Ctl& ctl) +{ + // analyze the columns + for (unsigned i = 1, n = countColumn(); i <= n; i++) { + Plan_ddl_column* column = getColumn(i); + column->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + } + // node was not replaced + return this; +} + +Exec_base* +Plan_ddl_row::codegen(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(false); + return 0; +} + +void +Plan_ddl_row::print(Ctx& ctx) +{ + ctx.print(" [ddl_row"); + for (unsigned i = 1, n = countColumn(); i <= n; i++) { + Plan_base* a = m_columnList[i]; + printList(ctx, &a, 1); + } +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl_row.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl_row.hpp new file mode 100644 index 00000000000..ac3eded1b2e --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_ddl_row.hpp @@ -0,0 +1,72 @@ +/* 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_Code_ddl_row_hpp +#define ODBC_CODEGEN_Code_ddl_row_hpp + +#include <common/common.hpp> +#include "Code_base.hpp" +#include "Code_ddl_column.hpp" + +/** + * @class Plan_ddl_row + * @brief Row of columns in create statement + */ +class Plan_ddl_row : public Plan_base { +public: + Plan_ddl_row(Plan_root* root); + virtual ~Plan_ddl_row(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + unsigned countColumn() const; + void addColumn(Plan_ddl_column* column); + Plan_ddl_column* getColumn(unsigned i) const; +protected: + DdlColumnVector m_columnList; +}; + +inline +Plan_ddl_row::Plan_ddl_row(Plan_root* root) : + Plan_base(root), + m_columnList(1) +{ +} + +// children + +inline unsigned +Plan_ddl_row::countColumn() const +{ + return m_columnList.size() - 1; +} + +inline void +Plan_ddl_row::addColumn(Plan_ddl_column* column) +{ + ctx_assert(column != 0); + m_columnList.push_back(column); +} + +inline Plan_ddl_column* +Plan_ddl_row::getColumn(unsigned i) const +{ + ctx_assert(1 <= i && i <= countColumn() && m_columnList[i] != 0); + return m_columnList[i]; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_delete.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_delete.cpp new file mode 100644 index 00000000000..35b3daa1aca --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_delete.cpp @@ -0,0 +1,205 @@ +/* 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/StmtArea.hpp> +#include "Code_delete.hpp" +#include "Code_delete_lookup.hpp" +#include "Code_delete_index.hpp" +#include "Code_delete_scan.hpp" +#include "Code_query_filter.hpp" +#include "Code_query_lookup.hpp" +#include "Code_query_index.hpp" +#include "Code_query_scan.hpp" +#include "Code_query_range.hpp" +#include "Code_query_repeat.hpp" +#include "Code_table.hpp" +#include "Code_root.hpp" + +Plan_delete::~Plan_delete() +{ +} + +Plan_base* +Plan_delete::analyze(Ctx& ctx, Ctl& ctl) +{ + stmtArea().stmtInfo().setName(Stmt_name_delete); + // analyze the table + ctx_assert(m_table != 0); + m_table->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + // set name resolution scope + ctl.m_tableList.resize(1 + 1); // indexed from 1 + ctl.m_tableList[1] = m_table; + Plan_dml* stmt = 0; + if (m_pred != 0) { + // analyze the predicate + ctl.m_topand = true; + ctl.m_extra = false; + m_pred = static_cast<Plan_pred*>(m_pred->analyze(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(m_pred != 0); + // check for key match + Plan_table::Index* indexBest = 0; + for (unsigned i = 0; i <= m_table->indexCount(); i++) { + Plan_table::Index& index = m_table->m_indexList[i]; + TableSet tsDone; + m_table->resolveSet(ctx, index, tsDone); + if (! ctx.ok()) + return 0; + if (! index.m_keyFound) + continue; + // prefer smaller rank, less unused keys + int k; + (k = (indexBest == 0)) || + (k = (indexBest->m_rank - index.m_rank)) || + (k = (indexBest->m_keyCountUnused - index.m_keyCountUnused)); + if (k > 0) + indexBest = &index; + } + if (indexBest != 0) { + const bool exactKey = indexBest->m_rank <= 1 ? m_table->exactKey(ctx, indexBest) : false; + const bool direct = ! ctl.m_extra && exactKey; + ctx_log3(("delete direct=%d: extra=%d exact=%d", direct, ctl.m_extra, exactKey)); + if (indexBest->m_rank == 0) { + // primary key + Plan_delete_lookup* deleteLookup = new Plan_delete_lookup(m_root); + m_root->saveNode(deleteLookup); + deleteLookup->setTable(m_table); + if (direct) { + // key match with no extra conditions + Plan_query_repeat* queryRepeat = new Plan_query_repeat(m_root, 1); + m_root->saveNode(queryRepeat); + deleteLookup->setQuery(queryRepeat); + } else { + // key match with extra conditions + Plan_query_lookup* queryLookup = new Plan_query_lookup(m_root); + m_root->saveNode(queryLookup); + Plan_query_filter* queryFilter = new Plan_query_filter(m_root); + m_root->saveNode(queryFilter); + queryLookup->setTable(m_table); + queryFilter->setQuery(queryLookup); + queryFilter->setPred(m_pred); + queryFilter->m_topTable = m_table; + deleteLookup->setQuery(queryFilter); + } + stmt = deleteLookup; + } else if (indexBest->m_rank == 1) { + // hash index + Plan_delete_index* deleteIndex = new Plan_delete_index(m_root); + m_root->saveNode(deleteIndex); + deleteIndex->setTable(m_table, indexBest); + if (direct) { + // key match with no extra conditions + Plan_query_repeat* queryRepeat = new Plan_query_repeat(m_root, 1); + m_root->saveNode(queryRepeat); + deleteIndex->setQuery(queryRepeat); + } else { + // key match with extra conditions + Plan_query_index* queryIndex = new Plan_query_index(m_root); + m_root->saveNode(queryIndex); + Plan_query_filter* queryFilter = new Plan_query_filter(m_root); + m_root->saveNode(queryFilter); + queryIndex->setTable(m_table, indexBest); + queryFilter->setQuery(queryIndex); + queryFilter->setPred(m_pred); + queryFilter->m_topTable = m_table; + deleteIndex->setQuery(queryFilter); + } + stmt = deleteIndex; + } else if (indexBest->m_rank == 2) { + // ordered index + Plan_delete_scan* deleteScan = new Plan_delete_scan(m_root); + m_root->saveNode(deleteScan); + Plan_query_filter* queryFilter = new Plan_query_filter(m_root); + m_root->saveNode(queryFilter); + Plan_query_range* queryRange = new Plan_query_range(m_root); + m_root->saveNode(queryRange); + queryRange->setTable(m_table, indexBest); + queryRange->setExclusive(); + queryFilter->setQuery(queryRange); + queryFilter->setPred(m_pred); + queryFilter->m_topTable = m_table; + const TableSet& ts2 = m_pred->noInterp(); + ctx_assert(ts2.size() <= 1); + if (ts2.size() == 0) { + queryRange->setInterp(m_pred); + } + deleteScan->setQuery(queryFilter); + stmt = deleteScan; + } else { + ctx_assert(false); + } + } else { + // scan delete with filter + Plan_delete_scan* deleteScan = new Plan_delete_scan(m_root); + m_root->saveNode(deleteScan); + Plan_query_filter* queryFilter = new Plan_query_filter(m_root); + m_root->saveNode(queryFilter); + Plan_query_scan* queryScan = new Plan_query_scan(m_root); + m_root->saveNode(queryScan); + queryScan->setTable(m_table); + queryScan->setExclusive(); + queryFilter->setQuery(queryScan); + queryFilter->setPred(m_pred); + queryFilter->m_topTable = m_table; + // interpeter + const TableSet& ts2 = m_pred->noInterp(); + ctx_assert(ts2.size() <= 1); + if (ts2.size() == 0) { + queryScan->setInterp(m_pred); + } + deleteScan->setQuery(queryFilter); + stmt = deleteScan; + } + } else { + // scan delete without filter + Plan_delete_scan* deleteScan = new Plan_delete_scan(m_root); + m_root->saveNode(deleteScan); + Plan_query_scan* queryScan = new Plan_query_scan(m_root); + m_root->saveNode(queryScan); + queryScan->setTable(m_table); + queryScan->setExclusive(); + deleteScan->setQuery(queryScan); + stmt = deleteScan; + } + // set base for column position offsets + m_table->m_resOff = 1; + return stmt; +} + +void +Plan_delete::describe(Ctx& ctx) +{ + stmtArea().setFunction(ctx, "DELETE WHERE", SQL_DIAG_DELETE_WHERE); +} + +Exec_base* +Plan_delete::codegen(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(false); + return 0; +} + +void +Plan_delete::print(Ctx& ctx) +{ + ctx.print(" [delete"); + Plan_base* a[] = { m_table, m_pred }; + printList(ctx, a, 1); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_delete.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_delete.hpp new file mode 100644 index 00000000000..c7fa245497b --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_delete.hpp @@ -0,0 +1,69 @@ +/* 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_Code_delete_hpp +#define ODBC_CODEGEN_Code_delete_hpp + +#include <common/common.hpp> +#include "Code_base.hpp" +#include "Code_dml.hpp" +#include "Code_table.hpp" +#include "Code_query.hpp" +#include "Code_pred.hpp" + +/** + * @class Plan_delete + * @brief Delete in PlanTree + */ +class Plan_delete : public Plan_dml { +public: + Plan_delete(Plan_root* root); + virtual ~Plan_delete(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + void describe(Ctx& ctx); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setTable(Plan_table* table); + void setPred(Plan_pred* pred); +protected: + Plan_table* m_table; + Plan_pred* m_pred; +}; + +inline +Plan_delete::Plan_delete(Plan_root* root) : + Plan_dml(root), + m_table(0), + m_pred(0) +{ +} + +inline void +Plan_delete::setTable(Plan_table* table) +{ + ctx_assert(table != 0); + m_table = table; +} + +inline void +Plan_delete::setPred(Plan_pred* pred) +{ + ctx_assert(pred != 0); + m_pred = pred; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_delete_index.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_delete_index.cpp new file mode 100644 index 00000000000..8f2c3be2848 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_delete_index.cpp @@ -0,0 +1,164 @@ +/* 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/StmtArea.hpp> +#include <dictionary/DictTable.hpp> +#include "Code_expr.hpp" +#include "Code_delete_index.hpp" +#include "Code_table.hpp" +#include "Code_root.hpp" + +Plan_delete_index::~Plan_delete_index() +{ +} + +Plan_base* +Plan_delete_index::analyze(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_query != 0); + m_query->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + ctx_assert(m_table != 0); + m_table->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + return this; +} + +void +Plan_delete_index::describe(Ctx& ctx) +{ + stmtArea().setFunction(ctx, "DELETE WHERE", SQL_DIAG_DELETE_WHERE); +} + +Exec_base* +Plan_delete_index::codegen(Ctx& ctx, Ctl& ctl) +{ + // create code for the query + ctx_assert(m_query != 0); + Exec_query* execQuery = static_cast<Exec_query*>(m_query->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execQuery != 0); + // set up + ctx_assert(m_table != 0 && m_index != 0); + const BaseString& tableName = m_table->getName(); + ctx_assert(m_index->m_dictIndex != 0); + const DictIndex& dictIndex = *m_index->m_dictIndex; + const BaseString& indexName = dictIndex.getName(); + const unsigned keyCount = m_index->m_keyCount; + // create the code + Exec_delete_index::Code& code = *new Exec_delete_index::Code(keyCount); + code.m_tableName = strcpy(new char[tableName.length() + 1], tableName.c_str()); + code.m_indexName = strcpy(new char[indexName.length() + 1], indexName.c_str()); + // key attributes + code.m_keyId = new NdbAttrId[1 + keyCount]; + code.m_keyId[0] = (NdbAttrId)-1; + for (unsigned k = 1; k <= keyCount; k++) { + const DictColumn* keyColumn = dictIndex.getColumn(k); + const SqlType& sqlType = keyColumn->sqlType(); + SqlSpec sqlSpec(sqlType, SqlSpec::Physical); + code.m_keySpecs.setEntry(k, sqlSpec); + code.m_keyId[k] = k - 1; // index column order + } + // matching expressions + ctx_assert(m_index->m_keyFound); + const ExprVector& keyEq = m_index->m_keyEq; + ctx_assert(keyEq.size() == 1 + keyCount); + code.m_keyMatch = new Exec_expr* [1 + keyCount]; + code.m_keyMatch[0] = 0; + for (unsigned k = 1; k <= keyCount; k++) { + Plan_expr* expr = keyEq[k]; + Exec_expr* execExpr = static_cast<Exec_expr*>(expr->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execExpr != 0); + code.m_keyMatch[k] = execExpr; + } + // create the exec + Exec_delete_index* exec = new Exec_delete_index(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + exec->setCode(code); + exec->setQuery(execQuery); + return exec; +} + +void +Plan_delete_index::print(Ctx& ctx) +{ + ctx.print(" [delete_index"); + Plan_base* a[] = { m_query, m_table }; + printList(ctx, a, 2); + ctx.print("]"); +} + +// Exec_delete_index + +Exec_delete_index::Code::~Code() +{ + delete[] m_tableName; + delete[] m_keyId; + delete[] m_keyMatch; +} + +Exec_delete_index::Data::~Data() +{ +} + +Exec_delete_index::~Exec_delete_index() +{ +} + +void +Exec_delete_index::alloc(Ctx& ctx, Ctl& ctl) +{ + const Code& code = getCode(); + // allocate the subquery + ctx_assert(m_query != 0); + m_query->alloc(ctx, ctl); + if (! ctx.ok()) + return; + // allocate matching expressions + for (unsigned k = 1; k <= code.m_keyCount; k++) { + Exec_expr* expr = code.m_keyMatch[k]; + ctx_assert(expr != 0); + expr->alloc(ctx, ctl); + if (! ctx.ok()) + return; + } + // create data + Data& data = *new Data; + setData(data); +} + +void +Exec_delete_index::close(Ctx& ctx) +{ + ctx_assert(m_query != 0); + m_query->close(ctx); +} + +void +Exec_delete_index::print(Ctx& ctx) +{ + const Code& code = getCode(); + ctx.print(" [delete_index"); + Exec_base* a[] = { m_query }; + printList(ctx, a, 1); + printList(ctx, (Exec_base**)&code.m_keyMatch[1], code.m_keyCount); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_delete_index.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_delete_index.hpp new file mode 100644 index 00000000000..1aaaa18abcb --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_delete_index.hpp @@ -0,0 +1,156 @@ +/* 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_Code_delete_index_hpp +#define ODBC_CODEGEN_Code_delete_index_hpp + +#include <common/common.hpp> +#include "Code_dml.hpp" +#include "Code_query.hpp" +#include "Code_table.hpp" + +/** + * @class Plan_delete_index + * @brief Delete by primary key + */ +class Plan_delete_index : public Plan_dml { +public: + Plan_delete_index(Plan_root* root); + virtual ~Plan_delete_index(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + void describe(Ctx& ctx); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setQuery(Plan_query* query); + void setTable(Plan_table* table, Plan_table::Index* index); +protected: + Plan_query* m_query; + Plan_table* m_table; + Plan_table::Index* m_index; +}; + +inline +Plan_delete_index::Plan_delete_index(Plan_root* root) : + Plan_dml(root), + m_query(0), + m_table(0) +{ +} + +inline void +Plan_delete_index::setQuery(Plan_query* query) +{ + ctx_assert(query != 0); + m_query = query; +} + +inline void +Plan_delete_index::setTable(Plan_table* table, Plan_table::Index* index) +{ + ctx_assert(table != 0 && index != 0 && index == &table->m_indexList[index->m_pos] && index->m_pos != 0); + m_table = table; + m_index = index; +} + +/** + * @class Exec_delete_index + * @brief Delete by primary key + */ +class Exec_delete_index : public Exec_dml { +public: + class Code : public Exec_dml::Code { + public: + Code(unsigned keyCount); + virtual ~Code(); + protected: + friend class Plan_delete_index; + friend class Exec_delete_index; + const char* m_tableName; + const char* m_indexName; + unsigned m_keyCount; + SqlSpecs m_keySpecs; // key types + NdbAttrId* m_keyId; + Exec_expr** m_keyMatch; // XXX pointers for now + }; + class Data : public Exec_dml::Data { + public: + Data(); + virtual ~Data(); + protected: + friend class Exec_delete_index; + }; + Exec_delete_index(Exec_root* root); + virtual ~Exec_delete_index(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setQuery(Exec_query* query); +protected: + Exec_query* m_query; +}; + +inline +Exec_delete_index::Code::Code(unsigned keyCount) : + m_tableName(0), + m_indexName(0), + m_keyCount(keyCount), + m_keySpecs(keyCount), + m_keyId(0), + m_keyMatch(0) +{ +} + +inline +Exec_delete_index::Data::Data() +{ +} + +inline +Exec_delete_index::Exec_delete_index(Exec_root* root) : + Exec_dml(root), + m_query(0) +{ +} + +// children + +inline const Exec_delete_index::Code& +Exec_delete_index::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_delete_index::Data& +Exec_delete_index::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_delete_index::setQuery(Exec_query* query) +{ + ctx_assert(query != 0 && m_query == 0); + m_query = query; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_delete_lookup.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_delete_lookup.cpp new file mode 100644 index 00000000000..4a6dec64654 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_delete_lookup.cpp @@ -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 */ + +#include <common/StmtArea.hpp> +#include <dictionary/DictTable.hpp> +#include "Code_expr.hpp" +#include "Code_delete_lookup.hpp" +#include "Code_table.hpp" +#include "Code_root.hpp" + +Plan_delete_lookup::~Plan_delete_lookup() +{ +} + +Plan_base* +Plan_delete_lookup::analyze(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_query != 0); + m_query->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + ctx_assert(m_table != 0); + m_table->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + return this; +} + +void +Plan_delete_lookup::describe(Ctx& ctx) +{ + stmtArea().setFunction(ctx, "DELETE WHERE", SQL_DIAG_DELETE_WHERE); +} + +Exec_base* +Plan_delete_lookup::codegen(Ctx& ctx, Ctl& ctl) +{ + // create code for the query + ctx_assert(m_query != 0); + Exec_query* execQuery = static_cast<Exec_query*>(m_query->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execQuery != 0); + // set up + ctx_assert(m_table != 0); + const BaseString& tableName = m_table->getName(); + const DictTable& dictTable = m_table->dictTable(); + const unsigned keyCount = dictTable.keyCount(); + // create the code + Exec_delete_lookup::Code& code = *new Exec_delete_lookup::Code(keyCount); + code.m_tableName = strcpy(new char[tableName.length() + 1], tableName.c_str()); + // key attributes + code.m_keyId = new NdbAttrId[1 + keyCount]; + code.m_keyId[0] = (NdbAttrId)-1; + for (unsigned k = 1; k <= keyCount; k++) { + const DictColumn* keyColumn = dictTable.getKey(k); + const SqlType& sqlType = keyColumn->sqlType(); + SqlSpec sqlSpec(sqlType, SqlSpec::Physical); + code.m_keySpecs.setEntry(k, sqlSpec); + code.m_keyId[k] = keyColumn->getAttrId(); + } + // matching expressions + const Plan_table::Index& index = m_table->m_indexList[0]; + ctx_assert(index.m_keyFound); + const ExprVector& keyEq = index.m_keyEq; + ctx_assert(keyEq.size() == 1 + keyCount); + code.m_keyMatch = new Exec_expr* [1 + keyCount]; + code.m_keyMatch[0] = 0; + for (unsigned k = 1; k <= keyCount; k++) { + Plan_expr* expr = keyEq[k]; + Exec_expr* execExpr = static_cast<Exec_expr*>(expr->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execExpr != 0); + code.m_keyMatch[k] = execExpr; + } + // create the exec + Exec_delete_lookup* exec = new Exec_delete_lookup(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + exec->setCode(code); + exec->setQuery(execQuery); + return exec; +} + +void +Plan_delete_lookup::print(Ctx& ctx) +{ + ctx.print(" [delete_lookup"); + Plan_base* a[] = { m_query, m_table }; + printList(ctx, a, 2); + ctx.print("]"); +} + +// Exec_delete_lookup + +Exec_delete_lookup::Code::~Code() +{ + delete[] m_tableName; + delete[] m_keyId; + delete[] m_keyMatch; +} + +Exec_delete_lookup::Data::~Data() +{ +} + +Exec_delete_lookup::~Exec_delete_lookup() +{ +} + +void +Exec_delete_lookup::alloc(Ctx& ctx, Ctl& ctl) +{ + const Code& code = getCode(); + // allocate the subquery + ctx_assert(m_query != 0); + m_query->alloc(ctx, ctl); + if (! ctx.ok()) + return; + // allocate matching expressions + for (unsigned k = 1; k <= code.m_keyCount; k++) { + Exec_expr* expr = code.m_keyMatch[k]; + ctx_assert(expr != 0); + expr->alloc(ctx, ctl); + if (! ctx.ok()) + return; + } + // create data + Data& data = *new Data; + setData(data); +} + +void +Exec_delete_lookup::close(Ctx& ctx) +{ + ctx_assert(m_query != 0); + m_query->close(ctx); +} + +void +Exec_delete_lookup::print(Ctx& ctx) +{ + const Code& code = getCode(); + ctx.print(" [delete_lookup"); + Exec_base* a[] = { m_query }; + printList(ctx, a, 1); + printList(ctx, (Exec_base**)&code.m_keyMatch[1], code.m_keyCount); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_delete_lookup.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_delete_lookup.hpp new file mode 100644 index 00000000000..4138baefa4c --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_delete_lookup.hpp @@ -0,0 +1,152 @@ +/* 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_Code_delete_lookup_hpp +#define ODBC_CODEGEN_Code_delete_lookup_hpp + +#include <common/common.hpp> +#include "Code_dml.hpp" +#include "Code_query.hpp" +#include "Code_table.hpp" + +/** + * @class Plan_delete_lookup + * @brief Delete by primary key + */ +class Plan_delete_lookup : public Plan_dml { +public: + Plan_delete_lookup(Plan_root* root); + virtual ~Plan_delete_lookup(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + void describe(Ctx& ctx); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setQuery(Plan_query* query); + void setTable(Plan_table* table); +protected: + Plan_query* m_query; + Plan_table* m_table; +}; + +inline +Plan_delete_lookup::Plan_delete_lookup(Plan_root* root) : + Plan_dml(root), + m_query(0), + m_table(0) +{ +} + +inline void +Plan_delete_lookup::setQuery(Plan_query* query) +{ + ctx_assert(query != 0); + m_query = query; +} + +inline void +Plan_delete_lookup::setTable(Plan_table* table) +{ + ctx_assert(table != 0); + m_table = table; +} + +/** + * @class Exec_delete_lookup + * @brief Delete by primary key + */ +class Exec_delete_lookup : public Exec_dml { +public: + class Code : public Exec_dml::Code { + public: + Code(unsigned keyCount); + virtual ~Code(); + protected: + friend class Plan_delete_lookup; + friend class Exec_delete_lookup; + char* m_tableName; + unsigned m_keyCount; + SqlSpecs m_keySpecs; // key types + NdbAttrId* m_keyId; + Exec_expr** m_keyMatch; // XXX pointers for now + }; + class Data : public Exec_dml::Data { + public: + Data(); + virtual ~Data(); + protected: + friend class Exec_delete_lookup; + }; + Exec_delete_lookup(Exec_root* root); + virtual ~Exec_delete_lookup(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setQuery(Exec_query* query); +protected: + Exec_query* m_query; +}; + +inline +Exec_delete_lookup::Code::Code(unsigned keyCount) : + m_tableName(0), + m_keyCount(keyCount), + m_keySpecs(keyCount), + m_keyId(0), + m_keyMatch(0) +{ +} + +inline +Exec_delete_lookup::Data::Data() +{ +} + +inline +Exec_delete_lookup::Exec_delete_lookup(Exec_root* root) : + Exec_dml(root), + m_query(0) +{ +} + +// children + +inline const Exec_delete_lookup::Code& +Exec_delete_lookup::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_delete_lookup::Data& +Exec_delete_lookup::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_delete_lookup::setQuery(Exec_query* query) +{ + ctx_assert(query != 0 && m_query == 0); + m_query = query; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_delete_scan.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_delete_scan.cpp new file mode 100644 index 00000000000..fed7244a026 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_delete_scan.cpp @@ -0,0 +1,110 @@ +/* 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/StmtArea.hpp> +#include "Code_delete_scan.hpp" +#include "Code_root.hpp" + +Plan_delete_scan::~Plan_delete_scan() +{ +} + +Plan_base* +Plan_delete_scan::analyze(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_query != 0); + m_query->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + return this; +} + +void +Plan_delete_scan::describe(Ctx& ctx) +{ + stmtArea().setFunction(ctx, "DELETE WHERE", SQL_DIAG_DELETE_WHERE); +} + +Exec_base* +Plan_delete_scan::codegen(Ctx& ctx, Ctl& ctl) +{ + // create code for the subquery + ctx_assert(m_query != 0); + Exec_query* execQuery = static_cast<Exec_query*>(m_query->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execQuery != 0); + // create the code + Exec_delete_scan* exec = new Exec_delete_scan(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + Exec_delete_scan::Code& code = *new Exec_delete_scan::Code; + exec->setCode(code); + exec->setQuery(execQuery); + return exec; +} + +void +Plan_delete_scan::print(Ctx& ctx) +{ + ctx.print(" [delete_scan"); + Plan_base* a[] = { m_query }; + printList(ctx, a, 1); + ctx.print("]"); +} + +// Exec_delete_scan + +Exec_delete_scan::Code::~Code() +{ +} + +Exec_delete_scan::Data::~Data() +{ +} + +Exec_delete_scan::~Exec_delete_scan() +{ +} + +void +Exec_delete_scan::alloc(Ctx& ctx, Ctl& ctl) +{ + // allocate the subquery + ctx_assert(m_query != 0); + m_query->alloc(ctx, ctl); + if (! ctx.ok()) + return; + // create data + Data& data = *new Data; + setData(data); +} + +void +Exec_delete_scan::close(Ctx& ctx) +{ + ctx_assert(m_query != 0); + m_query->close(ctx); +} + +void +Exec_delete_scan::print(Ctx& ctx) +{ + ctx.print(" [delete_scan"); + Exec_base* a[] = { m_query }; + printList(ctx, a, 1); + ctx.print("]"); +} + diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_delete_scan.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_delete_scan.hpp new file mode 100644 index 00000000000..eb013a8257e --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_delete_scan.hpp @@ -0,0 +1,130 @@ +/* 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_Code_delete_scan_hpp +#define ODBC_CODEGEN_Code_delete_scan_hpp + +#include <common/common.hpp> +#include "Code_dml.hpp" +#include "Code_query.hpp" + +/** + * @class Plan_delete_scan + * @brief Scan delete + */ +class Plan_delete_scan : public Plan_dml { +public: + Plan_delete_scan(Plan_root* root); + virtual ~Plan_delete_scan(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + void describe(Ctx& ctx); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setQuery(Plan_query* query); +protected: + Plan_query* m_query; +}; + +inline +Plan_delete_scan::Plan_delete_scan(Plan_root* root) : + Plan_dml(root), + m_query(0) +{ +} + +inline void +Plan_delete_scan::setQuery(Plan_query* query) +{ + ctx_assert(query != 0); + m_query = query; +} + +/** + * @class Exec_delete_scan + * @brief Scan delete + */ +class Exec_delete_scan : public Exec_dml { +public: + class Code : public Exec_dml::Code { + public: + Code(); + virtual ~Code(); + protected: + friend class Exec_delete_scan; + }; + class Data : public Exec_dml::Data { + public: + Data(); + virtual ~Data(); + protected: + friend class Exec_delete_scan; + }; + Exec_delete_scan(Exec_root* root); + virtual ~Exec_delete_scan(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setQuery(Exec_query* query); +protected: + Exec_query* m_query; +}; + +inline +Exec_delete_scan::Code::Code() +{ +} + +inline +Exec_delete_scan::Data::Data() +{ +} + +inline +Exec_delete_scan::Exec_delete_scan(Exec_root* root) : + Exec_dml(root), + m_query(0) +{ +} + +// children + +inline const Exec_delete_scan::Code& +Exec_delete_scan::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_delete_scan::Data& +Exec_delete_scan::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_delete_scan::setQuery(Exec_query* query) +{ + ctx_assert(query != 0 && m_query == 0); + m_query = query; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_dml.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_dml.cpp new file mode 100644 index 00000000000..44fd4478646 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_dml.cpp @@ -0,0 +1,51 @@ +/* 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/StmtArea.hpp> +#include "Code_dml.hpp" + +// Plan_dml + +Plan_dml::~Plan_dml() +{ +} + +// Exec_dml + +Exec_dml::Code::~Code() +{ +} + +Exec_dml::Data::~Data() +{ +} + +Exec_dml::~Exec_dml() +{ +} + +void +Exec_dml::execute(Ctx& ctx, Ctl& ctl) +{ + execImpl(ctx, ctl); + if (m_topLevel) { + if (ctx.ok()) { + if (stmtArea().getRowCount() == 0) { + ctx.setCode(SQL_NO_DATA); + } + } + } +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_dml.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_dml.hpp new file mode 100644 index 00000000000..0618f583984 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_dml.hpp @@ -0,0 +1,67 @@ +/* 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_Code_dml_hpp +#define ODBC_CODEGEN_Code_dml_hpp + +#include <common/common.hpp> +#include <common/ResultArea.hpp> +#include "Code_stmt.hpp" + +/** + * @class Plan_dml + * @brief Base class for DML statements in PlanTree + */ +class Plan_dml : public Plan_stmt { +public: + Plan_dml(Plan_root* root); + virtual ~Plan_dml() = 0; +}; + +inline +Plan_dml::Plan_dml(Plan_root* root) : + Plan_stmt(root) +{ +} + +/** + * @class Exec_dml + * @brief Base class for DML statements in ExecTree + */ +class Exec_dml : public Exec_stmt { +public: + class Code : public Exec_stmt::Code { + public: + virtual ~Code() = 0; + }; + class Data : public Exec_stmt::Data, public ResultArea { + public: + virtual ~Data() = 0; + }; + Exec_dml(Exec_root* root); + virtual ~Exec_dml() = 0; + void execute(Ctx& ctx, Ctl& ctl); +protected: + virtual void execImpl(Ctx& ctx, Ctl& ctl) = 0; +}; + +inline +Exec_dml::Exec_dml(Exec_root* root) : + Exec_stmt(root) +{ +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_dml_column.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_dml_column.cpp new file mode 100644 index 00000000000..808e2ac8c4b --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_dml_column.cpp @@ -0,0 +1,47 @@ +/* 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/StmtArea.hpp> +#include "Code_dml_column.hpp" + +// Plan_dml_column + +Plan_dml_column::~Plan_dml_column() +{ +} + +Plan_base* +Plan_dml_column::analyze(Ctx& ctx, Ctl& ctl) +{ + analyzeColumn(ctx, ctl); + if (! ctx.ok()) + return 0; + return this; +} + +Exec_base* +Plan_dml_column::codegen(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(false); + return 0; +} + +void +Plan_dml_column::print(Ctx& ctx) +{ + ctx.print(" [dml_column %s]", getPrintName()); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_dml_column.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_dml_column.hpp new file mode 100644 index 00000000000..0fb33944a3a --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_dml_column.hpp @@ -0,0 +1,46 @@ +/* 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_Code_dml_column_hpp +#define ODBC_CODEGEN_Code_dml_column_hpp + +#include <common/common.hpp> +#include "Code_column.hpp" + +class DictColumn; +class Plan_table; + +/** + * @class Plan_dml_column + * @brief Column in query expression + */ +class Plan_dml_column : public Plan_base, public Plan_column { +public: + Plan_dml_column(Plan_root* root, const BaseString& name); + virtual ~Plan_dml_column(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); +}; + +inline +Plan_dml_column::Plan_dml_column(Plan_root* root, const BaseString& name) : + Plan_base(root), + Plan_column(Type_dml, name) +{ +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_dml_row.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_dml_row.cpp new file mode 100644 index 00000000000..ceb63a9f7b9 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_dml_row.cpp @@ -0,0 +1,56 @@ +/* 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 "Code_dml_row.hpp" +#include "Code_dml_column.hpp" + +Plan_dml_row::~Plan_dml_row() +{ +} + +Plan_base* +Plan_dml_row::analyze(Ctx& ctx, Ctl& ctl) +{ + unsigned size = getSize(); + // analyze the columns + for (unsigned i = 1; i <= size; i++) { + Plan_dml_column* column = getColumn(i); + column->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + } + // node was not replaced + return this; +} + +Exec_base* +Plan_dml_row::codegen(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(false); + return 0; +} + +void +Plan_dml_row::print(Ctx& ctx) +{ + unsigned size = getSize(); + ctx.print(" [dml_row"); + for (unsigned i = 1; i <= size; i++) { + Plan_base* a = m_columnList[i]; + a == 0 ? ctx.print(" -") : a->print(ctx); + } + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_dml_row.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_dml_row.hpp new file mode 100644 index 00000000000..6c7e46ba9af --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_dml_row.hpp @@ -0,0 +1,76 @@ +/* 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_Code_dml_row_hpp +#define ODBC_CODEGEN_Code_dml_row_hpp + +#include <vector> +#include <common/common.hpp> +#include <common/DataRow.hpp> +#include "Code_base.hpp" +#include "Code_dml_column.hpp" + +class Plan_dml_column; + +/** + * @class Plan_dml_row + * @brief Row of lvalue columns in insert or update + */ +class Plan_dml_row : public Plan_base { +public: + Plan_dml_row(Plan_root* root); + virtual ~Plan_dml_row(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + unsigned getSize() const; + void addColumn(Plan_dml_column* column); + Plan_dml_column* getColumn(unsigned i) const; +protected: + DmlColumnVector m_columnList; +}; + +inline +Plan_dml_row::Plan_dml_row(Plan_root* root) : + Plan_base(root), + m_columnList(1) +{ +} + +// children + +inline unsigned +Plan_dml_row::getSize() const +{ + return m_columnList.size() - 1; +} + +inline void +Plan_dml_row::addColumn(Plan_dml_column* column) +{ + ctx_assert(column != 0); + m_columnList.push_back(column); +} + +inline Plan_dml_column* +Plan_dml_row::getColumn(unsigned i) const +{ + ctx_assert(1 <= i && i <= m_columnList.size() && m_columnList[i] != 0); + return m_columnList[i]; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_drop_index.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_drop_index.cpp new file mode 100644 index 00000000000..b6bae88e270 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_drop_index.cpp @@ -0,0 +1,87 @@ +/* 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/StmtArea.hpp> +#include "Code_drop_index.hpp" +#include "Code_root.hpp" + +// Plan_drop_index + +Plan_drop_index::~Plan_drop_index() +{ +} + +Plan_base* +Plan_drop_index::analyze(Ctx& ctx, Ctl& ctl) +{ + stmtArea().stmtInfo().setName(Stmt_name_drop_index); + return this; +} + +void +Plan_drop_index::describe(Ctx& ctx) +{ + stmtArea().setFunction(ctx, "DROP INDEX", SQL_DIAG_DROP_INDEX); +} + +Exec_base* +Plan_drop_index::codegen(Ctx& ctx, Ctl& ctl) +{ + Exec_drop_index* exec = new Exec_drop_index(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + Exec_drop_index::Code& code = *new Exec_drop_index::Code(m_name, m_tableName); + exec->setCode(code); + return exec; +} + +void +Plan_drop_index::print(Ctx& ctx) +{ + ctx.print(" [drop_index %s]", m_name.c_str()); +} + +// Exec_drop_index + +Exec_drop_index::Code::~Code() +{ +} + +Exec_drop_index::Data::~Data() +{ +} + +Exec_drop_index::~Exec_drop_index() +{ +} + +void +Exec_drop_index::alloc(Ctx& ctx, Ctl& ctl) +{ + Data& data = *new Data; + setData(data); +} + +void +Exec_drop_index::close(Ctx& ctx) +{ +} + +void +Exec_drop_index::print(Ctx& ctx) +{ + const Code& code = getCode(); + ctx.print(" [drop_index %s]", code.m_indexName.c_str()); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_drop_index.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_drop_index.hpp new file mode 100644 index 00000000000..99891c9a52f --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_drop_index.hpp @@ -0,0 +1,136 @@ +/* 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_Code_drop_index_hpp +#define ODBC_CODEGEN_Code_drop_index_hpp + +#include <vector> +#include <NdbApi.hpp> +#include <common/common.hpp> +#include "Code_ddl.hpp" + +class DictTable; +class DictColumn; + +/** + * @class Plan_drop_index + * @brief Drop index in PlanTree + */ +class Plan_drop_index : public Plan_ddl { +public: + Plan_drop_index(Plan_root* root, const BaseString& name); + Plan_drop_index(Plan_root* root, const BaseString& name, const BaseString& tableName); + virtual ~Plan_drop_index(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void describe(Ctx & ctx); + void print(Ctx& ctx); + // attributes + const BaseString& getName() const; +protected: + BaseString m_name; + BaseString m_tableName; +}; + +inline +Plan_drop_index::Plan_drop_index(Plan_root* root, const BaseString& name) : + Plan_ddl(root), + m_name(name) +{ +} + +inline +Plan_drop_index::Plan_drop_index(Plan_root* root, const BaseString& name, const BaseString& tableName) : + Plan_ddl(root), + m_name(name), + m_tableName(tableName) +{ +} + +inline const BaseString& +Plan_drop_index::getName() const +{ + return m_name; +} + +/** + * @class Exec_drop_index + * @brief Drop index in ExecTree + */ +class Exec_drop_index : public Exec_ddl { +public: + class Code : public Exec_ddl::Code { + public: + Code(const BaseString& indexName, const BaseString& tableName); + virtual ~Code(); + protected: + friend class Exec_drop_index; + const BaseString m_indexName; + const BaseString m_tableName; + }; + class Data : public Exec_ddl::Data { + public: + Data(); + virtual ~Data(); + protected: + friend class Exec_drop_index; + }; + Exec_drop_index(Exec_root* root); + virtual ~Exec_drop_index(); + void alloc(Ctx& ctx, Ctl& ctl); + void execute(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; +}; + +inline +Exec_drop_index::Code::Code(const BaseString& indexName, const BaseString& tableName) : + m_indexName(indexName), + m_tableName(tableName) +{ +} + +inline +Exec_drop_index::Data::Data() +{ +} + +inline +Exec_drop_index::Exec_drop_index(Exec_root* root) : + Exec_ddl(root) +{ +} + +// children + +inline const Exec_drop_index::Code& +Exec_drop_index::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_drop_index::Data& +Exec_drop_index::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_drop_table.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_drop_table.cpp new file mode 100644 index 00000000000..f20bf9fdae0 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_drop_table.cpp @@ -0,0 +1,87 @@ +/* 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/StmtArea.hpp> +#include "Code_drop_table.hpp" +#include "Code_root.hpp" + +// Plan_drop_table + +Plan_drop_table::~Plan_drop_table() +{ +} + +Plan_base* +Plan_drop_table::analyze(Ctx& ctx, Ctl& ctl) +{ + stmtArea().stmtInfo().setName(Stmt_name_drop_table); + return this; +} + +void +Plan_drop_table::describe(Ctx& ctx) +{ + stmtArea().setFunction(ctx, "DROP TABLE", SQL_DIAG_DROP_TABLE); +} + +Exec_base* +Plan_drop_table::codegen(Ctx& ctx, Ctl& ctl) +{ + Exec_drop_table* exec = new Exec_drop_table(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + Exec_drop_table::Code& code = *new Exec_drop_table::Code(m_name); + exec->setCode(code); + return exec; +} + +void +Plan_drop_table::print(Ctx& ctx) +{ + ctx.print(" [drop_table %s]", m_name.c_str()); +} + +// Exec_drop_table + +Exec_drop_table::Code::~Code() +{ +} + +Exec_drop_table::Data::~Data() +{ +} + +Exec_drop_table::~Exec_drop_table() +{ +} + +void +Exec_drop_table::alloc(Ctx& ctx, Ctl& ctl) +{ + Data& data = *new Data; + setData(data); +} + +void +Exec_drop_table::close(Ctx& ctx) +{ +} + +void +Exec_drop_table::print(Ctx& ctx) +{ + const Code& code = getCode(); + ctx.print(" [drop_table %s]", code.m_tableName.c_str()); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_drop_table.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_drop_table.hpp new file mode 100644 index 00000000000..849a472ed94 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_drop_table.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_CODEGEN_Code_drop_table_hpp +#define ODBC_CODEGEN_Code_drop_table_hpp + +#include <vector> +#include <NdbApi.hpp> +#include <common/common.hpp> +#include "Code_ddl.hpp" + +class DictTable; +class DictColumn; + +/** + * @class Plan_drop_table + * @brief Drop table in PlanTree + */ +class Plan_drop_table : public Plan_ddl { +public: + Plan_drop_table(Plan_root* root, const BaseString& name); + virtual ~Plan_drop_table(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void describe(Ctx & ctx); + void print(Ctx& ctx); + // attributes + const BaseString& getName() const; +protected: + BaseString m_name; +}; + +inline +Plan_drop_table::Plan_drop_table(Plan_root* root, const BaseString& name) : + Plan_ddl(root), + m_name(name) +{ +} + +inline const BaseString& +Plan_drop_table::getName() const +{ + return m_name; +} + +/** + * @class Exec_drop_table + * @brief Drop table in ExecTree + */ +class Exec_drop_table : public Exec_ddl { +public: + class Code : public Exec_ddl::Code { + public: + Code(const BaseString& tableName); + virtual ~Code(); + protected: + friend class Exec_drop_table; + const BaseString m_tableName; + }; + class Data : public Exec_ddl::Data { + public: + Data(); + virtual ~Data(); + protected: + friend class Exec_drop_table; + }; + Exec_drop_table(Exec_root* root); + virtual ~Exec_drop_table(); + void alloc(Ctx& ctx, Ctl& ctl); + void execute(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; +}; + +inline +Exec_drop_table::Code::Code(const BaseString& tableName) : + m_tableName(tableName) +{ +} + +inline +Exec_drop_table::Data::Data() +{ +} + +inline +Exec_drop_table::Exec_drop_table(Exec_root* root) : + Exec_ddl(root) +{ +} + +// children + +inline const Exec_drop_table::Code& +Exec_drop_table::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_drop_table::Data& +Exec_drop_table::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_expr.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr.cpp new file mode 100644 index 00000000000..4afa75986a0 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr.cpp @@ -0,0 +1,79 @@ +/* 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 "Code_expr.hpp" +#include "Code_expr_row.hpp" + +// Plan_expr + +Plan_expr::~Plan_expr() +{ +} + +bool +Plan_expr::isEqual(const Plan_expr* expr) const +{ + return false; +} + +bool +Plan_expr::isAnyEqual(const Plan_expr_row* row) const +{ + ctx_assert(row != 0); + const unsigned size = row->getSize(); + for (unsigned i = 1; i <= size; i++) { + if (isEqual(row->getExpr(i))) + return true; + } + return false; +} + +bool +Plan_expr::isGroupBy(const Plan_expr_row* row) const +{ + return false; +} + +// Exec_expr + +Exec_expr::Code::~Code() +{ +} + +Exec_expr::Data::~Data() +{ +} + +Exec_expr::~Exec_expr() +{ +} + +SqlField& +Exec_expr::Data::groupField(const SqlType& sqlType, unsigned i, bool initFlag) +{ + if (m_groupField.size() == 0) { + m_groupField.resize(1); + } + if (initFlag) { + //unsigned i2 = m_groupField.size(); + //ctx_assert(i == i2); + const SqlSpec sqlSpec(sqlType, SqlSpec::Physical); + const SqlField sqlField(sqlSpec); + m_groupField.push_back(sqlField); + } + ctx_assert(i != 0 && i < m_groupField.size()); + return m_groupField[i]; +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_expr.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr.hpp new file mode 100644 index 00000000000..b6f07471b4d --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr.hpp @@ -0,0 +1,219 @@ +/* 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_Code_expr_hpp +#define ODBC_CODEGEN_Code_expr_hpp + +#include <common/common.hpp> +#include <common/DataField.hpp> +#include "Code_base.hpp" + +class Ctx; +class Plan_expr_row; +class Exec_expr; + +/** + * @class Plan_expr + * @brief Base class for expressions in PlanTree + */ +class Plan_expr : public Plan_base { +public: + // type is convenient since RTTI cannot be used + enum Type { + TypeUndefined = 0, + TypeColumn, + TypeConst, + TypeConv, + TypeFunc, + TypeOp, + TypeParam, + TypeValue + }; + Plan_expr(Plan_root* root, Type type); + virtual ~Plan_expr() = 0; + Type type() const; + const SqlType& sqlType() const; // data type set by analyze + const TableSet& tableSet() const; + const BaseString& getAlias() const; + bool isAggr() const; + bool isBound() const; + bool isAnyEqual(const Plan_expr_row* row) const; + virtual bool isEqual(const Plan_expr* expr) const; + virtual bool isGroupBy(const Plan_expr_row* row) const; +protected: + friend class Plan_expr_row; + friend class Plan_expr_op; + friend class Plan_expr_func; + friend class Plan_comp_op; + const Type m_type; + SqlType m_sqlType; // subclass must set + BaseString m_alias; // for row expression alias + TableSet m_tableSet; // depends on these tables + bool m_isAggr; // contains an aggregate expression + bool m_isBound; // only constants and aggregates + Exec_expr* m_exec; // XXX wrong move +}; + +inline +Plan_expr::Plan_expr(Plan_root* root, Type type) : + Plan_base(root), + m_type(type), + m_isAggr(false), + m_isBound(false), + m_exec(0) +{ +} + +inline Plan_expr::Type +Plan_expr::type() const +{ + return m_type; +} + +inline const SqlType& +Plan_expr::sqlType() const +{ + ctx_assert(m_sqlType.type() != SqlType::Undef); + return m_sqlType; +} + +inline const Plan_base::TableSet& +Plan_expr::tableSet() const +{ + return m_tableSet; +} + +inline const BaseString& +Plan_expr::getAlias() const +{ + return m_alias; +} + +inline bool +Plan_expr::isAggr() const +{ + return m_isAggr; +} + +inline bool +Plan_expr::isBound() const +{ + return m_isBound; +} + +/** + * @class Exec_expr + * @brief Base class for expressions in ExecTree + */ +class Exec_expr : public Exec_base { +public: + /** + * Exec_expr::Code includes reference to SqlSpec which + * specifies data type and access method. + */ + class Code : public Exec_base::Code { + public: + Code(const SqlSpec& sqlSpec); + virtual ~Code() = 0; + const SqlSpec& sqlSpec() const; + protected: + friend class Exec_expr; + const SqlSpec& m_sqlSpec; // subclass must contain + }; + /** + * Exec_expr::Data includes reference to SqlField which + * contains specification and data address. + */ + class Data : public Exec_base::Data { + public: + Data(const SqlField& sqlField); + virtual ~Data() = 0; + const SqlField& sqlField() const; + const SqlField& groupField(unsigned i) const; + protected: + friend class Exec_expr; + const SqlField& m_sqlField; // subclass must contain + // group-by data + typedef std::vector<SqlField> GroupField; + GroupField m_groupField; + SqlField& groupField(const SqlType& sqlType, unsigned i, bool initFlag); + }; + Exec_expr(Exec_root* root); + virtual ~Exec_expr() = 0; + /** + * Evaluate the expression. Must be implemented by all + * subclasses. Check ctx.ok() for errors. + */ + virtual void evaluate(Ctx& ctx, Ctl& ctl) = 0; + // children + const Code& getCode() const; + Data& getData() const; +}; + +inline +Exec_expr::Code::Code(const SqlSpec& sqlSpec) : + m_sqlSpec(sqlSpec) +{ +} + +inline const SqlSpec& +Exec_expr::Code::sqlSpec() const { + return m_sqlSpec; +} + +inline +Exec_expr::Data::Data(const SqlField& sqlField) : + m_sqlField(sqlField) +{ +} + +inline const SqlField& +Exec_expr::Data::sqlField() const +{ + return m_sqlField; +} + +inline const SqlField& +Exec_expr::Data::groupField(unsigned i) const +{ + ctx_assert(i != 0 && i < m_groupField.size()); + return m_groupField[i]; +} + +inline +Exec_expr::Exec_expr(Exec_root* root) : + Exec_base(root) +{ +} + +// children + +inline const Exec_expr::Code& +Exec_expr::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_expr::Data& +Exec_expr::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_column.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_column.cpp new file mode 100644 index 00000000000..17a9a502d4c --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_column.cpp @@ -0,0 +1,160 @@ +/* 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/StmtArea.hpp> +#include <dictionary/DictSchema.hpp> +#include <dictionary/DictColumn.hpp> +#include "Code_query.hpp" +#include "Code_table.hpp" +#include "Code_expr_column.hpp" +#include "Code_root.hpp" + +// Plan_expr_column + +Plan_expr_column::~Plan_expr_column() +{ +} + +Plan_base* +Plan_expr_column::analyze(Ctx& ctx, Ctl& ctl) +{ + m_exec = 0; + analyzeColumn(ctx, ctl); + if (! ctx.ok()) + return 0; + Plan_expr::m_sqlType = Plan_column::m_sqlType; + // depends on one table + m_tableSet.insert(m_resTable); + // not constant as set-value + ctl.m_const = false; + // set alias name + m_alias = m_name; + return this; +} + +Exec_base* +Plan_expr_column::codegen(Ctx& ctx, Ctl& ctl) +{ + if (m_exec != 0) + return m_exec; + // connect column to query column + const Exec_query* execQuery = ctl.m_execQuery; + ctx_assert(execQuery != 0); + const Exec_query::Code& codeQuery = execQuery->getCode(); + const SqlSpec sqlSpec(Plan_expr::m_sqlType, SqlSpec::Reference); + // offset in final output row + ctx_assert(m_resTable != 0 && m_resTable->m_resOff != 0 && m_resPos != 0); + unsigned resOff = m_resTable->m_resOff + (m_resPos - 1); + // create the code + Exec_expr_column* exec = new Exec_expr_column(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + Exec_expr_column::Code& code = *new Exec_expr_column::Code(sqlSpec, resOff); + exec->setCode(code); + m_exec = exec; + return exec; +} + +bool +Plan_expr_column::resolveEq(Ctx& ctx, Plan_expr* expr) +{ + ctx_assert(m_resTable != 0 && expr != 0); + return m_resTable->resolveEq(ctx, this, expr); +} + +void +Plan_expr_column::print(Ctx& ctx) +{ + ctx.print(" [expr_column %s]", getPrintName()); +} + +bool +Plan_expr_column::isEqual(const Plan_expr* expr) const +{ + ctx_assert(expr != 0); + if (expr->type() != Plan_expr::TypeColumn) + return false; + const Plan_expr_column* expr2 = static_cast<const Plan_expr_column*>(expr); + ctx_assert(m_resTable != 0 && expr2->m_resTable != 0); + if (m_resTable != expr2->m_resTable) + return false; + ctx_assert(m_dictColumn != 0 && expr2->m_dictColumn != 0); + if (m_dictColumn != expr2->m_dictColumn) + return false; + return true; +} + +bool +Plan_expr_column::isGroupBy(const Plan_expr_row* row) const +{ + if (isAnyEqual(row)) + return true; + return false; +} + +// Exec_expr_column + +Exec_expr_column::Code::~Code() +{ +} + +Exec_expr_column::Data::~Data() +{ +} + +Exec_expr_column::~Exec_expr_column() +{ +} + +void +Exec_expr_column::alloc(Ctx& ctx, Ctl& ctl) +{ + if (m_data != 0) + return; + const Code& code = getCode(); + // connect column to query column + ctx_assert(ctl.m_query != 0); + const SqlRow& sqlRow = ctl.m_query->getData().sqlRow(); + SqlField& sqlField = sqlRow.getEntry(code.m_resOff); + // create the data + Data& data = *new Data(sqlField); + setData(data); +} + +void +Exec_expr_column::evaluate(Ctx& ctx, Ctl& ctl) +{ + const Code& code = getCode(); + Data& data = getData(); + if (ctl.m_groupIndex != 0) { + SqlField& out = data.groupField(code.sqlSpec().sqlType(), ctl.m_groupIndex, ctl.m_groupInit); + data.sqlField().copy(ctx, out); + } +} + +void +Exec_expr_column::close(Ctx& ctx) +{ + Data& data = getData(); + data.m_groupField.clear(); +} + +void +Exec_expr_column::print(Ctx& ctx) +{ + const Code& code = getCode(); + ctx.print(" [column %d]", code.m_resOff); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_column.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_column.hpp new file mode 100644 index 00000000000..2ce7c441e45 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_column.hpp @@ -0,0 +1,120 @@ +/* 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_Code_expr_column_hpp +#define ODBC_CODEGEN_Code_expr_column_hpp + +#include <common/common.hpp> +#include "Code_column.hpp" +#include "Code_expr.hpp" + +class DictColumn; +class Plan_table; + +/** + * @class Plan_expr_column + * @brief Column in query expression + */ +class Plan_expr_column : public Plan_expr, public Plan_column { +public: + Plan_expr_column(Plan_root* root, const BaseString& name); + virtual ~Plan_expr_column(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + bool resolveEq(Ctx& ctx, Plan_expr* expr); + void print(Ctx& ctx); + bool isEqual(const Plan_expr* expr) const; + bool isGroupBy(const Plan_expr_row* row) const; +}; + +inline +Plan_expr_column::Plan_expr_column(Plan_root* root, const BaseString& name) : + Plan_expr(root, TypeColumn), + Plan_column(Type_expr, name) +{ +} + +/** + * @class Exec_expr_column + * @brief Column in query expression + */ +class Exec_expr_column : public Exec_expr { +public: + class Code : public Exec_expr::Code { + public: + Code(const SqlSpec& sqlSpec, unsigned resOff); + virtual ~Code(); + protected: + friend class Exec_expr_column; + SqlSpec m_sqlSpec; + unsigned m_resOff; + }; + class Data : public Exec_expr::Data { + public: + Data(SqlField& sqlField); + virtual ~Data(); + protected: + friend class Exec_expr_column; + // set reference to SqlField in query + }; + Exec_expr_column(Exec_root* root); + virtual ~Exec_expr_column(); + void alloc(Ctx& ctx, Ctl& ctl); + void evaluate(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; +}; + +inline +Exec_expr_column::Code::Code(const SqlSpec& sqlSpec, unsigned resOff) : + Exec_expr::Code(m_sqlSpec), + m_sqlSpec(sqlSpec), + m_resOff(resOff) +{ +} + +inline +Exec_expr_column::Data::Data(SqlField& sqlField) : + Exec_expr::Data(sqlField) +{ +} + +inline +Exec_expr_column::Exec_expr_column(Exec_root* root) : + Exec_expr(root) +{ +} + +// children + +inline const Exec_expr_column::Code& +Exec_expr_column::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_expr_column::Data& +Exec_expr_column::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_const.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_const.cpp new file mode 100644 index 00000000000..564d307a4f8 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_const.cpp @@ -0,0 +1,138 @@ +/* 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 "Code_expr_const.hpp" +#include "Code_root.hpp" + +// Plan_expr_const + +Plan_expr_const::~Plan_expr_const() +{ +} + +Plan_base* +Plan_expr_const::analyze(Ctx& ctx, Ctl& ctl) +{ + m_exec = 0; + // convert data type + m_lexType.convert(ctx, m_sqlType, m_string.length()); + if (! ctx.ok()) + return 0; + // depends on no tables + // set alias name + m_alias = m_string; + // node was not changed + return this; +} + +Exec_base* +Plan_expr_const::codegen(Ctx& ctx, Ctl& ctl) +{ + if (m_exec != 0) + return m_exec; + // convert data + SqlSpec sqlSpec(m_sqlType, SqlSpec::Physical); + SqlField sqlField(sqlSpec); + LexSpec lexSpec(m_lexType); + lexSpec.convert(ctx, m_string, sqlField); + if (! ctx.ok()) + return 0; + // create code + Exec_expr_const* exec = new Exec_expr_const(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + Exec_expr_const::Code& code = *new Exec_expr_const::Code(sqlField); + exec->setCode(code); + m_exec = exec; + return exec; +} + +void +Plan_expr_const::print(Ctx& ctx) +{ + ctx.print(" [const %s]", m_string.c_str()); +} + +bool +Plan_expr_const::isEqual(const Plan_expr* expr) const +{ + ctx_assert(expr != 0); + if (expr->type() != Plan_expr::TypeConst) + return false; + const Plan_expr_const* expr2 = static_cast<const Plan_expr_const*>(expr); + if (strcmp(m_string.c_str(), expr2->m_string.c_str()) != 0) + return false; + return true; +} + +bool +Plan_expr_const::isGroupBy(const Plan_expr_row* row) const +{ + return true; +} + +// Exec_expr_const + +Exec_expr_const::Code::~Code() +{ +} + +Exec_expr_const::Data::~Data() +{ +} + +Exec_expr_const::~Exec_expr_const() +{ +} + +void +Exec_expr_const::alloc(Ctx& ctx, Ctl& ctl) +{ + if (m_data != 0) + return; + // copy the value for const correctness reasons + SqlField sqlField(getCode().m_sqlField); + Data& data = *new Data(sqlField); + setData(data); +} + +void +Exec_expr_const::evaluate(Ctx& ctx, Ctl& ctl) +{ + const Code& code = getCode(); + Data& data = getData(); + if (ctl.m_groupIndex != 0) { + SqlField& out = data.groupField(code.sqlSpec().sqlType(), ctl.m_groupIndex, ctl.m_groupInit); + data.sqlField().copy(ctx, out); + } +} + +void +Exec_expr_const::close(Ctx& ctx) +{ + Data& data = getData(); + data.m_groupField.clear(); +} + +void +Exec_expr_const::print(Ctx& ctx) +{ + const Code& code = getCode(); + ctx.print(" ["); + char buf[500]; + code.m_sqlField.print(buf, sizeof(buf)); + ctx.print("%s", buf); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_const.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_const.hpp new file mode 100644 index 00000000000..2e26c637a23 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_const.hpp @@ -0,0 +1,120 @@ +/* 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_Code_expr_const_hpp +#define ODBC_CODEGEN_Code_expr_const_hpp + +#include <common/common.hpp> +#include <common/DataField.hpp> +#include "Code_expr.hpp" + +/** + * @class Plan_expr_const + * @brief Constant expression value in PlanTree + */ +class Plan_expr_const : public Plan_expr { +public: + Plan_expr_const(Plan_root* root, LexType lexType, const char* value); + virtual ~Plan_expr_const(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + bool isEqual(const Plan_expr* expr) const; + bool isGroupBy(const Plan_expr_row* row) const; +protected: + // lexical type and token set by the parser + LexType m_lexType; + BaseString m_string; +}; + +inline +Plan_expr_const::Plan_expr_const(Plan_root* root, LexType lexType, const char* value) : + Plan_expr(root, TypeConst), + m_lexType(lexType), + m_string(value) +{ +} + +/** + * @class Exec_expr_const + * @brief Constant expression value in ExecTree + */ +class Exec_expr_const : public Exec_expr { +public: + class Code : public Exec_expr::Code { + public: + Code(const SqlField& sqlField); + virtual ~Code(); + protected: + friend class Exec_expr_const; + const SqlField m_sqlField; + }; + class Data : public Exec_expr::Data { + public: + Data(SqlField& sqlField); + virtual ~Data(); + protected: + friend class Exec_expr_const; + SqlField m_sqlField; + }; + Exec_expr_const(Exec_root* root); + virtual ~Exec_expr_const(); + void alloc(Ctx& ctx, Ctl& ctl); + void evaluate(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; +}; + +inline +Exec_expr_const::Code::Code(const SqlField& sqlField) : + Exec_expr::Code(m_sqlField.sqlSpec()), + m_sqlField(sqlField) +{ +} + +inline +Exec_expr_const::Data::Data(SqlField& sqlField) : + Exec_expr::Data(m_sqlField), + m_sqlField(sqlField) +{ +} + +inline +Exec_expr_const::Exec_expr_const(Exec_root* root) : + Exec_expr(root) +{ +} + +// children + +inline const Exec_expr_const::Code& +Exec_expr_const::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_expr_const::Data& +Exec_expr_const::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_conv.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_conv.cpp new file mode 100644 index 00000000000..bc89482fedc --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_conv.cpp @@ -0,0 +1,273 @@ +/* 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 "Code_expr.hpp" +#include "Code_expr_conv.hpp" +#include "Code_root.hpp" + +// Plan_expr_conv + +Plan_expr_conv::~Plan_expr_conv() +{ +} + +Plan_base* +Plan_expr_conv::analyze(Ctx& ctx, Ctl& ctl) +{ + m_exec = 0; + const SqlType& t1 = sqlType(); + ctx_assert(m_expr != 0); + m_expr->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + const SqlType& t2 = m_expr->sqlType(); + if (t2.type() == SqlType::Unbound) { + return m_expr; + } + if (t1.equal(t2)) { + return m_expr; + } + // XXX move to runtime or make table-driven + bool ok = false; + if (t2.type() == SqlType::Null) { + ok = true; + } else if (t1.type() == SqlType::Char) { + if (t2.type() == SqlType::Char) { + ok = true; + } else if (t2.type() == SqlType::Varchar) { + ok = true; + } else if (t2.type() == SqlType::Binary) { + ok = true; + } else if (t2.type() == SqlType::Varbinary) { + ok = true; + } + } else if (t1.type() == SqlType::Varchar) { + if (t2.type() == SqlType::Char) { + ok = true; + } else if (t2.type() == SqlType::Varchar) { + ok = true; + } else if (t2.type() == SqlType::Binary) { + ok = true; + } else if (t2.type() == SqlType::Varbinary) { + ok = true; + } + } else if (t1.type() == SqlType::Binary) { + if (t2.type() == SqlType::Char) { + ok = true; + } else if (t2.type() == SqlType::Varchar) { + ok = true; + } else if (t2.type() == SqlType::Binary) { + ok = true; + } else if (t2.type() == SqlType::Varbinary) { + ok = true; + } + } else if (t1.type() == SqlType::Varbinary) { + if (t2.type() == SqlType::Char) { + ok = true; + } else if (t2.type() == SqlType::Varchar) { + ok = true; + } else if (t2.type() == SqlType::Binary) { + ok = true; + } else if (t2.type() == SqlType::Varbinary) { + ok = true; + } + } else if (t1.type() == SqlType::Smallint) { + if (t2.type() == SqlType::Smallint) { + ok = true; + } else if (t2.type() == SqlType::Integer) { + ok = true; + } else if (t2.type() == SqlType::Bigint) { + ok = true; + } else if (t2.type() == SqlType::Real) { + ok = true; + } else if (t2.type() == SqlType::Double) { + ok = true; + } + } else if (t1.type() == SqlType::Integer) { + if (t2.type() == SqlType::Smallint) { + ok = true; + } else if (t2.type() == SqlType::Integer) { + ok = true; + } else if (t2.type() == SqlType::Bigint) { + ok = true; + } else if (t2.type() == SqlType::Real) { + ok = true; + } else if (t2.type() == SqlType::Double) { + ok = true; + } + } else if (t1.type() == SqlType::Bigint) { + if (t2.type() == SqlType::Smallint) { + ok = true; + } else if (t2.type() == SqlType::Integer) { + ok = true; + } else if (t2.type() == SqlType::Bigint) { + ok = true; + } else if (t2.type() == SqlType::Real) { + ok = true; + } else if (t2.type() == SqlType::Double) { + ok = true; + } + } else if (t1.type() == SqlType::Real) { + if (t2.type() == SqlType::Smallint) { + ok = true; + } else if (t2.type() == SqlType::Integer) { + ok = true; + } else if (t2.type() == SqlType::Bigint) { + ok = true; + } else if (t2.type() == SqlType::Real) { + ok = true; + } else if (t2.type() == SqlType::Double) { + ok = true; + } + } else if (t1.type() == SqlType::Double) { + if (t2.type() == SqlType::Smallint) { + ok = true; + } else if (t2.type() == SqlType::Integer) { + ok = true; + } else if (t2.type() == SqlType::Bigint) { + ok = true; + } else if (t2.type() == SqlType::Real) { + ok = true; + } else if (t2.type() == SqlType::Double) { + ok = true; + } + } else if (t1.type() == SqlType::Datetime) { + if (t2.type() == SqlType::Datetime) { + ok = true; + } + } + if (! ok) { + char b1[40], b2[40]; + t1.print(b1, sizeof(b1)); + t2.print(b2, sizeof(b2)); + ctx.pushStatus(Error::Gen, "cannot convert %s to %s", b2, b1); + return 0; + } + // depend on same tables + const TableSet& ts = m_expr->tableSet(); + m_tableSet.insert(ts.begin(), ts.end()); + // set alias + m_alias = m_expr->getAlias(); + return this; +} + +Exec_base* +Plan_expr_conv::codegen(Ctx& ctx, Ctl& ctl) +{ + if (m_exec != 0) + return m_exec; + Exec_expr_conv* exec = new Exec_expr_conv(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + // create code for subexpression + ctx_assert(m_expr != 0); + Exec_expr* execExpr = static_cast<Exec_expr*>(m_expr->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + exec->setExpr(execExpr); + // create the code + SqlSpec sqlSpec(sqlType(), SqlSpec::Physical); + Exec_expr_conv::Code& code = *new Exec_expr_conv::Code(sqlSpec); + exec->setCode(code); + m_exec = exec; + return exec; +} + +void +Plan_expr_conv::print(Ctx& ctx) +{ + ctx.print(" [expr_conv "); + char buf[100]; + m_sqlType.print(buf, sizeof(buf)); + ctx.print("%s", buf); + Plan_base* a[] = { m_expr }; + printList(ctx, a, 1); + ctx.print("]"); +} + +bool +Plan_expr_conv::isEqual(const Plan_expr* expr) const +{ + ctx_assert(expr != 0); + if (expr->type() != Plan_expr::TypeConv) + return false; + const Plan_expr_conv* expr2 = static_cast<const Plan_expr_conv*>(expr); + if (! m_sqlType.equal(expr2->m_sqlType)) + return false; + ctx_assert(m_expr != 0 && expr2->m_expr != 0); + if (! m_expr->isEqual(expr2->m_expr)) + return false; + return true; +} + +bool +Plan_expr_conv::isGroupBy(const Plan_expr_row* row) const +{ + if (isAnyEqual(row)) + return true; + ctx_assert(m_expr != 0); + if (m_expr->isGroupBy(row)) + return true; + return false; +} + +// Code_expr_conv + +Exec_expr_conv::Code::~Code() +{ +} + +Exec_expr_conv::Data::~Data() +{ +} + +Exec_expr_conv::~Exec_expr_conv() +{ +} + +void +Exec_expr_conv::alloc(Ctx& ctx, Ctl& ctl) +{ + if (m_data != 0) + return; + const Code& code = getCode(); + // allocate subexpression + ctx_assert(m_expr != 0); + m_expr->alloc(ctx, ctl); + if (! ctx.ok()) + return; + SqlField sqlField(code.m_sqlSpec); + Data& data = *new Data(sqlField); + setData(data); +} + +void +Exec_expr_conv::close(Ctx& ctx) +{ + ctx_assert(m_expr != 0); + m_expr->close(ctx); + Data& data = getData(); + data.m_groupField.clear(); +} + +void +Exec_expr_conv::print(Ctx& ctx) +{ + const Code& code = getCode(); + ctx.print(" [expr_conv"); + Exec_base* a[] = { m_expr }; + printList(ctx, a, sizeof(a)/sizeof(a[0])); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_conv.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_conv.hpp new file mode 100644 index 00000000000..3294960c7b3 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_conv.hpp @@ -0,0 +1,141 @@ +/* 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_Code_expr_conv_hpp +#define ODBC_CODEGEN_Code_expr_conv_hpp + +#include <common/common.hpp> +#include <common/DataField.hpp> +#include "Code_expr.hpp" + +/** + * @class Plan_expr_conv + * @brief Data type conversion in PlanTree + * + * Inserted to convert value to another compatible type. + */ +class Plan_expr_conv : public Plan_expr { +public: + Plan_expr_conv(Plan_root* root, const SqlType& sqlType); + virtual ~Plan_expr_conv(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + bool isEqual(const Plan_expr* expr) const; + bool isGroupBy(const Plan_expr_row* row) const; + // children + void setExpr(Plan_expr* expr); +protected: + Plan_expr* m_expr; +}; + +inline +Plan_expr_conv::Plan_expr_conv(Plan_root* root, const SqlType& sqlType) : + Plan_expr(root, TypeConv), + m_expr(0) +{ + ctx_assert(sqlType.type() != SqlType::Undef); + m_sqlType = sqlType; +} + +inline void +Plan_expr_conv::setExpr(Plan_expr* expr) +{ + ctx_assert(expr != 0); + m_expr = expr; +} + +/** + * @class Exec_expr_conv + * @brief Data type conversion in ExecTree + */ +class Exec_expr_conv : public Exec_expr { +public: + class Code : public Exec_expr::Code { + public: + Code(const SqlSpec& spec); + virtual ~Code(); + protected: + friend class Exec_expr_conv; + const SqlSpec m_sqlSpec; + }; + class Data : public Exec_expr::Data { + public: + Data(const SqlField& sqlField); + virtual ~Data(); + protected: + friend class Exec_expr_conv; + SqlField m_sqlField; + }; + Exec_expr_conv(Exec_root* root); + virtual ~Exec_expr_conv(); + void alloc(Ctx& ctx, Ctl& ctl); + void evaluate(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setExpr(Exec_expr* expr); +protected: + Exec_expr* m_expr; +}; + +inline +Exec_expr_conv::Code::Code(const SqlSpec& sqlSpec) : + Exec_expr::Code(m_sqlSpec), + m_sqlSpec(sqlSpec) +{ +} + +inline +Exec_expr_conv::Data::Data(const SqlField& sqlField) : + Exec_expr::Data(m_sqlField), + m_sqlField(sqlField) +{ +} + +inline +Exec_expr_conv::Exec_expr_conv(Exec_root* root) : + Exec_expr(root), + m_expr(0) +{ +} + +// children + +inline const Exec_expr_conv::Code& +Exec_expr_conv::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_expr_conv::Data& +Exec_expr_conv::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_expr_conv::setExpr(Exec_expr* expr) +{ + ctx_assert(m_expr == 0 && expr != 0); + m_expr = expr; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_func.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_func.cpp new file mode 100644 index 00000000000..96b461a72d9 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_func.cpp @@ -0,0 +1,401 @@ +/* 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 "Code_expr.hpp" +#include "Code_expr_func.hpp" +#include "Code_expr_conv.hpp" +#include "Code_root.hpp" +#include "PortDefs.h" + + +// Expr_func + +static const struct { const char* alias; const char* name; } +expr_func_alias[] = { + { "SUBSTRING", "SUBSTR" }, + { 0, 0 } +}; + +static const Expr_func +expr_func[] = { + Expr_func(Expr_func::Substr, "SUBSTR", false ), + Expr_func(Expr_func::Left, "LEFT", false ), + Expr_func(Expr_func::Right, "RIGHT", false ), + Expr_func(Expr_func::Count, "COUNT", true ), + Expr_func(Expr_func::Max, "MAX", true ), + Expr_func(Expr_func::Min, "MIN", true ), + Expr_func(Expr_func::Sum, "SUM", true ), + Expr_func(Expr_func::Avg, "AVG", true ), + Expr_func(Expr_func::Rownum, "ROWNUM", false ), + Expr_func(Expr_func::Sysdate, "SYSDATE", false ), + Expr_func(Expr_func::Undef, 0, false ) +}; + +const Expr_func& +Expr_func::find(const char* name) +{ + for (unsigned i = 0; expr_func_alias[i].alias != 0; i++) { + if (strcasecmp(expr_func_alias[i].alias, name) == 0) { + name = expr_func_alias[i].name; + break; + } + } + const Expr_func* p; + for (p = expr_func; p->m_name != 0; p++) { + if (strcasecmp(p->m_name, name) == 0) + break; + } + return *p; +} + +// Plan_expr_func + +Plan_expr_func::~Plan_expr_func() +{ + delete[] m_conv; + m_conv = 0; +} + +Plan_base* +Plan_expr_func::analyze(Ctx& ctx, Ctl& ctl) +{ + m_exec = 0; + ctx_assert(m_narg == 0 || m_args != 0); + // aggregate check + if (m_func.m_aggr) { + if (! ctl.m_aggrok) { + ctx.pushStatus(Error::Gen, "%s: invalid use of aggregate function", m_func.m_name); + return 0; + } + if (ctl.m_aggrin) { + // XXX actually possible with group-by but too hard + ctx.pushStatus(Error::Gen, "%s: nested aggregate function", m_func.m_name); + return 0; + } + ctl.m_aggrin = true; + m_isAggr = true; + m_isBound = true; + } + // analyze argument expressions + if (m_func.m_code != Expr_func::Rownum) + m_isBound = true; + for (unsigned i = 1; i <= m_narg; i++) { + Plan_expr* expr = m_args->getExpr(i); + expr = static_cast<Plan_expr*>(expr->analyze(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(expr != 0); + if (expr->m_isAggr) + m_isAggr = true; + if (! m_func.m_aggr && ! expr->m_isBound) + m_isBound = false; + } + if (m_func.m_aggr) + ctl.m_aggrin = false; + // find result type and conversion types + SqlType res; + const Expr_func::Code fc = m_func.m_code; + const char* const invalidArgCount = "%s: argument count %u is invalid"; + const char* const invalidArgType = "%s: argument %u has invalid type"; + if (fc == Expr_func::Substr || fc == Expr_func::Left || fc == Expr_func::Right) { + if ((m_narg != (unsigned)2) && (m_narg != (unsigned)(fc == Expr_func::Substr ? 3 : 2))) { + ctx.pushStatus(Error::Gen, invalidArgCount, m_func.m_name, m_narg); + return 0; + } + const SqlType& t1 = m_args->getExpr(1)->sqlType(); + switch (t1.type()) { + case SqlType::Char: + { + // XXX convert to varchar for now to get length right + SqlType tx(SqlType::Varchar, t1.length()); + res = m_conv[1] = tx; + } + break; + case SqlType::Varchar: + case SqlType::Unbound: + res = m_conv[1] = t1; + break; + default: + ctx.pushStatus(Error::Gen, invalidArgType, m_func.m_name, 1); + return 0; + } + for (unsigned i = 2; i <= m_narg; i++) { + const SqlType& t2 = m_args->getExpr(i)->sqlType(); + switch (t2.type()) { + case SqlType::Smallint: + case SqlType::Integer: + case SqlType::Bigint: + case SqlType::Unbound: + m_conv[i] = t2; + break; + default: + ctx.pushStatus(Error::Gen, invalidArgType, m_func.m_name, i); + return 0; + } + } + } else if (fc == Expr_func::Count) { + ctx_assert(m_args != 0); + if (m_args->getAsterisk()) { + ctx_assert(m_narg == 0); + } else { + if (m_narg != 1) { + ctx.pushStatus(Error::Gen, invalidArgCount, m_func.m_name, m_narg); + return 0; + } + m_conv[1] = m_args->getExpr(1)->sqlType(); + } + res.setType(ctx, SqlType::Bigint); + } else if (fc == Expr_func::Min || fc == Expr_func::Max) { + if (m_narg != 1) { + ctx.pushStatus(Error::Gen, invalidArgCount, m_func.m_name, m_narg); + return 0; + } + const SqlType& t1 = m_args->getExpr(1)->sqlType(); + res = m_conv[1] = t1; + } else if (fc == Expr_func::Sum) { + if (m_narg != 1) { + ctx.pushStatus(Error::Gen, invalidArgCount, m_func.m_name, m_narg); + return 0; + } + const SqlType& t1 = m_args->getExpr(1)->sqlType(); + switch (t1.type()) { + case SqlType::Smallint: + case SqlType::Integer: + case SqlType::Bigint: + res.setType(ctx, SqlType::Bigint); + m_conv[1] = res; + break; + case SqlType::Real: + case SqlType::Double: + res.setType(ctx, SqlType::Double); + m_conv[1] = res; + break; + case SqlType::Unbound: + res = m_conv[1] = t1; + break; + default: + ctx.pushStatus(Error::Gen, invalidArgType, m_func.m_name, 1); + return 0; + } + } else if (fc == Expr_func::Avg) { + if (m_narg != 1) { + ctx.pushStatus(Error::Gen, invalidArgCount, m_func.m_name, m_narg); + return 0; + } + const SqlType& t1 = m_args->getExpr(1)->sqlType(); + switch (t1.type()) { + case SqlType::Smallint: + case SqlType::Integer: + case SqlType::Bigint: + case SqlType::Real: + case SqlType::Double: + res.setType(ctx, SqlType::Double); + m_conv[1] = res; + break; + case SqlType::Unbound: + res = m_conv[1] = t1; + break; + default: + ctx.pushStatus(Error::Gen, invalidArgType, m_func.m_name, 1); + return 0; + } + } else if (fc == Expr_func::Rownum) { + ctx_assert(m_narg == 0 && m_args == 0); + res.setType(ctx, SqlType::Bigint); + } else if (fc == Expr_func::Sysdate) { + ctx_assert(m_narg == 0 && m_args == 0); + res.setType(ctx, SqlType::Datetime); + } else { + ctx_assert(false); + } + // insert required conversions + for (unsigned i = 1; i <= m_narg; i++) { + if (m_conv[i].type() == SqlType::Unbound) { + // parameter type not yet bound + continue; + } + Plan_expr_conv* exprConv = new Plan_expr_conv(m_root, m_conv[i]); + m_root->saveNode(exprConv); + exprConv->setExpr(m_args->getExpr(i)); + Plan_expr* expr = static_cast<Plan_expr*>(exprConv->analyze(ctx, ctl)); + if (! ctx.ok()) + return 0; + m_args->setExpr(i, expr); + } + // set result type + m_sqlType = res; + // set table dependencies + for (unsigned i = 1; i <= m_narg; i++) { + const TableSet& ts = m_args->getExpr(i)->tableSet(); + m_tableSet.insert(ts.begin(), ts.end()); + } + // set alias name + m_alias.assign(m_func.m_name); + if (m_narg == 0) { + if (fc == Expr_func::Count) + m_alias.append("(*)"); + } else { + m_alias.append("("); + for (unsigned i = 1; i <= m_narg; i++) { + if (i > 1) + m_alias.append(","); + m_alias.append(m_args->getExpr(i)->getAlias()); + } + m_alias.append(")"); + } + return this; +} + +Exec_base* +Plan_expr_func::codegen(Ctx& ctx, Ctl& ctl) +{ + if (m_exec != 0) + return m_exec; + Exec_expr_func* exec = new Exec_expr_func(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + SqlSpec sqlSpec(sqlType(), SqlSpec::Physical); + Exec_expr_func::Code& code = *new Exec_expr_func::Code(m_func, sqlSpec); + exec->setCode(code); + code.m_narg = m_narg; + code.m_args = new Exec_expr* [1 + m_narg]; + for (unsigned i = 0; i <= m_narg; i++) + code.m_args[i] = 0; + // create code for arguments + for (unsigned i = 1; i <= m_narg; i++) { + Plan_expr* expr = m_args->getExpr(i); + ctx_assert(expr != 0); + Exec_expr* execExpr = static_cast<Exec_expr*>(expr->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execExpr != 0); + code.m_args[i] = execExpr; + } + m_exec = exec; + return exec; +} + +void +Plan_expr_func::print(Ctx& ctx) +{ + ctx.print(" [%s", m_func.m_name); + Plan_base* a[] = { m_args }; + printList(ctx, a, sizeof(a)/sizeof(a[1])); + ctx.print("]"); +} + +bool +Plan_expr_func::isEqual(const Plan_expr* expr) const +{ + ctx_assert(expr != 0); + if (expr->type() != Plan_expr::TypeFunc) + return false; + const Plan_expr_func* expr2 = static_cast<const Plan_expr_func*>(expr); + if (m_func.m_code != expr2->m_func.m_code) + return false; + if (m_narg != expr2->m_narg) + return false; + ctx_assert(m_args != 0 && expr2->m_args != 0); + for (unsigned i = 1; i <= m_narg; i++) { + if (! m_args->getExpr(i)->isEqual(expr2->m_args->getExpr(i))) + return false; + } + return true; +} + +bool +Plan_expr_func::isGroupBy(const Plan_expr_row* row) const +{ + if (m_func.m_aggr) + return true; + switch (m_func.m_code) { + case Expr_func::Substr: + case Expr_func::Left: + case Expr_func::Right: + ctx_assert(m_narg >= 1); + if (m_args->getExpr(1)->isGroupBy(row)) + return true; + break; + case Expr_func::Sysdate: + return true; + default: + break; + } + if (isAnyEqual(row)) + return true; + return false; +} + +// Exec_expr_func + +Exec_expr_func::Code::~Code() +{ + delete[] m_args; + m_args = 0; +} + +Exec_expr_func::Data::~Data() +{ +} + +Exec_expr_func::~Exec_expr_func() +{ +} + +void +Exec_expr_func::alloc(Ctx& ctx, Ctl& ctl) +{ + if (m_data != 0) + return; + const Code& code = getCode(); + // allocate arguments + for (unsigned i = 1; i <= code.m_narg; i++) { + ctx_assert(code.m_args != 0 && code.m_args[i] != 0); + code.m_args[i]->alloc(ctx, ctl); + if (! ctx.ok()) + return; + } + SqlField sqlField(code.m_sqlSpec); + Data& data = *new Data(sqlField); + setData(data); + ctx_assert(ctl.m_groupIndex == 0); + init(ctx, ctl); +} + +void +Exec_expr_func::close(Ctx& ctx) +{ + const Code& code = getCode(); + Data& data = getData(); + for (unsigned i = 1; i <= code.m_narg; i++) { + ctx_assert(code.m_args != 0 && code.m_args[i] != 0); + code.m_args[i]->close(ctx); + } + data.m_groupField.clear(); + Ctl ctl(0); + init(ctx, ctl); +} + +void +Exec_expr_func::print(Ctx& ctx) +{ + const Code& code = getCode(); + ctx.print(" [%s", code.m_func.m_name); + for (unsigned i = 1; i <= code.m_narg; i++) { + Exec_base* a[] = { code.m_args[i] }; + printList(ctx, a, sizeof(a)/sizeof(a[0])); + } + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_func.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_func.hpp new file mode 100644 index 00000000000..856d7529875 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_func.hpp @@ -0,0 +1,193 @@ +/* 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_Code_expr_func_hpp +#define ODBC_CODEGEN_Code_expr_func_hpp + +#include <common/common.hpp> +#include <common/DataField.hpp> +#include "Code_expr.hpp" +#include "Code_expr_row.hpp" + +/** + * @class Expr_func + * @brief Specifies a function + */ +struct Expr_func { + enum Code { + Undef = 0, + Substr, + Left, + Right, + Count, + Max, + Min, + Sum, + Avg, + Rownum, + Sysdate + }; + Expr_func(Code code, const char* name, bool aggr); + Code m_code; + const char* m_name; + bool m_aggr; + static const Expr_func& find(const char* name); +}; + +inline +Expr_func::Expr_func(Code code, const char* name, bool aggr) : + m_code(code), + m_name(name), + m_aggr(aggr) +{ +} + +/** + * @class Plan_expr_func + * @brief Function node in an expression in PlanTree + */ +class Plan_expr_func : public Plan_expr { +public: + Plan_expr_func(Plan_root* root, const Expr_func& func); + virtual ~Plan_expr_func(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + bool isEqual(const Plan_expr* expr) const; + bool isGroupBy(const Plan_expr_row* row) const; + // children + void setArgs(Plan_expr_row* args); +protected: + const Expr_func& m_func; + Plan_expr_row* m_args; + unsigned m_narg; + SqlType* m_conv; // temp work area +}; + +inline +Plan_expr_func::Plan_expr_func(Plan_root* root, const Expr_func& func) : + Plan_expr(root, TypeFunc), + m_func(func), + m_args(0), + m_narg(0), + m_conv(0) +{ +} + +inline void +Plan_expr_func::setArgs(Plan_expr_row* args) +{ + if (args == 0) { + m_args = 0; + m_narg = 0; + } else { + m_args = args; + m_narg = m_args->getSize(); + delete[] m_conv; + m_conv = new SqlType[1 + m_narg]; + } +} + +/** + * @class Exec_expr_func + * @brief Function node in an expression in ExecTree + */ +class Exec_expr_func : public Exec_expr { +public: + class Code : public Exec_expr::Code { + public: + Code(const Expr_func& func, const SqlSpec& spec); + virtual ~Code(); + protected: + friend class Plan_expr_func; + friend class Exec_expr_func; + const Expr_func& m_func; + const SqlSpec m_sqlSpec; + unsigned m_narg; + Exec_expr** m_args; // XXX pointers for now + }; + class Data : public Exec_expr::Data { + public: + Data(const SqlField& sqlField); + virtual ~Data(); + protected: + friend class Exec_expr_func; + SqlField m_sqlField; + struct Acc { // accumulators etc + SqlBigint m_count; // current row count + union { + SqlBigint m_bigint; + SqlDouble m_double; + SqlDatetime m_sysdate; + }; + }; + // group-by extra accumulators (default in entry 0) + typedef std::vector<Acc> GroupAcc; + GroupAcc m_groupAcc; + }; + Exec_expr_func(Exec_root* root); + virtual ~Exec_expr_func(); + void alloc(Ctx& ctx, Ctl& ctl); + void evaluate(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; +protected: + void init(Ctx &ctx, Ctl& ctl); // initialize values +}; + +inline +Exec_expr_func::Code::Code(const Expr_func& func, const SqlSpec& sqlSpec) : + Exec_expr::Code(m_sqlSpec), + m_func(func), + m_sqlSpec(sqlSpec), + m_args(0) +{ +} + +inline +Exec_expr_func::Data::Data(const SqlField& sqlField) : + Exec_expr::Data(m_sqlField), + m_sqlField(sqlField), + m_groupAcc(1) +{ +} + +inline +Exec_expr_func::Exec_expr_func(Exec_root* root) : + Exec_expr(root) +{ +} + +// children + +inline const Exec_expr_func::Code& +Exec_expr_func::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_expr_func::Data& +Exec_expr_func::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_op.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_op.cpp new file mode 100644 index 00000000000..7e8314c1741 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_op.cpp @@ -0,0 +1,424 @@ +/* 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 "Code_expr.hpp" +#include "Code_expr_op.hpp" +#include "Code_expr_conv.hpp" +#include "Code_root.hpp" + +// Expr_op + +const char* +Expr_op::name() const +{ + switch (m_opcode) { + case Add: + return "+"; + case Subtract: + return "-"; + case Multiply: + return "*"; + case Divide: + return "/"; + case Plus: + return "+"; + case Minus: + return "-"; + } + ctx_assert(false); + return ""; +} + +unsigned +Expr_op::arity() const +{ + switch (m_opcode) { + case Add: + case Subtract: + case Multiply: + case Divide: + return 2; + case Plus: + case Minus: + return 1; + } + ctx_assert(false); + return 0; +} + +// Plan_expr_op + +Plan_expr_op::~Plan_expr_op() +{ +} + +Plan_base* +Plan_expr_op::analyze(Ctx& ctx, Ctl& ctl) +{ + m_exec = 0; + unsigned arity = m_op.arity(); + // analyze operands + m_isAggr = false; + m_isBound = true; + for (unsigned i = 1; i <= arity; i++) { + ctx_assert(m_expr[i] != 0); + m_expr[i]->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + if (m_expr[i]->m_isAggr) + m_isAggr = true; + if (! m_expr[i]->m_isBound) + m_isBound = false; + } + // find result type and conversion types (currently same) + SqlType res; + SqlType con[1 + 2]; + if (arity == 1) { + const SqlType& t1 = m_expr[1]->sqlType(); + switch (t1.type()) { + case SqlType::Char: + case SqlType::Varchar: + break; + case SqlType::Smallint: + case SqlType::Integer: + case SqlType::Bigint: + res.setType(ctx, SqlType::Bigint); + con[1] = res; + break; + case SqlType::Real: + case SqlType::Double: + res.setType(ctx, SqlType::Double); + con[1] = res; + break; + case SqlType::Null: + res.setType(ctx, SqlType::Null); + con[1] = res; + break; + case SqlType::Unbound: + res.setType(ctx, SqlType::Unbound); + con[1] = res; + default: + break; + } + if (con[1].type() == SqlType::Undef) { + char b1[40]; + t1.print(b1, sizeof(b1)); + ctx.pushStatus(Error::Gen, "type mismatch in operation: %s %s", m_op.name(), b1); + return 0; + } + } else if (arity == 2) { + const SqlType& t1 = m_expr[1]->sqlType(); + const SqlType& t2 = m_expr[2]->sqlType(); + switch (t1.type()) { + case SqlType::Char: // handle char types as in oracle + switch (t2.type()) { + case SqlType::Char: + res.setType(ctx, SqlType::Char, t1.length() + t2.length()); + con[1] = t1; + con[2] = t2; + break; + case SqlType::Varchar: + res.setType(ctx, SqlType::Varchar, t1.length() + t2.length()); + con[1] = t1; + con[2] = t2; + break; + case SqlType::Null: + res.setType(ctx, SqlType::Varchar, t1.length()); + con[1] = t1; + con[2] = t2; + break; + case SqlType::Unbound: + res.setType(ctx, SqlType::Unbound); + con[1] = con[2] = res; + break; + default: + break; + } + break; + case SqlType::Varchar: + switch (t2.type()) { + case SqlType::Char: + res.setType(ctx, SqlType::Varchar, t1.length() + t2.length()); + con[1] = t1; + con[2] = t2; + break; + case SqlType::Varchar: + res.setType(ctx, SqlType::Varchar, t1.length() + t2.length()); + con[1] = t1; + con[2] = t2; + break; + case SqlType::Null: + res.setType(ctx, SqlType::Varchar, t1.length()); + con[1] = t1; + con[2] = t2; + break; + case SqlType::Unbound: + res.setType(ctx, SqlType::Unbound); + con[1] = con[2] = res; + break; + default: + break; + } + break; + case SqlType::Smallint: + case SqlType::Integer: + case SqlType::Bigint: + switch (t2.type()) { + case SqlType::Smallint: + case SqlType::Integer: + case SqlType::Bigint: + res.setType(ctx, SqlType::Bigint); + con[1] = con[2] = res; + if (t1.unSigned() || t2.unSigned()) { + con[1].unSigned(true); + con[2].unSigned(true); + } + break; + case SqlType::Real: + case SqlType::Double: + res.setType(ctx, SqlType::Double); + con[1] = con[2] = res; + break; + case SqlType::Null: + res.setType(ctx, SqlType::Null); + con[1] = con[2] = res; + break; + case SqlType::Unbound: + res.setType(ctx, SqlType::Unbound); + con[1] = con[2] = res; + break; + default: + break; + } + break; + case SqlType::Real: + case SqlType::Double: + switch (t2.type()) { + case SqlType::Smallint: + case SqlType::Integer: + case SqlType::Bigint: + case SqlType::Real: + case SqlType::Double: + res.setType(ctx, SqlType::Double); + con[1] = con[2] = res; + break; + case SqlType::Null: + res.setType(ctx, SqlType::Null); + con[1] = con[2] = res; + break; + case SqlType::Unbound: + res.setType(ctx, SqlType::Unbound); + con[1] = con[2] = res; + break; + default: + break; + } + break; + case SqlType::Null: + switch (t2.type()) { + case SqlType::Char: + case SqlType::Varchar: + res.setType(ctx, SqlType::Varchar, t2.length()); + con[1] = con[2] = res; + break; + case SqlType::Unbound: + res.setType(ctx, SqlType::Unbound); + con[1] = con[2] = res; + break; + default: + res.setType(ctx, SqlType::Null); + con[1] = con[2] = res; + break; + } + break; + case SqlType::Unbound: + res.setType(ctx, SqlType::Unbound); + con[1] = con[2] = res; + break; + default: + break; + } + if (con[1].type() == SqlType::Undef || con[2].type() == SqlType::Undef) { + char b1[40], b2[40]; + t1.print(b1, sizeof(b1)); + t2.print(b2, sizeof(b2)); + ctx.pushStatus(Error::Gen, "type mismatch in operation: %s %s %s", b1, m_op.name(), b2); + return 0; + } + } else { + ctx_assert(false); + return 0; + } + if (! ctx.ok()) + return 0; + // insert required conversions + for (unsigned i = 1; i <= arity; i++) { + if (con[i].type() == SqlType::Undef) { + ctx.pushStatus(Error::Gen, "mismatched types in operation"); + return 0; + } + if (con[i].type() == SqlType::Unbound) { + // parameter type not yet bound + continue; + } + Plan_expr_conv* exprConv = new Plan_expr_conv(m_root, con[i]); + m_root->saveNode(exprConv); + exprConv->setExpr(m_expr[i]); + m_expr[i] = static_cast<Plan_expr*>(exprConv->analyze(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(m_expr[i] != 0); + } + // set result type + m_sqlType = res; + // table dependencies are union from operands + for (unsigned i = 1; i <= arity; i++) { + const TableSet& ts = m_expr[i]->tableSet(); + m_tableSet.insert(ts.begin(), ts.end()); + } + // set alias name XXX misses operator precedence + if (arity == 1) { + m_alias.assign(m_op.name()); + m_alias.append(m_expr[1]->m_alias); + } else if (arity == 2) { + m_alias.assign(m_expr[1]->m_alias); + m_alias.append(m_op.name()); + m_alias.append(m_expr[2]->m_alias); + } + return this; +} + +Exec_base* +Plan_expr_op::codegen(Ctx& ctx, Ctl& ctl) +{ + if (m_exec != 0) + return m_exec; + unsigned arity = m_op.arity(); + Exec_expr_op* exec = new Exec_expr_op(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + // create code for operands + for (unsigned i = 1; i <= arity; i++) { + ctx_assert(m_expr[i] != 0); + Exec_expr* execExpr = static_cast<Exec_expr*>(m_expr[i]->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execExpr != 0); + exec->setExpr(i, execExpr); + } + // create the code + SqlSpec sqlSpec(sqlType(), SqlSpec::Physical); + Exec_expr_op::Code& code = *new Exec_expr_op::Code(m_op, sqlSpec); + exec->setCode(code); + m_exec = exec; + return exec; +} + +void +Plan_expr_op::print(Ctx& ctx) +{ + ctx.print(" [%s", m_op.name()); + Plan_base* a[] = { m_expr[1], m_expr[2] }; + printList(ctx, a, m_op.arity()); + ctx.print("]"); +} + +bool +Plan_expr_op::isEqual(const Plan_expr* expr) const +{ + ctx_assert(expr != 0); + if (expr->type() != Plan_expr::TypeOp) + return false; + const Plan_expr_op* expr2 = static_cast<const Plan_expr_op*>(expr); + if (m_op.m_opcode != expr2->m_op.m_opcode) + return false; + const unsigned arity = m_op.arity(); + for (unsigned i = 1; i <= arity; i++) { + ctx_assert(m_expr[i] != 0); + if (! m_expr[i]->isEqual(expr2->m_expr[i])) + return false; + } + return true; +} + +bool +Plan_expr_op::isGroupBy(const Plan_expr_row* row) const +{ + if (isAnyEqual(row)) + return true; + const unsigned arity = m_op.arity(); + for (unsigned i = 1; i <= arity; i++) { + ctx_assert(m_expr[i] != 0); + if (! m_expr[i]->isGroupBy(row)) + return false; + } + return true; +} + +// Code_expr_op + +Exec_expr_op::Code::~Code() +{ +} + +Exec_expr_op::Data::~Data() +{ +} + +Exec_expr_op::~Exec_expr_op() +{ +} + +void +Exec_expr_op::alloc(Ctx& ctx, Ctl& ctl) +{ + if (m_data != 0) + return; + const Code& code = getCode(); + // allocate subexpressions + unsigned arity = code.m_op.arity(); + for (unsigned i = 1; i <= arity; i++) { + ctx_assert(m_expr[i] != 0); + m_expr[i]->alloc(ctx, ctl); + if (! ctx.ok()) + return; + } + SqlField sqlField(code.m_sqlSpec); + Data& data = *new Data(sqlField); + setData(data); +} + +void +Exec_expr_op::close(Ctx& ctx) +{ + const Code& code = getCode(); + unsigned arity = code.m_op.arity(); + for (unsigned i = 1; i <= arity; i++) { + ctx_assert(m_expr[i] != 0); + m_expr[i]->close(ctx); + } + Data& data = getData(); + data.m_groupField.clear(); +} + +void +Exec_expr_op::print(Ctx& ctx) +{ + const Code& code = getCode(); + ctx.print(" [%s", code.m_op.name()); + Exec_base* a[] = { m_expr[1], m_expr[2] }; + printList(ctx, a, code.m_op.arity()); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_op.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_op.hpp new file mode 100644 index 00000000000..f9686cad151 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_op.hpp @@ -0,0 +1,166 @@ +/* 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_Code_expr_op_hpp +#define ODBC_CODEGEN_Code_expr_op_hpp + +#include <common/common.hpp> +#include <common/DataField.hpp> +#include "Code_expr.hpp" + +/** + * @class Expr_op + * @brief Arithmetic and string operators + */ +struct Expr_op { + enum Opcode { + Add = 1, // binary + Subtract, + Multiply, + Divide, + Plus, // unary + Minus + }; + Expr_op(Opcode opcode); + const char* name() const; + unsigned arity() const; + Opcode m_opcode; +}; + +inline +Expr_op::Expr_op(Opcode opcode) : + m_opcode(opcode) +{ +} + +/** + * @class Plan_expr_op + * @brief Operator node in an expression in PlanTree + */ +class Plan_expr_op : public Plan_expr { +public: + Plan_expr_op(Plan_root* root, Expr_op op); + virtual ~Plan_expr_op(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + bool isEqual(const Plan_expr* expr) const; + bool isGroupBy(const Plan_expr_row* row) const; + // children + void setExpr(unsigned i, Plan_expr* expr); +protected: + Expr_op m_op; + Plan_expr* m_expr[1 + 2]; +}; + +inline +Plan_expr_op::Plan_expr_op(Plan_root* root, Expr_op op) : + Plan_expr(root, TypeOp), + m_op(op) +{ + m_expr[0] = m_expr[1] = m_expr[2] = 0; +} + +inline void +Plan_expr_op::setExpr(unsigned i, Plan_expr* expr) +{ + ctx_assert(1 <= i && i <= 2 && expr != 0); + m_expr[i] = expr; +} + +/** + * @class Exec_expr_op + * @brief Operator node in an expression in ExecTree + */ +class Exec_expr_op : public Exec_expr { +public: + class Code : public Exec_expr::Code { + public: + Code(Expr_op op, const SqlSpec& spec); + virtual ~Code(); + protected: + friend class Exec_expr_op; + Expr_op m_op; + const SqlSpec m_sqlSpec; + }; + class Data : public Exec_expr::Data { + public: + Data(const SqlField& sqlField); + virtual ~Data(); + protected: + friend class Exec_expr_op; + SqlField m_sqlField; + }; + Exec_expr_op(Exec_root* root); + virtual ~Exec_expr_op(); + void alloc(Ctx& ctx, Ctl& ctl); + void evaluate(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setExpr(unsigned i, Exec_expr* expr); +protected: + Exec_expr* m_expr[1 + 2]; +}; + +inline +Exec_expr_op::Code::Code(Expr_op op, const SqlSpec& sqlSpec) : + Exec_expr::Code(m_sqlSpec), + m_op(op), + m_sqlSpec(sqlSpec) +{ +} + +inline +Exec_expr_op::Data::Data(const SqlField& sqlField) : + Exec_expr::Data(m_sqlField), + m_sqlField(sqlField) +{ +} + +inline +Exec_expr_op::Exec_expr_op(Exec_root* root) : + Exec_expr(root) +{ + m_expr[0] = m_expr[1] = m_expr[2] = 0; +} + +// children + +inline const Exec_expr_op::Code& +Exec_expr_op::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_expr_op::Data& +Exec_expr_op::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_expr_op::setExpr(unsigned i, Exec_expr* expr) +{ + ctx_assert(1 <= i && i <= 2 && m_expr[i] == 0); + m_expr[i] = expr; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_param.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_param.cpp new file mode 100644 index 00000000000..93892cae5e6 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_param.cpp @@ -0,0 +1,279 @@ +/* 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 "Code_expr_param.hpp" +#include "Code_root.hpp" + +// Plan_expr_param + +Plan_expr_param::~Plan_expr_param() +{ +} + +Plan_base* +Plan_expr_param::analyze(Ctx& ctx, Ctl& ctl) +{ + m_exec = 0; + ctx_assert(m_paramNumber != 0); + ctx_assert(m_paramNumber < m_root->m_paramList.size()); + m_root->m_paramList[m_paramNumber] = this; + m_sqlType.setType(ctx, SqlType::Unbound); + // check if type is bound now + DescArea& ipd = descArea(Desc_usage_IPD); + if (m_paramNumber <= ipd.getCount()) { + DescRec& rec = ipd.getRecord(m_paramNumber); + OdbcData descData; + rec.getField(ctx, SQL_DESC_TYPE, descData); + if (descData.type() != OdbcData::Undef) { + SQLSMALLINT desc_TYPE = descData.smallint(); + // XXX wrong but fixes sun.jdbc.odbc + if (desc_TYPE == SQL_CHAR) + desc_TYPE = SQL_VARCHAR; + if (desc_TYPE == SQL_CHAR) { + rec.getField(ctx, SQL_DESC_LENGTH, descData); + if (descData.type() != OdbcData::Undef) { + unsigned desc_LENGTH = descData.uinteger(); + m_sqlType.setType(ctx, SqlType::Char, desc_LENGTH); + } + } else if (desc_TYPE == SQL_VARCHAR) { + rec.getField(ctx, SQL_DESC_LENGTH, descData); + if (descData.type() != OdbcData::Undef) { + unsigned desc_LENGTH = descData.uinteger(); + m_sqlType.setType(ctx, SqlType::Varchar, desc_LENGTH); + } + } else if (desc_TYPE == SQL_BINARY) { + rec.getField(ctx, SQL_DESC_LENGTH, descData); + if (descData.type() != OdbcData::Undef) { + unsigned desc_LENGTH = descData.uinteger(); + m_sqlType.setType(ctx, SqlType::Binary, desc_LENGTH); + } + } else if (desc_TYPE == SQL_VARBINARY) { + rec.getField(ctx, SQL_DESC_LENGTH, descData); + if (descData.type() != OdbcData::Undef) { + unsigned desc_LENGTH = descData.uinteger(); + m_sqlType.setType(ctx, SqlType::Varbinary, desc_LENGTH); + } else { + // XXX BLOB hack + unsigned desc_LENGTH = FAKE_BLOB_SIZE; + m_sqlType.setType(ctx, SqlType::Varbinary, desc_LENGTH); + } + } else if (desc_TYPE == SQL_SMALLINT) { + m_sqlType.setType(ctx, SqlType::Smallint); + } else if (desc_TYPE == SQL_INTEGER) { + m_sqlType.setType(ctx, SqlType::Integer); + } else if (desc_TYPE == SQL_BIGINT) { + m_sqlType.setType(ctx, SqlType::Bigint); + } else if (desc_TYPE == SQL_REAL) { + m_sqlType.setType(ctx, SqlType::Real); + } else if (desc_TYPE == SQL_DOUBLE) { + m_sqlType.setType(ctx, SqlType::Double); + } else if (desc_TYPE == SQL_TYPE_TIMESTAMP) { + m_sqlType.setType(ctx, SqlType::Datetime); + // XXX BLOB hack + } else if (desc_TYPE == SQL_LONGVARBINARY) { + m_sqlType.setType(ctx, SqlType::Varbinary, (unsigned)FAKE_BLOB_SIZE); + } else { + ctx.pushStatus(Error::Gen, "parameter %u unsupported SQL type %d", m_paramNumber, (int)desc_TYPE); + return 0; + } + char buf[100]; + m_sqlType.print(buf, sizeof(buf)); + ctx_log2(("parameter %u SQL type bound to %s", m_paramNumber, buf)); + } + } + return this; +} + +void +Plan_expr_param::describe(Ctx& ctx) +{ + DescArea& ipd = descArea(Desc_usage_IPD); + if (ipd.getCount() < m_paramNumber) + ipd.setCount(ctx, m_paramNumber); + // XXX describe if possible + DescRec& rec = ipd.getRecord(m_paramNumber); +} + +Exec_base* +Plan_expr_param::codegen(Ctx& ctx, Ctl& ctl) +{ + if (m_exec != 0) + return m_exec; + SqlSpec sqlSpec(m_sqlType, SqlSpec::Physical); + // create code + Exec_expr_param* exec = new Exec_expr_param(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + ctx_assert(m_paramNumber != 0); + Exec_expr_param::Code& code = *new Exec_expr_param::Code(sqlSpec, m_paramNumber); + exec->setCode(code); + m_exec = exec; + return exec; +} + +void +Plan_expr_param::print(Ctx& ctx) +{ + ctx.print(" [param %u]", m_paramNumber); +} + +bool +Plan_expr_param::isEqual(const Plan_expr* expr) const +{ + ctx_assert(expr != 0); + if (expr->type() != Plan_expr::TypeParam) + return false; + const Plan_expr_param* expr2 = static_cast<const Plan_expr_param*>(expr); + // params are not equal ever + return false; +} + +bool +Plan_expr_param::isGroupBy(const Plan_expr_row* row) const +{ + // params are constants + return true; +} + +// Exec_expr_param + +Exec_expr_param::Code::~Code() +{ +} + +Exec_expr_param::Data::~Data() +{ + delete m_extField; + m_extField = 0; +} + +Exec_expr_param::~Exec_expr_param() +{ +} + +void +Exec_expr_param::alloc(Ctx& ctx, Ctl& ctl) +{ + if (m_data != 0) + return; + const Code& code = getCode(); + SqlField sqlField(code.sqlSpec()); + Data& data = *new Data(sqlField); + setData(data); +} + +void +Exec_expr_param::bind(Ctx& ctx) +{ + const Code& code = getCode(); + Data& data = getData(); + DescArea& apd = descArea(Desc_usage_APD); + if (apd.getCount() < code.m_paramNumber) { + ctx_log1(("parameter %u is not bound", code.m_paramNumber)); + return; + } + const unsigned paramNumber = code.m_paramNumber; + DescRec& rec = apd.getRecord(paramNumber); + OdbcData descData; + // create type + rec.getField(ctx, SQL_DESC_TYPE, descData); + if (descData.type() == OdbcData::Undef) { + ctx.pushStatus(Error::Gen, "parameter %u external type not defined", paramNumber); + return; + } + ExtType extType; + SQLSMALLINT desc_TYPE = descData.smallint(); + switch (desc_TYPE) { + case SQL_C_CHAR: + case SQL_C_SHORT: // for sun.jdbc.odbc + case SQL_C_SSHORT: + case SQL_C_USHORT: + case SQL_C_LONG: // for sun.jdbc.odbc + case SQL_C_SLONG: + case SQL_C_ULONG: + case SQL_C_SBIGINT: + case SQL_C_UBIGINT: + case SQL_C_FLOAT: + case SQL_C_DOUBLE: + case SQL_C_TYPE_TIMESTAMP: + case SQL_C_BINARY: // XXX BLOB hack + break; + default: + ctx.pushStatus(Error::Gen, "parameter %u unsupported external type %d", paramNumber, (int)desc_TYPE); + return; + } + extType.setType(ctx, static_cast<ExtType::Type>(desc_TYPE)); + ExtSpec extSpec(extType); + // create data field + rec.getField(ctx, SQL_DESC_DATA_PTR, descData); + if (descData.type() == OdbcData::Undef) { + ctx.pushStatus(Error::Gen, "parameter %u data address not defined", paramNumber); + return; + } + SQLPOINTER desc_DATA_PTR = descData.pointer(); + rec.getField(ctx, SQL_DESC_OCTET_LENGTH, descData); + if (descData.type() == OdbcData::Undef) { + ctx.pushStatus(Error::Gen, "parameter %u data length not defined", paramNumber); + return; + } + SQLINTEGER desc_OCTET_LENGTH = descData.integer(); + rec.getField(ctx, SQL_DESC_INDICATOR_PTR, descData); + if (descData.type() == OdbcData::Undef) { + ctx.pushStatus(Error::Gen, "parameter %u indicator address not defined", paramNumber); + return; + } + SQLINTEGER* desc_INDICATOR_PTR = descData.integerPtr(); + ctx_log4(("parameter %u bind to 0x%x %d 0x%x", paramNumber, (unsigned)desc_DATA_PTR, (int)desc_OCTET_LENGTH, (unsigned)desc_INDICATOR_PTR)); + ExtField& extField = *new ExtField(extSpec, desc_DATA_PTR, desc_OCTET_LENGTH, desc_INDICATOR_PTR, paramNumber); + data.m_atExec = false; + if (desc_INDICATOR_PTR != 0 && *desc_INDICATOR_PTR < 0) { + if (*desc_INDICATOR_PTR == SQL_NULL_DATA) { + ; + } else if (*desc_INDICATOR_PTR == SQL_DATA_AT_EXEC) { + data.m_atExec = true; + } else if (*desc_INDICATOR_PTR <= SQL_LEN_DATA_AT_EXEC(0)) { + data.m_atExec = true; + } + } + delete data.m_extField; + data.m_extField = &extField; +} + +void +Exec_expr_param::evaluate(Ctx& ctx, Ctl& ctl) +{ + if (ctl.m_postEval) + return; + const Code& code = getCode(); + Data& data = getData(); + if (data.m_atExec) + return; + ctx_assert(data.m_extField != 0); + data.m_sqlField.copyin(ctx, *data.m_extField); +} + +void +Exec_expr_param::close(Ctx& ctx) +{ + Data& data = getData(); + data.m_extPos = -1; +} + +void +Exec_expr_param::print(Ctx& ctx) +{ + const Code& code = getCode(); + ctx.print(" [param %u]", code.m_paramNumber); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_param.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_param.hpp new file mode 100644 index 00000000000..783e5c087b4 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_param.hpp @@ -0,0 +1,136 @@ +/* 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_Code_expr_param_hpp +#define ODBC_CODEGEN_Code_expr_param_hpp + +#include <common/common.hpp> +#include <common/DataField.hpp> +#include "Code_expr.hpp" + +/** + * @class Plan_expr_param + * @brief Constant expression value in PlanTree + */ +class Plan_expr_param : public Plan_expr { +public: + Plan_expr_param(Plan_root* root, unsigned paramNumber); + virtual ~Plan_expr_param(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + void describe(Ctx& ctx); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + bool isEqual(const Plan_expr* expr) const; + bool isGroupBy(const Plan_expr_row* row) const; +protected: + const unsigned m_paramNumber; +}; + +inline +Plan_expr_param::Plan_expr_param(Plan_root* root, unsigned paramNumber) : + Plan_expr(root, TypeParam), + m_paramNumber(paramNumber) +{ +} + +/** + * @class Exec_expr_param + * @brief Constant expression value in ExecTree + */ +class Exec_expr_param : public Exec_expr { +public: + class Code : public Exec_expr::Code { + public: + Code(const SqlSpec& sqlSpec, unsigned paramNumber); + virtual ~Code(); + protected: + friend class Plan_expr_param; + friend class Exec_expr_param; + const SqlSpec m_sqlSpec; + const unsigned m_paramNumber; + }; + class Data : public Exec_expr::Data { + public: + Data(SqlField& sqlField); + virtual ~Data(); + ExtField* extField() const; + protected: + friend class Exec_expr_param; + friend class Exec_root; + SqlField m_sqlField; + ExtField* m_extField; // input binding + bool m_atExec; // data at exec + int m_extPos; // position for SQLPutData (-1 before first call) + }; + Exec_expr_param(Exec_root* root); + virtual ~Exec_expr_param(); + void alloc(Ctx& ctx, Ctl& ctl); + void bind(Ctx& ctx); + void evaluate(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; +}; + +inline +Exec_expr_param::Code::Code(const SqlSpec& sqlSpec, unsigned paramNumber) : + Exec_expr::Code(m_sqlSpec), + m_sqlSpec(sqlSpec), + m_paramNumber(paramNumber) +{ +} + +inline +Exec_expr_param::Data::Data(SqlField& sqlField) : + Exec_expr::Data(m_sqlField), + m_sqlField(sqlField), + m_extField(0), + m_atExec(false), + m_extPos(-1) +{ +} + +inline ExtField* +Exec_expr_param::Data::extField() const +{ + return m_extField; +} + +inline +Exec_expr_param::Exec_expr_param(Exec_root* root) : + Exec_expr(root) +{ +} + +// children + +inline const Exec_expr_param::Code& +Exec_expr_param::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_expr_param::Data& +Exec_expr_param::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_row.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_row.cpp new file mode 100644 index 00000000000..da1751d41d1 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_row.cpp @@ -0,0 +1,204 @@ +/* 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/DataType.hpp> +#include "Code_expr_row.hpp" +#include "Code_expr.hpp" +#include "Code_expr_conv.hpp" +#include "Code_dml_row.hpp" +#include "Code_root.hpp" + +// Plan_expr_row + +Plan_expr_row::~Plan_expr_row() +{ +} + +Plan_base* +Plan_expr_row::analyze(Ctx& ctx, Ctl& ctl) +{ + unsigned size = getSize(); + // analyze subexpressions + m_anyAggr = false; + m_allBound = true; + for (unsigned i = 1; i <= size; i++) { + Plan_expr* expr1 = getExpr(i); + Plan_expr* expr2 = static_cast<Plan_expr*>(expr1->analyze(ctx, ctl)); + if (! ctx.ok()) + return 0; + setExpr(i, expr2); + if (expr2->isAggr()) + m_anyAggr = true; + if (! expr2->isBound()) + m_allBound = false; + } + // insert conversions if requested XXX ugly hack + if (ctl.m_dmlRow != 0) { + if (ctl.m_dmlRow->getSize() > getSize()) { + ctx.pushStatus(Sqlstate::_21S01, Error::Gen, "not enough values (%u > %u)", ctl.m_dmlRow->getSize(), getSize()); + return 0; + } + if (ctl.m_dmlRow->getSize() < getSize()) { + ctx.pushStatus(Sqlstate::_21S01, Error::Gen, "too many values (%u < %u)", ctl.m_dmlRow->getSize(), getSize()); + return 0; + } + for (unsigned i = 1; i <= size; i++) { + const SqlType& sqlType = ctl.m_dmlRow->getColumn(i)->sqlType(); + Plan_expr_conv* exprConv = new Plan_expr_conv(m_root, sqlType); + m_root->saveNode(exprConv); + exprConv->setExpr(getExpr(i)); + Plan_expr* expr = static_cast<Plan_expr*>(exprConv->analyze(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(expr != 0); + setExpr(i, expr); + } + } + // set aliases + m_aliasList.resize(1 + size); + for (unsigned i = 1; i <= size; i++) { + if (m_aliasList[i].empty()) { + setAlias(i, getExpr(i)->getAlias()); + } + } + // node was not replaced + return this; +} + +Exec_base* +Plan_expr_row::codegen(Ctx& ctx, Ctl& ctl) +{ + unsigned size = getSize(); + Exec_expr_row* exec = new Exec_expr_row(ctl.m_execRoot, size); + ctl.m_execRoot->saveNode(exec); + SqlSpecs sqlSpecs(size); + // create code for subexpressions + for (unsigned i = 1; i <= size; i++) { + Plan_expr* planExpr = getExpr(i); + Exec_expr* execExpr = static_cast<Exec_expr*>(planExpr->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execExpr != 0); + exec->setExpr(i, execExpr); + const SqlSpec sqlSpec(execExpr->getCode().sqlSpec(), SqlSpec::Reference); + sqlSpecs.setEntry(i, sqlSpec); + } + // create alias list + Exec_expr_row::Code::Alias* aliasList = new Exec_expr_row::Code::Alias[1 + size]; + strcpy(aliasList[0], "?"); + for (unsigned i = 1; i <= size; i++) { + const char* s = m_aliasList[i].c_str(); + if (strlen(s) == 0) + s = getExpr(i)->getAlias().c_str(); + unsigned n = strlen(s); + if (n >= sizeof(Exec_expr_row::Code::Alias)) + n = sizeof(Exec_expr_row::Code::Alias) - 1; + strncpy(aliasList[i], s, n); + aliasList[i][n] = 0; + } + // create the code + Exec_expr_row::Code& code = *new Exec_expr_row::Code(sqlSpecs, aliasList); + exec->setCode(code); + return exec; +} + +void +Plan_expr_row::print(Ctx& ctx) +{ + const unsigned size = getSize(); + ctx.print(" [expr_row"); + for (unsigned i = 1; i <= size; i++) { + Plan_base* a = m_exprList[i]; + a == 0 ? ctx.print(" -") : a->print(ctx); + } + ctx.print("]"); +} + +bool +Plan_expr_row::isAllGroupBy(const Plan_expr_row* row) const +{ + const unsigned size = getSize(); + for (unsigned i = 1; i <= size; i++) { + if (! getExpr(i)->isGroupBy(row)) + return false; + } + return true; +} + +// Exec_expr_row + +Exec_expr_row::Code::~Code() +{ + delete[] m_aliasList; +} + +Exec_expr_row::Data::~Data() +{ +} + +Exec_expr_row::~Exec_expr_row() +{ + delete[] m_expr; +} + +void +Exec_expr_row::alloc(Ctx& ctx, Ctl& ctl) +{ + // allocate subexpressions + for (unsigned i = 1; i <= m_size; i++) { + getExpr(i)->alloc(ctx, ctl); + } + // construct SqlRow of references + const Code& code = getCode(); + SqlRow sqlRow(getCode().m_sqlSpecs); + for (unsigned i = 1; i <= m_size; i++) { + const Exec_expr::Data& dataExpr = getExpr(i)->getData(); + const SqlSpec& sqlSpec = code.m_sqlSpecs.getEntry(i); + const SqlField sqlField(sqlSpec, &dataExpr.sqlField()); + sqlRow.setEntry(i, sqlField); + } + // create the data + Data& data = *new Data(sqlRow); + setData(data); +} + +void +Exec_expr_row::evaluate(Ctx& ctx, Ctl& ctl) +{ + for (unsigned i = 1; i <= m_size; i++) { + getExpr(i)->evaluate(ctx, ctl); + if (! ctx.ok()) + return; + } +} + +void +Exec_expr_row::close(Ctx& ctx) +{ + for (unsigned i = 1; i <= m_size; i++) { + getExpr(i)->close(ctx); + } +} + +void +Exec_expr_row::print(Ctx& ctx) +{ + ctx.print(" [expr_row"); + for (unsigned i = 1; i <= m_size; i++) { + getExpr(i)->print(ctx); + } + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_row.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_row.hpp new file mode 100644 index 00000000000..94527931dba --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_expr_row.hpp @@ -0,0 +1,272 @@ +/* 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_Code_expr_row_hpp +#define ODBC_CODEGEN_Code_expr_row_hpp + +#include <vector> +#include <common/common.hpp> +#include <common/DataRow.hpp> +#include "Code_base.hpp" +#include "Code_expr.hpp" + +class Plan_expr; + +/** + * @class Plan_expr_row + * @brief Row of expressions in PlanTree + * + * Used for select, value, and order by rows. + */ +class Plan_expr_row : public Plan_base { +public: + Plan_expr_row(Plan_root* root); + virtual ~Plan_expr_row(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setAsterisk(); + bool getAsterisk() const; + unsigned getSize() const; + Plan_expr* getExpr(unsigned i) const; + void setExpr(unsigned i, Plan_expr* expr); + void addExpr(Plan_expr* expr); + void addExpr(Plan_expr* expr, const BaseString& alias); + void setAlias(unsigned i, const BaseString& alias); + void addExpr(Plan_expr* expr, bool asc); + bool anyAggr() const; + bool allBound() const; + bool isAllGroupBy(const Plan_expr_row* row) const; +protected: + friend class Plan_query; + friend class Plan_query_sort; + bool m_asterisk; // early plan node type + ExprVector m_exprList; + typedef std::vector<BaseString> AliasList; + AliasList m_aliasList; + typedef std::vector<bool> AscList; + AscList m_ascList; + bool m_anyAggr; // at least one aggreate + bool m_allBound; // all bound +}; + +inline +Plan_expr_row::Plan_expr_row(Plan_root* root) : + Plan_base(root), + m_asterisk(false), + m_exprList(1), + m_aliasList(1), + m_ascList(1), + m_anyAggr(false), + m_allBound(false) +{ +} + +// children + +inline void +Plan_expr_row::setAsterisk() +{ + m_asterisk = true; +} + +inline bool +Plan_expr_row::getAsterisk() const +{ + return m_asterisk; +} + +inline unsigned +Plan_expr_row::getSize() const +{ + ctx_assert(m_exprList.size() >= 1); + return m_exprList.size() - 1; +} + +inline void +Plan_expr_row::addExpr(Plan_expr* expr) +{ + ctx_assert(expr != 0); + addExpr(expr, expr->m_alias); +} + +inline void +Plan_expr_row::addExpr(Plan_expr* expr, const BaseString& alias) +{ + ctx_assert(expr != 0); + m_exprList.push_back(expr); + m_aliasList.push_back(alias); +} + +inline void +Plan_expr_row::addExpr(Plan_expr* expr, bool asc) +{ + ctx_assert(expr != 0); + m_exprList.push_back(expr); + m_ascList.push_back(asc); +} + +inline void +Plan_expr_row::setExpr(unsigned i, Plan_expr* expr) +{ + ctx_assert(1 <= i && i < m_exprList.size() && expr != 0); + m_exprList[i] = expr; +} + +inline Plan_expr* +Plan_expr_row::getExpr(unsigned i) const +{ + ctx_assert(1 <= i && i < m_exprList.size() && m_exprList[i] != 0); + return m_exprList[i]; +} + +inline void +Plan_expr_row::setAlias(unsigned i, const BaseString& alias) +{ + ctx_assert(1 <= i && i < m_aliasList.size()); + m_aliasList[i] = alias; +} + +inline bool +Plan_expr_row::anyAggr() const +{ + return m_anyAggr; +} + +inline bool +Plan_expr_row::allBound() const +{ + return m_allBound; +} + +/** + * @class Expr_expr_row + * @brief Row of expressions in ExecTree + */ +class Exec_expr_row : public Exec_base { +public: + class Code : public Exec_base::Code { + public: + typedef char Alias[40]; + Code(const SqlSpecs& sqlSpecs, const Alias* aliasList); + virtual ~Code(); + const SqlSpecs& sqlSpecs() const; + const char* getAlias(unsigned i) const; + protected: + friend class Exec_expr_row; + const SqlSpecs m_sqlSpecs; + const Alias* m_aliasList; + }; + class Data : public Exec_base::Data { + public: + Data(const SqlRow& sqlRow); + virtual ~Data(); + const SqlRow& sqlRow() const; + protected: + friend class Exec_expr_row; + SqlRow m_sqlRow; + }; + Exec_expr_row(Exec_root* root, unsigned size); + virtual ~Exec_expr_row(); + void alloc(Ctx& ctx, Ctl& ctl); + void evaluate(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + Exec_expr* getExpr(unsigned i) const; + void setExpr(unsigned i, Exec_expr* expr); +protected: + Exec_expr** m_expr; // numbered from 1 + unsigned m_size; +}; + +inline +Exec_expr_row::Code::Code(const SqlSpecs& sqlSpecs, const Alias* aliasList) : + m_sqlSpecs(sqlSpecs), + m_aliasList(aliasList) +{ +} + +inline const SqlSpecs& +Exec_expr_row::Code::sqlSpecs() const +{ + return m_sqlSpecs; +} + +inline const char* +Exec_expr_row::Code::getAlias(unsigned i) const +{ + ctx_assert(1 <= i && i <= m_sqlSpecs.count() && m_aliasList != 0); + return m_aliasList[i]; +} + +inline +Exec_expr_row::Data::Data(const SqlRow& sqlRow) : + m_sqlRow(sqlRow) +{ +} + +inline const SqlRow& +Exec_expr_row::Data::sqlRow() const +{ + return m_sqlRow; +} + +inline +Exec_expr_row::Exec_expr_row(Exec_root* root, unsigned size) : + Exec_base(root), + m_expr(new Exec_expr* [1 + size]), + m_size(size) +{ + m_expr[0] = (Exec_expr*)-1; + for (unsigned i = 1; i <= m_size; i++) + m_expr[i] = 0; +} + +// children + +inline const Exec_expr_row::Code& +Exec_expr_row::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_expr_row::Data& +Exec_expr_row::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline Exec_expr* +Exec_expr_row::getExpr(unsigned i) const +{ + ctx_assert(1 <= i && i <= m_size && m_expr != 0 && m_expr[i] != 0); + return m_expr[i]; +} + +inline void +Exec_expr_row::setExpr(unsigned i, Exec_expr* expr) +{ + ctx_assert(1 <= i && i <= m_size && m_expr != 0 && m_expr[i] == 0); + m_expr[i] = expr; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_idx_column.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_idx_column.cpp new file mode 100644 index 00000000000..584ffef3e01 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_idx_column.cpp @@ -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 */ + +#include <NdbApi.hpp> +#include <common/StmtArea.hpp> +#include "Code_idx_column.hpp" +#include "Code_expr_conv.hpp" +#include "Code_root.hpp" + +// Plan_idx_column + +Plan_idx_column::~Plan_idx_column() +{ +} + +Plan_base* +Plan_idx_column::analyze(Ctx& ctx, Ctl& ctl) +{ + analyzeColumn(ctx, ctl); + if (! ctx.ok()) + return 0; + return this; +} + +Exec_base* +Plan_idx_column::codegen(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(false); + return 0; +} + +void +Plan_idx_column::print(Ctx& ctx) +{ + ctx.print(" [idx_column %s]", getPrintName()); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_idx_column.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_idx_column.hpp new file mode 100644 index 00000000000..209ed705b48 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_idx_column.hpp @@ -0,0 +1,50 @@ +/* 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_Code_idx_column_hpp +#define ODBC_CODEGEN_Code_idx_column_hpp + +#include <common/common.hpp> +#include "Code_column.hpp" +#include "Code_data_type.hpp" +#include "Code_expr.hpp" + +class DictColumn; +class Plan_table; + +/** + * @class Plan_idx_column + * @brief Column in create index statement + */ +class Plan_idx_column : public Plan_base, public Plan_column { +public: + Plan_idx_column(Plan_root* root, const BaseString& name); + virtual ~Plan_idx_column(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); +protected: + friend class Plan_create_row; +}; + +inline +Plan_idx_column::Plan_idx_column(Plan_root* root, const BaseString& name) : + Plan_base(root), + Plan_column(Type_idx, name) +{ +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_insert.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_insert.cpp new file mode 100644 index 00000000000..c442186c181 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_insert.cpp @@ -0,0 +1,253 @@ +/* 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/StmtArea.hpp> +#include <dictionary/DictTable.hpp> +#include <dictionary/DictColumn.hpp> +#include "Code_insert.hpp" +#include "Code_query_repeat.hpp" +#include "Code_query_project.hpp" +#include "Code_table.hpp" +#include "Code_root.hpp" + +// Plan_insert + +Plan_insert::~Plan_insert() +{ +} + +Plan_base* +Plan_insert::analyze(Ctx& ctx, Ctl& ctl) +{ + stmtArea().stmtInfo().setName(Stmt_name_insert); + ctx_assert(m_table != 0); + m_table->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + // handle MySql syntax + if (m_mysqlRow != 0) { + setDmlRow(m_mysqlRow->m_dmlRow); + setExprRow(m_mysqlRow->m_exprRow); + m_mysqlRow = 0; + } + if (m_dmlRow == 0) { + // construct column list + setDmlRow(new Plan_dml_row(m_root)); + m_root->saveNode(m_dmlRow); + const DictTable& dictTable = m_table->dictTable(); + unsigned n = dictTable.getSize(); + for (unsigned i = 1; i <= n; i++) { + DictColumn* dictColumn = dictTable.getColumn(i); + Plan_dml_column* column = new Plan_dml_column(m_root, dictColumn->getName()); + m_root->saveNode(column); + m_dmlRow->addColumn(column); + } + } + // set name resolution scope + ctl.m_tableList.resize(1 + 1); // indexed from 1 + ctl.m_tableList[1] = m_table; + // analyze the dml columns + m_dmlRow->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + ctl.m_dmlRow = m_dmlRow; // row type to convert to + if (m_query != 0) { + m_query->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + } else if (m_select == 0) { + // analyze the expression row + m_exprRow->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + // transform the row into query + Plan_query_repeat* queryRepeat = new Plan_query_repeat(m_root, 1); + m_root->saveNode(queryRepeat); + Plan_query_project* queryProject = new Plan_query_project(m_root); + m_root->saveNode(queryProject); + queryProject->setQuery(queryRepeat); + queryProject->setRow(m_exprRow); + setQuery(queryProject); + } else { + // analyze the select into query + Plan_query* query = static_cast<Plan_query*>(m_select->analyze(ctx, ctl)); + if (! ctx.ok()) + return 0; + setQuery(query); + } + return this; +} + +void +Plan_insert::describe(Ctx& ctx) +{ + stmtArea().setFunction(ctx, "INSERT", SQL_DIAG_INSERT); +} + +Exec_base* +Plan_insert::codegen(Ctx& ctx, Ctl& ctl) +{ + // create code for the query + ctx_assert(m_query != 0); + Exec_query* execQuery = static_cast<Exec_query*>(m_query->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execQuery != 0); + // set up + ctx_assert(m_table != 0); + const BaseString& tableName = m_table->getName(); + const DictTable& dictTable = m_table->dictTable(); + const ColumnVector& columns = m_table->dmlColumns(); + ctx_assert(columns.size() > 0); + const unsigned attrCount = columns.size() - 1; + // create the code + Exec_insert::Code& code = *new Exec_insert::Code(); + code.m_insertOp = m_insertOp; + code.m_tableName = strcpy(new char[tableName.length() + 1], tableName.c_str()); + code.m_attrCount = attrCount; + code.m_attrId = new NdbAttrId[1 + attrCount]; + code.m_isKey = new bool[1 + attrCount]; + code.m_attrId[0] = (NdbAttrId)-1; + code.m_tupleId = dictTable.tupleId(); // maybe 0 + code.m_autoIncrement = dictTable.autoIncrement(); // maybe 0 + unsigned k; + if ((k = code.m_tupleId) != 0 || (k = code.m_autoIncrement) != 0) { + const DictColumn& dictColumn = *dictTable.getColumn(k); + code.m_idType = dictColumn.sqlType(); + } + for (unsigned i = 1; i <= attrCount; i++) { + Plan_column* column = columns[i]; + ctx_assert(column != 0); + const DictColumn& dictColumn = column->dictColumn(); + code.m_attrId[i] = dictColumn.getAttrId(); + code.m_isKey[i] = dictColumn.isKey(); + } + // default values XXX a mess + code.m_defaultCount = 0; + for (unsigned j = 1; j <= dictTable.getSize(); j++) { + const DictColumn& dictColumn = *dictTable.getColumn(j); + if (dictColumn.getDefaultValue() != 0 && ! code.findAttrId(dictColumn.getAttrId())) + code.m_defaultCount++; + } + if (code.m_defaultCount != 0) { + code.m_defaultId = new NdbAttrId[1 + code.m_defaultCount]; + for (unsigned i = 0, j = 1; j <= dictTable.getSize(); j++) { + const DictColumn& dictColumn = *dictTable.getColumn(j); + if (dictColumn.getDefaultValue() != 0 && ! code.findAttrId(dictColumn.getAttrId())) + code.m_defaultId[++i] = dictColumn.getAttrId(); + } + SqlSpecs sqlSpecs(code.m_defaultCount); + for (unsigned i = 0, j = 1; j <= dictTable.getSize(); j++) { + const DictColumn& dictColumn = *dictTable.getColumn(j); + if (dictColumn.getDefaultValue() != 0 && ! code.findAttrId(dictColumn.getAttrId())) { + SqlSpec sqlSpec(dictColumn.sqlType(), SqlSpec::Physical); + sqlSpecs.setEntry(++i, sqlSpec); + } + } + code.m_defaultValue = new SqlRow(sqlSpecs); + for (unsigned i = 0, j = 1; j <= dictTable.getSize(); j++) { + const DictColumn& dictColumn = *dictTable.getColumn(j); + if (dictColumn.getDefaultValue() != 0 && ! code.findAttrId(dictColumn.getAttrId())) { + const char* defaultValue = dictColumn.getDefaultValue(); + ExtType extType(ExtType::Char); + ExtSpec extSpec(extType); + SQLINTEGER ind = SQL_NTS; + ExtField extField(extSpec, (SQLPOINTER)defaultValue, 0, &ind); + SqlField& f = code.m_defaultValue->getEntry(++i); + f.copyin(ctx, extField); + if (! ctx.ok()) + return 0; + } + } + } + // create the exec + Exec_insert* exec = new Exec_insert(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + exec->setCode(code); + exec->setQuery(execQuery); + return exec; +} + +void +Plan_insert::print(Ctx& ctx) +{ + ctx.print(" [%s", m_insertOp == Insert_op_insert ? "insert" : "write"); + Plan_base* a[] = { m_table, m_dmlRow, m_exprRow, m_query }; + printList(ctx, a, 4); + ctx.print("]"); +} + +// Exec_insert + +Exec_insert::Code::~Code() +{ + delete[] m_tableName; + delete[] m_attrId; + delete[] m_isKey; + delete[] m_defaultId; + delete m_defaultValue; +} + +bool +Exec_insert::Code::findAttrId(NdbAttrId attrId) const +{ + for (unsigned i = 1; i <= m_attrCount; i++) { + if (m_attrId[i] == attrId) + return true; + } + return false; +} + +Exec_insert::Data::~Data() +{ +} + +Exec_insert::~Exec_insert() +{ +} + +void +Exec_insert::alloc(Ctx& ctx, Ctl& ctl) +{ + // allocate the query + ctx_assert(m_query != 0); + m_query->alloc(ctx, ctl); + // create data + Data& data = *new Data(); + setData(data); +} + +void +Exec_insert::close(Ctx& ctx) +{ +} + +void +Exec_insert::print(Ctx& ctx) +{ + const Code& code = getCode(); + ctx_assert(m_query != 0); + ctx.print(" [insert"); + ctx.print(" attrId="); + for (unsigned i = 1; i <= code.m_attrCount; i++) { + if (i > 1) + ctx.print(","); + ctx.print("%u", (unsigned)code.m_attrId[i]); + } + ctx.print(" table=%s", code.m_tableName); + m_query->print(ctx); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_insert.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_insert.hpp new file mode 100644 index 00000000000..748b092e33a --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_insert.hpp @@ -0,0 +1,229 @@ +/* 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_Code_insert_hpp +#define ODBC_CODEGEN_Code_insert_hpp + +#include <common/common.hpp> +#include "Code_base.hpp" +#include "Code_dml.hpp" +#include "Code_dml_row.hpp" +#include "Code_expr_row.hpp" +#include "Code_select.hpp" +#include "Code_query.hpp" +#include "Code_table.hpp" +#include "Code_set_row.hpp" + +enum Insert_op { + Insert_op_undef = 0, + Insert_op_insert = 1, + Insert_op_write = 2 +}; + +/** + * @class Plan_insert + * @brief Insert in PlanTree + * + * Insert. Becomes directly executable. + */ +class Plan_insert : public Plan_dml { +public: + Plan_insert(Plan_root* root, Insert_op insertOp); + virtual ~Plan_insert(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + void describe(Ctx& ctx); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setTable(Plan_table* table); + Plan_dml_row* getDmlRow() const; + void setDmlRow(Plan_dml_row* dmlRow); + void setExprRow(Plan_expr_row* exprRow); + void setSelect(Plan_select* select); + void setQuery(Plan_query* query); + void setMysqlRow(Plan_set_row* mysqlRow); +protected: + Insert_op m_insertOp; + Plan_table* m_table; + Plan_dml_row* m_dmlRow; + Plan_expr_row* m_exprRow; + Plan_select* m_select; + Plan_query* m_query; + Plan_set_row* m_mysqlRow; +}; + +inline +Plan_insert::Plan_insert(Plan_root* root, Insert_op insertOp) : + Plan_dml(root), + m_insertOp(insertOp), + m_table(0), + m_dmlRow(0), + m_exprRow(0), + m_select(0), + m_query(0), + m_mysqlRow(0) +{ +} + +// children + +inline void +Plan_insert::setTable(Plan_table* table) +{ + ctx_assert(table != 0); + m_table = table; +} + +inline void +Plan_insert::setDmlRow(Plan_dml_row* dmlRow) +{ + ctx_assert(dmlRow != 0); + m_dmlRow = dmlRow; +} + +inline Plan_dml_row* +Plan_insert::getDmlRow() const +{ + ctx_assert(m_dmlRow != 0); + return m_dmlRow; +} + +inline void +Plan_insert::setExprRow(Plan_expr_row* exprRow) +{ + ctx_assert(exprRow != 0); + m_exprRow = exprRow; +} + +inline void +Plan_insert::setSelect(Plan_select* select) +{ + ctx_assert(select != 0); + m_select = select; +} + +inline void +Plan_insert::setQuery(Plan_query* query) +{ + ctx_assert(query != 0); + m_query = query; +} + +inline void +Plan_insert::setMysqlRow(Plan_set_row* mysqlRow) +{ + ctx_assert(mysqlRow != 0); + m_mysqlRow = mysqlRow; +} + +/** + * @class Exec_insert + * @brief Executable insert + */ +class Exec_insert : public Exec_dml { +public: + class Code : public Exec_dml::Code { + public: + Code(); + virtual ~Code(); + protected: + friend class Plan_insert; + friend class Exec_insert; + Insert_op m_insertOp; + char* m_tableName; + unsigned m_attrCount; + NdbAttrId* m_attrId; + bool* m_isKey; + unsigned m_tupleId; // position of tuple id + unsigned m_autoIncrement; // position of ai key + SqlType m_idType; // type of tuple id or ai key + unsigned m_defaultCount; + NdbAttrId* m_defaultId; + SqlRow* m_defaultValue; + bool findAttrId(NdbAttrId attrId) const; + }; + class Data : public Exec_dml::Data { + public: + Data(); + virtual ~Data(); + protected: + friend class Exec_insert; + }; + Exec_insert(Exec_root* root); + virtual ~Exec_insert(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setQuery(Exec_query* query); +private: + Exec_query* m_query; +}; + +inline +Exec_insert::Code::Code() : + m_insertOp(Insert_op_undef), + m_tableName(0), + m_attrCount(0), + m_attrId(0), + m_isKey(0), + m_tupleId(0), + m_autoIncrement(0), + m_defaultCount(0), + m_defaultId(0), + m_defaultValue(0) +{ +} + +inline +Exec_insert::Data::Data() +{ +} + +inline +Exec_insert::Exec_insert(Exec_root* root) : + Exec_dml(root), + m_query(0) +{ +} + +// children + +inline const Exec_insert::Code& +Exec_insert::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_insert::Data& +Exec_insert::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_insert::setQuery(Exec_query* query) +{ + ctx_assert(m_query == 0 && query != 0); + m_query = query; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_pred.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_pred.cpp new file mode 100644 index 00000000000..fe7cac7606e --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_pred.cpp @@ -0,0 +1,70 @@ +/* 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 "Code_pred.hpp" +#include "Code_pred_op.hpp" +#include "Code_root.hpp" + +// Plan_pred + +Plan_pred::~Plan_pred() +{ +} + +bool +Plan_pred::isGroupBy(const Plan_expr_row* row) const +{ + return false; +} + +Plan_pred* +Plan_pred::opAnd(Plan_pred* pred2) +{ + Plan_pred_op* predAnd = new Plan_pred_op(m_root, Pred_op::And); + m_root->saveNode(predAnd); + predAnd->setPred(1, this); + predAnd->setPred(2, pred2); + return predAnd; +} + +// Exec_pred + +Exec_pred::Code::~Code() +{ +} + +Exec_pred::Data::~Data() +{ +} + +Exec_pred::~Exec_pred() +{ +} + +Pred_value& +Exec_pred::Data::groupValue(unsigned i, bool initFlag) +{ + if (m_groupValue.size() == 0) { + m_groupValue.resize(1); + } + if (initFlag) { + //unsigned i2 = m_groupValue.size(); + //ctx_assert(i == i2); + m_groupValue.push_back(Pred_value_unknown); + } + ctx_assert(i != 0 && i < m_groupValue.size()); + return m_groupValue[i]; +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_pred.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_pred.hpp new file mode 100644 index 00000000000..a77c1161fa1 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_pred.hpp @@ -0,0 +1,172 @@ +/* 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_Code_pred_hpp +#define ODBC_CODEGEN_Code_pred_hpp + +#include <common/common.hpp> +#include <common/DataField.hpp> +#include "Code_base.hpp" + +enum Pred_value { + Pred_value_unknown = -1, + Pred_value_false = 0, + Pred_value_true = 1 +}; + +class Ctx; +class Plan_expr_row; +class Exec_pred; + +/** + * @class Plan_pred + * @brief Base class for predicates in PlanTree + * + * Predicate represents a boolean value. + */ +class Plan_pred : public Plan_base { +public: + // type is convenient since RTTI cannot be used + enum Type { + TypeUndefined = 0, + TypeComp = 1, + TypeOp = 2 + }; + Plan_pred(Plan_root* root, Type type); + virtual ~Plan_pred() = 0; + Type type() const; + const TableSet& tableSet() const; + const TableSet& noInterp() const; + virtual bool isGroupBy(const Plan_expr_row* row) const; + // helpers + Plan_pred* opAnd(Plan_pred* pred2); +protected: + const Type m_type; + TableSet m_tableSet; // depends on these tables + TableSet m_noInterp; // cannot use interpreted TUP program on these tables + Exec_pred* m_exec; // probably stupid +}; + +inline +Plan_pred::Plan_pred(Plan_root* root, Type type) : + Plan_base(root), + m_type(type), + m_exec(0) +{ +} + +inline Plan_pred::Type +Plan_pred::type() const +{ + return m_type; +} + +inline const Plan_pred::TableSet& +Plan_pred::tableSet() const +{ + return m_tableSet; +} + +inline const Plan_pred::TableSet& +Plan_pred::noInterp() const +{ + return m_noInterp; +} + +/** + * @class Exec_pred + * @brief Base class for predicates in ExecTree + */ +class Exec_pred : public Exec_base { +public: + class Code : public Exec_base::Code { + public: + Code(); + virtual ~Code() = 0; + protected: + friend class Exec_pred; + }; + class Data : public Exec_base::Data { + public: + Data(); + virtual ~Data() = 0; + Pred_value getValue() const; + Pred_value groupValue(unsigned i) const; + protected: + friend class Exec_pred; + Pred_value m_value; // the value + // group-by data + typedef std::vector<Pred_value> GroupValue; + GroupValue m_groupValue; + Pred_value& groupValue(unsigned i, bool initFlag); + }; + Exec_pred(Exec_root* root); + virtual ~Exec_pred() = 0; + virtual void execInterp(Ctx& ctx, Ctl& ctl) = 0; + virtual void evaluate(Ctx& ctx, Ctl& ctl) = 0; + // children + const Code& getCode() const; + Data& getData() const; +}; + +inline +Exec_pred::Code::Code() +{ +} + +inline +Exec_pred::Data::Data() : + m_value(Pred_value_unknown) +{ +} + +inline Pred_value +Exec_pred::Data::getValue() const +{ + return m_value; +} + +inline Pred_value +Exec_pred::Data::groupValue(unsigned i) const +{ + ctx_assert(i != 0 && i < m_groupValue.size()); + return m_groupValue[i]; +} + +inline +Exec_pred::Exec_pred(Exec_root* root) : + Exec_base(root) +{ +} + +// children + +inline const Exec_pred::Code& +Exec_pred::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_pred::Data& +Exec_pred::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_pred_op.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_pred_op.cpp new file mode 100644 index 00000000000..29736e45818 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_pred_op.cpp @@ -0,0 +1,188 @@ +/* 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 "Code_pred.hpp" +#include "Code_pred_op.hpp" +#include "Code_root.hpp" + +// Pred_op + +const char* +Pred_op::name() const +{ + switch (m_opcode) { + case And: + return "and"; + case Or: + return "or"; + case Not: + return "not"; + } + ctx_assert(false); + return ""; +} + +unsigned +Pred_op::arity() const +{ + switch (m_opcode) { + case And: + case Or: + return 2; + case Not: + return 1; + } + ctx_assert(false); + return 0; +} + +// Plan_pred_op + +Plan_pred_op::~Plan_pred_op() +{ +} + +Plan_base* +Plan_pred_op::analyze(Ctx& ctx, Ctl& ctl) +{ + m_exec = 0; + unsigned arity = m_op.arity(); + // check if we remain in top-level AND-clause + const bool topand = ctl.m_topand; + if (m_op.m_opcode != Pred_op::And) + ctl.m_topand = false; + // analyze sub-predicates + for (unsigned i = 1; i <= arity; i++) { + ctx_assert(m_pred[i] != 0); + m_pred[i]->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + } + // save top level predicate on list + if (topand && ! ctl.m_topand) { + ctl.m_topcomp.push_back(this); + } + ctl.m_topand = topand; + // table dependencies are union from operands + m_tableSet.clear(); + for (unsigned i = 1; i <= arity; i++) { + const TableSet& ts = m_pred[i]->tableSet(); + m_tableSet.insert(ts.begin(), ts.end()); + } + // set of tables for which interpreter cannot be used + m_noInterp.clear(); + for (unsigned i = 1; i <= arity; i++) { + const TableSet& ts = m_pred[i]->noInterp(); + m_noInterp.insert(ts.begin(), ts.end()); + } + return this; +} + +Exec_base* +Plan_pred_op::codegen(Ctx& ctx, Ctl& ctl) +{ + if (m_exec != 0) + return m_exec; + unsigned arity = m_op.arity(); + Exec_pred_op* exec = new Exec_pred_op(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + // create code for operands + for (unsigned i = 1; i <= arity; i++) { + ctx_assert(m_pred[i] != 0); + Exec_pred* execPred = static_cast<Exec_pred*>(m_pred[i]->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execPred != 0); + exec->setPred(i, execPred); + } + // create the code + Exec_pred_op::Code& code = *new Exec_pred_op::Code(m_op); + exec->setCode(code); + m_exec = exec; + return exec; +} + +void +Plan_pred_op::print(Ctx& ctx) +{ + ctx.print(" [%s", m_op.name()); + Plan_base* a[] = { m_pred[1], m_pred[2] }; + printList(ctx, a, m_op.arity()); + ctx.print("]"); +} + +bool +Plan_pred_op::isGroupBy(const Plan_expr_row* row) const +{ + const unsigned arity = m_op.arity(); + for (unsigned i = 1; i <= arity; i++) { + ctx_assert(m_pred[i] != 0); + if (! m_pred[i]->isGroupBy(row)) + return false; + } + return true; +} + +// Code_pred_op + +Exec_pred_op::Code::~Code() +{ +} + +Exec_pred_op::Data::~Data() +{ +} + +Exec_pred_op::~Exec_pred_op() +{ +} + +void +Exec_pred_op::alloc(Ctx& ctx, Ctl& ctl) +{ + const Code& code = getCode(); + // allocate sub-predicates + unsigned arity = code.m_op.arity(); + for (unsigned i = 1; i <= arity; i++) { + ctx_assert(m_pred[i] != 0); + m_pred[i]->alloc(ctx, ctl); + if (! ctx.ok()) + return; + } + Data& data = *new Data; + setData(data); +} + +void +Exec_pred_op::close(Ctx& ctx) +{ + const Code& code = getCode(); + unsigned arity = code.m_op.arity(); + for (unsigned i = 1; i <= arity; i++) { + ctx_assert(m_pred[i] != 0); + m_pred[i]->close(ctx); + } +} + +void +Exec_pred_op::print(Ctx& ctx) +{ + const Code& code = getCode(); + ctx.print(" [%s", code.m_op.name()); + Exec_base* a[] = { m_pred[1], m_pred[2] }; + printList(ctx, a, code.m_op.arity()); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_pred_op.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_pred_op.hpp new file mode 100644 index 00000000000..9130bc3cb81 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_pred_op.hpp @@ -0,0 +1,158 @@ +/* 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_Code_pred_op_hpp +#define ODBC_CODEGEN_Code_pred_op_hpp + +#include <common/common.hpp> +#include <common/DataField.hpp> +#include "Code_pred.hpp" + +/** + * @class Pred_op + * @brief Boolean operators + */ +struct Pred_op { + enum Opcode { + And = 1, // binary + Or, + Not // unary + }; + Pred_op(Opcode opcode); + const char* name() const; + unsigned arity() const; + Opcode m_opcode; +}; + +inline +Pred_op::Pred_op(Opcode opcode) : + m_opcode(opcode) +{ +} + +/** + * @class Plan_pred_op + * @brief Operator node in a predicate in PlanTree + */ +class Plan_pred_op : public Plan_pred { +public: + Plan_pred_op(Plan_root* root, Pred_op op); + virtual ~Plan_pred_op(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + bool isGroupBy(const Plan_expr_row* row) const; + // children + void setPred(unsigned i, Plan_pred* pred); +protected: + friend class Plan_pred; + Pred_op m_op; + Plan_pred* m_pred[1 + 2]; +}; + +inline +Plan_pred_op::Plan_pred_op(Plan_root* root, Pred_op op) : + Plan_pred(root, TypeOp), + m_op(op) +{ + m_pred[0] = m_pred[1] = m_pred[2] = 0; +} + +inline void +Plan_pred_op::setPred(unsigned i, Plan_pred* pred) +{ + ctx_assert(1 <= i && i <= m_op.arity() && pred != 0); + m_pred[i] = pred; +} + +/** + * @class Exec_pred_op + * @brief Operator node in a predicate in ExecTree + */ +class Exec_pred_op : public Exec_pred { +public: + class Code : public Exec_pred::Code { + public: + Code(Pred_op op); + virtual ~Code(); + protected: + friend class Exec_pred_op; + Pred_op m_op; + }; + class Data : public Exec_pred::Data { + public: + Data(); + virtual ~Data(); + protected: + friend class Exec_pred_op; + }; + Exec_pred_op(Exec_root* root); + virtual ~Exec_pred_op(); + void alloc(Ctx& ctx, Ctl& ctl); + void execInterp(Ctx& ctx, Ctl& ctl); + void evaluate(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setPred(unsigned i, Exec_pred* pred); +protected: + Exec_pred* m_pred[1 + 2]; +}; + +inline +Exec_pred_op::Code::Code(Pred_op op) : + m_op(op) +{ +} + +inline +Exec_pred_op::Data::Data() +{ +} + +inline +Exec_pred_op::Exec_pred_op(Exec_root* root) : + Exec_pred(root) +{ + m_pred[0] = m_pred[1] = m_pred[2] = 0; +} + +// children + +inline const Exec_pred_op::Code& +Exec_pred_op::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_pred_op::Data& +Exec_pred_op::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_pred_op::setPred(unsigned i, Exec_pred* pred) +{ + ctx_assert(1 <= i && i <= 2 && m_pred[i] == 0); + m_pred[i] = pred; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query.cpp new file mode 100644 index 00000000000..9e983942601 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query.cpp @@ -0,0 +1,299 @@ +/* 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/StmtArea.hpp> +#include "Code_query.hpp" +#include "Code_query_project.hpp" +#include "Code_query_count.hpp" + +// Plan_query + +Plan_query::~Plan_query() +{ +} + +Plan_expr_row* +Plan_query::getRow() +{ + ctx_assert(false); + return 0; +} + +void +Plan_query::describe(Ctx& ctx) +{ + const Plan_expr_row* exprRow = getRow(); + const unsigned count = exprRow->getSize(); + // create IRD + DescArea& ird = descArea(Desc_usage_IRD); + ird.setCount(ctx, count); + for (unsigned i = 1; i <= count; i++) { + DescRec& rec = ird.getRecord(i); + const Plan_expr* expr = exprRow->m_exprList[i]; + const SqlType& sqlType = expr->sqlType(); + // data type + SQLSMALLINT desc_TYPE = sqlType.type(); + rec.setField(SQL_DESC_TYPE, desc_TYPE); + SQLSMALLINT desc_CONCISE_TYPE = desc_TYPE; + rec.setField(SQL_DESC_CONCISE_TYPE, desc_CONCISE_TYPE); + SQLSMALLINT desc_DESC_DATETIME_INTERVAL_CODE = 0; + rec.setField(SQL_DESC_DATETIME_INTERVAL_CODE, desc_DESC_DATETIME_INTERVAL_CODE); + // nullable + SQLSMALLINT desc_NULLABLE = sqlType.nullable() ? SQL_NULLABLE : SQL_NO_NULLS; + rec.setField(SQL_DESC_NULLABLE, desc_NULLABLE); + // unsigned + SQLSMALLINT desc_UNSIGNED; + switch (sqlType.type()) { + case SQL_SMALLINT: + case SQL_INTEGER: + case SQL_BIGINT: + desc_UNSIGNED = sqlType.unSigned() ? SQL_TRUE : SQL_FALSE; + break; + default: + desc_UNSIGNED = SQL_TRUE; // thus spake microsoft + break; + } + rec.setField(SQL_DESC_UNSIGNED, desc_UNSIGNED); + // sizes + SQLUINTEGER desc_LENGTH = sqlType.length(); + rec.setField(SQL_DESC_LENGTH, desc_LENGTH); + SQLINTEGER desc_OCTET_LENGTH = sqlType.size(); + rec.setField(SQL_DESC_OCTET_LENGTH, desc_OCTET_LENGTH); + SQLINTEGER desc_DISPLAY_SIZE = sqlType.displaySize(); + rec.setField(SQL_DESC_DISPLAY_SIZE, desc_DISPLAY_SIZE); + // name + ctx_assert(i < exprRow->m_aliasList.size()); + const char* desc_NAME = exprRow->m_aliasList[i].c_str(); + rec.setField(SQL_DESC_NAME, desc_NAME); + } + ctx_log3(("describe %u columns done", count)); + stmtArea().setFunction(ctx, "SELECT CURSOR", SQL_DIAG_SELECT_CURSOR); +} + +// Exec_query + +Exec_query::Code::~Code() +{ +} + +Exec_query::Data::~Data() +{ + delete m_extRow; + m_extRow = 0; + delete[] m_extPos; + m_extPos = 0; +} + +Exec_query::~Exec_query() +{ +} + +const Exec_query* +Exec_query::getRawQuery() const +{ + ctx_assert(false); + return 0; +} + +void +Exec_query::bind(Ctx& ctx) +{ + const Code& code = getCode(); + const SqlSpecs& sqlSpecs = code.sqlSpecs(); + const unsigned count = sqlSpecs.count(); + // read ARD + DescArea& ard = descArea(Desc_usage_ARD); + const unsigned ardCount = ard.getCount(); + // create specification row + ExtSpecs extSpecs(count); + for (unsigned i = 1; i <= count; i++) { + ExtType extType; + if (i <= ardCount) { + OdbcData descData; + DescRec& rec = ard.getRecord(i); + // check for unbound column + rec.getField(ctx, SQL_DESC_DATA_PTR, descData); + SQLPOINTER desc_DATA_PTR = descData.type() != OdbcData::Undef ? descData.pointer() : 0; + if (desc_DATA_PTR == 0) { + extType.setType(ctx, ExtType::Unbound); + } else { + rec.getField(ctx, SQL_DESC_TYPE, descData); + if (descData.type() == OdbcData::Undef) { + ctx.pushStatus(Error::Gen, "query column %u: external type not defined", i); + return; + } + SQLSMALLINT desc_TYPE = descData.smallint(); + if (desc_TYPE == SQL_C_DEFAULT) { + if (i <= code.m_sqlSpecs.count()) + desc_TYPE = code.m_sqlSpecs.getEntry(i).sqlType().sqlcdefault(ctx); + } + switch (desc_TYPE) { + case SQL_C_CHAR: + case SQL_C_BINARY: + case SQL_C_SHORT: // for sun.jdbc.odbc + case SQL_C_SSHORT: + case SQL_C_USHORT: + case SQL_C_LONG: // for sun.jdbc.odbc + case SQL_C_SLONG: + case SQL_C_ULONG: + case SQL_C_SBIGINT: + case SQL_C_UBIGINT: + case SQL_C_FLOAT: + case SQL_C_DOUBLE: + case SQL_C_TYPE_TIMESTAMP: + break; + default: + ctx.pushStatus(Error::Gen, "query column %u: unsupported external type %d", i, (int)desc_TYPE); + return; + } + extType.setType(ctx, static_cast<ExtType::Type>(desc_TYPE)); + } + } else { + extType.setType(ctx, ExtType::Unbound); + } + const ExtSpec extSpec(extType); + extSpecs.setEntry(i, extSpec); + } + // create data row + ExtRow& extRow = *new ExtRow(extSpecs); + unsigned boundCount = 0; + for (unsigned i = 1; i <= count; i++) { + const ExtSpec& extSpec = extSpecs.getEntry(i); + if (extSpec.extType().type() != ExtType::Unbound) { + OdbcData descData; + DescRec& rec = ard.getRecord(i); + rec.getField(ctx, SQL_DESC_DATA_PTR, descData); + SQLPOINTER desc_DATA_PTR = descData.type() != OdbcData::Undef ? descData.pointer() : 0; + rec.getField(ctx, SQL_DESC_OCTET_LENGTH, descData); + SQLINTEGER desc_OCTET_LENGTH = descData.type() != OdbcData::Undef ? descData.integer() : 0; + rec.getField(ctx, SQL_DESC_INDICATOR_PTR, descData); + SQLINTEGER* desc_INDICATOR_PTR = descData.type() != OdbcData::Undef ? descData.integerPtr() : 0; + ctx_log4(("column %u: bind to 0x%x %d 0x%x", i, (unsigned)desc_DATA_PTR, (int)desc_OCTET_LENGTH, (unsigned)desc_INDICATOR_PTR)); + ExtField extField(extSpec, desc_DATA_PTR, desc_OCTET_LENGTH, desc_INDICATOR_PTR, i); + extRow.setEntry(i, extField); + boundCount++; + } else { + ExtField extField(extSpec, i); + extRow.setEntry(i, extField); + } + } + Data& data = getData(); + delete data.m_extRow; + data.m_extRow = &extRow; + ctx_log3(("bound %u out of %u columns", boundCount, count)); +} + +// execute and fetch + +void +Exec_query::execute(Ctx& ctx, Ctl& ctl) +{ + Data& data = getData(); + execImpl(ctx, ctl); + if (! ctx.ok()) + return; + data.initState(); + if (m_topLevel) { + stmtArea().setRowCount(ctx, data.getCount()); + } +} + +bool +Exec_query::fetch(Ctx& ctx, Ctl& ctl) +{ + const Code& code = getCode(); + Data& data = getData(); + if (data.fetch(ctx, ctl)) { + if (m_topLevel) { + stmtArea().setRowCount(ctx, data.getCount()); + } + if (data.m_extRow != 0) { + data.sqlRow().copyout(ctx, *data.m_extRow); + if (! ctx.ok()) + return false; + } + if (data.m_extPos != 0) { + const unsigned count = code.sqlSpecs().count(); + for (unsigned i = 0; i <= count; i++) { + data.m_extPos[i] = 0; + } + } + return true; + } + if (m_topLevel) { + stmtArea().setRowCount(ctx, data.getCount()); + if (ctx.ok()) { + ctx.setCode(SQL_NO_DATA); + } + } + return false; +} + +// odbc support + +void +Exec_query::sqlGetData(Ctx& ctx, SQLUSMALLINT columnNumber, SQLSMALLINT targetType, SQLPOINTER targetValue, SQLINTEGER bufferLength, SQLINTEGER* strlen_or_Ind) +{ + const Code& code = getCode(); + Data& data = getData(); + const SqlSpecs& sqlSpecs = code.m_sqlSpecs; + const unsigned count = sqlSpecs.count(); + if (columnNumber == 0 || columnNumber > count) { + ctx.pushStatus(Sqlstate::_07009, Error::Gen, "column index %u is not within 1 to %u", (unsigned)columnNumber, count); + return; + } + // create positions array on first use + if (data.m_extPos == 0) { + data.m_extPos = new int[1 + count]; + for (unsigned i = 0; i <= count; i++) { + data.m_extPos[i] = 0; + } + } + if (targetType == SQL_ARD_TYPE) { + // get type from ARD + DescArea& ard = descArea(Desc_usage_ARD); + const unsigned ardCount = ard.getCount(); + if (columnNumber <= ardCount) { + OdbcData descData; + DescRec& rec = ard.getRecord(columnNumber); + rec.getField(ctx, SQL_DESC_CONCISE_TYPE, descData); + if (descData.type() != OdbcData::Undef) { + targetType = descData.smallint(); + } + } + if (targetType == SQL_ARD_TYPE) { + ctx.pushStatus(Sqlstate::_07009, Error::Gen, "output column %u type not bound - cannot use SQL_ARD_TYPE", (unsigned)columnNumber); + return; + } + } + ExtType extType; + if (targetValue != 0) { + extType.setType(ctx, static_cast<ExtType::Type>(targetType)); + // check if supported + if (! ctx.ok()) + return; + } else { + extType.setType(ctx, ExtType::Unbound); + } + ExtSpec extSpec(extType); + ExtField extField(extSpec, targetValue, bufferLength, strlen_or_Ind, columnNumber); + // copy out and update position + extField.setPos(data.m_extPos[columnNumber]); + const SqlRow& sqlRow = data.sqlRow(); + const SqlField& sqlField = sqlRow.getEntry(columnNumber); + sqlField.copyout(ctx, extField); + data.m_extPos[columnNumber] = extField.getPos(); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query.hpp new file mode 100644 index 00000000000..97f98f859ff --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query.hpp @@ -0,0 +1,155 @@ +/* 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_Code_query_hpp +#define ODBC_CODEGEN_Code_query_hpp + +#include <common/common.hpp> +#include <common/DataRow.hpp> +#include <common/ResultArea.hpp> +#include "Code_stmt.hpp" + +class Plan_expr_row; +class Plan_table; +class Exec_expr_row; + +/** + * @class Plan_query + * @brief Base class for queries in PlanTree + */ +class Plan_query : public Plan_stmt { +public: + Plan_query(Plan_root* root); + virtual ~Plan_query() = 0; + void describe(Ctx& ctx); + virtual Plan_expr_row* getRow(); +}; + +inline +Plan_query::Plan_query(Plan_root* root) : + Plan_stmt(root) +{ +} + +/** + * @class Exec_query + * @brief Base class for executable queries. + * + * Executable queriable statement. + */ +class Exec_query : public Exec_stmt { +public: + class Code : public Exec_stmt::Code { + public: + Code(const SqlSpecs& sqlSpecs); + virtual ~Code() = 0; + const SqlSpecs& sqlSpecs() const; + protected: + friend class Exec_query; + const SqlSpecs& m_sqlSpecs; // subclass must contain + }; + class Data : public Exec_stmt::Data, public ResultSet { + public: + Data(Exec_query* node, const SqlRow& sqlRow); + virtual ~Data() = 0; + const SqlRow& sqlRow() const; + ExtRow* extRow() const; + bool fetchImpl(Ctx& ctx, Ctl& ctl); + protected: + friend class Exec_query; + Exec_query* const m_node; + ExtRow* m_extRow; // output bindings + int* m_extPos; // positions for SQLGetData + }; + Exec_query(Exec_root* root); + virtual ~Exec_query() = 0; + void bind(Ctx& ctx); + void execute(Ctx& ctx, Ctl& ctl); + bool fetch(Ctx& ctx, Ctl& ctl); + // children + const Code& getCode() const; + Data& getData() const; + virtual const Exec_query* getRawQuery() const; + // odbc support + void sqlGetData(Ctx& ctx, SQLUSMALLINT columnNumber, SQLSMALLINT targetType, SQLPOINTER targetValue, SQLINTEGER bufferLength, SQLINTEGER* strlen_or_Ind); +protected: + friend class Data; + virtual void execImpl(Ctx& ctx, Ctl& ctl) = 0; + virtual bool fetchImpl(Ctx& ctx, Ctl& ctl) = 0; +}; + +inline +Exec_query::Code::Code(const SqlSpecs& sqlSpecs) : + m_sqlSpecs(sqlSpecs) +{ +} + +inline const SqlSpecs& +Exec_query::Code::sqlSpecs() const +{ + return m_sqlSpecs; +} + +inline +Exec_query::Data::Data(Exec_query* node, const SqlRow& sqlRow) : + ResultSet(sqlRow), + m_node(node), + m_extRow(0), + m_extPos(0) +{ +} + +inline const SqlRow& +Exec_query::Data::sqlRow() const +{ + return static_cast<const SqlRow&>(m_dataRow); +} + +inline ExtRow* +Exec_query::Data::extRow() const +{ + return m_extRow; +} + +inline bool +Exec_query::Data::fetchImpl(Ctx& ctx, Ctl& ctl) +{ + return m_node->fetchImpl(ctx, ctl); +} + +inline +Exec_query::Exec_query(Exec_root* root) : + Exec_stmt(root) +{ +} + +// children + +inline const Exec_query::Code& +Exec_query::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_query::Data& +Exec_query::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_count.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_count.cpp new file mode 100644 index 00000000000..f52c41df802 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_count.cpp @@ -0,0 +1,177 @@ +/* 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/StmtArea.hpp> +#include <dictionary/DictTable.hpp> +#include <dictionary/DictColumn.hpp> +#include "Code_query_count.hpp" +#include "Code_column.hpp" +#include "Code_expr_row.hpp" +#include "Code_root.hpp" + +// Plan_query_count + +Plan_query_count::~Plan_query_count() +{ +} + +Plan_expr_row* +Plan_query_count::getRow() +{ + ctx_assert(m_exprRow != 0); + return m_exprRow; +} + +Plan_base* +Plan_query_count::analyze(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_exprRow != 0); + ctl.m_aggrok = true; + ctl.m_aggrin = false; + m_exprRow->analyze(ctx, ctl); + ctl.m_aggrok = false; + if (! ctx.ok()) + return 0; + ctx_assert(m_query != 0); + m_query->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + return this; +} + +Exec_base* +Plan_query_count::codegen(Ctx& ctx, Ctl& ctl) +{ + // create code for the subquery + ctx_assert(m_query != 0); + Exec_query* execQuery = static_cast<Exec_query*>(m_query->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execQuery != 0); + // create code for the row based on query code + ctx_assert(m_exprRow != 0); + ctl.m_execQuery = execQuery; + Exec_expr_row* execRow = static_cast<Exec_expr_row*>(m_exprRow->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execRow != 0); + Exec_query_count* exec = new Exec_query_count(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + // re-use SqlSpecs from the row + const SqlSpecs& sqlSpecs = execRow->getCode().sqlSpecs(); + Exec_query_count::Code& code = *new Exec_query_count::Code(sqlSpecs); + exec->setCode(code); + exec->setQuery(execQuery); + exec->setRow(execRow); + return exec; +} + +void +Plan_query_count::print(Ctx& ctx) +{ + ctx.print(" [query_count"); + Plan_base* a[] = { m_query, m_exprRow }; + printList(ctx, a, sizeof(a)/sizeof(a[0])); + ctx.print("]"); +} + +// Exec_query_count + +Exec_query_count::Code::~Code() +{ +} + +Exec_query_count::Data::~Data() +{ +} + +Exec_query_count::~Exec_query_count() +{ +} + +const Exec_query* +Exec_query_count::getRawQuery() const +{ + ctx_assert(m_query != 0); + return m_query; +} + +void +Exec_query_count::alloc(Ctx& ctx, Ctl& ctl) +{ + // allocate the subquery + ctx_assert(m_query != 0); + m_query->alloc(ctx, ctl); + // allocate the row based on subquery data + ctx_assert(m_exprRow != 0); + ctl.m_query = m_query; + m_exprRow->alloc(ctx, ctl); + if (! ctx.ok()) + return; + // re-use SqlRow from the expression row + const SqlRow& sqlRow = m_exprRow->getData().sqlRow(); + Data& data = *new Data(this, sqlRow); + setData(data); +} + +void +Exec_query_count::execImpl(Ctx& ctx, Ctl& ctl) +{ + Data& data = getData(); + // zero counters + ctx_assert(m_exprRow != 0); + m_exprRow->close(ctx); + data.m_done = false; + // execute the subquery + ctx_assert(m_query != 0); + m_query->execute(ctx, ctl); +} + +bool +Exec_query_count::fetchImpl(Ctx& ctx, Ctl& ctl) +{ + Data& data = getData(); + // returns one row only + if (data.m_done) + return false; + ctx_assert(m_query != 0 && m_exprRow != 0); + while (m_query->fetch(ctx, ctl)) { + // accumulate values + m_exprRow->evaluate(ctx, ctl); + if (! ctx.ok()) + return false; + } + data.m_done = true; + return true; +} + +void +Exec_query_count::close(Ctx& ctx) +{ + ctx_assert(m_query != 0); + m_query->close(ctx); + ctx_assert(m_exprRow != 0); + m_exprRow->close(ctx); +} + +void +Exec_query_count::print(Ctx& ctx) +{ + ctx.print(" [query_count"); + Exec_base* a[] = { m_query }; + printList(ctx, a, 1); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_count.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_count.hpp new file mode 100644 index 00000000000..a094eba4519 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_count.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_CODEGEN_Code_query_count_hpp +#define ODBC_CODEGEN_Code_query_count_hpp + +#include <common/common.hpp> +#include "Code_query.hpp" +#include "Code_expr_row.hpp" +#include "Code_root.hpp" + +class Ctx; + +/** + * @class Plan_query_count + * @brief Select count and other aggregates (no group by) + */ +class Plan_query_count : public Plan_query { +public: + Plan_query_count(Plan_root* root); + virtual ~Plan_query_count(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setQuery(Plan_query* query); + void setRow(Plan_expr_row* exprRow); +protected: + Plan_expr_row* getRow(); + Plan_query* m_query; + Plan_expr_row* m_exprRow; +}; + +inline +Plan_query_count::Plan_query_count(Plan_root* root) : + Plan_query(root), + m_query(0), + m_exprRow(0) +{ +} + +// children + +inline void +Plan_query_count::setQuery(Plan_query* query) +{ + ctx_assert(query != 0); + m_query = query; +} + +inline void +Plan_query_count::setRow(Plan_expr_row* exprRow) +{ + ctx_assert(exprRow != 0); + m_exprRow = exprRow; +} + +/** + * @class Exec_query_count + * @brief Select count and other aggregates (no group by) + */ +class Exec_query_count : public Exec_query { +public: + class Code : public Exec_query::Code { + public: + Code(const SqlSpecs& sqlSpecs); + virtual ~Code(); + protected: + friend class Exec_query_count; + // sets reference to Sqlspecs from the row + }; + class Data : public Exec_query::Data { + public: + Data(Exec_query_count* node, const SqlRow& sqlRow); + virtual ~Data(); + protected: + friend class Exec_query_count; + // sets reference to SqlRow from the row + bool m_done; // returns one row + }; + Exec_query_count(Exec_root* root); + virtual ~Exec_query_count(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + bool fetchImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setQuery(Exec_query* query); + void setRow(Exec_expr_row* exprRow); + const Exec_query* getRawQuery() const; +protected: + Exec_query* m_query; + Exec_expr_row* m_exprRow; +}; + +inline +Exec_query_count::Code::Code(const SqlSpecs& sqlSpecs) : + Exec_query::Code(sqlSpecs) +{ +} + +inline +Exec_query_count::Data::Data(Exec_query_count* node, const SqlRow& sqlRow) : + Exec_query::Data(node, sqlRow) +{ +} + +inline +Exec_query_count::Exec_query_count(Exec_root* root) : + Exec_query(root), + m_query(0), + m_exprRow(0) +{ +} + +// children + +inline const Exec_query_count::Code& +Exec_query_count::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_query_count::Data& +Exec_query_count::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_query_count::setQuery(Exec_query* query) +{ + ctx_assert(query != 0); + m_query = query; +} + +inline void +Exec_query_count::setRow(Exec_expr_row* exprRow) +{ + ctx_assert(m_exprRow == 0 && exprRow != 0); + m_exprRow = exprRow; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_distinct.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_distinct.cpp new file mode 100644 index 00000000000..4cbfbfe812d --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_distinct.cpp @@ -0,0 +1,204 @@ +/* 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 <algorithm> +#include "Code_query_distinct.hpp" +#include "Code_root.hpp" + +// Plan_query_distinct + +Plan_query_distinct::~Plan_query_distinct() +{ +} + +Plan_expr_row* +Plan_query_distinct::getRow() +{ + ctx_assert(m_query != 0); + return m_query->getRow(); +} + +Plan_base* +Plan_query_distinct::analyze(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_query != 0); + m_query->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + return this; +} + +Exec_base* +Plan_query_distinct::codegen(Ctx& ctx, Ctl& ctl) +{ + // create code for the subquery + ctx_assert(m_query != 0); + Exec_query* execQuery = static_cast<Exec_query*>(m_query->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execQuery != 0); + // the exec node + Exec_query_distinct* exec = new Exec_query_distinct(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + // re-use SqlSpecs from subquery + const Exec_query::Code& codeQuery = execQuery->getCode(); + const SqlSpecs& sqlSpecs = codeQuery.sqlSpecs(); + Exec_query_distinct::Code& code = *new Exec_query_distinct::Code(sqlSpecs); + exec->setCode(code); + exec->setQuery(execQuery); + return exec; +} + +void +Plan_query_distinct::print(Ctx& ctx) +{ + ctx.print(" [query_distinct"); + Plan_base* a[] = { m_query }; + printList(ctx, a, 1); + ctx.print("]"); +} + +// Exec_query_distinct + +Exec_query_distinct::Code::~Code() +{ +} + +Exec_query_distinct::Data::~Data() +{ + for (DistinctList::iterator i = m_groupList.begin(); i != m_groupList.end(); i++) { + delete (*i).first; + } +} + +Exec_query_distinct::~Exec_query_distinct() +{ +} + +const Exec_query* +Exec_query_distinct::getRawQuery() const +{ + ctx_assert(m_query != 0); + return m_query->getRawQuery(); +} + +void +Exec_query_distinct::alloc(Ctx& ctx, Ctl& ctl) +{ + // allocate subquery + ctx_assert(m_query != 0); + m_query->alloc(ctx, ctl); + if (! ctx.ok()) + return; + Data& data = *new Data(this, getCode().sqlSpecs()); + setData(data); +} + +void +Exec_query_distinct::execImpl(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_query != 0); + m_query->execute(ctx, ctl); +} + +bool +DistinctLess::operator()(const SqlRow* s1, const SqlRow* s2) const +{ + ctx_assert(s1 != 0 && s2 != 0); + const SqlRow& r1 = *s1; + const SqlRow& r2 = *s2; + for (unsigned i = 1; i <= r1.count(); i++) { + const SqlField& f1 = r1.getEntry(i); + const SqlField& f2 = r2.getEntry(i); + // nulls last is default in oracle + const bool f1null = f1.sqlNull(); + const bool f2null = f2.sqlNull(); + if (f1null && f2null) + continue; + if (! f1null && f2null) + return true; + if (f1null && ! f2null) + return false; + if (f1.less(f2)) + return true; + if (f2.less(f1)) + return false; + } + return false; +} + +bool +Exec_query_distinct::fetchImpl(Ctx& ctx, Ctl& ctl) +{ + Data& data = getData(); + ctx_assert(m_query != 0); + if (! data.m_grouped) { + // read and group all rows + while (m_query->fetch(ctx, ctl)) { + const SqlRow* dataRow = &m_query->getData().sqlRow(); + DistinctList::iterator i = data.m_groupList.find(dataRow); + if (i != data.m_groupList.end()) + continue; + unsigned index = data.m_count++; + dataRow = dataRow->copy(); + const DistinctList::value_type groupPair(dataRow, index); + data.m_groupList.insert(groupPair); + data.m_groupVector.push_back(dataRow); + } + if (! ctx.ok()) + return false; + data.m_index = 0; + data.m_grouped = true; + } + ctx_assert(data.m_count == data.m_groupVector.size()); + if (data.m_index < data.m_count) { + const SqlRow* currRow = data.m_groupVector[data.m_index]; + // make our SqlRow reference to it + for (unsigned i = 1; i <= data.m_sqlRow.count(); i++) { + const SqlField& currField = currRow->getEntry(i); + SqlSpec sqlSpec(currField.sqlSpec(), SqlSpec::Reference); + SqlField sqlField(sqlSpec, &currField); + data.m_sqlRow.setEntry(i, sqlField); + } + data.m_index++; + return true; + } + return false; +} + +void +Exec_query_distinct::close(Ctx& ctx) +{ + Data& data = getData(); + ctx_assert(m_query != 0); + m_query->close(ctx); + data.m_grouped = false; + data.m_count = 0; + for (DistinctList::iterator i = data.m_groupList.begin(); i != data.m_groupList.end(); i++) { + delete (*i).first; + } + data.m_groupList.clear(); + data.m_groupVector.clear(); +} + +void +Exec_query_distinct::print(Ctx& ctx) +{ + ctx.print(" [query_distinct"); + Exec_base* a[] = { m_query }; + printList(ctx, a, 1); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_distinct.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_distinct.hpp new file mode 100644 index 00000000000..62c46bda901 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_distinct.hpp @@ -0,0 +1,165 @@ +/* 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_Code_query_distinct_hpp +#define ODBC_CODEGEN_Code_query_distinct_hpp + +#include <functional> +#include <common/common.hpp> +#include "Code_query.hpp" +#include "Code_expr_row.hpp" +#include "Code_pred.hpp" + +/** + * @class Plan_query_distinct + * @brief Group-by node in PlanTree + */ +class Plan_query_distinct : public Plan_query { +public: + Plan_query_distinct(Plan_root* root); + virtual ~Plan_query_distinct(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setQuery(Plan_query* query); + Plan_expr_row* getRow(); +protected: + Plan_query* m_query; +}; + +inline +Plan_query_distinct::Plan_query_distinct(Plan_root* root) : + Plan_query(root), + m_query(0) +{ +} + +// children + +inline void +Plan_query_distinct::setQuery(Plan_query* query) +{ + ctx_assert(query != 0); + m_query = query; +} + +/** + * Distinct preserves order of input rows so we use 2 data structures: + * map<row> = index and vector<index> = row (index >= 0). + */ + +class Exec_query_distinct; + +struct DistinctLess : std::binary_function<const SqlRow*, const SqlRow*, bool> { + bool operator()(const SqlRow* s1, const SqlRow* s2) const; +}; + +typedef std::map<const SqlRow*, unsigned, DistinctLess> DistinctList; + +typedef std::vector<const SqlRow*> DistinctVector; + +/** + * @class Exec_query_distinct + * @brief Group-by node in ExecTree + */ +class Exec_query_distinct : public Exec_query { +public: + class Code : public Exec_query::Code { + public: + Code(const SqlSpecs& sqlSpecs); + virtual ~Code(); + protected: + friend class Exec_query_distinct; + // sets reference to Sqlspecs from subquery + }; + class Data : public Exec_query::Data { + public: + Data(Exec_query_distinct* node, const SqlSpecs& sqlSpecs); + virtual ~Data(); + protected: + friend class Exec_query_distinct; + SqlRow m_sqlRow; // current row + bool m_grouped; // fetch and group-by done + unsigned m_count; + DistinctList m_groupList; + DistinctVector m_groupVector; + unsigned m_index; + }; + Exec_query_distinct(Exec_root* root); + virtual ~Exec_query_distinct(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + bool fetchImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setQuery(Exec_query* query); + const Exec_query* getRawQuery() const; +protected: + friend class Exec_query; + Exec_query* m_query; +}; + +inline +Exec_query_distinct::Code::Code(const SqlSpecs& sqlSpecs) : + Exec_query::Code(sqlSpecs) +{ +} + +inline +Exec_query_distinct::Data::Data(Exec_query_distinct* node, const SqlSpecs& sqlSpecs) : + Exec_query::Data(node, m_sqlRow), + m_sqlRow(sqlSpecs), + m_grouped(false), + m_count(0), + m_index(0) +{ +} + +inline +Exec_query_distinct::Exec_query_distinct(Exec_root* root) : + Exec_query(root), + m_query(0) +{ +} + +// children + +inline const Exec_query_distinct::Code& +Exec_query_distinct::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_query_distinct::Data& +Exec_query_distinct::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_query_distinct::setQuery(Exec_query* query) +{ + ctx_assert(m_query == 0 && query != 0); + m_query = query; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_filter.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_filter.cpp new file mode 100644 index 00000000000..934a24d182d --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_filter.cpp @@ -0,0 +1,161 @@ +/* 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 "Code_query_filter.hpp" +#include "Code_query_join.hpp" +#include "Code_query_scan.hpp" +#include "Code_root.hpp" + +// Plan_query_filter + +Plan_query_filter::~Plan_query_filter() +{ +} + +Plan_base* +Plan_query_filter::analyze(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_query != 0); + m_query->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + ctx_assert(m_pred != 0); + m_pred->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + return this; +} + +Exec_base* +Plan_query_filter::codegen(Ctx& ctx, Ctl& ctl) +{ + // generate code for the subquery + ctx_assert(m_query != 0); + Exec_query* execQuery = static_cast<Exec_query*>(m_query->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execQuery != 0); + // create code for the predicate based on query code + Exec_pred* execPred = 0; + ctl.m_execQuery = execQuery; + ctx_assert(m_topTable != 0); + ctl.m_topTable = m_topTable; + ctx_assert(m_pred != 0); + execPred = static_cast<Exec_pred*>(m_pred->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execPred != 0); + ctl.m_topTable = 0; + // re-use SqlSpecs from subquery + const Exec_query::Code& codeQuery = execQuery->getCode(); + const SqlSpecs& sqlSpecs = codeQuery.sqlSpecs(); + Exec_query_filter* exec = new Exec_query_filter(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + Exec_query_filter::Code& code = *new Exec_query_filter::Code(sqlSpecs); + exec->setCode(code); + exec->setQuery(execQuery); + exec->setPred(execPred); + return exec; +} + +void +Plan_query_filter::print(Ctx& ctx) +{ + ctx.print(" [query_filter"); + Plan_base* a[] = { m_query, m_pred }; + printList(ctx, a, 2); + ctx.print("]"); +} + +// Exec_query_filter + +Exec_query_filter::Code::~Code() +{ +} + +Exec_query_filter::Data::~Data() +{ +} + +Exec_query_filter::~Exec_query_filter() +{ +} + +void +Exec_query_filter::alloc(Ctx& ctx, Ctl& ctl) +{ + // allocate the subquery + ctx_assert(m_query != 0); + m_query->alloc(ctx, ctl); + if (! ctx.ok()) + return; + // allocate the predicate + ctl.m_query = m_query; + ctx_assert(m_pred != 0); + m_pred->alloc(ctx, ctl); + if (! ctx.ok()) + return; + // re-use SqlRow from subquery + Exec_query::Data& dataQuery = m_query->getData(); + Data& data = *new Data(this, dataQuery.sqlRow()); + setData(data); +} + +void +Exec_query_filter::execImpl(Ctx& ctx, Ctl& ctl) +{ + // execute subquery + ctx_assert(m_query != 0); + m_query->execute(ctx, ctl); +} + +bool +Exec_query_filter::fetchImpl(Ctx& ctx, Ctl& ctl) +{ + // invoke fetch on subquery until predicate is true + ctx_assert(m_query != 0); + while (m_query->fetch(ctx, ctl)) { + ctx_assert(m_pred != 0); + m_pred->evaluate(ctx, ctl); + if (! ctx.ok()) + return false; + if (m_pred->getData().getValue() == Pred_value_true) { + ctl.m_postEval = true; + m_pred->evaluate(ctx, ctl); + ctl.m_postEval = false; + return true; + } + } + return false; +} + +void +Exec_query_filter::close(Ctx& ctx) +{ + ctx_assert(m_query != 0); + m_query->close(ctx); + ctx_assert(m_pred != 0); + m_pred->close(ctx); +} + +void +Exec_query_filter::print(Ctx& ctx) +{ + ctx.print(" [query_filter"); + Exec_base* a[] = { m_query, m_pred }; + printList(ctx, a, 2); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_filter.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_filter.hpp new file mode 100644 index 00000000000..60cbf0f86a7 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_filter.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_CODEGEN_Code_query_filter_hpp +#define ODBC_CODEGEN_Code_query_filter_hpp + +#include <common/common.hpp> +#include "Code_query.hpp" +#include "Code_table_list.hpp" +#include "Code_pred.hpp" + +/** + * @class Plan_query_filter + * @brief Filter node in PlanTree + */ +class Plan_query_filter : public Plan_query { +public: + Plan_query_filter(Plan_root* root); + virtual ~Plan_query_filter(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setQuery(Plan_query* query); + void setPred(Plan_pred* pred); +protected: + friend class Plan_select; + friend class Plan_update; + friend class Plan_delete; + Plan_query* m_query; + Plan_pred* m_pred; + Plan_table* m_topTable; // top level table for interpreted progs +}; + +inline +Plan_query_filter::Plan_query_filter(Plan_root* root) : + Plan_query(root), + m_query(0), + m_pred(0), + m_topTable(0) +{ +} + +// children + +inline void +Plan_query_filter::setQuery(Plan_query* query) +{ + ctx_assert(query != 0); + m_query = query; +} + +inline void +Plan_query_filter::setPred(Plan_pred* pred) +{ + ctx_assert(pred != 0); + m_pred = pred; +} + +/** + * @class Exec_query_filter + * @brief Filter node in ExecTree + */ +class Exec_query_filter : public Exec_query { +public: + class Code : public Exec_query::Code { + public: + Code(const SqlSpecs& sqlSpecs); + virtual ~Code(); + protected: + friend class Exec_query_filter; + // sets reference to SqlSpecs from subquery + }; + class Data : public Exec_query::Data { + public: + Data(Exec_query_filter* node, const SqlRow& sqlRow); + virtual ~Data(); + protected: + friend class Exec_query_filter; + // sets reference to SqlRow from subquery + }; + Exec_query_filter(Exec_root* root); + virtual ~Exec_query_filter(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + bool fetchImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setQuery(Exec_query* query); + void setPred(Exec_pred* pred); +protected: + Exec_query* m_query; + Exec_pred* m_pred; +}; + +inline +Exec_query_filter::Code::Code(const SqlSpecs& sqlSpecs) : + Exec_query::Code(sqlSpecs) +{ +} + +inline +Exec_query_filter::Data::Data(Exec_query_filter* node, const SqlRow& sqlRow) : + Exec_query::Data(node, sqlRow) +{ +} + +inline +Exec_query_filter::Exec_query_filter(Exec_root* root) : + Exec_query(root), + m_query(0), + m_pred(0) +{ +} + +// children + +inline const Exec_query_filter::Code& +Exec_query_filter::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_query_filter::Data& +Exec_query_filter::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_query_filter::setQuery(Exec_query* query) +{ + ctx_assert(query != 0); + m_query = query; +} + +inline void +Exec_query_filter::setPred(Exec_pred* pred) +{ + ctx_assert(pred != 0); + m_pred = pred; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_group.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_group.cpp new file mode 100644 index 00000000000..c3019efaa85 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_group.cpp @@ -0,0 +1,301 @@ +/* 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 <algorithm> +#include "Code_query_group.hpp" +#include "Code_root.hpp" + +// Plan_query_group + +Plan_query_group::~Plan_query_group() +{ +} + +Plan_expr_row* +Plan_query_group::getRow() +{ + ctx_assert(m_dataRow != 0); + return m_dataRow; +} + +Plan_base* +Plan_query_group::analyze(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_query != 0); + m_query->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + ctx_assert(m_dataRow != 0); + m_dataRow->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + ctx_assert(m_groupRow != 0); + m_groupRow->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + if (m_havingPred != 0) { + ctl.m_having = true; + m_havingPred->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + ctl.m_having = false; + } + return this; +} + +Exec_base* +Plan_query_group::codegen(Ctx& ctx, Ctl& ctl) +{ + // create code for the subquery + ctx_assert(m_query != 0); + Exec_query* execQuery = static_cast<Exec_query*>(m_query->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execQuery != 0); + // create code for the rows based on query code + ctl.m_execQuery = execQuery; + ctx_assert(m_dataRow != 0); + Exec_expr_row* execDataRow = static_cast<Exec_expr_row*>(m_dataRow->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execDataRow != 0); + ctx_assert(m_groupRow != 0); + Exec_expr_row* execGroupRow = static_cast<Exec_expr_row*>(m_groupRow->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execGroupRow != 0); + Exec_pred* execHavingPred = 0; + if (m_havingPred != 0) { + ctl.m_having = true; + execHavingPred = static_cast<Exec_pred*>(m_havingPred->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execHavingPred != 0); + ctl.m_having = false; + } + // the exec node + Exec_query_group* exec = new Exec_query_group(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + // re-use SqlSpecs from data row + const SqlSpecs& sqlSpecs = execDataRow->getCode().sqlSpecs(); + Exec_query_group::Code& code = *new Exec_query_group::Code(sqlSpecs); + exec->setCode(code); + exec->setQuery(execQuery); + exec->setDataRow(execDataRow); + exec->setGroupRow(execGroupRow); + if (execHavingPred != 0) + exec->setHavingPred(execHavingPred); + return exec; +} + +void +Plan_query_group::print(Ctx& ctx) +{ + ctx.print(" [query_group"); + Plan_base* a[] = { m_query, m_dataRow, m_groupRow }; + printList(ctx, a, 3); + ctx.print("]"); +} + +// Exec_query_group + +Exec_query_group::Code::~Code() +{ +} + +Exec_query_group::Data::~Data() +{ + for (GroupList::iterator i = m_groupList.begin(); i != m_groupList.end(); i++) { + delete (*i).first; + } +} + +Exec_query_group::~Exec_query_group() +{ +} + +const Exec_query* +Exec_query_group::getRawQuery() const +{ + ctx_assert(m_query != 0); + return m_query; +} + +void +Exec_query_group::alloc(Ctx& ctx, Ctl& ctl) +{ + // allocate subquery + ctx_assert(m_query != 0); + m_query->alloc(ctx, ctl); + if (! ctx.ok()) + return; + // allocate rows based on subquery data + ctl.m_query = m_query; + ctx_assert(m_dataRow != 0); + m_dataRow->alloc(ctx, ctl); + if (! ctx.ok()) + return; + ctx_assert(m_groupRow != 0); + m_groupRow->alloc(ctx, ctl); + if (! ctx.ok()) + return; + if (m_havingPred != 0) { + m_havingPred->alloc(ctx, ctl); + if (! ctx.ok()) + return; + } + Data& data = *new Data(this, getCode().sqlSpecs()); + setData(data); +} + +void +Exec_query_group::execImpl(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_query != 0); + m_query->execute(ctx, ctl); +} + +bool +GroupLess::operator()(const SqlRow* s1, const SqlRow* s2) const +{ + ctx_assert(s1 != 0 && s2 != 0); + const SqlRow& r1 = *s1; + const SqlRow& r2 = *s2; + for (unsigned i = 1; i <= r1.count(); i++) { + const SqlField& f1 = r1.getEntry(i); + const SqlField& f2 = r2.getEntry(i); + // nulls last is default in oracle + const bool f1null = f1.sqlNull(); + const bool f2null = f2.sqlNull(); + if (f1null && f2null) + continue; + if (! f1null && f2null) + return true; + if (f1null && ! f2null) + return false; + if (f1.less(f2)) + return true; + if (f2.less(f1)) + return false; + } + return false; +} + +bool +Exec_query_group::fetchImpl(Ctx& ctx, Ctl& ctl) +{ + Data& data = getData(); + ctx_assert(m_query != 0 && m_groupRow != 0); + if (! data.m_grouped) { + // read and group all rows + while (m_query->fetch(ctx, ctl)) { + // evaluate and insert group-by values + m_groupRow->evaluate(ctx, ctl); + if (! ctx.ok()) + return false; + const SqlRow* groupRow = 0; + unsigned index = 0; + bool init; + GroupList::iterator i = data.m_groupList.find(&m_groupRow->getData().sqlRow()); + if (i == data.m_groupList.end()) { + groupRow = m_groupRow->getData().sqlRow().copy(); + index = ++data.m_count; + const GroupList::value_type groupPair(groupRow, index); + data.m_groupList.insert(groupPair); + init = true; + } else { + groupRow = (*i).first; + index = (*i).second; + ctx_assert(groupRow != 0 && index != 0); + init = false; + } + // evaluate rows saving expression values at index position + ctl.m_groupIndex = index; + ctl.m_groupInit = init; + m_dataRow->evaluate(ctx, ctl); + if (! ctx.ok()) + return false; + if (m_havingPred != 0) { + m_havingPred->evaluate(ctx, ctl); + if (! ctx.ok()) + return false; + } + if (ctl.m_sortRow != 0) { + ctl.m_sortRow->evaluate(ctx, ctl); + if (! ctx.ok()) + return false; + } + ctl.m_groupIndex = 0; + } + if (! ctx.ok()) + return false; + data.m_iterator = data.m_groupList.begin(); + data.m_grouped = true; + } + while (data.m_iterator != data.m_groupList.end()) { + const SqlRow* groupRow = (*data.m_iterator).first; + const unsigned index = (*data.m_iterator).second; + ctx_assert(groupRow != 0 && index != 0); + if (m_havingPred != 0) { + Pred_value v = m_havingPred->getData().groupValue(index); + if (v != Pred_value_true) { + data.m_iterator++; + continue; + } + } + // make our SqlRow reference to the saved values + for (unsigned i = 1; i <= data.m_sqlRow.count(); i++) { + const SqlField& currField = m_dataRow->getExpr(i)->getData().groupField(index); + SqlSpec sqlSpec(currField.sqlSpec(), SqlSpec::Reference); + SqlField sqlField(sqlSpec, &currField); + data.m_sqlRow.setEntry(i, sqlField); + } + // send group index up for possible order by + ctl.m_groupIndex = index; + data.m_iterator++; + return true; + } + return false; +} + +void +Exec_query_group::close(Ctx& ctx) +{ + Data& data = getData(); + ctx_assert(m_query != 0); + m_query->close(ctx); + ctx_assert(m_dataRow != 0); + m_dataRow->close(ctx); + ctx_assert(m_groupRow != 0); + m_groupRow->close(ctx); + if (m_havingPred != 0) + m_havingPred->close(ctx); + data.m_grouped = false; + data.m_count = 0; + for (GroupList::iterator i = data.m_groupList.begin(); i != data.m_groupList.end(); i++) { + delete (*i).first; + } + data.m_groupList.clear(); +} + +void +Exec_query_group::print(Ctx& ctx) +{ + ctx.print(" [query_group"); + Exec_base* a[] = { m_query, m_dataRow, m_groupRow }; + printList(ctx, a, 3); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_group.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_group.hpp new file mode 100644 index 00000000000..e79022c5284 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_group.hpp @@ -0,0 +1,221 @@ +/* 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_Code_query_group_hpp +#define ODBC_CODEGEN_Code_query_group_hpp + +#include <functional> +#include <common/common.hpp> +#include "Code_query.hpp" +#include "Code_expr_row.hpp" +#include "Code_pred.hpp" + +/** + * @class Plan_query_group + * @brief Group-by node in PlanTree + */ +class Plan_query_group : public Plan_query { +public: + Plan_query_group(Plan_root* root); + virtual ~Plan_query_group(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setQuery(Plan_query* query); + void setDataRow(Plan_expr_row* dataRow); + void setGroupRow(Plan_expr_row* groupRow); + void setHavingPred(Plan_pred* havingPred); + Plan_expr_row* getRow(); +protected: + Plan_query* m_query; + Plan_expr_row* m_dataRow; + Plan_expr_row* m_groupRow; + Plan_pred* m_havingPred; +}; + +inline +Plan_query_group::Plan_query_group(Plan_root* root) : + Plan_query(root), + m_query(0), + m_dataRow(0), + m_groupRow(0), + m_havingPred(0) +{ +} + +// children + +inline void +Plan_query_group::setQuery(Plan_query* query) +{ + ctx_assert(query != 0); + m_query = query; +} + +inline void +Plan_query_group::setDataRow(Plan_expr_row* dataRow) +{ + ctx_assert(dataRow != 0); + m_dataRow = dataRow; +} + +inline void +Plan_query_group::setGroupRow(Plan_expr_row* groupRow) +{ + ctx_assert(groupRow != 0); + m_groupRow = groupRow; +} + +inline void +Plan_query_group::setHavingPred(Plan_pred* havingPred) +{ + ctx_assert(havingPred != 0); + m_havingPred = havingPred; +} + +/** + * Group-by uses a std::map. Key is values grouped by. Data is unique index + * (starting at 1) into arrays in expression data. + */ + +class Exec_query_group; + +struct GroupLess : std::binary_function<const SqlRow*, const SqlRow*, bool> { + bool operator()(const SqlRow* s1, const SqlRow* s2) const; +}; + +typedef std::map<const SqlRow*, unsigned, GroupLess> GroupList; + +/** + * @class Exec_query_group + * @brief Group-by node in ExecTree + */ +class Exec_query_group : public Exec_query { +public: + class Code : public Exec_query::Code { + public: + Code(const SqlSpecs& sqlSpecs); + virtual ~Code(); + protected: + friend class Exec_query_group; + // sets reference to Sqlspecs from subquery + }; + class Data : public Exec_query::Data { + public: + Data(Exec_query_group* node, const SqlSpecs& sqlSpecs); + virtual ~Data(); + protected: + friend class Exec_query_group; + SqlRow m_sqlRow; // current row + bool m_grouped; // fetch and group-by done + unsigned m_count; + GroupList m_groupList; + GroupList::iterator m_iterator; + }; + Exec_query_group(Exec_root* root); + virtual ~Exec_query_group(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + bool fetchImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setQuery(Exec_query* query); + void setDataRow(Exec_expr_row* dataRow); + void setGroupRow(Exec_expr_row* groupRow); + void setHavingPred(Exec_pred* havingPred); + const Exec_query* getRawQuery() const; +protected: + friend class Exec_query; + Exec_query* m_query; + Exec_expr_row* m_dataRow; + Exec_expr_row* m_groupRow; + Exec_pred* m_havingPred; +}; + +inline +Exec_query_group::Code::Code(const SqlSpecs& sqlSpecs) : + Exec_query::Code(sqlSpecs) +{ +} + +inline +Exec_query_group::Data::Data(Exec_query_group* node, const SqlSpecs& sqlSpecs) : + Exec_query::Data(node, m_sqlRow), + m_sqlRow(sqlSpecs), + m_grouped(false), + m_count(0) +{ +} + +inline +Exec_query_group::Exec_query_group(Exec_root* root) : + Exec_query(root), + m_query(0), + m_dataRow(0), + m_groupRow(0), + m_havingPred(0) +{ +} + +// children + +inline const Exec_query_group::Code& +Exec_query_group::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_query_group::Data& +Exec_query_group::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_query_group::setQuery(Exec_query* query) +{ + ctx_assert(m_query == 0 && query != 0); + m_query = query; +} + +inline void +Exec_query_group::setDataRow(Exec_expr_row* dataRow) +{ + ctx_assert(m_dataRow == 0 && dataRow != 0); + m_dataRow = dataRow; +} + +inline void +Exec_query_group::setGroupRow(Exec_expr_row* groupRow) +{ + ctx_assert(m_groupRow == 0 && groupRow != 0); + m_groupRow = groupRow; +} + +inline void +Exec_query_group::setHavingPred(Exec_pred* havingPred) +{ + ctx_assert(m_havingPred == 0 && havingPred != 0); + m_havingPred = havingPred; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_index.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_index.cpp new file mode 100644 index 00000000000..ee19d6123cc --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_index.cpp @@ -0,0 +1,186 @@ +/* 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/StmtArea.hpp> +#include <dictionary/DictTable.hpp> +#include <dictionary/DictColumn.hpp> +#include "Code_query_index.hpp" +#include "Code_column.hpp" +#include "Code_expr.hpp" +#include "Code_root.hpp" + +// Plan_query_index + +Plan_query_index::~Plan_query_index() +{ +} + +Plan_base* +Plan_query_index::analyze(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_table != 0); + m_table->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + return this; +} + +Exec_base* +Plan_query_index::codegen(Ctx& ctx, Ctl& ctl) +{ + // set up + ctx_assert(m_table != 0 && m_index != 0); + const BaseString& tableName = m_table->getName(); + ctx_assert(m_index->m_dictIndex != 0); + const DictIndex& dictIndex = *m_index->m_dictIndex; + const BaseString& indexName = dictIndex.getName(); + const unsigned keyCount = m_index->m_keyCount; + const ColumnVector& columns = m_table->exprColumns(); + ctx_assert(columns.size() > 0); + const unsigned attrCount = columns.size() - 1; + // create the code + Exec_query_index::Code& code = *new Exec_query_index::Code(keyCount, attrCount); + code.m_tableName = strcpy(new char[tableName.length() + 1], tableName.c_str()); + code.m_indexName = strcpy(new char[indexName.length() + 1], indexName.c_str()); + // key attributes + code.m_keyId = new NdbAttrId[1 + keyCount]; + code.m_keyId[0] = (NdbAttrId)-1; + for (unsigned k = 1; k <= keyCount; k++) { + const DictColumn* keyColumn = dictIndex.getColumn(k); + const SqlType& sqlType = keyColumn->sqlType(); + SqlSpec sqlSpec(sqlType, SqlSpec::Physical); + code.m_keySpecs.setEntry(k, sqlSpec); + code.m_keyId[k] = k - 1; // index column order + } + // matching expressions + ctx_assert(m_index->m_keyFound); + const ExprVector& keyEq = m_index->m_keyEq; + ctx_assert(keyEq.size() == 1 + keyCount); + code.m_keyMatch = new Exec_expr* [1 + keyCount]; + code.m_keyMatch[0] = 0; + for (unsigned k = 1; k <= keyCount; k++) { + Plan_expr* expr = keyEq[k]; + Exec_expr* execExpr = static_cast<Exec_expr*>(expr->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execExpr != 0); + code.m_keyMatch[k] = execExpr; + } + // queried attributes + code.m_attrId = new NdbAttrId[1 + attrCount]; + code.m_attrId[0] = (NdbAttrId)-1; + for (unsigned i = 1; i <= attrCount; i++) { + Plan_column* column = columns[i]; + ctx_assert(column != 0); + const DictColumn& dictColumn = column->dictColumn(); + const SqlType& sqlType = dictColumn.sqlType(); + SqlSpec sqlSpec(sqlType, SqlSpec::Physical); + code.m_sqlSpecs.setEntry(i, sqlSpec); + code.m_attrId[i] = dictColumn.getAttrId(); + } + // create the exec + Exec_query_index* exec = new Exec_query_index(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + exec->setCode(code); + return exec; +} + +void +Plan_query_index::print(Ctx& ctx) +{ + ctx.print(" [query_index"); + Plan_base* a[] = { m_table }; + printList(ctx, a, 1); + ctx.print("]"); +} + +// Exec_query_index + +Exec_query_index::Code::~Code() +{ + delete[] m_tableName; + delete[] m_keyId; + delete[] m_keyMatch; + delete[] m_attrId; +} + +Exec_query_index::Data::~Data() +{ + delete[] m_recAttr; +} + +Exec_query_index::~Exec_query_index() +{ +} + +void +Exec_query_index::alloc(Ctx& ctx, Ctl& ctl) +{ + const Code& code = getCode(); + // create data + Data& data = *new Data(this, code.sqlSpecs()); + setData(data); + // allocate matching expressions + for (unsigned k = 1; k <= code.m_keyCount; k++) { + Exec_expr* expr = code.m_keyMatch[k]; + ctx_assert(expr != 0); + expr->alloc(ctx, ctl); + if (! ctx.ok()) + return; + } + // needed for isNULL + data.m_recAttr = new NdbRecAttr* [1 + code.m_attrCount]; + for (unsigned i = 0; i <= code.m_attrCount; i++) { + data.m_recAttr[i] = 0; + } +} + +void +Exec_query_index::close(Ctx& ctx) +{ + Data& data = getData(); + if (data.m_con != 0) { + Ndb* const ndb = ndbObject(); + ndb->closeTransaction(data.m_con); + data.m_con = 0; + data.m_op = 0; + data.m_done = true; + ctx_log2(("lookup closed at statement close")); + } +} + +void +Exec_query_index::print(Ctx& ctx) +{ + ctx.print(" [query_index"); + if (m_code != 0) { + const Code& code = getCode(); + ctx.print(" keyId="); + for (unsigned i = 1; i <= code.m_keyCount; i++) { + if (i > 1) + ctx.print(","); + ctx.print("%u", (unsigned)code.m_keyId[i]); + } + ctx.print(" attrId="); + for (unsigned i = 1; i <= code.m_attrCount; i++) { + if (i > 1) + ctx.print(","); + ctx.print("%u", (unsigned)code.m_attrId[i]); + } + ctx.print(" table=%s", code.m_tableName); + } + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_index.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_index.hpp new file mode 100644 index 00000000000..87affd50580 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_index.hpp @@ -0,0 +1,160 @@ +/* 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_Code_query_index_hpp +#define ODBC_CODEGEN_Code_query_index_hpp + +#include <common/common.hpp> +#include "Code_query.hpp" +#include "Code_table.hpp" + +class Ctx; +class StmtArea; +class NdbConnection; +class NdbOperation; +class NdbRecAttr; + +/** + * @class Plan_query_index + * @brief Full select (no where clause) + */ +class Plan_query_index : public Plan_query { +public: + Plan_query_index(Plan_root* root); + virtual ~Plan_query_index(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setTable(Plan_table* table, Plan_table::Index* index); +protected: + Plan_table* m_table; + Plan_table::Index* m_index; +}; + +inline +Plan_query_index::Plan_query_index(Plan_root* root) : + Plan_query(root), + m_table(0), + m_index(0) +{ +} + +// children + +inline void +Plan_query_index::setTable(Plan_table* table, Plan_table::Index* index) +{ + ctx_assert(table != 0 && index != 0 && index == &table->m_indexList[index->m_pos] && index->m_pos != 0); + m_table = table; + m_index = index; +} + +/** + * @class Exec_query_index + * @brief Full select (no where clause) + */ +class Exec_query_index : public Exec_query { +public: + class Code : public Exec_query::Code { + public: + Code(unsigned keyCount, unsigned attrCount); + virtual ~Code(); + protected: + friend class Plan_query_index; + friend class Exec_query_index; + const char* m_tableName; + const char* m_indexName; + unsigned m_keyCount; + SqlSpecs m_keySpecs; // key types + NdbAttrId* m_keyId; + Exec_expr** m_keyMatch; // XXX pointers for now + unsigned m_attrCount; + SqlSpecs m_sqlSpecs; + NdbAttrId* m_attrId; + }; + class Data : public Exec_query::Data { + public: + Data(Exec_query_index* node, const SqlSpecs& sqlSpecs); + virtual ~Data(); + protected: + friend class Exec_query_index; + SqlRow m_sqlRow; + NdbConnection* m_con; + NdbOperation* m_op; + NdbRecAttr** m_recAttr; + bool m_done; // returns one row + }; + Exec_query_index(Exec_root* root); + virtual ~Exec_query_index(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + bool fetchImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; +}; + +inline +Exec_query_index::Code::Code(unsigned keyCount, unsigned attrCount) : + Exec_query::Code(m_sqlSpecs), + m_tableName(0), + m_indexName(0), + m_keyCount(keyCount), + m_keySpecs(keyCount), + m_keyId(0), + m_attrCount(attrCount), + m_sqlSpecs(attrCount), + m_attrId(0) +{ +} + +inline +Exec_query_index::Data::Data(Exec_query_index* node, const SqlSpecs& sqlSpecs) : + Exec_query::Data(node, m_sqlRow), + m_sqlRow(sqlSpecs), + m_con(0), + m_op(0), + m_recAttr(0), + m_done(false) +{ +} + +inline +Exec_query_index::Exec_query_index(Exec_root* root) : + Exec_query(root) +{ +} + +// children + +inline const Exec_query_index::Code& +Exec_query_index::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_query_index::Data& +Exec_query_index::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_join.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_join.cpp new file mode 100644 index 00000000000..89aafe13610 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_join.cpp @@ -0,0 +1,192 @@ +/* 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 "Code_query.hpp" +#include "Code_query_join.hpp" +#include "Code_query_scan.hpp" +#include "Code_root.hpp" + +// Plan_query_join + +Plan_query_join::~Plan_query_join() +{ +} + +Plan_base* +Plan_query_join::analyze(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_inner != 0); + m_inner->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + ctx_assert(m_outer != 0); + m_outer->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + return this; +} + +Exec_base* +Plan_query_join::codegen(Ctx& ctx, Ctl& ctl) +{ + // generate code for subqueries + ctx_assert(m_inner != 0); + Exec_query* execInner = static_cast<Exec_query*>(m_inner->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execInner != 0); + ctx_assert(m_outer != 0); + ctl.m_execQuery = execInner; + Exec_query* execOuter = static_cast<Exec_query*>(m_outer->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execOuter != 0); + // combine sql specs from subqueries + const SqlSpecs& specsInner = execInner->getCode().sqlSpecs(); + const SqlSpecs& specsOuter = execOuter->getCode().sqlSpecs(); + SqlSpecs sqlSpecs(specsInner.count() + specsOuter.count()); + for (unsigned i = 1; i <= specsInner.count(); i++) { + const SqlSpec sqlSpec(specsInner.getEntry(i), SqlSpec::Reference); + sqlSpecs.setEntry(i, sqlSpec); + } + for (unsigned i = 1; i <= specsOuter.count(); i++) { + const SqlSpec sqlSpec(specsOuter.getEntry(i), SqlSpec::Reference); + sqlSpecs.setEntry(specsInner.count() + i, sqlSpec); + } + // create the code + Exec_query_join* exec = new Exec_query_join(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + exec->setInner(execInner); + exec->setOuter(execOuter); + Exec_query_join::Code& code = *new Exec_query_join::Code(sqlSpecs); + exec->setCode(code); + return exec; +} + +void +Plan_query_join::print(Ctx& ctx) +{ + ctx.print(" [query_join"); + Plan_base* a[] = { m_inner, m_outer }; + printList(ctx, a, 2); + ctx.print("]"); +} + +// Exec_query_join + +Exec_query_join::Code::~Code() +{ +} + +Exec_query_join::Data::~Data() +{ +} + +Exec_query_join::~Exec_query_join() +{ +} + +void +Exec_query_join::alloc(Ctx& ctx, Ctl& ctl) +{ + // allocate the subqueries + ctx_assert(m_inner != 0); + m_inner->alloc(ctx, ctl); + if (! ctx.ok()) + return; + ctx_assert(m_outer != 0); + ctl.m_query = m_inner; + m_outer->alloc(ctx, ctl); + if (! ctx.ok()) + return; + // combine data rows from subqueries + const Code& code = getCode(); + const SqlRow& rowInner = m_inner->getData().sqlRow(); + const SqlRow& rowOuter = m_outer->getData().sqlRow(); + SqlRow sqlRow(code.m_sqlSpecs); + for (unsigned i = 1; i <= rowInner.count(); i++) { + const SqlSpec& sqlSpec = code.m_sqlSpecs.getEntry(i); + const SqlField sqlField(sqlSpec, &rowInner.getEntry(i)); + sqlRow.setEntry(i, sqlField); + } + for (unsigned i = 1; i <= rowOuter.count(); i++) { + const SqlSpec& sqlSpec = code.m_sqlSpecs.getEntry(rowInner.count() + i); + const SqlField sqlField(sqlSpec, &rowOuter.getEntry(i)); + sqlRow.setEntry(rowInner.count() + i, sqlField); + } + // create the data + Data& data = *new Data(this, sqlRow); + setData(data); +} + +void +Exec_query_join::execImpl(Ctx& ctx, Ctl& ctl) +{ + // execute only inner query + ctx_assert(m_inner != 0); + m_inner->execute(ctx, ctl); +} + +bool +Exec_query_join::fetchImpl(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_inner != 0); + ctx_assert(m_outer != 0); + if (getData().getState() == ResultSet::State_init) { + // fetch first row from inner + if (! m_inner->fetch(ctx, ctl)) + return false; + } + while (1) { + if (m_outer->getData().getState() == ResultSet::State_end) { + // execute or re-execute outer + Ctl ctl(0); + m_outer->close(ctx); + if (! ctx.ok()) + return false; + m_outer->execute(ctx, ctl); + if (! ctx.ok()) + return false; + } + if (! m_outer->fetch(ctx, ctl)) { + if (! ctx.ok()) + return false; + // fetch next row from inner + if (! m_inner->fetch(ctx, ctl)) + return false; + } + else + return true; + } +} + +void +Exec_query_join::close(Ctx& ctx) +{ + ctx_assert(m_inner != 0); + m_inner->close(ctx); + ctx_assert(m_outer != 0); + m_outer->close(ctx); +} + +void +Exec_query_join::print(Ctx& ctx) +{ + ctx.print(" [query_join"); + Exec_base* a[] = { m_inner, m_outer }; + printList(ctx, a, 2); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_join.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_join.hpp new file mode 100644 index 00000000000..f6ac9205329 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_join.hpp @@ -0,0 +1,159 @@ +/* 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_Code_query_join_hpp +#define ODBC_CODEGEN_Code_query_join_hpp + +#include <common/common.hpp> +#include "Code_query.hpp" +#include "Code_table_list.hpp" +#include "Code_pred.hpp" + +/** + * @class Plan_query_join + * @brief Filter node in PlanTree + */ +class Plan_query_join : public Plan_query { +public: + Plan_query_join(Plan_root* root); + virtual ~Plan_query_join(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setInner(Plan_query* query); + void setOuter(Plan_query* query); +protected: + Plan_query* m_inner; + Plan_query* m_outer; +}; + +inline +Plan_query_join::Plan_query_join(Plan_root* root) : + Plan_query(root), + m_inner(0), + m_outer(0) +{ +} + +// children + +inline void +Plan_query_join::setInner(Plan_query* query) +{ + ctx_assert(query != 0); + m_inner = query; +} + +inline void +Plan_query_join::setOuter(Plan_query* query) +{ + ctx_assert(query != 0); + m_outer = query; +} + +/** + * @class Exec_query_join + * @brief Filter node in ExecTree + */ +class Exec_query_join : public Exec_query { +public: + class Code : public Exec_query::Code { + public: + Code(const SqlSpecs& sqlSpecs); + virtual ~Code(); + protected: + friend class Exec_query_join; + SqlSpecs m_sqlSpecs; + }; + class Data : public Exec_query::Data { + public: + Data(Exec_query_join* node, const SqlRow& sqlRow); + virtual ~Data(); + protected: + friend class Exec_query_join; + SqlRow m_sqlRow; + }; + Exec_query_join(Exec_root* root); + virtual ~Exec_query_join(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + bool fetchImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setInner(Exec_query* query); + void setOuter(Exec_query* query); +protected: + Exec_query* m_inner; + Exec_query* m_outer; +}; + +inline +Exec_query_join::Code::Code(const SqlSpecs& sqlSpecs) : + Exec_query::Code(m_sqlSpecs), + m_sqlSpecs(sqlSpecs) +{ +} + +inline +Exec_query_join::Data::Data(Exec_query_join* node, const SqlRow& sqlRow) : + Exec_query::Data(node, m_sqlRow), + m_sqlRow(sqlRow) +{ +} + +inline +Exec_query_join::Exec_query_join(Exec_root* root) : + Exec_query(root), + m_inner(0), + m_outer(0) +{ +} + +// children + +inline const Exec_query_join::Code& +Exec_query_join::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_query_join::Data& +Exec_query_join::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_query_join::setInner(Exec_query* query) +{ + ctx_assert(query != 0); + m_inner = query; +} + +inline void +Exec_query_join::setOuter(Exec_query* query) +{ + ctx_assert(query != 0); + m_outer = query; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_lookup.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_lookup.cpp new file mode 100644 index 00000000000..bad4199190b --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_lookup.cpp @@ -0,0 +1,184 @@ +/* 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/StmtArea.hpp> +#include <dictionary/DictTable.hpp> +#include <dictionary/DictColumn.hpp> +#include "Code_query_lookup.hpp" +#include "Code_column.hpp" +#include "Code_expr.hpp" +#include "Code_root.hpp" + +// Plan_query_lookup + +Plan_query_lookup::~Plan_query_lookup() +{ +} + +Plan_base* +Plan_query_lookup::analyze(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_table != 0); + m_table->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + return this; +} + +Exec_base* +Plan_query_lookup::codegen(Ctx& ctx, Ctl& ctl) +{ + // set up + ctx_assert(m_table != 0); + const BaseString& tableName = m_table->getName(); + const DictTable& dictTable = m_table->dictTable(); + const unsigned keyCount = dictTable.keyCount(); + const ColumnVector& columns = m_table->exprColumns(); + ctx_assert(columns.size() > 0); + const unsigned attrCount = columns.size() - 1; + // create the code + Exec_query_lookup::Code& code = *new Exec_query_lookup::Code(keyCount, attrCount); + code.m_tableName = strcpy(new char[tableName.length() + 1], tableName.c_str()); + // key attributes + code.m_keyId = new NdbAttrId[1 + keyCount]; + code.m_keyId[0] = (NdbAttrId)-1; + for (unsigned k = 1; k <= keyCount; k++) { + const DictColumn* keyColumn = dictTable.getKey(k); + const SqlType& sqlType = keyColumn->sqlType(); + SqlSpec sqlSpec(sqlType, SqlSpec::Physical); + code.m_keySpecs.setEntry(k, sqlSpec); + code.m_keyId[k] = keyColumn->getAttrId(); + } + // matching expressions + const Plan_table::Index& index = m_table->m_indexList[0]; + ctx_assert(index.m_keyFound); + const ExprVector& keyEq = index.m_keyEq; + ctx_assert(keyEq.size() == 1 + keyCount); + code.m_keyMatch = new Exec_expr* [1 + keyCount]; + code.m_keyMatch[0] = 0; + for (unsigned k = 1; k <= keyCount; k++) { + Plan_expr* expr = keyEq[k]; + Exec_expr* execExpr = static_cast<Exec_expr*>(expr->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execExpr != 0); + code.m_keyMatch[k] = execExpr; + } + // queried attributes + code.m_attrId = new NdbAttrId[1 + attrCount]; + code.m_attrId[0] = (NdbAttrId)-1; + for (unsigned i = 1; i <= attrCount; i++) { + Plan_column* column = columns[i]; + ctx_assert(column != 0); + const DictColumn& dictColumn = column->dictColumn(); + const SqlType& sqlType = dictColumn.sqlType(); + SqlSpec sqlSpec(sqlType, SqlSpec::Physical); + code.m_sqlSpecs.setEntry(i, sqlSpec); + code.m_attrId[i] = dictColumn.getAttrId(); + } + // create the exec + Exec_query_lookup* exec = new Exec_query_lookup(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + exec->setCode(code); + return exec; +} + +void +Plan_query_lookup::print(Ctx& ctx) +{ + ctx.print(" [query_lookup"); + Plan_base* a[] = { m_table }; + printList(ctx, a, 1); + ctx.print("]"); +} + +// Exec_query_lookup + +Exec_query_lookup::Code::~Code() +{ + delete[] m_tableName; + delete[] m_keyId; + delete[] m_keyMatch; + delete[] m_attrId; +} + +Exec_query_lookup::Data::~Data() +{ + delete[] m_recAttr; +} + +Exec_query_lookup::~Exec_query_lookup() +{ +} + +void +Exec_query_lookup::alloc(Ctx& ctx, Ctl& ctl) +{ + const Code& code = getCode(); + // create data + Data& data = *new Data(this, code.sqlSpecs()); + setData(data); + // allocate matching expressions + for (unsigned k = 1; k <= code.m_keyCount; k++) { + Exec_expr* expr = code.m_keyMatch[k]; + ctx_assert(expr != 0); + expr->alloc(ctx, ctl); + if (! ctx.ok()) + return; + } + // needed for isNULL + data.m_recAttr = new NdbRecAttr* [1 + code.m_attrCount]; + for (unsigned i = 0; i <= code.m_attrCount; i++) { + data.m_recAttr[i] = 0; + } +} + +void +Exec_query_lookup::close(Ctx& ctx) +{ + Data& data = getData(); + if (data.m_con != 0) { + Ndb* const ndb = ndbObject(); + ndb->closeTransaction(data.m_con); + data.m_con = 0; + data.m_op = 0; + data.m_done = true; + ctx_log2(("lookup closed at statement close")); + } +} + +void +Exec_query_lookup::print(Ctx& ctx) +{ + ctx.print(" [query_lookup"); + if (m_code != 0) { + const Code& code = getCode(); + ctx.print(" keyId="); + for (unsigned i = 1; i <= code.m_keyCount; i++) { + if (i > 1) + ctx.print(","); + ctx.print("%u", (unsigned)code.m_keyId[i]); + } + ctx.print(" attrId="); + for (unsigned i = 1; i <= code.m_attrCount; i++) { + if (i > 1) + ctx.print(","); + ctx.print("%u", (unsigned)code.m_attrId[i]); + } + ctx.print(" table=%s", code.m_tableName); + } + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_lookup.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_lookup.hpp new file mode 100644 index 00000000000..e66623d4030 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_lookup.hpp @@ -0,0 +1,155 @@ +/* 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_Code_query_lookup_hpp +#define ODBC_CODEGEN_Code_query_lookup_hpp + +#include <common/common.hpp> +#include "Code_query.hpp" +#include "Code_table.hpp" + +class Ctx; +class StmtArea; +class NdbConnection; +class NdbOperation; +class NdbRecAttr; + +/** + * @class Plan_query_lookup + * @brief Full select (no where clause) + */ +class Plan_query_lookup : public Plan_query { +public: + Plan_query_lookup(Plan_root* root); + virtual ~Plan_query_lookup(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setTable(Plan_table* table); +protected: + Plan_table* m_table; +}; + +inline +Plan_query_lookup::Plan_query_lookup(Plan_root* root) : + Plan_query(root), + m_table(0) +{ +} + +// children + +inline void +Plan_query_lookup::setTable(Plan_table* table) +{ + ctx_assert(table != 0); + m_table = table; +} + +/** + * @class Exec_query_lookup + * @brief Full select (no where clause) + */ +class Exec_query_lookup : public Exec_query { +public: + class Code : public Exec_query::Code { + public: + Code(unsigned keyCount, unsigned attrCount); + virtual ~Code(); + protected: + friend class Plan_query_lookup; + friend class Exec_query_lookup; + char* m_tableName; + unsigned m_keyCount; + SqlSpecs m_keySpecs; // key types + NdbAttrId* m_keyId; + Exec_expr** m_keyMatch; // XXX pointers for now + unsigned m_attrCount; + SqlSpecs m_sqlSpecs; + NdbAttrId* m_attrId; + }; + class Data : public Exec_query::Data { + public: + Data(Exec_query_lookup* node, const SqlSpecs& sqlSpecs); + virtual ~Data(); + protected: + friend class Exec_query_lookup; + SqlRow m_sqlRow; + NdbConnection* m_con; + NdbOperation* m_op; + NdbRecAttr** m_recAttr; + bool m_done; // returns one row + }; + Exec_query_lookup(Exec_root* root); + virtual ~Exec_query_lookup(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + bool fetchImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; +}; + +inline +Exec_query_lookup::Code::Code(unsigned keyCount, unsigned attrCount) : + Exec_query::Code(m_sqlSpecs), + m_tableName(0), + m_keyCount(keyCount), + m_keySpecs(keyCount), + m_keyId(0), + m_attrCount(attrCount), + m_sqlSpecs(attrCount), + m_attrId(0) +{ +} + +inline +Exec_query_lookup::Data::Data(Exec_query_lookup* node, const SqlSpecs& sqlSpecs) : + Exec_query::Data(node, m_sqlRow), + m_sqlRow(sqlSpecs), + m_con(0), + m_op(0), + m_recAttr(0), + m_done(false) +{ +} + +inline +Exec_query_lookup::Exec_query_lookup(Exec_root* root) : + Exec_query(root) +{ +} + +// children + +inline const Exec_query_lookup::Code& +Exec_query_lookup::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_query_lookup::Data& +Exec_query_lookup::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_project.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_project.cpp new file mode 100644 index 00000000000..54043ce3d5d --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_project.cpp @@ -0,0 +1,184 @@ +/* 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 "Code_query_project.hpp" +#include "Code_root.hpp" + +// Plan_query_project + +Plan_query_project::~Plan_query_project() +{ +} + +Plan_base* +Plan_query_project::analyze(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_query != 0); + m_query->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + ctx_assert(m_exprRow != 0); + ctl.m_aggrok = true; + ctl.m_aggrin = false; + m_exprRow->analyze(ctx, ctl); + ctl.m_aggrok = false; + if (! ctx.ok()) + return 0; + return this; +} + +Plan_expr_row* +Plan_query_project::getRow() +{ + ctx_assert(m_exprRow != 0); + return m_exprRow; +} + +Exec_base* +Plan_query_project::codegen(Ctx& ctx, Ctl& ctl) +{ + // create code for the subquery + ctx_assert(m_query != 0); + Exec_query* execQuery = static_cast<Exec_query*>(m_query->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execQuery != 0); + // create code for the row based on query code + ctx_assert(m_exprRow != 0); + ctl.m_execQuery = execQuery; + Exec_expr_row* execRow = static_cast<Exec_expr_row*>(m_exprRow->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execRow != 0); + Exec_query_project* exec = new Exec_query_project(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + // re-use SqlSpecs from the row + const SqlSpecs& sqlSpecs = execRow->getCode().sqlSpecs(); + Exec_query_project::Code& code = *new Exec_query_project::Code(sqlSpecs); + code.m_limitOff = m_limitOff; + code.m_limitCnt = m_limitCnt; + exec->setCode(code); + exec->setQuery(execQuery); + exec->setRow(execRow); + return exec; +} + +void +Plan_query_project::print(Ctx& ctx) +{ + ctx.print(" [query_project"); + Plan_base* a[] = { m_query, m_exprRow }; + printList(ctx, a, 2); + ctx.print("]"); +} + +// Exec_query_project + +Exec_query_project::Code::~Code() +{ +} + +Exec_query_project::Data::~Data() +{ +} + +Exec_query_project::~Exec_query_project() +{ +} + +const Exec_query* +Exec_query_project::getRawQuery() const +{ + ctx_assert(m_query != 0); + return m_query; +} + +void +Exec_query_project::alloc(Ctx& ctx, Ctl& ctl) +{ + // allocate the subquery + ctx_assert(m_query != 0); + m_query->alloc(ctx, ctl); + if (! ctx.ok()) + return; + // allocate the row based on subquery data + ctx_assert(m_exprRow != 0); + ctl.m_query = m_query; + m_exprRow->alloc(ctx, ctl); + if (! ctx.ok()) + return; + // re-use SqlRow from the expression row + const SqlRow& sqlRow = m_exprRow->getData().sqlRow(); + Data& data = *new Data(this, sqlRow); + setData(data); +} + +void +Exec_query_project::execImpl(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_query != 0); + m_query->execute(ctx, ctl); +} + +bool +Exec_query_project::fetchImpl(Ctx& ctx, Ctl& ctl) +{ + const Code& code = getCode(); + Data& data = getData(); + ctx_assert(m_query != 0); + while (1) { + if (! m_query->fetch(ctx, ctl)) + return false; + ctx_assert(m_exprRow != 0); + m_exprRow->evaluate(ctx, ctl); + if (! ctx.ok()) + return false; + ctl.m_postEval = true; + m_exprRow->evaluate(ctx, ctl); + ctl.m_postEval = false; + const int n = ++data.m_cnt; + const int o = code.m_limitOff <= 0 ? 0 : code.m_limitOff; + const int c = code.m_limitCnt; + if (n <= o) + continue; + if (c < 0) + break; + if (n - o <= c) + break; + return false; + } + return true; +} + +void +Exec_query_project::close(Ctx& ctx) +{ + Data& data = getData(); + data.m_cnt = 0; + ctx_assert(m_query != 0); + m_query->close(ctx); + ctx_assert(m_exprRow != 0); + m_exprRow->close(ctx); +} + +void +Exec_query_project::print(Ctx& ctx) +{ + ctx.print(" [query_project"); + Exec_base* a[] = { m_query, m_exprRow }; + printList(ctx, a, 2); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_project.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_project.hpp new file mode 100644 index 00000000000..545685ab9df --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_project.hpp @@ -0,0 +1,178 @@ +/* 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_Code_query_project_hpp +#define ODBC_CODEGEN_Code_query_project_hpp + +#include <common/common.hpp> +#include "Code_query.hpp" +#include "Code_expr_row.hpp" + +/** + * @class Plan_query_project + * @brief Project node in PlanTree + */ +class Plan_query_project : public Plan_query { +public: + Plan_query_project(Plan_root* root); + virtual ~Plan_query_project(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setQuery(Plan_query* query); + void setRow(Plan_expr_row* exprRow); + void setLimit(int off, int cnt); +protected: + Plan_expr_row* getRow(); + Plan_query* m_query; + Plan_expr_row* m_exprRow; + int m_limitOff; + int m_limitCnt; +}; + +inline +Plan_query_project::Plan_query_project(Plan_root* root) : + Plan_query(root), + m_query(0), + m_exprRow(0), + m_limitOff(0), + m_limitCnt(-1) +{ +} + +// children + +inline void +Plan_query_project::setQuery(Plan_query* query) +{ + ctx_assert(query != 0); + m_query = query; +} + +inline void +Plan_query_project::setRow(Plan_expr_row* exprRow) +{ + ctx_assert(exprRow != 0); + m_exprRow = exprRow; +} + +inline void +Plan_query_project::setLimit(int off, int cnt) +{ + m_limitOff = off; + m_limitCnt = cnt; +} + +/** + * @class Exec_query_project + * @brief Project node in ExecTree + */ +class Exec_query_project : public Exec_query { +public: + class Code : public Exec_query::Code { + public: + Code(const SqlSpecs& sqlSpecs); + virtual ~Code(); + protected: + friend class Plan_query_project; + friend class Exec_query_project; + // sets reference to Sqlspecs from the row + int m_limitOff; + int m_limitCnt; + }; + class Data : public Exec_query::Data { + public: + Data(Exec_query_project* node, const SqlRow& sqlRow); + virtual ~Data(); + protected: + friend class Exec_query_project; + // sets reference to SqlRow from the row + unsigned m_cnt; + }; + Exec_query_project(Exec_root* root); + virtual ~Exec_query_project(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + bool fetchImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setQuery(Exec_query* query); + void setRow(Exec_expr_row* exprRow); + const Exec_query* getRawQuery() const; +protected: + friend class Exec_query; + Exec_query* m_query; + Exec_expr_row* m_exprRow; +}; + +inline +Exec_query_project::Code::Code(const SqlSpecs& sqlSpecs) : + Exec_query::Code(sqlSpecs), + m_limitOff(0), + m_limitCnt(-1) +{ +} + +inline +Exec_query_project::Data::Data(Exec_query_project* node, const SqlRow& sqlRow) : + Exec_query::Data(node, sqlRow), + m_cnt(0) +{ +} + +inline +Exec_query_project::Exec_query_project(Exec_root* root) : + Exec_query(root), + m_query(0), + m_exprRow(0) +{ +} + +// children + +inline const Exec_query_project::Code& +Exec_query_project::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_query_project::Data& +Exec_query_project::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_query_project::setQuery(Exec_query* query) +{ + ctx_assert(m_query == 0 && query != 0); + m_query = query; +} + +inline void +Exec_query_project::setRow(Exec_expr_row* exprRow) +{ + ctx_assert(m_exprRow == 0 && exprRow != 0); + m_exprRow = exprRow; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_range.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_range.cpp new file mode 100644 index 00000000000..5d29c5af315 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_range.cpp @@ -0,0 +1,211 @@ +/* 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/StmtArea.hpp> +#include <dictionary/DictTable.hpp> +#include <dictionary/DictColumn.hpp> +#include "Code_query_range.hpp" +#include "Code_column.hpp" +#include "Code_expr.hpp" +#include "Code_root.hpp" + +// Plan_query_range + +Plan_query_range::~Plan_query_range() +{ +} + +Plan_base* +Plan_query_range::analyze(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_table != 0); + m_table->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + return this; +} + +Exec_base* +Plan_query_range::codegen(Ctx& ctx, Ctl& ctl) +{ + // set up + ctx_assert(m_table != 0 && m_index != 0); + const BaseString& tableName = m_table->getName(); + ctx_assert(m_index->m_dictIndex != 0); + const DictIndex& dictIndex = *m_index->m_dictIndex; + const BaseString& indexName = dictIndex.getName(); + const unsigned keyCount = m_index->m_keyCountUsed; + const ColumnVector& columns = m_table->exprColumns(); + ctx_assert(columns.size() > 0); + const unsigned attrCount = columns.size() - 1; + // create the code + Exec_query_range::Code& code = *new Exec_query_range::Code(keyCount, attrCount); + code.m_tableName = strcpy(new char[tableName.length() + 1], tableName.c_str()); + code.m_indexName = strcpy(new char[indexName.length() + 1], indexName.c_str()); + code.m_exclusive = m_exclusive; + // key attributes + code.m_keyId = new NdbAttrId[1 + keyCount]; + code.m_keyId[0] = (NdbAttrId)-1; + for (unsigned k = 1; k <= keyCount; k++) { + const DictColumn* keyColumn = dictIndex.getColumn(k); + const SqlType& sqlType = keyColumn->sqlType(); + SqlSpec sqlSpec(sqlType, SqlSpec::Physical); + code.m_keySpecs.setEntry(k, sqlSpec); + code.m_keyId[k] = k - 1; // index column order + } + // matching expressions + ctx_assert(m_index->m_keyFound); + const ExprVector& keyEq = m_index->m_keyEq; + // check size matches + ctx_assert(keyEq.size() == 1 + keyCount); + code.m_keyMatch = new Exec_expr* [1 + keyCount]; + code.m_keyMatch[0] = 0; + for (unsigned k = 1; k <= keyCount; k++) { + Plan_expr* expr = keyEq[k]; + Exec_expr* execExpr = static_cast<Exec_expr*>(expr->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execExpr != 0); + code.m_keyMatch[k] = execExpr; + } + // queried attributes + code.m_attrId = new NdbAttrId[1 + attrCount]; + code.m_attrId[0] = (NdbAttrId)-1; + for (unsigned i = 1; i <= attrCount; i++) { + Plan_column* column = columns[i]; + ctx_assert(column != 0); + const DictColumn& dictColumn = column->dictColumn(); + const SqlType& sqlType = dictColumn.sqlType(); + SqlSpec sqlSpec(sqlType, SqlSpec::Physical); + code.m_sqlSpecs.setEntry(i, sqlSpec); + code.m_attrId[i] = dictColumn.getAttrId(); + } + // create the exec + Exec_query_range* exec = new Exec_query_range(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + exec->setCode(code); + // interpreter + ctl.m_execQuery = exec; + Exec_pred* execInterp = 0; + ctl.m_topTable = m_table; + if (m_interp != 0) { + execInterp = static_cast<Exec_pred*>(m_interp->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execInterp != 0); + } + ctl.m_topTable = 0; + if (m_interp != 0) + exec->setInterp(execInterp); + return exec; +} + +void +Plan_query_range::print(Ctx& ctx) +{ + ctx.print(" [query_range"); + Plan_base* a[] = { m_table }; + printList(ctx, a, 1); + ctx.print("]"); +} + +// Exec_query_range + +Exec_query_range::Code::~Code() +{ + delete[] m_tableName; + delete[] m_keyId; + delete[] m_keyMatch; + delete[] m_attrId; +} + +Exec_query_range::Data::~Data() +{ + delete[] m_recAttr; +} + +Exec_query_range::~Exec_query_range() +{ +} + +void +Exec_query_range::alloc(Ctx& ctx, Ctl& ctl) +{ + const Code& code = getCode(); + // create data + Data& data = *new Data(this, code.sqlSpecs()); + setData(data); + // allocate matching expressions + for (unsigned k = 1; k <= code.m_keyCount; k++) { + Exec_expr* expr = code.m_keyMatch[k]; + ctx_assert(expr != 0); + expr->alloc(ctx, ctl); + if (! ctx.ok()) + return; + } + // needed for isNULL + data.m_recAttr = new NdbRecAttr* [1 + code.m_attrCount]; + for (unsigned i = 0; i <= code.m_attrCount; i++) { + data.m_recAttr[i] = 0; + } + // parallel + data.m_parallel = code.m_exclusive ? 1 : 240; // best supported + // interpreter + if (m_interp != 0) { + //m_interp->alloc(ctx, ctl); XXX + if (! ctx.ok()) + return; + } +} + +void +Exec_query_range::close(Ctx& ctx) +{ + Data& data = getData(); + if (data.m_con != 0) { + Ndb* const ndb = ndbObject(); + ndb->closeTransaction(data.m_con); + data.m_con = 0; + data.m_op = 0; + data.m_done = true; + ctx_log2(("lookup closed at statement close")); + } + // if (m_interp != 0) + // m_interp->close(ctx); +} + +void +Exec_query_range::print(Ctx& ctx) +{ + ctx.print(" [query_range"); + if (m_code != 0) { + const Code& code = getCode(); + ctx.print(" keyId="); + for (unsigned i = 1; i <= code.m_keyCount; i++) { + if (i > 1) + ctx.print(","); + ctx.print("%u", (unsigned)code.m_keyId[i]); + } + ctx.print(" attrId="); + for (unsigned i = 1; i <= code.m_attrCount; i++) { + if (i > 1) + ctx.print(","); + ctx.print("%u", (unsigned)code.m_attrId[i]); + } + ctx.print(" table=%s", code.m_tableName); + } + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_range.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_range.hpp new file mode 100644 index 00000000000..4438189522c --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_range.hpp @@ -0,0 +1,186 @@ +/* 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_Code_query_range_hpp +#define ODBC_CODEGEN_Code_query_range_hpp + +#include <common/common.hpp> +#include "Code_query.hpp" +#include "Code_table.hpp" +#include "Code_pred.hpp" + +class Ctx; +class StmtArea; +class NdbConnection; +class NdbOperation; +class NdbRecAttr; + +/* + * Range scan via ordered index. We implement only the case of equality + * on an initial sequence of index keys. + */ + +class Plan_query_range : public Plan_query { +public: + Plan_query_range(Plan_root* root); + virtual ~Plan_query_range(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + void setTable(Plan_table* table, Plan_table::Index* index); + void setInterp(Plan_pred* interp); + void setExclusive(); +protected: + Plan_table* m_table; + Plan_table::Index* m_index; + Plan_pred* m_interp; + bool m_exclusive; +}; + +inline +Plan_query_range::Plan_query_range(Plan_root* root) : + Plan_query(root), + m_table(0), + m_index(0), + m_interp(0), + m_exclusive(false) +{ +} + +inline void +Plan_query_range::setTable(Plan_table* table, Plan_table::Index* index) +{ + ctx_assert(table != 0 && index != 0 && index == &table->m_indexList[index->m_pos] && index->m_pos != 0); + m_table = table; + m_index = index; +} + +inline void +Plan_query_range::setInterp(Plan_pred* interp) +{ + ctx_assert(interp != 0); + m_interp = interp; +} + +inline void +Plan_query_range::setExclusive() +{ + m_exclusive = true; +} + +class Exec_query_range : public Exec_query { +public: + class Code : public Exec_query::Code { + public: + Code(unsigned keyCount, unsigned attrCount); + virtual ~Code(); + protected: + friend class Plan_query_range; + friend class Exec_query_range; + const char* m_tableName; + const char* m_indexName; + unsigned m_keyCount; + SqlSpecs m_keySpecs; // key types + NdbAttrId* m_keyId; + Exec_expr** m_keyMatch; // XXX pointers for now + unsigned m_attrCount; + SqlSpecs m_sqlSpecs; + NdbAttrId* m_attrId; + bool m_exclusive; + }; + class Data : public Exec_query::Data { + public: + Data(Exec_query_range* node, const SqlSpecs& sqlSpecs); + virtual ~Data(); + protected: + friend class Exec_query_range; + SqlRow m_sqlRow; + NdbConnection* m_con; + NdbOperation* m_op; + NdbRecAttr** m_recAttr; + unsigned m_parallel; + bool m_done; // if no match possible due to range + }; + Exec_query_range(Exec_root* root); + virtual ~Exec_query_range(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + bool fetchImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + const Code& getCode() const; + Data& getData() const; + void setInterp(Exec_pred* interp); +protected: + Exec_pred* m_interp; +}; + +inline +Exec_query_range::Code::Code(unsigned keyCount, unsigned attrCount) : + Exec_query::Code(m_sqlSpecs), + m_tableName(0), + m_indexName(0), + m_keyCount(keyCount), + m_keySpecs(keyCount), + m_keyId(0), + m_attrCount(attrCount), + m_sqlSpecs(attrCount), + m_attrId(0), + m_exclusive(false) +{ +} + +inline +Exec_query_range::Data::Data(Exec_query_range* node, const SqlSpecs& sqlSpecs) : + Exec_query::Data(node, m_sqlRow), + m_sqlRow(sqlSpecs), + m_con(0), + m_op(0), + m_recAttr(0), + m_parallel(1), + m_done(false) +{ +} + +inline +Exec_query_range::Exec_query_range(Exec_root* root) : + Exec_query(root), + m_interp(0) +{ +} + +inline const Exec_query_range::Code& +Exec_query_range::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_query_range::Data& +Exec_query_range::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_query_range::setInterp(Exec_pred* interp) +{ + ctx_assert(interp != 0); + m_interp = interp; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_repeat.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_repeat.cpp new file mode 100644 index 00000000000..8b295a97916 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_repeat.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 "Code_query_repeat.hpp" +#include "Code_root.hpp" + +// Plan_query_repeat + +Plan_query_repeat::~Plan_query_repeat() +{ +} + +Plan_base* +Plan_query_repeat::analyze(Ctx& ctx, Ctl& ctl) +{ + return this; +} + +Exec_base* +Plan_query_repeat::codegen(Ctx& ctx, Ctl& ctl) +{ + Exec_query_repeat* exec = new Exec_query_repeat(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + // SqlSpecs is empty + const SqlSpecs sqlSpecs(0); + Exec_query_repeat::Code& code = *new Exec_query_repeat::Code(sqlSpecs, m_forever, m_maxcount); + exec->setCode(code); + return exec; +} + +void +Plan_query_repeat::print(Ctx& ctx) +{ + ctx.print(" [query_repeat"); + if (! m_forever) + ctx.print(" %ld", (long)m_maxcount); + ctx.print("]"); +} + +// Exec_query_repeat + +Exec_query_repeat::Code::~Code() +{ +} + +Exec_query_repeat::Data::~Data() +{ +} + +Exec_query_repeat::~Exec_query_repeat() +{ +} + +void +Exec_query_repeat::alloc(Ctx& ctx, Ctl& ctl) +{ + const Code& code = getCode(); + // SqlRow is empty + Data& data = *new Data(this, code.sqlSpecs()); + setData(data); +} + +void +Exec_query_repeat::execImpl(Ctx& ctx, Ctl& ctl) +{ + Data& data = getData(); + data.m_count = 0; +} + +bool +Exec_query_repeat::fetchImpl(Ctx& ctx, Ctl& ctl) +{ + const Code& code = getCode(); + Data& data = getData(); + // fetch until count is up + if (code.m_forever || data.m_count < code.m_maxcount) { + data.m_count++; + return true; + } + return false; +} + +void +Exec_query_repeat::close(Ctx& ctx) +{ +} + +void +Exec_query_repeat::print(Ctx& ctx) +{ + const Code& code = getCode(); + ctx.print(" [query_repeat"); + if (! code.m_forever) + ctx.print(" %ld", (long)code.m_maxcount); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_repeat.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_repeat.hpp new file mode 100644 index 00000000000..90d6ef55104 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_repeat.hpp @@ -0,0 +1,133 @@ +/* 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_Code_query_repeat_hpp +#define ODBC_CODEGEN_Code_query_repeat_hpp + +#include <common/common.hpp> +#include "Code_query.hpp" +#include "Code_expr_row.hpp" + +/** + * @class Plan_query_repeat + * @brief Constant query node in PlanTree + */ +class Plan_query_repeat : public Plan_query { +public: + Plan_query_repeat(Plan_root* root); + Plan_query_repeat(Plan_root* root, CountType maxcount); + virtual ~Plan_query_repeat(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); +private: + bool m_forever; + CountType m_maxcount; +}; + +inline +Plan_query_repeat::Plan_query_repeat(Plan_root* root) : + Plan_query(root), + m_forever(true), + m_maxcount(0) +{ +} + +inline +Plan_query_repeat::Plan_query_repeat(Plan_root* root, CountType maxcount) : + Plan_query(root), + m_forever(false), + m_maxcount(maxcount) +{ +} + +/** + * @class Exec_query_repeat + * @brief Constant query node in ExecTree + */ +class Exec_query_repeat : public Exec_query { +public: + class Code : public Exec_query::Code { + public: + Code(const SqlSpecs& sqlSpecs, bool forever, CountType maxcount); + virtual ~Code(); + protected: + friend class Exec_query_repeat; + SqlSpecs m_sqlSpecs; + bool m_forever; + CountType m_maxcount; + }; + class Data : public Exec_query::Data { + public: + Data(Exec_query_repeat* node, const SqlSpecs& sqlSpecs); + virtual ~Data(); + protected: + friend class Exec_query_repeat; + SqlRow m_sqlRow; + CountType m_count; + }; + Exec_query_repeat(Exec_root* root); + virtual ~Exec_query_repeat(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + bool fetchImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; +}; + +inline +Exec_query_repeat::Code::Code(const SqlSpecs& sqlSpecs, bool forever, CountType maxcount) : + Exec_query::Code(m_sqlSpecs), + m_sqlSpecs(sqlSpecs), + m_forever(forever), + m_maxcount(maxcount) +{ +} + +inline +Exec_query_repeat::Data::Data(Exec_query_repeat* node, const SqlSpecs& sqlSpecs) : + Exec_query::Data(node, m_sqlRow), + m_sqlRow(sqlSpecs), + m_count(0) +{ +} + +inline +Exec_query_repeat::Exec_query_repeat(Exec_root* root) : + Exec_query(root) +{ +} + +// children + +inline const Exec_query_repeat::Code& +Exec_query_repeat::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_query_repeat::Data& +Exec_query_repeat::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_scan.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_scan.cpp new file mode 100644 index 00000000000..1c0f58980e5 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_scan.cpp @@ -0,0 +1,177 @@ +/* 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/StmtArea.hpp> +#include <dictionary/DictTable.hpp> +#include <dictionary/DictColumn.hpp> +#include "Code_query_scan.hpp" +#include "Code_column.hpp" +#include "Code_root.hpp" + +// Plan_query_scan + +Plan_query_scan::~Plan_query_scan() +{ +} + +Plan_base* +Plan_query_scan::analyze(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_table != 0); + m_table->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + if (m_interp != 0) { + m_interp = static_cast<Plan_pred*>(m_interp->analyze(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(m_interp != 0); + } + return this; +} + +Exec_base* +Plan_query_scan::codegen(Ctx& ctx, Ctl& ctl) +{ + // set up + ctx_assert(m_table != 0); + const BaseString& tableName = m_table->getName(); + const DictTable& dictTable = m_table->dictTable(); + const ColumnVector& columns = m_table->exprColumns(); + ctx_assert(columns.size() > 0); + const unsigned attrCount = columns.size() - 1; + // create the code + Exec_query_scan::Code& code = *new Exec_query_scan::Code(attrCount); + code.m_tableName = strcpy(new char[tableName.length() + 1], tableName.c_str()); + code.m_exclusive = m_exclusive; + // queried attributes + code.m_attrId = new NdbAttrId[1 + attrCount]; + code.m_attrId[0] = (NdbAttrId)-1; + for (unsigned i = 1; i <= attrCount; i++) { + Plan_column* column = columns[i]; + ctx_assert(column != 0); + const DictColumn& dictColumn = column->dictColumn(); + const SqlType& sqlType = dictColumn.sqlType(); + SqlSpec sqlSpec(sqlType, SqlSpec::Physical); + code.m_sqlSpecs.setEntry(i, sqlSpec); + code.m_attrId[i] = dictColumn.getAttrId(); + } + // create the exec + Exec_query_scan* exec = new Exec_query_scan(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + exec->setCode(code); + // interpreter + Exec_pred* execInterp = 0; + ctl.m_execQuery = exec; + ctl.m_topTable = m_table; + if (m_interp != 0) { + execInterp = static_cast<Exec_pred*>(m_interp->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execInterp != 0); + } + ctl.m_topTable = 0; + if (m_interp != 0) + exec->setInterp(execInterp); + return exec; +} + +void +Plan_query_scan::print(Ctx& ctx) +{ + ctx.print(" [query_scan"); + Plan_base* a[] = { m_table, m_interp }; + printList(ctx, a, 2); + ctx.print("]"); +} + +// Exec_query_scan + +Exec_query_scan::Code::~Code() +{ + delete[] m_tableName; + delete[] m_attrId; +} + +Exec_query_scan::Data::~Data() +{ + delete[] m_recAttr; +} + +Exec_query_scan::~Exec_query_scan() +{ +} + +void +Exec_query_scan::alloc(Ctx& ctx, Ctl& ctl) +{ + const Code& code = getCode(); + // create data + Data& data = *new Data(this, code.sqlSpecs()); + // needed for isNULL + data.m_recAttr = new NdbRecAttr* [1 + code.m_attrCount]; + for (unsigned i = 0; i <= code.m_attrCount; i++) { + data.m_recAttr[i] = 0; + } + data.m_parallel = code.m_exclusive ? 1 : 240; // best supported + setData(data); + // interpreter + ctl.m_query = this; + if (m_interp != 0) { + //m_interp->alloc(ctx, ctl); XXX + if (! ctx.ok()) + return; + } +} + +void +Exec_query_scan::close(Ctx& ctx) +{ + Data& data = getData(); + if (data.m_con != 0) { + Ndb* const ndb = ndbObject(); + int ret = data.m_con->stopScan(); + if (ret == -1) { + ctx.pushStatus(ndb, data.m_con, data.m_op, "stopScan"); + } + ndb->closeTransaction(data.m_con); + data.m_con = 0; + data.m_op = 0; + ctx_log2(("scan closed at statement close")); + } + if (m_interp != 0) + m_interp->close(ctx); +} + +void +Exec_query_scan::print(Ctx& ctx) +{ + ctx.print(" [query_scan"); + if (m_code != 0) { + const Code& code = getCode(); + ctx.print(" attrId="); + for (unsigned i = 1; i <= code.m_attrCount; i++) { + if (i > 1) + ctx.print(","); + ctx.print("%u", (unsigned)code.m_attrId[i]); + } + ctx.print(" table=%s", code.m_tableName); + } + if (m_interp != 0) + m_interp->print(ctx); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_scan.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_scan.hpp new file mode 100644 index 00000000000..d6d1630ddf8 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_scan.hpp @@ -0,0 +1,174 @@ +/* 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_Code_query_scan_hpp +#define ODBC_CODEGEN_Code_query_scan_hpp + +#include <common/common.hpp> +#include "Code_query.hpp" +#include "Code_table.hpp" +#include "Code_pred.hpp" + +class Ctx; +class StmtArea; +class NdbConnection; +class NdbOperation; +class NdbRecAttr; + +/* + * Table scan. + */ + +class Plan_query_scan : public Plan_query { +public: + Plan_query_scan(Plan_root* root); + virtual ~Plan_query_scan(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + void setTable(Plan_table* table); + void setInterp(Plan_pred* interp); + void setExclusive(); +protected: + Plan_table* m_table; + Plan_pred* m_interp; + bool m_exclusive; // exclusive +}; + +inline +Plan_query_scan::Plan_query_scan(Plan_root* root) : + Plan_query(root), + m_table(0), + m_interp(0), + m_exclusive(false) +{ +} + +inline void +Plan_query_scan::setTable(Plan_table* table) +{ + ctx_assert(table != 0); + m_table = table; +} + +inline void +Plan_query_scan::setInterp(Plan_pred* interp) +{ + ctx_assert(interp != 0); + m_interp = interp; +} + +inline void +Plan_query_scan::setExclusive() +{ + m_exclusive = true; +} + +class Exec_query_scan : public Exec_query { +public: + class Code : public Exec_query::Code { + public: + Code(unsigned attrCount); + virtual ~Code(); + protected: + friend class Plan_query_scan; + friend class Exec_query_scan; + char* m_tableName; + unsigned m_attrCount; + SqlSpecs m_sqlSpecs; + NdbAttrId* m_attrId; + bool m_exclusive; + }; + class Data : public Exec_query::Data { + public: + Data(Exec_query_scan* node, const SqlSpecs& sqlSpecs); + virtual ~Data(); + protected: + friend class Exec_query_scan; + SqlRow m_sqlRow; + NdbConnection* m_con; + NdbOperation* m_op; + NdbRecAttr** m_recAttr; + unsigned m_parallel; // parallelism could be runtime option + }; + Exec_query_scan(Exec_root* root); + virtual ~Exec_query_scan(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + bool fetchImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setInterp(Exec_pred* interp); +protected: + Exec_pred* m_interp; +}; + +inline +Exec_query_scan::Code::Code(unsigned attrCount) : + Exec_query::Code(m_sqlSpecs), + m_tableName(0), + m_attrCount(attrCount), + m_sqlSpecs(attrCount), + m_attrId(0), + m_exclusive(false) +{ +} + +inline +Exec_query_scan::Data::Data(Exec_query_scan* node, const SqlSpecs& sqlSpecs) : + Exec_query::Data(node, m_sqlRow), + m_sqlRow(sqlSpecs), + m_con(0), + m_op(0), + m_recAttr(0), + m_parallel(1) +{ +} + +inline +Exec_query_scan::Exec_query_scan(Exec_root* root) : + Exec_query(root), + m_interp(0) +{ +} + +// children + +inline const Exec_query_scan::Code& +Exec_query_scan::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_query_scan::Data& +Exec_query_scan::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_query_scan::setInterp(Exec_pred* interp) +{ + ctx_assert(interp != 0); + m_interp = interp; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_sort.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_sort.cpp new file mode 100644 index 00000000000..4ea6db8c4e2 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_sort.cpp @@ -0,0 +1,239 @@ +/* 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 <algorithm> +#include "Code_query_sort.hpp" +#include "Code_root.hpp" + +// Plan_query_sort + +Plan_query_sort::~Plan_query_sort() +{ +} + +Plan_expr_row* +Plan_query_sort::getRow() +{ + ctx_assert(m_query != 0); + return m_query->getRow(); +} + +Plan_base* +Plan_query_sort::analyze(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_query != 0); + m_query->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + ctx_assert(m_sortRow != 0); + m_sortRow->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + return this; +} + +Exec_base* +Plan_query_sort::codegen(Ctx& ctx, Ctl& ctl) +{ + // create code for the subquery + ctx_assert(m_query != 0); + Exec_query* execQuery = static_cast<Exec_query*>(m_query->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execQuery != 0); + // create code for the row based on query code + ctx_assert(m_sortRow != 0); + ctl.m_execQuery = execQuery->getRawQuery(); + Exec_expr_row* execRow = static_cast<Exec_expr_row*>(m_sortRow->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execRow != 0); + Exec_query_sort* exec = new Exec_query_sort(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + // re-use SqlSpecs from subquery + const Exec_query::Code& codeQuery = execQuery->getCode(); + const SqlSpecs& sqlSpecs = codeQuery.sqlSpecs(); + // make asc + unsigned size = m_sortRow->getSize(); + bool* asc = new bool[1 + size]; + for (unsigned i = 1; i <= size; i++) { + asc[i] = m_sortRow->m_ascList[i]; + } + Exec_query_sort::Code& code = *new Exec_query_sort::Code(sqlSpecs, asc); + exec->setCode(code); + exec->setQuery(execQuery); + exec->setRow(execRow); + return exec; +} + +void +Plan_query_sort::print(Ctx& ctx) +{ + ctx.print(" [query_sort"); + Plan_base* a[] = { m_query, m_sortRow }; + printList(ctx, a, 2); + ctx.print("]"); +} + +// Exec_query_sort + +Exec_query_sort::Code::~Code() +{ +} + +Exec_query_sort::Data::~Data() +{ + for (unsigned i = 0; i < m_sortList.size(); i++) { + SortItem& sortItem = m_sortList[i]; + delete sortItem.m_dataRow; + delete sortItem.m_sortRow; + } +} + +Exec_query_sort::~Exec_query_sort() +{ +} + +void +Exec_query_sort::alloc(Ctx& ctx, Ctl& ctl) +{ + // allocate subquery + ctx_assert(m_query != 0); + m_query->alloc(ctx, ctl); + if (! ctx.ok()) + return; + // allocate sort row based on subquery data + ctx_assert(m_sortRow != 0); + ctl.m_query = m_query->getRawQuery(); + m_sortRow->alloc(ctx, ctl); + if (! ctx.ok()) + return; + Data& data = *new Data(this, getCode().sqlSpecs()); + setData(data); +} + +void +Exec_query_sort::execImpl(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_query != 0 && m_sortRow != 0); + ctl.m_sortRow = m_sortRow; + m_query->execute(ctx, ctl); +} + +bool +SortLess::operator()(SortItem s1, SortItem s2) const +{ + const Exec_query_sort::Code& code = m_node->getCode(); + const SqlRow& r1 = *s1.m_sortRow; + const SqlRow& r2 = *s2.m_sortRow; + for (unsigned i = 1; i <= r1.count(); i++) { + const SqlField& f1 = r1.getEntry(i); + const SqlField& f2 = r2.getEntry(i); + // nulls last is default in oracle + bool f1null = f1.sqlNull(); + bool f2null = f2.sqlNull(); + if (f1null && f2null) + continue; + if (! f1null && f2null) + return code.getAsc(i) ? true : false; + if (f1null && ! f2null) + return code.getAsc(i) ? false : true; + if (f1.less(f2)) + return code.getAsc(i) ? true : false; + if (f2.less(f1)) + return code.getAsc(i) ? false : true; + } + return false; +} + +bool +Exec_query_sort::fetchImpl(Ctx& ctx, Ctl& ctl) +{ + Data& data = getData(); + ctx_assert(m_query != 0 && m_sortRow != 0); + ctl.m_sortRow = m_sortRow; + if (! data.m_sorted) { + // read and cache all rows + data.m_count = 0; + while (m_query->fetch(ctx, ctl)) { + const SqlRow* dataRow = m_query->getData().sqlRow().copy(); + const SqlRow* sortRow = 0; + if (ctl.m_groupIndex == 0) { + // evaluate sort row + m_sortRow->evaluate(ctx, ctl); + if (! ctx.ok()) + return false; + sortRow = m_sortRow->getData().sqlRow().copy(); + } else { + // evaluate done by group-by + SqlRow tmpSortRow(m_sortRow->getCode().sqlSpecs()); + for (unsigned i = 1; i <= tmpSortRow.count(); i++) { + tmpSortRow.setEntry(i, m_sortRow->getExpr(i)->getData().groupField(ctl.m_groupIndex)); + } + sortRow = tmpSortRow.copy(); + } + SortItem sortItem(dataRow, sortRow); + data.m_sortList.push_back(sortItem); + data.m_count++; + } + data.m_index = 0; + if (! ctx.ok()) + return false; + // sort the rows XXX use iterated stable_sort + SortLess sortLess(this); + std::sort(data.m_sortList.begin(), data.m_sortList.end(), sortLess); + data.m_sorted = true; + } + if (data.m_index < data.m_count) { + // make our SqlRow reference to current row + const SqlRow& currRow = *data.m_sortList[data.m_index].m_dataRow; + for (unsigned i = 1; i <= data.m_sqlRow.count(); i++) { + const SqlField& currField = currRow.getEntry(i); + SqlSpec sqlSpec(currField.sqlSpec(), SqlSpec::Reference); + SqlField sqlField(sqlSpec, &currField); + data.m_sqlRow.setEntry(i, sqlField); + } + data.m_index++; + return true; + } + return false; +} + +void +Exec_query_sort::close(Ctx& ctx) +{ + Data& data = getData(); + ctx_assert(m_query != 0); + m_query->close(ctx); + data.m_sorted = false; + for (unsigned i = 0; i < data.m_sortList.size(); i++) { + SortItem& sortItem = data.m_sortList[i]; + delete sortItem.m_dataRow; + delete sortItem.m_sortRow; + } + data.m_sortList.clear(); + data.m_count = 0; + data.m_index = 0; +} + +void +Exec_query_sort::print(Ctx& ctx) +{ + ctx.print(" [query_sort"); + Exec_base* a[] = { m_query, m_sortRow }; + printList(ctx, a, 2); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_sort.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_sort.hpp new file mode 100644 index 00000000000..d1aa03d9aef --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_sort.hpp @@ -0,0 +1,208 @@ +/* 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_Code_query_sort_hpp +#define ODBC_CODEGEN_Code_query_sort_hpp + +#include <functional> +#include <common/common.hpp> +#include "Code_query.hpp" +#include "Code_expr_row.hpp" + +/** + * @class Plan_query_sort + * @brief Project node in PlanTree + */ +class Plan_query_sort : public Plan_query { +public: + Plan_query_sort(Plan_root* root); + virtual ~Plan_query_sort(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setQuery(Plan_query* query); + void setRow(Plan_expr_row* sortRow); +protected: + Plan_expr_row* getRow(); + Plan_query* m_query; + Plan_expr_row* m_sortRow; +}; + +inline +Plan_query_sort::Plan_query_sort(Plan_root* root) : + Plan_query(root), + m_query(0), + m_sortRow(0) +{ +} + +// children + +inline void +Plan_query_sort::setQuery(Plan_query* query) +{ + ctx_assert(query != 0); + m_query = query; +} + +inline void +Plan_query_sort::setRow(Plan_expr_row* sortRow) +{ + ctx_assert(sortRow != 0); + m_sortRow = sortRow; +} + +/** + * Item to sort includes data row and sort row. + */ +struct SortItem { + SortItem(const SqlRow* dataRow, const SqlRow* sortRow); + const SqlRow* m_dataRow; // copy of fetched row from subquery + const SqlRow* m_sortRow; // copy of values to sort on +}; + +typedef std::vector<SortItem> SortList; + +class Exec_query_sort; + +struct SortLess : std::binary_function<SortItem, SortItem, bool> { + SortLess(const Exec_query_sort* node); + const Exec_query_sort* m_node; + bool operator()(SortItem s1, SortItem s2) const; +}; + +inline +SortItem::SortItem(const SqlRow* dataRow, const SqlRow* sortRow) : + m_dataRow(dataRow), + m_sortRow(sortRow) +{ +} + +inline +SortLess::SortLess(const Exec_query_sort* node) : + m_node(node) +{ +} + +/** + * @class Exec_query_sort + * @brief Project node in ExecTree + */ +class Exec_query_sort : public Exec_query { +public: + class Code : public Exec_query::Code { + public: + Code(const SqlSpecs& sqlSpecs, bool* asc); + virtual ~Code(); + bool getAsc(unsigned i) const; + protected: + friend class Exec_query_sort; + const bool* const m_asc; + // sets reference to Sqlspecs from subquery + }; + class Data : public Exec_query::Data { + public: + Data(Exec_query_sort* node, const SqlSpecs& sqlSpecs); + virtual ~Data(); + protected: + friend class Exec_query_sort; + SqlRow m_sqlRow; // current row + bool m_sorted; // fetch and sort done + SortList m_sortList; + unsigned m_count; // number of rows + unsigned m_index; // current fetch index + }; + Exec_query_sort(Exec_root* root); + virtual ~Exec_query_sort(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + bool fetchImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setQuery(Exec_query* query); + void setRow(Exec_expr_row* sortRow); +protected: + friend class Exec_query; + Exec_query* m_query; + Exec_expr_row* m_sortRow; +}; + +inline +Exec_query_sort::Code::Code(const SqlSpecs& sqlSpecs, bool* asc) : + Exec_query::Code(sqlSpecs), + m_asc(asc) +{ +} + +inline bool +Exec_query_sort::Code::getAsc(unsigned i) const +{ + return m_asc[i]; +} + +inline +Exec_query_sort::Data::Data(Exec_query_sort* node, const SqlSpecs& sqlSpecs) : + Exec_query::Data(node, m_sqlRow), + m_sqlRow(sqlSpecs), + m_sorted(false), + m_count(0), + m_index(0) +{ +} + +inline +Exec_query_sort::Exec_query_sort(Exec_root* root) : + Exec_query(root), + m_query(0), + m_sortRow(0) +{ +} + +// children + +inline const Exec_query_sort::Code& +Exec_query_sort::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_query_sort::Data& +Exec_query_sort::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_query_sort::setQuery(Exec_query* query) +{ + ctx_assert(m_query == 0 && query != 0); + m_query = query; +} + +inline void +Exec_query_sort::setRow(Exec_expr_row* sortRow) +{ + ctx_assert(m_sortRow == 0 && sortRow != 0); + m_sortRow = sortRow; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_sys.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_sys.cpp new file mode 100644 index 00000000000..affe3dc1264 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_sys.cpp @@ -0,0 +1,130 @@ +/* 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/StmtArea.hpp> +#include <dictionary/DictTable.hpp> +#include <dictionary/DictColumn.hpp> +#include "Code_query_sys.hpp" +#include "Code_column.hpp" +#include "Code_root.hpp" + +// Plan_query_sys + +Plan_query_sys::~Plan_query_sys() +{ +} + +Plan_base* +Plan_query_sys::analyze(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_table != 0); + m_table->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + return this; +} + +Exec_base* +Plan_query_sys::codegen(Ctx& ctx, Ctl& ctl) +{ + // set up + ctx_assert(m_table != 0); + const DictTable& dictTable = m_table->dictTable(); + const ColumnVector& columns = m_table->exprColumns(); + ctx_assert(columns.size() > 0); + const unsigned attrCount = columns.size() - 1; + // create the code + Exec_query_sys::Code& code = *new Exec_query_sys::Code(attrCount); + code.m_sysId = dictTable.sysId(); + // queried attributes + code.m_attrId = new NdbAttrId[1 + attrCount]; + code.m_attrId[0] = (NdbAttrId)-1; + for (unsigned i = 1; i <= attrCount; i++) { + Plan_column* column = columns[i]; + ctx_assert(column != 0); + const DictColumn& dictColumn = column->dictColumn(); + const SqlType& sqlType = dictColumn.sqlType(); + SqlSpec sqlSpec(sqlType, SqlSpec::Physical); + code.m_sqlSpecs.setEntry(i, sqlSpec); + code.m_attrId[i] = dictColumn.getAttrId(); + } + // create the exec + Exec_query_sys* exec = new Exec_query_sys(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + exec->setCode(code); + return exec; +} + +void +Plan_query_sys::print(Ctx& ctx) +{ + ctx.print(" [query_sys"); + Plan_base* a[] = { m_table }; + printList(ctx, a, 1); + ctx.print("]"); +} + +// Exec_query_sys + +Exec_query_sys::Code::~Code() +{ + delete[] m_attrId; +} + +Exec_query_sys::Data::~Data() +{ +} + +Exec_query_sys::~Exec_query_sys() +{ +} + +void +Exec_query_sys::alloc(Ctx& ctx, Ctl& ctl) +{ + const Code& code = getCode(); + // create data + Data& data = *new Data(this, code.sqlSpecs()); + setData(data); +} + +void +Exec_query_sys::close(Ctx& ctx) +{ + Data& data = getData(); + data.m_rowPos = 0; + data.m_tablePos = 0; + data.m_attrPos = 0; + data.m_keyPos = 0; +} + +void +Exec_query_sys::print(Ctx& ctx) +{ + ctx.print(" [query_sys"); + if (m_code != 0) { + const Code& code = getCode(); + ctx.print(" attrId="); + for (unsigned i = 1; i <= code.m_attrCount; i++) { + if (i > 1) + ctx.print(","); + ctx.print("%u", (unsigned)code.m_attrId[i]); + } + ctx.print(" sysId=%u", (unsigned)code.m_sysId); + } + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_query_sys.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_sys.hpp new file mode 100644 index 00000000000..8eb069d0413 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_query_sys.hpp @@ -0,0 +1,148 @@ +/* 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_Code_query_sys_hpp +#define ODBC_CODEGEN_Code_query_sys_hpp + +#include <common/common.hpp> +#include <dictionary/DictSys.hpp> +#include "Code_query.hpp" +#include "Code_table.hpp" + +class Ctx; +class StmtArea; +class NdbConnection; +class NdbOperation; +class NdbRecAttr; + +/** + * @class Plan_query_sys + * @brief Full select (no where clause) + */ +class Plan_query_sys : public Plan_query { +public: + Plan_query_sys(Plan_root* root); + virtual ~Plan_query_sys(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setTable(Plan_table* table); +protected: + Plan_table* m_table; +}; + +inline +Plan_query_sys::Plan_query_sys(Plan_root* root) : + Plan_query(root), + m_table(0) +{ +} + +// children + +inline void +Plan_query_sys::setTable(Plan_table* table) +{ + ctx_assert(table != 0); + m_table = table; +} + +/** + * @class Exec_query_sys + * @brief Full select (no where clause) + */ +class Exec_query_sys : public Exec_query { +public: + class Code : public Exec_query::Code { + public: + Code(unsigned attrCount); + virtual ~Code(); + protected: + friend class Plan_query_sys; + friend class Exec_query_sys; + DictSys::Id m_sysId; + unsigned m_attrCount; + SqlSpecs m_sqlSpecs; + NdbAttrId* m_attrId; + }; + class Data : public Exec_query::Data { + public: + Data(Exec_query_sys* node, const SqlSpecs& sqlSpecs); + virtual ~Data(); + protected: + friend class Exec_query_sys; + SqlRow m_sqlRow; + // for typeinfo + unsigned m_rowPos; + // for tables and columns + NdbDictionary::Dictionary::List m_objectList; + unsigned m_tablePos; + unsigned m_attrPos; + unsigned m_keyPos; + }; + Exec_query_sys(Exec_root* root); + virtual ~Exec_query_sys(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + bool fetchImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; +}; + +inline +Exec_query_sys::Code::Code(unsigned attrCount) : + Exec_query::Code(m_sqlSpecs), + m_sysId(DictSys::Undef), + m_attrCount(attrCount), + m_sqlSpecs(attrCount), + m_attrId(0) +{ +} + +inline +Exec_query_sys::Data::Data(Exec_query_sys* node, const SqlSpecs& sqlSpecs) : + Exec_query::Data(node, m_sqlRow), + m_sqlRow(sqlSpecs) +{ +} + +inline +Exec_query_sys::Exec_query_sys(Exec_root* root) : + Exec_query(root) +{ +} + +// children + +inline const Exec_query_sys::Code& +Exec_query_sys::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_query_sys::Data& +Exec_query_sys::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_root.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_root.cpp new file mode 100644 index 00000000000..4f45bdffdaf --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_root.cpp @@ -0,0 +1,307 @@ +/* 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/StmtArea.hpp> +#include "Code_root.hpp" +#include "Code_stmt.hpp" +#include "Code_query.hpp" +#include "Code_expr_param.hpp" +#include "Code_root.hpp" + +// Plan_root + +Plan_root::~Plan_root() +{ +} + +Plan_base* +Plan_root::analyze(Ctx& ctx, Ctl& ctl) +{ + // analyze statement + ctx_assert(m_stmt != 0); + m_stmt = static_cast<Plan_stmt*>(m_stmt->analyze(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(m_stmt != 0); + // analyze parameters + ctx_assert(m_paramList.size() > 0); + const unsigned paramCount = m_paramList.size() - 1; + DescArea& ipd = descArea(Desc_usage_IPD); + ipd.setCount(ctx, paramCount); + for (unsigned i = 1; i <= paramCount; i++) { + Plan_expr_param* param = m_paramList[i]; + ctx_assert(param != 0); + // analyze the parameter + param->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + } + // must return self + return this; +} + +void +Plan_root::describe(Ctx& ctx) +{ + // describe statement + ctx_assert(m_stmt != 0); + m_stmt->describe(ctx); + // describe parameters + ctx_assert(m_paramList.size() > 0); + const unsigned paramCount = m_paramList.size() - 1; + DescArea& ipd = descArea(Desc_usage_IPD); + ipd.setCount(ctx, paramCount); + unsigned unbound = 0; + for (unsigned i = 1; i <= paramCount; i++) { + Plan_expr_param* param = m_paramList[i]; + ctx_assert(param != 0); + // describe the parameter + param->describe(ctx); + // check if SQL type is bound + ctx_assert(param->sqlType().type() != SqlType::Undef); + if (param->sqlType().type() == SqlType::Unbound) + unbound++; + } + if (unbound > 0) + ctx_log2(("%u out of %u params have unbound SQL type", unbound, paramCount)); + m_stmtArea.m_unbound = unbound; +} + +Exec_base* +Plan_root::codegen(Ctx& ctx, Ctl& ctl) +{ + Exec_root* execRoot = new Exec_root(m_stmtArea); + Exec_root::Code& code = *new Exec_root::Code; + execRoot->setCode(code); + // set root in helper struct + ctl.m_execRoot = execRoot; + // generate code for the statement + ctx_assert(m_stmt != 0); + Exec_stmt* execStmt = static_cast<Exec_stmt*>(m_stmt->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + execRoot->setStmt(execStmt); + // create parameters list + execRoot->m_paramList.resize(m_paramList.size()); + for (unsigned i = 1; i < m_paramList.size(); i++) { + Plan_expr_param* param = m_paramList[i]; + ctx_assert(param != 0); + Exec_expr_param* execParam = static_cast<Exec_expr_param*>(param->codegen(ctx, ctl)); + ctx_assert(execParam != 0); + execRoot->m_paramList[i] = execParam; + } + return execRoot; +} + +void +Plan_root::print(Ctx& ctx) +{ + ctx.print("[root"); + Plan_base* a[] = { m_stmt }; + printList(ctx, a, 1); + ctx.print("]\n"); +} + +void +Plan_root::saveNode(Plan_base* node) +{ + ctx_assert(node != 0); + m_nodeList.push_back(node); +} + +void +Plan_root::freeNodeList() +{ + for (NodeList::iterator i = m_nodeList.begin(); i != m_nodeList.end(); i++) { + Plan_base* node = *i; + *i = 0; + delete node; + } + m_nodeList.clear(); +} + +// Exec_root + +Exec_root::Code::~Code() +{ +} + +Exec_root::Data::~Data() +{ +} + +Exec_root::~Exec_root() +{ +} + +StmtArea& +Exec_root::stmtArea() const +{ + return m_stmtArea; +} + +void +Exec_root::alloc(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_stmt != 0); + m_stmt->alloc(ctx, ctl); +} + +void +Exec_root::bind(Ctx& ctx) +{ + // bind output cols + ctx_assert(m_stmt != 0); + m_stmt->bind(ctx); + // bind input params + for (unsigned i = 1; i < m_paramList.size(); i++) { + Exec_expr_param* param = m_paramList[i]; + ctx_assert(param != 0); + param->bind(ctx); + if (! ctx.ok()) + return; + } +} + +void +Exec_root::execute(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_stmt != 0); + // check if data is needed + for (unsigned i = 1; i < m_paramList.size(); i++) { + Exec_expr_param* param = m_paramList[i]; + ctx_assert(param != 0); + Exec_expr_param::Data& paramData = param->getData(); + if (paramData.m_atExec && paramData.m_extPos == -1) { + ctx.setCode(SQL_NEED_DATA); + return; + } + } + m_stmt->execute(ctx, ctl); +} + +void +Exec_root::fetch(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(m_stmt != 0); + Exec_query* query = static_cast<Exec_query*>(m_stmt); + ctx_assert(query != 0); + query->fetch(ctx, ctl); +} + +void +Exec_root::close(Ctx& ctx) +{ + ctx_assert(m_stmt != 0); + m_stmt->close(ctx); + for (unsigned i = 1; i < m_paramList.size(); i++) { + Exec_expr_param* param = m_paramList[i]; + ctx_assert(param != 0); + param->close(ctx); + } +} + +void +Exec_root::print(Ctx& ctx) +{ + ctx.print("[root"); + Exec_base* a[] = { m_stmt }; + printList(ctx, a, sizeof(a)/sizeof(a[0])); + ctx.print("]\n"); +} + +void +Exec_root::saveNode(Exec_base* node) +{ + ctx_assert(node != 0); + m_nodeList.push_back(node); +} + +void +Exec_root::freeNodeList() +{ + for (NodeList::iterator i = m_nodeList.begin(); i != m_nodeList.end(); i++) { + Exec_base* node = *i; + *i = 0; + delete node; + } + m_nodeList.clear(); +} + +// odbc support + +void +Exec_root::sqlGetData(Ctx& ctx, SQLUSMALLINT columnNumber, SQLSMALLINT targetType, SQLPOINTER targetValue, SQLINTEGER bufferLength, SQLINTEGER* strlen_or_Ind) +{ + ctx_assert(m_stmt != 0); + Exec_query* query = static_cast<Exec_query*>(m_stmt); + ctx_assert(query != 0); + query->sqlGetData(ctx, columnNumber, targetType, targetValue, bufferLength, strlen_or_Ind); +} + +void +Exec_root::sqlParamData(Ctx& ctx, SQLPOINTER* value) +{ + ctx_assert(m_paramList.size() > 0); + unsigned count = m_paramList.size() - 1; + for (unsigned i = 1; i <= count; i++) { + Exec_expr_param* param = m_paramList[i]; + ctx_assert(param != 0); + Exec_expr_param::Data& paramData = param->getData(); + if (! paramData.m_atExec || paramData.m_extPos >= 0) + continue; + ctx_assert(paramData.m_extField != 0); + ExtField& extField = *paramData.m_extField; + if (value != 0) + *value = extField.m_dataPtr; + m_paramData = i; + ctx.setCode(SQL_NEED_DATA); + return; + } +} + +void +Exec_root::sqlPutData(Ctx& ctx, SQLPOINTER data, SQLINTEGER strlen_or_Ind) +{ + ctx_assert(m_paramList.size() > 0); + unsigned count = m_paramList.size() - 1; + unsigned i = m_paramData; + if (i == 0) { + ctx.pushStatus(Sqlstate::_HY010, Error::Gen, "missing call to SQLParamData"); + return; + } + if (i > count) { + ctx.pushStatus(Sqlstate::_HY010, Error::Gen, "parameter %u out of range 1 to %u", i, count); + return; + } + Exec_expr_param* param = m_paramList[i]; + ctx_assert(param != 0); + Exec_expr_param::Data& paramData = param->getData(); + if (! paramData.m_atExec) { + ctx.pushStatus(Sqlstate::_HY010, Error::Gen, "parameter %u not marked for data-at-exec", i); + return; + } + ctx_assert(paramData.m_extField != 0); + ExtField extField(paramData.m_extField->extSpec(), data, 0, &strlen_or_Ind, i); + if (paramData.m_extPos == -1) + paramData.m_extPos = 0; + extField.setPos(paramData.m_extPos); + // copy in and update position + SqlField& sqlField = paramData.m_sqlField; + sqlField.copyin(ctx, extField); + paramData.m_extPos = extField.getPos(); + ctx_log4(("parameter %u data received", i)); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_root.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_root.hpp new file mode 100644 index 00000000000..4f0f96725e3 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_root.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_CODEGEN_Code_root_hpp +#define ODBC_CODEGEN_Code_root_hpp + +#include <list> +#include <common/common.hpp> +#include "Code_base.hpp" +#include "Code_stmt.hpp" + +class SqlField; +class ExtField; + +/** + * @class Plan_root + * @brief Root node above top level statement node + */ +class Plan_root : public Plan_base { +public: + Plan_root(StmtArea& stmtArea); + virtual ~Plan_root(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + void describe(Ctx& ctx); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setStmt(Plan_stmt* stmt); + // save and free nodes + void saveNode(Plan_base* node); + void freeNodeList(); +private: + friend class CodeGen; + friend class Plan_base; + friend class Plan_expr_param; + StmtArea& m_stmtArea; + Plan_stmt* m_stmt; + ParamVector m_paramList; + typedef std::list<Plan_base*> NodeList; + NodeList m_nodeList; +}; + +inline +Plan_root::Plan_root(StmtArea& stmtArea) : + Plan_base(this), + m_stmtArea(stmtArea), + m_stmt(0) +{ +} + +inline void +Plan_root::setStmt(Plan_stmt* stmt) +{ + ctx_assert(stmt != 0); + m_stmt = stmt; +} + +/** + * @class Exec_root + * @brief Root node above top level statement node + */ +class Exec_root : public Exec_base { +public: + class Code : public Exec_base::Code { + public: + Code(); + virtual ~Code(); + }; + class Data : public Exec_base::Data { + public: + Data(); + virtual ~Data(); + }; + Exec_root(StmtArea& stmtArea); + virtual ~Exec_root(); + StmtArea& stmtArea() const; + void alloc(Ctx& ctx, Ctl& ctl); + void bind(Ctx& ctx); + void execute(Ctx& ctx, Ctl& ctl); + void fetch(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setStmt(Exec_stmt* stmt); + // save and free nodes + void saveNode(Exec_base* node); + void freeNodeList(); + // odbc support + void sqlGetData(Ctx& ctx, SQLUSMALLINT columnNumber, SQLSMALLINT targetType, SQLPOINTER targetValue, SQLINTEGER bufferLength, SQLINTEGER* strlen_or_Ind); + void sqlParamData(Ctx& ctx, SQLPOINTER* value); + void sqlPutData(Ctx& ctx, SQLPOINTER data, SQLINTEGER strlen_or_Ind); +private: + friend class Plan_root; + friend class Exec_base; + friend class CodeGen; + StmtArea& m_stmtArea; + Exec_stmt* m_stmt; + ParamVector m_paramList; + unsigned m_paramData; // position of SQLParamData + typedef std::list<Exec_base*> NodeList; + NodeList m_nodeList; +}; + +inline +Exec_root::Code::Code() +{ +} + +inline +Exec_root::Data::Data() +{ +} + +inline +Exec_root::Exec_root(StmtArea& stmtArea) : + Exec_base(this), + m_stmtArea(stmtArea), + m_stmt(0), + m_paramData(0) +{ +} + +// children + +inline const Exec_root::Code& +Exec_root::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_root::Data& +Exec_root::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_root::setStmt(Exec_stmt* stmt) +{ + ctx_assert(stmt != 0); + m_stmt = stmt; + m_stmt->m_topLevel = true; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_select.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_select.cpp new file mode 100644 index 00000000000..611b491968d --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_select.cpp @@ -0,0 +1,406 @@ +/* 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 <algorithm> +#include <common/StmtArea.hpp> +#include <dictionary/DictTable.hpp> +#include "Code_select.hpp" +#include "Code_query_lookup.hpp" +#include "Code_query_index.hpp" +#include "Code_query_scan.hpp" +#include "Code_query_range.hpp" +#include "Code_query_sys.hpp" +#include "Code_query_project.hpp" +#include "Code_query_filter.hpp" +#include "Code_query_join.hpp" +#include "Code_query_count.hpp" +#include "Code_query_sort.hpp" +#include "Code_query_group.hpp" +#include "Code_query_distinct.hpp" +#include "Code_expr_column.hpp" +#include "Code_expr_const.hpp" +#include "Code_pred_op.hpp" +#include "Code_root.hpp" + +Plan_select::~Plan_select() +{ +} + +Plan_base* +Plan_select::analyze(Ctx& ctx, Ctl& ctl) +{ + stmtArea().stmtInfo().setName(Stmt_name_select); + // analyze tables + ctx_assert(m_tableList != 0); + for (unsigned i = 1; i <= m_tableList->countTable(); i++) { + Plan_table* table = m_tableList->getTable(i); + table->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + } + ctx_assert(m_exprRow != 0); + if (m_exprRow->getAsterisk()) { + // expand unqualified asterisk to table-qualified columns + setRow(new Plan_expr_row(m_root)); + m_root->saveNode(m_exprRow); + for (unsigned i = 1; i <= m_tableList->countTable(); i++) { + const Plan_table* table = m_tableList->getTable(i); + const DictTable& dictTable = table->dictTable(); + for (unsigned i = 1; i <= dictTable.getSize(); i++) { + DictColumn* dictColumn = dictTable.getColumn(i); + Plan_expr_column* column = new Plan_expr_column(m_root, dictColumn->getName()); + m_root->saveNode(column); + column->setCname(table->getCname()); + m_exprRow->addExpr(column); + } + } + } + // set name resolution scope + ctl.m_tableList = m_tableList->m_tableList; + ctx_assert(ctl.m_tableList.size() >= 1 + 1); + ctl.m_aggrin = false; + // analyze select row + ctl.m_aggrok = true; + ctx_assert(m_exprRow != 0); + m_exprRow = static_cast<Plan_expr_row*>(m_exprRow->analyze(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(m_exprRow != 0); + // analyze group by row + ctl.m_aggrok = false; + if (m_groupRow != 0) { + m_groupRow = static_cast<Plan_expr_row*>(m_groupRow->analyze(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(m_groupRow != 0); + } + // analyze having predicate + ctl.m_aggrok = true; + if (m_havingPred != 0) { + m_havingPred = static_cast<Plan_pred*>(m_havingPred->analyze(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(m_havingPred != 0); + } + // ana|yze order by row + ctl.m_aggrok = true; + if (m_sortRow != 0) { + m_sortRow = static_cast<Plan_expr_row*>(m_sortRow->analyze(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(m_sortRow != 0); + } + // analyze the predicate + ctl.m_aggrok = false; + ctl.m_topand = true; + ctl.m_extra = false; + if (m_pred != 0) { + m_pred = static_cast<Plan_pred*>(m_pred->analyze(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(m_pred != 0); + } + // check if group by required + if (m_exprRow->anyAggr() && ! m_exprRow->allBound() && m_groupRow == 0) { + ctx.pushStatus(Error::Gen, "missing GROUP BY clause"); + return 0; + } + // in special cases add "group by 1" + if (m_groupRow == 0) { + bool addgb = false; + if (m_havingPred != 0) { + // allowed by oracle but nearly useless + addgb = true; + } else if (m_exprRow->anyAggr() && m_sortRow != 0) { + // allowed by oracle but useless + ctx_assert(m_exprRow->allBound()); + addgb = true; + } + if (addgb) { + ctx_log2(("adding 'group by 1'")); + m_groupRow = new Plan_expr_row(m_root); + m_root->saveNode(m_groupRow); + LexType type(LexType::Integer); + Plan_expr* expr = new Plan_expr_const(m_root, type, "1"); + m_root->saveNode(expr); + m_groupRow->addExpr(expr); + m_groupRow = static_cast<Plan_expr_row*>(m_groupRow->analyze(ctx, ctl)); + ctx_assert(ctx.ok()); + ctx_assert(m_groupRow != 0); + } + } + // check group by allowed + if (m_groupRow != 0) { + if (! m_exprRow->isAllGroupBy(m_groupRow)) { + ctx.pushStatus(Error::Gen, "invalid GROUP BY expression in SELECT list"); + return 0; + } + if (m_havingPred != 0) { + if (! m_havingPred->isGroupBy(m_groupRow)) { + ctx.pushStatus(Error::Gen, "invalid GROUP BY expression in HAVING clause"); + return 0; + } + } + if (m_sortRow != 0) { + if (! m_sortRow->isAllGroupBy(m_groupRow)) { + ctx.pushStatus(Error::Gen, "invalid GROUP BY expression in ORDER BY clause"); + return 0; + } + } + } + // log top level predicate + { + unsigned n = 0; + for (PredList::iterator i = ctl.m_topcomp.begin(); i != ctl.m_topcomp.end(); i++) + ctx_log2(("top level pred %u: count tables = %u, not interp = %u", + ++n, + (unsigned)(*i)->tableSet().size(), + (unsigned)(*i)->noInterp().size())); + } + // compose the raw query from lookups and scans + Plan_query* queryRaw = 0; + TableVector tableVector(1); + TableSet tsDone; + while (tableVector.size() < ctl.m_tableList.size()) { + Plan_table* tableBest = 0; + Plan_table::Index* indexBest = 0; + for (unsigned n = 1; n < ctl.m_tableList.size(); n++) { + Plan_table* table = ctl.m_tableList[n]; + if (tsDone.find(table) != tsDone.end()) + continue; + // get system table out of the way + if (table->dictTable().sysId()) { + tableBest = table; + break; + } + // find best match for primary key or index + for (unsigned i = 0; i <= table->indexCount(); i++) { + Plan_table::Index& index = table->m_indexList[i]; + table->resolveSet(ctx, index, tsDone); + if (! ctx.ok()) + return 0; + if (! index.m_keyFound) + continue; + // prefer smaller dependency set, smaller rank, less unused keys + int k; + (k = (indexBest == 0)) || + (k = (indexBest->m_keySet.size() - index.m_keySet.size())) || + (k = (indexBest->m_rank - index.m_rank)) || + (k = (indexBest->m_keyCountUnused - index.m_keyCountUnused)); + if (k > 0) { + tableBest = table; + indexBest = &index; + } + } + } + Plan_query* queryNext = 0; + Plan_table* tableNext = 0; + Plan_query_scan* queryScan = 0; // for pushing interpreted program + Plan_query_range* queryRange = 0; // ditto + if (tableBest == 0) { + // scan first unprocessed table + for (unsigned n = 1; n < ctl.m_tableList.size(); n++) { + Plan_table* table = ctl.m_tableList[n]; + if (tsDone.find(table) != tsDone.end()) + continue; + tableNext = table; + break; + } + ctx_assert(tableNext != 0); + queryScan = new Plan_query_scan(m_root); + m_root->saveNode(queryScan); + queryScan->setTable(tableNext); + queryNext = queryScan; + ctx_log2(("optim: scan %s", tableNext->getPrintName())); + } else if (tableBest->dictTable().sysId()) { + // "scan" system table + tableNext = tableBest; + Plan_query_sys* querySys = new Plan_query_sys(m_root); + m_root->saveNode(querySys); + querySys->setTable(tableNext); + queryNext = querySys; + ctx_log2(("optim: scan %s", tableNext->getPrintName())); + } else if (indexBest->m_keySet.size() > 0) { + // scan first table this one depends on + const TableSet& keySet = indexBest->m_keySet; + for (unsigned n = 1; n < ctl.m_tableList.size(); n++) { + Plan_table* table = ctl.m_tableList[n]; + if (keySet.find(table) == keySet.end()) + continue; + ctx_assert(tsDone.find(table) == tsDone.end()); + tableNext = table; + break; + } + ctx_assert(tableNext != 0); + queryScan = new Plan_query_scan(m_root); + m_root->saveNode(queryScan); + queryScan->setTable(tableNext); + queryNext = queryScan; + ctx_log2(("optim: scan %s for %s", tableNext->getPrintName(), tableBest->getPrintName())); + } else if (indexBest->m_rank == 0) { + // primary key depends only on processed tables + tableNext = tableBest; + Plan_query_lookup* queryLookup = new Plan_query_lookup(m_root); + m_root->saveNode(queryLookup); + queryLookup->setTable(tableNext); + queryNext = queryLookup; + ctx_log2(("optim: lookup %s", tableNext->getPrintName())); + } else if (indexBest->m_rank == 1) { + // hash index key depends only on processed tables + tableNext = tableBest; + Plan_query_index* queryIndex = new Plan_query_index(m_root); + m_root->saveNode(queryIndex); + queryIndex->setTable(tableNext, indexBest); + queryNext = queryIndex; + ctx_log2(("optim: lookup %s via index %s", tableNext->getPrintName(), indexBest->m_dictIndex->getName().c_str())); + } else if (indexBest->m_rank == 2) { + // ordered index key depends only on processed tables + tableNext = tableBest; + queryRange = new Plan_query_range(m_root); + m_root->saveNode(queryRange); + queryRange->setTable(tableNext, indexBest); + queryNext = queryRange; + ctx_log2(("optim: range scan %s via index %s", tableNext->getPrintName(), indexBest->m_dictIndex->getName().c_str())); + } else { + ctx_assert(false); + } + if (queryRaw == 0) { + queryRaw = queryNext; + } else { + Plan_query_join* queryJoin = new Plan_query_join(m_root); + m_root->saveNode(queryJoin); + queryJoin->setInner(queryRaw); + queryJoin->setOuter(queryNext); + queryRaw = queryJoin; + } + tableVector.push_back(tableNext); + tsDone.insert(tableNext); + // push down part of top level predicate to table scan or range scan + Plan_pred* predPush = 0; + Plan_pred* predInterp = 0; + PredList::iterator i = ctl.m_topcomp.begin(); + while (i != ctl.m_topcomp.end()) { + const TableSet& ts = (*i)->tableSet(); + if (! std::includes(tsDone.begin(), tsDone.end(), ts.begin(), ts.end())) { + i++; + continue; + } + predPush = predPush == 0 ? *i : predPush->opAnd(*i); + if (queryScan != 0) { + const TableSet& ts2 = (*i)->noInterp(); + if (ts2.find(tableNext) == ts2.end()) + predInterp = predInterp == 0 ? *i : predInterp->opAnd(*i); + } + if (queryRange != 0) { + const TableSet& ts2 = (*i)->noInterp(); + if (ts2.find(tableNext) == ts2.end()) + predInterp = predInterp == 0 ? *i : predInterp->opAnd(*i); + } + // remove it from top level predicate + PredList::iterator j = i; + i++; + ctl.m_topcomp.erase(j); + } + if (predPush != 0) { + Plan_query_filter* queryPush = new Plan_query_filter(m_root); + m_root->saveNode(queryPush); + queryPush->setQuery(queryRaw); + queryPush->setPred(predPush); + queryPush->m_topTable = tableNext; + queryRaw = queryPush; + } + if (predInterp != 0) { + if (queryScan != 0) + queryScan->setInterp(predInterp); + else if (queryRange != 0) + queryRange->setInterp(predInterp); + else + ctx_assert(false); + } + } + ctx_assert(ctl.m_topcomp.empty()); + // set base for column position offsets + for (unsigned n = 1; n < tableVector.size(); n++) { + Plan_table* table = tableVector[n]; + if (n == 1) { + table->m_resOff = 1; + } else { + Plan_table* tablePrev = tableVector[n - 1]; + table->m_resOff = tablePrev->m_resOff + tablePrev->m_exprColumns.size() - 1; + } + } + // next level up is one of project, count, group by + Plan_query* queryTop; + if (m_groupRow == 0) { + if (! m_exprRow->anyAggr()) { + Plan_query_project* queryProject = new Plan_query_project(m_root); + m_root->saveNode(queryProject); + queryProject->setQuery(queryRaw); + queryProject->setRow(m_exprRow); + queryProject->setLimit(m_limitOff, m_limitCnt); + queryTop = queryProject; + } else { + ctx_assert(m_exprRow->allBound()); + Plan_query_count* queryCount = new Plan_query_count(m_root); + m_root->saveNode(queryCount); + queryCount->setQuery(queryRaw); + queryCount->setRow(m_exprRow); + queryTop = queryCount; + } + } else { + Plan_query_group* queryGroup = new Plan_query_group(m_root); + m_root->saveNode(queryGroup); + queryGroup->setQuery(queryRaw); + queryGroup->setDataRow(m_exprRow); + queryGroup->setGroupRow(m_groupRow); + if (m_havingPred != 0) + queryGroup->setHavingPred(m_havingPred); + queryTop = queryGroup; + } + // optional sort becomes new top level + if (m_sortRow != 0) { + Plan_query_sort* querySort = new Plan_query_sort(m_root); + m_root->saveNode(querySort); + querySort->setQuery(queryTop); + querySort->setRow(m_sortRow); + queryTop = querySort; + } + // optional distinct becomes new top level + if (m_distinct) { + Plan_query_distinct* queryDistinct = new Plan_query_distinct(m_root); + m_root->saveNode(queryDistinct); + queryDistinct->setQuery(queryTop); + queryTop = queryDistinct; + } + // return top node + return queryTop; +} + +Exec_base* +Plan_select::codegen(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(false); + return 0; +} + +void +Plan_select::print(Ctx& ctx) +{ + ctx.print(" [select"); + Plan_base* a[] = { m_tableList, m_exprRow, m_pred, m_groupRow, m_havingPred }; + printList(ctx, a, 5); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_select.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_select.hpp new file mode 100644 index 00000000000..eaa9b801f29 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_select.hpp @@ -0,0 +1,132 @@ +/* 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_Code_select_hpp +#define ODBC_CODEGEN_Code_select_hpp + +#include <common/common.hpp> +#include "Code_stmt.hpp" +#include "Code_expr_row.hpp" +#include "Code_table_list.hpp" +#include "Code_pred.hpp" + +/** + * @class Plan_select + * @brief General select in PlanTree + * + * General select. An initial PlanTree node. + */ +class Plan_select : public Plan_stmt { +public: + Plan_select(Plan_root* root); + virtual ~Plan_select(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setList(Plan_table_list* tableList); + void setRow(Plan_expr_row* exprRow); + void setPred(Plan_pred* pred); + void setSort(Plan_expr_row* sortRow); + void setDistinct(bool distinct); + void setGroup(Plan_expr_row* groupRow); + void setHaving(Plan_pred* havingPred); + void setLimit(int off, int cnt); +protected: + Plan_table_list* m_tableList; + Plan_expr_row* m_exprRow; + Plan_pred* m_pred; + Plan_expr_row* m_sortRow; + bool m_distinct; + Plan_expr_row* m_groupRow; + Plan_pred* m_havingPred; + int m_limitOff; + int m_limitCnt; +}; + +inline +Plan_select::Plan_select(Plan_root* root) : + Plan_stmt(root), + m_tableList(0), + m_exprRow(0), + m_pred(0), + m_sortRow(0), + m_distinct(false), + m_groupRow(0), + m_havingPred(0), + m_limitOff(0), + m_limitCnt(-1) +{ +} + +// children + +inline void +Plan_select::setList(Plan_table_list* tableList) +{ + ctx_assert(tableList != 0); + m_tableList = tableList; +} + +inline void +Plan_select::setRow(Plan_expr_row* exprRow) +{ + ctx_assert(exprRow != 0); + m_exprRow = exprRow; +} + +inline void +Plan_select::setPred(Plan_pred* pred) +{ + ctx_assert(pred != 0); + m_pred = pred; +} + +inline void +Plan_select::setSort(Plan_expr_row* sortRow) +{ + ctx_assert(sortRow != 0); + m_sortRow = sortRow; +} + +inline void +Plan_select::setDistinct(bool distinct) +{ + m_distinct = distinct; +} + +inline void +Plan_select::setGroup(Plan_expr_row* groupRow) +{ + ctx_assert(groupRow != 0); + m_groupRow = groupRow; +} + +inline void +Plan_select::setHaving(Plan_pred* havingPred) +{ + ctx_assert(havingPred != 0); + m_havingPred = havingPred; +} + +inline void +Plan_select::setLimit(int off, int cnt) +{ + m_limitOff = off; + m_limitCnt = cnt; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_set_row.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_set_row.cpp new file mode 100644 index 00000000000..dd13ba0c3f7 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_set_row.cpp @@ -0,0 +1,44 @@ +/* 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 "Code_set_row.hpp" +#include "Code_dml_column.hpp" + +Plan_set_row::~Plan_set_row() +{ +} + +Plan_base* +Plan_set_row::analyze(Ctx& ctx, Ctl& ctl) +{ + return this; +} + +Exec_base* +Plan_set_row::codegen(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(false); + return 0; +} + +void +Plan_set_row::print(Ctx& ctx) +{ + ctx.print(" [set_row"); + Plan_base* a[] = { m_dmlRow, m_exprRow }; + printList(ctx, a, 2); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_set_row.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_set_row.hpp new file mode 100644 index 00000000000..10d62826ac7 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_set_row.hpp @@ -0,0 +1,76 @@ +/* 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_Code_set_row_hpp +#define ODBC_CODEGEN_Code_set_row_hpp + +#include <vector> +#include <common/common.hpp> +#include <common/DataRow.hpp> +#include "Code_base.hpp" +#include "Code_dml_row.hpp" +#include "Code_expr_row.hpp" +#include "Code_root.hpp" + +/** + * @class Plan_set_row + * @brief Row of column assigments in update + * + * Used only in parse. The column and expression rows are moved + * to the update node immediately after parse. + */ +class Plan_set_row : public Plan_base { +public: + Plan_set_row(Plan_root* root); + virtual ~Plan_set_row(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void addColumn(Plan_dml_column* column); + void addExpr(Plan_expr* expr); +protected: + friend class Plan_update; + friend class Plan_insert; // for MySql + Plan_dml_row* m_dmlRow; + Plan_expr_row* m_exprRow; +}; + +inline +Plan_set_row::Plan_set_row(Plan_root* root) : + Plan_base(root) +{ + m_dmlRow = new Plan_dml_row(root); + root->saveNode(m_dmlRow); + m_exprRow = new Plan_expr_row(root); + root->saveNode(m_exprRow); +} + +// children + +inline void +Plan_set_row::addColumn(Plan_dml_column* column) +{ + m_dmlRow->addColumn(column); +} + +inline void +Plan_set_row::addExpr(Plan_expr* expr) +{ + m_exprRow->addExpr(expr); +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_stmt.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_stmt.cpp new file mode 100644 index 00000000000..d790f667b84 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_stmt.cpp @@ -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 */ + +#include "Code_stmt.hpp" + +// Plan_stmt + +Plan_stmt::~Plan_stmt() +{ +} + +// XXX remove +void +Plan_stmt::describe(Ctx& ctx) +{ + ctx_log1(("unimplemented describe")); +} + +// Exec_stmt + +Exec_stmt::Code::~Code() +{ +} + +Exec_stmt::Data::~Data() +{ +} + +Exec_stmt::~Exec_stmt() +{ +} + +void +Exec_stmt::bind(Ctx& ctx) +{ +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_stmt.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_stmt.hpp new file mode 100644 index 00000000000..20b7fb965fb --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_stmt.hpp @@ -0,0 +1,76 @@ +/* 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_Code_stmt_hpp +#define ODBC_CODEGEN_Code_stmt_hpp + +#include <common/common.hpp> +#include <common/DataType.hpp> +#include "Code_base.hpp" + +class Ctx; + +/** + * @class Plan_stmt + * @brief Base class for statements in PlanTree + * + * A statement is a complete or partial SQL statement which can + * be optimized into executable statements Exec_stmt. + */ +class Plan_stmt : public Plan_base { +public: + Plan_stmt(Plan_root* root); + virtual ~Plan_stmt() = 0; + virtual void describe(Ctx& ctx); +}; + +inline +Plan_stmt::Plan_stmt(Plan_root* root) : + Plan_base(root) +{ +} + +/** + * @class Exec_stmt + * @brief Base class for statements in ExecTree + */ +class Exec_stmt : public Exec_base { +public: + class Code : public Exec_base::Code { + public: + virtual ~Code() = 0; + }; + class Data : public Exec_base::Data { + public: + virtual ~Data() = 0; + }; + Exec_stmt(Exec_root* root); + virtual ~Exec_stmt() = 0; + virtual void bind(Ctx& ctx); + virtual void execute(Ctx& ctx, Ctl& ctl) = 0; +protected: + friend class Exec_root; + bool m_topLevel; +}; + +inline +Exec_stmt::Exec_stmt(Exec_root* root) : + Exec_base(root), + m_topLevel(false) +{ +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_table.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_table.cpp new file mode 100644 index 00000000000..ee3c2a2ed07 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_table.cpp @@ -0,0 +1,254 @@ +/* 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/StmtArea.hpp> +#include <dictionary/DictSchema.hpp> +#include <dictionary/DictTable.hpp> +#include <dictionary/DictColumn.hpp> +#include "Code_table.hpp" +#include "Code_column.hpp" +#include "Code_expr_column.hpp" + +Plan_table::~Plan_table() +{ +} + +Plan_base* +Plan_table::analyze(Ctx& ctx, Ctl& ctl) +{ + if (m_dictTable != 0) // already done + return this; + DictTable* table = dictSchema().findTable(m_name); + if (table == 0) { + table = dictSchema().loadTable(ctx, m_name); + if (table == 0) { + ctx.pushStatus(Sqlstate::_42S02, Error::Gen, "table %s not found", m_name.c_str()); + return 0; + } + } + m_dictTable = table; + // indexes + m_indexList.resize(1 + m_dictTable->indexCount()); + for (unsigned i = 0; i <= indexCount(); i++) { + Index& index = m_indexList[i]; + index.m_pos = i; + if (index.m_pos == 0) { + index.m_keyCount = m_dictTable->keyCount(); + index.m_rank = 0; + } else { + index.m_dictIndex = m_dictTable->getIndex(i); + index.m_keyCount = index.m_dictIndex->getSize(); + if (index.m_dictIndex->getType() == NdbDictionary::Object::UniqueHashIndex) { + index.m_rank = 1; + } else if (index.m_dictIndex->getType() == NdbDictionary::Object::OrderedIndex) { + index.m_rank = 2; + } else { + ctx_assert(false); + } + } + index.m_keyEqList.resize(1 + index.m_keyCount); + } + return this; +} + +int +Plan_table::resolveColumn(Ctx& ctx, Plan_column* column, bool stripSchemaName) +{ + ctx_assert(column != 0); + bool dml, unq; + switch (column->m_type) { + case Plan_column::Type_expr: + dml = false; + unq = false; + break; + case Plan_column::Type_dml: + dml = true; + unq = true; + break; + case Plan_column::Type_idx: + dml = false; + unq = true; + break; + default: + ctx_assert(false); + break; + } + ColumnVector& columns = ! dml ? m_exprColumns : m_dmlColumns; + const BaseString& name = column->m_name; + const BaseString& cname = column->m_cname; + ctx_log3(("resolve %s column %s in table %s", ! dml ? "expr" : "dml", column->getPrintName(), getPrintName())); + // find column in table + DictColumn* dictColumn = dictTable().findColumn(name); + if (dictColumn == 0) + return 0; + // qualified column must match table correlation name + if (! cname.empty()) { + const char* str; + if (! m_cname.empty()) { + str = m_cname.c_str(); + } else { + str = m_name.c_str(); + if (stripSchemaName && strrchr(str, '.') != 0) + str = strrchr(str, '.') + 1; + } + if (strcmp(cname.c_str(), str) != 0) + return 0; + } + // find in positional list or add to it + unsigned resPos; + for (resPos = 1; resPos < columns.size(); resPos++) { + if (strcmp(columns[resPos]->getName().c_str(), name.c_str()) != 0) + continue; + // these columns must be unique + if (unq) { + ctx.pushStatus(Error::Gen, "duplicate column %s", column->getName().c_str()); + return -1; + } + break; + } + if (resPos >= columns.size()) { + columns.push_back(column); + } + ctx_log3(("resolve to attrId %u pos %u", (unsigned)dictColumn->getAttrId(), resPos)); + column->m_dictColumn = dictColumn; + column->m_resTable = this; + column->m_resPos = resPos; + // found + return 1; +} + +bool +Plan_table::resolveEq(Ctx& ctx, Plan_expr_column* column, Plan_expr* expr) +{ + ctx_assert(m_dictTable != 0); + const TableSet& ts = expr->tableSet(); + TableSet::const_iterator i = ts.find(this); + if (i != ts.end()) + return false; + unsigned found = 0; + for (unsigned i = 0; i <= indexCount(); i++) { + Index& index = m_indexList[i]; + for (unsigned n = 1, cnt = 0; n <= index.m_keyCount; n++) { + const DictColumn* dictColumn = 0; + if (index.m_pos == 0) { + ctx_assert(m_dictTable != 0); + dictColumn = m_dictTable->getKey(n); + } else { + ctx_assert(index.m_dictIndex != 0); + dictColumn = index.m_dictIndex->getColumn(n); + } + if (dictColumn != &column->dictColumn()) + continue; + ctx_assert(++cnt == 1); + index.m_keyEqList[n].push_back(expr); + if (index.m_pos == 0) + ctx_log2(("%s: found match to primary key column %s pos %u", getPrintName(), column->getPrintName(), n)); + else + ctx_log2(("%s: found match to index %s column %s pos %u", getPrintName(), index.m_dictIndex->getName().c_str(), column->getPrintName(), n)); + found++; + } + } + return (found != 0); +} + +void +Plan_table::resolveSet(Ctx& ctx, Index& index, const TableSet& tsDone) +{ + index.m_keyFound = false; + ExprVector keyEq; + keyEq.resize(1 + index.m_keyCount); + resolveSet(ctx, index, tsDone, keyEq, 1); +} + +void +Plan_table::resolveSet(Ctx& ctx, Index& index, const TableSet& tsDone, ExprVector& keyEq, unsigned n) +{ + if (n <= index.m_keyCount) { + // building up combinations + ExprList& keyEqList = index.m_keyEqList[n]; + for (ExprList::iterator i = keyEqList.begin(); i != keyEqList.end(); i++) { + keyEq[n] = *i; + resolveSet(ctx, index, tsDone, keyEq, n + 1); + } + if (! keyEqList.empty() || index.m_rank <= 1 || n == 1) + return; + // ordered index with maximal initial key match + } + TableSet keySet; + for (unsigned i = 1; i <= n - 1; i++) { + const TableSet& tableSet = keyEq[i]->tableSet(); + for (TableSet::const_iterator j = tableSet.begin(); j != tableSet.end(); j++) { + if (tsDone.find(*j) == tsDone.end()) + keySet.insert(*j); + } + } + if (! index.m_keyFound || index.m_keySet.size() > keySet.size()) { + index.m_keyFound = true; + index.m_keyEq = keyEq; + index.m_keySet = keySet; + index.m_keyCountUsed = n - 1; + index.m_keyCountUnused = index.m_keyCount - index.m_keyCountUsed; + // set matching size + index.m_keyEq.resize(1 + index.m_keyCountUsed); + } +} + +bool +Plan_table::exactKey(Ctx& ctx, const Index* indexKey) const +{ + ctx_assert(indexKey != 0 && indexKey == &m_indexList[indexKey->m_pos]); + for (unsigned i = 0; i <= indexCount(); i++) { + const Index& index = m_indexList[i]; + const ExprListVector& keyEqList = index.m_keyEqList; + for (unsigned n = 1; n <= index.m_keyCount; n++) { + if (index.m_pos == indexKey->m_pos) { + ctx_assert(keyEqList[n].size() >= 1); + if (keyEqList[n].size() > 1) { + ctx_log2(("index %u not exact: column %u has %u > 1 matches", + indexKey->m_pos, + n, + (unsigned)keyEqList[n].size())); + return false; + } + } else { + if (keyEqList[n].size() > 0) { + ctx_log2(("index %u not exact: index %u column %u has %u > 0 matches", + indexKey->m_pos, + index.m_pos, + n, + (unsigned)keyEqList[n].size())); + return false; + } + } + } + } + ctx_log2(("index %u is exact", indexKey->m_pos)); + return true; +} + +Exec_base* +Plan_table::codegen(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(false); + return 0; +} + +void +Plan_table::print(Ctx& ctx) +{ + ctx.print(" [table %s]", getPrintName()); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_table.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_table.hpp new file mode 100644 index 00000000000..8a95b8fa26c --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_table.hpp @@ -0,0 +1,202 @@ +/* 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_Code_table_hpp +#define ODBC_CODEGEN_Code_table_hpp + +#include <vector> +#include <common/common.hpp> +#include "Code_base.hpp" + +class DictTable; +class DictColumn; +class DictIndex; +class Plan_query_filter; +class Plan_query_lookup; +class Plan_query_range; +class Plan_column; +class Plan_expr_column; +class Plan_select; +class Plan_delete; +class Plan_delete_lookup; +class Plan_update; +class Plan_update_lookup; + +/** + * @class Plan_table + * @brief Table node in PlanTree + * + * This is a pure Plan node. Final executable nodes have table + * information built-in. + */ +class Plan_table : public Plan_base { +public: + Plan_table(Plan_root* root, const BaseString& name); + virtual ~Plan_table(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // attributes + const BaseString& getName() const; + const BaseString& getCname() const; + const char* getPrintName() const; + void setCname(const BaseString& cname); + const DictTable& dictTable() const; + unsigned indexCount() const; + // resolve + const ColumnVector& exprColumns() const; + const ColumnVector& dmlColumns() const; +protected: + friend class Plan_column; + friend class Plan_query_filter; + friend class Plan_query_lookup; + friend class Plan_query_index; + friend class Plan_query_range; + friend class Plan_expr_column; + friend class Plan_select; + friend class Plan_delete; + friend class Plan_delete_lookup; + friend class Plan_delete_index; + friend class Plan_update; + friend class Plan_update_lookup; + friend class Plan_update_index; + BaseString m_name; + BaseString m_cname; + BaseString m_printName; + DictTable* m_dictTable; + /* + * Resolve column. Returns 1 on found, 0 on not found, and -1 on error. + * Modifies both table and column data. + */ + int resolveColumn(Ctx& ctx, Plan_column* column, bool stripSchemaName = false); + ColumnVector m_exprColumns; + ColumnVector m_dmlColumns; + /* + * Offset for resolved columns in join. This is sum over m_exprColumns + * lengths for all preceding tables. + */ + unsigned m_resOff; + /* + * Each column in primary key and unique hash index has list of + * expressions it is set equal to in the where-clause (at top level). + */ + bool resolveEq(Ctx& ctx, Plan_expr_column* column, Plan_expr* expr); + /* + * Index struct for primary key and indexes. + */ + struct Index { + Index() : + m_pos(0), + m_keyFound(false), + m_dictIndex(0), + m_rank(~0), + m_keyCount(0), + m_keyCountUsed(0) { + } + unsigned m_pos; + ExprListVector m_keyEqList; + bool m_keyFound; + ExprVector m_keyEq; + TableSet m_keySet; + const DictIndex* m_dictIndex; // for index only + unsigned m_rank; // 0-pk 1-hash index 2-ordered index + unsigned m_keyCount; // number of columns + unsigned m_keyCountUsed; // may be less for ordered index + unsigned m_keyCountUnused; // m_keyCount - m_keyCountUsed + }; + typedef std::vector<Index> IndexList; // primary key is entry 0 + IndexList m_indexList; + /* + * Find set of additional tables (maybe empty) required to resolve the key + * columns. + */ + void resolveSet(Ctx& ctx, Index& index, const TableSet& tsDone); + void resolveSet(Ctx& ctx, Index& index, const TableSet& tsDone, ExprVector& keyEq, unsigned n); + /* + * Check for exactly one key or index match. + */ + bool exactKey(Ctx& ctx, const Index* indexKey) const; +}; + +inline +Plan_table::Plan_table(Plan_root* root, const BaseString& name) : + Plan_base(root), + m_name(name), + m_printName(name), + m_dictTable(0), + m_exprColumns(1), // 1-based + m_dmlColumns(1), // 1-based + m_resOff(0), + m_indexList(1) +{ +} + +inline const BaseString& +Plan_table::getName() const +{ + return m_name; +} + +inline const BaseString& +Plan_table::getCname() const +{ + return m_cname; +} + +inline const char* +Plan_table::getPrintName() const +{ + return m_printName.c_str(); +} + +inline void +Plan_table::setCname(const BaseString& cname) +{ + m_cname.assign(cname); + m_printName.assign(m_name); + if (! m_cname.empty()) { + m_printName.append(" "); + m_printName.append(m_cname); + } +} + +inline const DictTable& +Plan_table::dictTable() const +{ + ctx_assert(m_dictTable != 0); + return *m_dictTable; +} + +inline unsigned +Plan_table::indexCount() const +{ + ctx_assert(m_indexList.size() > 0); + return m_indexList.size() - 1; +} + +inline const Plan_table::ColumnVector& +Plan_table::exprColumns() const +{ + return m_exprColumns; +} + +inline const Plan_table::ColumnVector& +Plan_table::dmlColumns() const +{ + return m_dmlColumns; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_table_list.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_table_list.cpp new file mode 100644 index 00000000000..ea9f4fdc26e --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_table_list.cpp @@ -0,0 +1,53 @@ +/* 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 "Code_table_list.hpp" + +Plan_table_list::~Plan_table_list() +{ +} + +Plan_base* +Plan_table_list::analyze(Ctx& ctx, Ctl& ctl) +{ + // analyze the tables + for (unsigned i = 1, n = countTable(); i <= n; i++) { + Plan_table* table = getTable(i); + table->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + } + // node was not replaced + return this; +} + +Exec_base* +Plan_table_list::codegen(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(false); + return 0; +} + +void +Plan_table_list::print(Ctx& ctx) +{ + ctx.print(" [table_list"); + for (unsigned i = 1, n = countTable(); i <= n; i++) { + Plan_base* a[] = { m_tableList[i] }; + printList(ctx, a, 1); + } + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_table_list.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_table_list.hpp new file mode 100644 index 00000000000..47989166cac --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_table_list.hpp @@ -0,0 +1,73 @@ +/* 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_Code_table_list_hpp +#define ODBC_CODEGEN_Code_table_list_hpp + +#include <common/common.hpp> +#include "Code_base.hpp" +#include "Code_table.hpp" + +/** + * @class Plan_table_list + * @brief List of tables in select statement + */ +class Plan_table_list : public Plan_base { +public: + Plan_table_list(Plan_root* root); + virtual ~Plan_table_list(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + unsigned countTable() const; + void addTable(Plan_table* table); + Plan_table* getTable(unsigned i) const; +protected: + friend class Plan_select; + TableVector m_tableList; +}; + +inline +Plan_table_list::Plan_table_list(Plan_root* root) : + Plan_base(root), + m_tableList(1) +{ +} + +// children + +inline unsigned +Plan_table_list::countTable() const +{ + return m_tableList.size() - 1; +} + +inline void +Plan_table_list::addTable(Plan_table* table) +{ + ctx_assert(table != 0); + m_tableList.push_back(table); +} + +inline Plan_table* +Plan_table_list::getTable(unsigned i) const +{ + ctx_assert(1 <= i && i <= countTable() && m_tableList[i] != 0); + return m_tableList[i]; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_update.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_update.cpp new file mode 100644 index 00000000000..0b33cd628b4 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_update.cpp @@ -0,0 +1,246 @@ +/* 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/StmtArea.hpp> +#include <dictionary/DictTable.hpp> +#include <dictionary/DictColumn.hpp> +#include "Code_update.hpp" +#include "Code_update_lookup.hpp" +#include "Code_update_index.hpp" +#include "Code_update_scan.hpp" +#include "Code_table.hpp" +#include "Code_query_project.hpp" +#include "Code_query_filter.hpp" +#include "Code_query_scan.hpp" +#include "Code_query_lookup.hpp" +#include "Code_query_index.hpp" +#include "Code_query_range.hpp" +#include "Code_query_repeat.hpp" +#include "Code_root.hpp" + +// Plan_update + +Plan_update::~Plan_update() +{ +} + +Plan_base* +Plan_update::analyze(Ctx& ctx, Ctl& ctl) +{ + stmtArea().stmtInfo().setName(Stmt_name_update); + // analyze the table + ctx_assert(m_table != 0); + m_table->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + // get column and expression rows + ctx_assert(m_setRow != 0); + setDmlRow(m_setRow->m_dmlRow); + setExprRow(m_setRow->m_exprRow); + m_setRow = 0; + // implied by parse + ctx_assert(m_dmlRow->getSize() == m_exprRow->getSize()); + // set name resolution scope + ctl.m_tableList.resize(1 + 1); // indexed from 1 + ctl.m_tableList[1] = m_table; + // analyze the rows + m_dmlRow->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + ctl.m_dmlRow = m_dmlRow; // row type to convert to + ctl.m_const = true; // set to constants + m_exprRow->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + bool setConst = ctl.m_const; + ctl.m_dmlRow = 0; + Plan_dml* stmt = 0; + // top level query is a project + Plan_query_project* queryProject = new Plan_query_project(m_root); + m_root->saveNode(queryProject); + queryProject->setRow(m_exprRow); + if (m_pred != 0) { + // analyze the predicate + ctl.m_topand = true; + ctl.m_extra = false; + m_pred = static_cast<Plan_pred*>(m_pred->analyze(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(m_pred != 0); + // check for key match + Plan_table::Index* indexBest = 0; + for (unsigned i = 0; i <= m_table->indexCount(); i++) { + Plan_table::Index& index = m_table->m_indexList[i]; + TableSet tsDone; + m_table->resolveSet(ctx, index, tsDone); + if (! ctx.ok()) + return 0; + if (! index.m_keyFound) + continue; + // prefer smaller rank, less unused keys + int k; + (k = (indexBest == 0)) || + (k = (indexBest->m_rank - index.m_rank)) || + (k = (indexBest->m_keyCountUnused - index.m_keyCountUnused)); + if (k > 0) + indexBest = &index; + } + if (indexBest != 0) { + const bool exactKey = indexBest->m_rank <= 1 ? m_table->exactKey(ctx, indexBest) : false; + const bool direct = setConst && ! ctl.m_extra && exactKey; + ctx_log3(("update direct=%d: const=%d extra=%d exact=%d", direct, setConst, ctl.m_extra, exactKey)); + if (indexBest->m_rank == 0) { + // primary key + Plan_update_lookup* updateLookup = new Plan_update_lookup(m_root); + m_root->saveNode(updateLookup); + updateLookup->setTable(m_table); + updateLookup->setDmlRow(m_dmlRow); + if (direct) { + // constant values and exact key match + Plan_query_repeat* queryRepeat = new Plan_query_repeat(m_root, 1); + m_root->saveNode(queryRepeat); + queryProject->setQuery(queryRepeat); + } else { + // more conditions or non-constant values + Plan_query_lookup* queryLookup = new Plan_query_lookup(m_root); + m_root->saveNode(queryLookup); + Plan_query_filter* queryFilter = new Plan_query_filter(m_root); + m_root->saveNode(queryFilter); + queryLookup->setTable(m_table); + queryFilter->setQuery(queryLookup); + queryFilter->setPred(m_pred); + queryFilter->m_topTable = m_table; + queryProject->setQuery(queryFilter); + } + updateLookup->setQuery(queryProject); + stmt = updateLookup; + } else if (indexBest->m_rank == 1) { + // hash index + Plan_update_index* updateIndex = new Plan_update_index(m_root); + m_root->saveNode(updateIndex); + updateIndex->setTable(m_table, indexBest); + updateIndex->setDmlRow(m_dmlRow); + if (direct) { + // constant values and exact key match + Plan_query_repeat* queryRepeat = new Plan_query_repeat(m_root, 1); + m_root->saveNode(queryRepeat); + queryProject->setQuery(queryRepeat); + } else { + // more conditions or non-constant values + Plan_query_index* queryIndex = new Plan_query_index(m_root); + m_root->saveNode(queryIndex); + Plan_query_filter* queryFilter = new Plan_query_filter(m_root); + m_root->saveNode(queryFilter); + queryIndex->setTable(m_table, indexBest); + queryFilter->setQuery(queryIndex); + queryFilter->setPred(m_pred); + queryFilter->m_topTable = m_table; + queryProject->setQuery(queryFilter); + } + updateIndex->setQuery(queryProject); + stmt = updateIndex; + } else if (indexBest->m_rank == 2) { + // ordered index + Plan_update_scan* updateScan = new Plan_update_scan(m_root); + m_root->saveNode(updateScan); + updateScan->setTable(m_table); + updateScan->setDmlRow(m_dmlRow); + Plan_query_range* queryRange = new Plan_query_range(m_root); + m_root->saveNode(queryRange); + queryRange->setTable(m_table, indexBest); + queryRange->setExclusive(); + Plan_query_filter* queryFilter = new Plan_query_filter(m_root); + m_root->saveNode(queryFilter); + queryFilter->setQuery(queryRange); + queryFilter->setPred(m_pred); + queryFilter->m_topTable = m_table; + // interpeter + const TableSet& ts2 = m_pred->noInterp(); + ctx_assert(ts2.size() <= 1); + if (ts2.size() == 0) { + queryRange->setInterp(m_pred); + } + queryProject->setQuery(queryFilter); + updateScan->setQuery(queryProject); + stmt = updateScan; + } else { + ctx_assert(false); + } + } else { + // scan update with filter + Plan_update_scan* updateScan = new Plan_update_scan(m_root); + m_root->saveNode(updateScan); + updateScan->setTable(m_table); + updateScan->setDmlRow(m_dmlRow); + Plan_query_scan* queryScan = new Plan_query_scan(m_root); + m_root->saveNode(queryScan); + queryScan->setTable(m_table); + queryScan->setExclusive(); + Plan_query_filter* queryFilter = new Plan_query_filter(m_root); + m_root->saveNode(queryFilter); + queryFilter->setQuery(queryScan); + queryFilter->setPred(m_pred); + queryFilter->m_topTable = m_table; + // interpeter + const TableSet& ts2 = m_pred->noInterp(); + ctx_assert(ts2.size() <= 1); + if (ts2.size() == 0) { + queryScan->setInterp(m_pred); + } + queryProject->setQuery(queryFilter); + updateScan->setQuery(queryProject); + stmt = updateScan; + } + } else { + // scan update without filter + Plan_update_scan* updateScan = new Plan_update_scan(m_root); + m_root->saveNode(updateScan); + updateScan->setTable(m_table); + updateScan->setDmlRow(m_dmlRow); + Plan_query_scan* queryScan = new Plan_query_scan(m_root); + m_root->saveNode(queryScan); + queryScan->setTable(m_table); + queryScan->setExclusive(); + queryProject->setQuery(queryScan); + updateScan->setQuery(queryProject); + stmt = updateScan; + } + // set base for column position offsets + m_table->m_resOff = 1; + return stmt; +} + +void +Plan_update::describe(Ctx& ctx) +{ + stmtArea().setFunction(ctx, "UPDATE WHERE", SQL_DIAG_UPDATE_WHERE); +} + +Exec_base* +Plan_update::codegen(Ctx& ctx, Ctl& ctl) +{ + ctx_assert(false); + return 0; +} + +void +Plan_update::print(Ctx& ctx) +{ + ctx.print(" [update"); + Plan_base* a[] = { m_table, m_setRow, m_dmlRow, m_exprRow }; + printList(ctx, a, 4); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_update.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_update.hpp new file mode 100644 index 00000000000..380b651518b --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_update.hpp @@ -0,0 +1,102 @@ +/* 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_Code_update_hpp +#define ODBC_CODEGEN_Code_update_hpp + +#include <common/common.hpp> +#include "Code_base.hpp" +#include "Code_dml.hpp" +#include "Code_set_row.hpp" +#include "Code_table.hpp" +#include "Code_pred.hpp" +#include "Code_query.hpp" + +/** + * @class Plan_update + * @brief Update in PlanTree + */ +class Plan_update : public Plan_dml { +public: + Plan_update(Plan_root* root); + virtual ~Plan_update(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void describe(Ctx& ctx); + void print(Ctx& ctx); + // children + void setTable(Plan_table* table); + void setRow(Plan_set_row* setRow); + void setDmlRow(Plan_dml_row* dmlRow); + void setExprRow(Plan_expr_row* exprRow); + void setPred(Plan_pred* pred); +protected: + Plan_table* m_table; + Plan_set_row* m_setRow; + Plan_dml_row* m_dmlRow; + Plan_expr_row* m_exprRow; + Plan_pred* m_pred; +}; + +inline +Plan_update::Plan_update(Plan_root* root) : + Plan_dml(root), + m_table(0), + m_setRow(0), + m_dmlRow(0), + m_exprRow(0), + m_pred(0) +{ +} + +// children + +inline void +Plan_update::setTable(Plan_table* table) +{ + ctx_assert(table != 0); + m_table = table; +} + +inline void +Plan_update::setRow(Plan_set_row* setRow) +{ + ctx_assert(setRow != 0); + m_setRow = setRow; +} + +inline void +Plan_update::setDmlRow(Plan_dml_row* dmlRow) +{ + ctx_assert(dmlRow != 0); + m_dmlRow = dmlRow; +} + +inline void +Plan_update::setExprRow(Plan_expr_row* exprRow) +{ + ctx_assert(exprRow != 0); + m_exprRow = exprRow; +} + +inline void +Plan_update::setPred(Plan_pred* pred) +{ + ctx_assert(pred != 0); + m_pred = pred; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_update_index.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_update_index.cpp new file mode 100644 index 00000000000..6f74db0d913 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_update_index.cpp @@ -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 */ + +#include <common/StmtArea.hpp> +#include <dictionary/DictTable.hpp> +#include <dictionary/DictColumn.hpp> +#include "Code_dml_column.hpp" +#include "Code_expr.hpp" +#include "Code_update_index.hpp" +#include "Code_table.hpp" +#include "Code_root.hpp" + +// Plan_update_index + +Plan_update_index::~Plan_update_index() +{ +} + +Plan_base* +Plan_update_index::analyze(Ctx& ctx, Ctl& ctl) +{ + ctl.m_dmlRow = m_dmlRow; // row type to convert to + ctx_assert(m_query != 0); + m_query->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + ctx_assert(m_table != 0); + m_table->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + return this; +} + +void +Plan_update_index::describe(Ctx& ctx) +{ + stmtArea().setFunction(ctx, "UPDATE WHERE", SQL_DIAG_UPDATE_WHERE); +} + +Exec_base* +Plan_update_index::codegen(Ctx& ctx, Ctl& ctl) +{ + // generate code for the query + ctx_assert(m_query != 0); + Exec_query* execQuery = static_cast<Exec_query*>(m_query->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execQuery != 0); + // set up + ctx_assert(m_table != 0 && m_index != 0); + const BaseString& tableName = m_table->getName(); + ctx_assert(m_index->m_dictIndex != 0); + const DictIndex& dictIndex = *m_index->m_dictIndex; + const BaseString& indexName = dictIndex.getName(); + const unsigned keyCount = m_index->m_keyCount; + const ColumnVector& columns = m_table->dmlColumns(); + ctx_assert(columns.size() > 0); + const unsigned attrCount = columns.size() - 1; + // create the code + Exec_update_index::Code& code = *new Exec_update_index::Code(keyCount); + code.m_tableName = strcpy(new char[tableName.length() + 1], tableName.c_str()); + code.m_indexName = strcpy(new char[indexName.length() + 1], indexName.c_str()); + // key attributes + code.m_keyId = new NdbAttrId[1 + keyCount]; + code.m_keyId[0] = (NdbAttrId)-1; + for (unsigned k = 1; k <= keyCount; k++) { + const DictColumn* keyColumn = dictIndex.getColumn(k); + const SqlType& sqlType = keyColumn->sqlType(); + SqlSpec sqlSpec(sqlType, SqlSpec::Physical); + code.m_keySpecs.setEntry(k, sqlSpec); + code.m_keyId[k] = k - 1; // index column order + } + // matching expressions + ctx_assert(m_index->m_keyFound); + const ExprVector& keyEq = m_index->m_keyEq; + ctx_assert(keyEq.size() == 1 + keyCount); + code.m_keyMatch = new Exec_expr* [1 + keyCount]; + code.m_keyMatch[0] = 0; + for (unsigned k = 1; k <= keyCount; k++) { + Plan_expr* expr = keyEq[k]; + Exec_expr* execExpr = static_cast<Exec_expr*>(expr->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execExpr != 0); + code.m_keyMatch[k] = execExpr; + } + // updated attributes + code.m_attrCount = attrCount; + code.m_attrId = new NdbAttrId[1 + attrCount]; + code.m_attrId[0] = (NdbAttrId)-1; + for (unsigned i = 1; i <= attrCount; i++) { + Plan_column* column = columns[i]; + ctx_assert(column != 0); + const DictColumn& dictColumn = column->dictColumn(); + code.m_attrId[i] = dictColumn.getAttrId(); + } + // create the exec + Exec_update_index* exec = new Exec_update_index(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + exec->setCode(code); + exec->setQuery(execQuery); + return exec; +} + +void +Plan_update_index::print(Ctx& ctx) +{ + ctx.print(" [update_index"); + Plan_base* a[] = { m_table, m_query }; + printList(ctx, a, sizeof(a)/sizeof(a[0])); + ctx.print("]"); +} + +// Exec_delete + +Exec_update_index::Code::~Code() +{ + delete[] m_tableName; + delete[] m_keyId; + delete[] m_keyMatch; + delete[] m_attrId; +} + +Exec_update_index::Data::~Data() +{ +} + +Exec_update_index::~Exec_update_index() +{ +} + +void +Exec_update_index::alloc(Ctx& ctx, Ctl& ctl) +{ + const Code& code = getCode(); + // allocate the subquery + ctx_assert(m_query != 0); + m_query->alloc(ctx, ctl); + if (! ctx.ok()) + return; + // create data + Data& data = *new Data; + setData(data); + // allocate matching expressions + for (unsigned k = 1; k <= code.m_keyCount; k++) { + Exec_expr* expr = code.m_keyMatch[k]; + ctx_assert(expr != 0); + expr->alloc(ctx, ctl); + if (! ctx.ok()) + return; + } +} + +void +Exec_update_index::close(Ctx& ctx) +{ + ctx_assert(m_query != 0); + m_query->close(ctx); +} + +void +Exec_update_index::print(Ctx& ctx) +{ + ctx.print(" [update_index"); + if (m_code != 0) { + const Code& code = getCode(); + ctx.print(" keyId="); + for (unsigned i = 1; i <= code.m_keyCount; i++) { + if (i > 1) + ctx.print(","); + ctx.print("%u", (unsigned)code.m_keyId[i]); + } + ctx.print(" attrId="); + for (unsigned i = 1; i <= code.m_attrCount; i++) { + if (i > 1) + ctx.print(","); + ctx.print("%u", (unsigned)code.m_attrId[i]); + } + } + Exec_base* a[] = { m_query }; + printList(ctx, a, 1); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_update_index.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_update_index.hpp new file mode 100644 index 00000000000..bbad822650a --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_update_index.hpp @@ -0,0 +1,171 @@ +/* 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_Code_update_index_hpp +#define ODBC_CODEGEN_Code_update_index_hpp + +#include <common/common.hpp> +#include "Code_base.hpp" +#include "Code_dml.hpp" +#include "Code_table.hpp" +#include "Code_query.hpp" + +/** + * @class Plan_update_index + * @brief Update in PlanTree + */ +class Plan_update_index : public Plan_dml { +public: + Plan_update_index(Plan_root* root); + virtual ~Plan_update_index(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + void describe(Ctx& ctx); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setTable(Plan_table* table, Plan_table::Index* index); + void setDmlRow(Plan_dml_row* dmlRow); + void setQuery(Plan_query* query); +protected: + Plan_table* m_table; + Plan_table::Index* m_index; + Plan_dml_row* m_dmlRow; + Plan_query* m_query; +}; + +inline +Plan_update_index::Plan_update_index(Plan_root* root) : + Plan_dml(root), + m_table(0), + m_dmlRow(0), + m_query(0) +{ +} + +inline void +Plan_update_index::setTable(Plan_table* table, Plan_table::Index* index) +{ + ctx_assert(table != 0 && index != 0 && index == &table->m_indexList[index->m_pos] && index->m_pos != 0); + m_table = table; + m_index = index; +} + +inline void +Plan_update_index::setDmlRow(Plan_dml_row* dmlRow) +{ + ctx_assert(dmlRow != 0); + m_dmlRow = dmlRow; +} + +inline void +Plan_update_index::setQuery(Plan_query* query) +{ + ctx_assert(query != 0); + m_query = query; +} + +/** + * @class Exec_update_index + * @brief Insert in ExecTree + */ +class Exec_update_index : public Exec_dml { +public: + class Code : public Exec_dml::Code { + public: + Code(unsigned keyCount); + virtual ~Code(); + protected: + friend class Plan_update_index; + friend class Exec_update_index; + const char* m_tableName; + const char* m_indexName; + unsigned m_keyCount; + SqlSpecs m_keySpecs; // key types + NdbAttrId* m_keyId; + Exec_expr** m_keyMatch; // XXX pointers for now + unsigned m_attrCount; + NdbAttrId* m_attrId; + }; + class Data : public Exec_dml::Data { + public: + Data(); + virtual ~Data(); + protected: + friend class Exec_update_index; + }; + Exec_update_index(Exec_root* root); + virtual ~Exec_update_index(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setQuery(Exec_query* query); +protected: + Exec_query* m_query; +}; + +inline +Exec_update_index::Code::Code(unsigned keyCount) : + m_tableName(0), + m_indexName(0), + m_keyCount(keyCount), + m_keySpecs(keyCount), + m_keyId(0), + m_keyMatch(0), + m_attrCount(0), + m_attrId(0) +{ +} + +inline +Exec_update_index::Data::Data() +{ +} + +inline +Exec_update_index::Exec_update_index(Exec_root* root) : + Exec_dml(root), + m_query(0) +{ +} + +// children + +inline const Exec_update_index::Code& +Exec_update_index::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_update_index::Data& +Exec_update_index::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_update_index::setQuery(Exec_query* query) +{ + ctx_assert(query != 0 && m_query == 0); + m_query = query; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_update_lookup.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_update_lookup.cpp new file mode 100644 index 00000000000..7525fb72692 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_update_lookup.cpp @@ -0,0 +1,194 @@ +/* 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/StmtArea.hpp> +#include <dictionary/DictTable.hpp> +#include <dictionary/DictColumn.hpp> +#include "Code_dml_column.hpp" +#include "Code_expr.hpp" +#include "Code_update_lookup.hpp" +#include "Code_table.hpp" +#include "Code_root.hpp" + +// Plan_update_lookup + +Plan_update_lookup::~Plan_update_lookup() +{ +} + +Plan_base* +Plan_update_lookup::analyze(Ctx& ctx, Ctl& ctl) +{ + ctl.m_dmlRow = m_dmlRow; // row type to convert to + ctx_assert(m_query != 0); + m_query->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + ctx_assert(m_table != 0); + m_table->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + return this; +} + +void +Plan_update_lookup::describe(Ctx& ctx) +{ + stmtArea().setFunction(ctx, "UPDATE WHERE", SQL_DIAG_UPDATE_WHERE); +} + +Exec_base* +Plan_update_lookup::codegen(Ctx& ctx, Ctl& ctl) +{ + // generate code for the query + ctx_assert(m_query != 0); + Exec_query* execQuery = static_cast<Exec_query*>(m_query->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execQuery != 0); + // set up + ctx_assert(m_table != 0); + const BaseString& tableName = m_table->getName(); + const DictTable& dictTable = m_table->dictTable(); + const unsigned keyCount = dictTable.keyCount(); + const ColumnVector& columns = m_table->dmlColumns(); + ctx_assert(columns.size() > 0); + const unsigned attrCount = columns.size() - 1; + // create the code + Exec_update_lookup::Code& code = *new Exec_update_lookup::Code(keyCount); + code.m_tableName = strcpy(new char[tableName.length() + 1], tableName.c_str()); + // key attributes + code.m_keyId = new NdbAttrId[1 + keyCount]; + code.m_keyId[0] = (NdbAttrId)-1; + for (unsigned k = 1; k <= keyCount; k++) { + const DictColumn* keyColumn = dictTable.getKey(k); + const SqlType& sqlType = keyColumn->sqlType(); + SqlSpec sqlSpec(sqlType, SqlSpec::Physical); + code.m_keySpecs.setEntry(k, sqlSpec); + code.m_keyId[k] = keyColumn->getAttrId(); + } + // matching expressions + const Plan_table::Index& index = m_table->m_indexList[0]; + ctx_assert(index.m_keyFound); + const ExprVector& keyEq = index.m_keyEq; + ctx_assert(keyEq.size() == 1 + keyCount); + code.m_keyMatch = new Exec_expr* [1 + keyCount]; + code.m_keyMatch[0] = 0; + for (unsigned k = 1; k <= keyCount; k++) { + Plan_expr* expr = keyEq[k]; + Exec_expr* execExpr = static_cast<Exec_expr*>(expr->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execExpr != 0); + code.m_keyMatch[k] = execExpr; + } + // updated attributes + code.m_attrCount = attrCount; + code.m_attrId = new NdbAttrId[1 + attrCount]; + code.m_attrId[0] = (NdbAttrId)-1; + for (unsigned i = 1; i <= attrCount; i++) { + Plan_column* column = columns[i]; + ctx_assert(column != 0); + const DictColumn& dictColumn = column->dictColumn(); + code.m_attrId[i] = dictColumn.getAttrId(); + } + // create the exec + Exec_update_lookup* exec = new Exec_update_lookup(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + exec->setCode(code); + exec->setQuery(execQuery); + return exec; +} + +void +Plan_update_lookup::print(Ctx& ctx) +{ + ctx.print(" [update_lookup"); + Plan_base* a[] = { m_table, m_query }; + printList(ctx, a, sizeof(a)/sizeof(a[0])); + ctx.print("]"); +} + +// Exec_delete + +Exec_update_lookup::Code::~Code() +{ + delete[] m_tableName; + delete[] m_keyId; + delete[] m_keyMatch; + delete[] m_attrId; +} + +Exec_update_lookup::Data::~Data() +{ +} + +Exec_update_lookup::~Exec_update_lookup() +{ +} + +void +Exec_update_lookup::alloc(Ctx& ctx, Ctl& ctl) +{ + const Code& code = getCode(); + // allocate the subquery + ctx_assert(m_query != 0); + m_query->alloc(ctx, ctl); + if (! ctx.ok()) + return; + // create data + Data& data = *new Data; + setData(data); + // allocate matching expressions + for (unsigned k = 1; k <= code.m_keyCount; k++) { + Exec_expr* expr = code.m_keyMatch[k]; + ctx_assert(expr != 0); + expr->alloc(ctx, ctl); + if (! ctx.ok()) + return; + } +} + +void +Exec_update_lookup::close(Ctx& ctx) +{ + ctx_assert(m_query != 0); + m_query->close(ctx); +} + +void +Exec_update_lookup::print(Ctx& ctx) +{ + ctx.print(" [update_lookup"); + if (m_code != 0) { + const Code& code = getCode(); + ctx.print(" keyId="); + for (unsigned i = 1; i <= code.m_keyCount; i++) { + if (i > 1) + ctx.print(","); + ctx.print("%u", (unsigned)code.m_keyId[i]); + } + ctx.print(" attrId="); + for (unsigned i = 1; i <= code.m_attrCount; i++) { + if (i > 1) + ctx.print(","); + ctx.print("%u", (unsigned)code.m_attrId[i]); + } + } + Exec_base* a[] = { m_query }; + printList(ctx, a, 1); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_update_lookup.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_update_lookup.hpp new file mode 100644 index 00000000000..fc4341880dd --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_update_lookup.hpp @@ -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 */ + +#ifndef ODBC_CODEGEN_Code_update_lookup_hpp +#define ODBC_CODEGEN_Code_update_lookup_hpp + +#include <common/common.hpp> +#include "Code_base.hpp" +#include "Code_dml.hpp" +#include "Code_table.hpp" +#include "Code_query.hpp" + +/** + * @class Plan_update_lookup + * @brief Update in PlanTree + */ +class Plan_update_lookup : public Plan_dml { +public: + Plan_update_lookup(Plan_root* root); + virtual ~Plan_update_lookup(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + void describe(Ctx& ctx); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setTable(Plan_table* table); + void setDmlRow(Plan_dml_row* dmlRow); + void setQuery(Plan_query* query); +protected: + Plan_table* m_table; + Plan_dml_row* m_dmlRow; + Plan_query* m_query; +}; + +inline +Plan_update_lookup::Plan_update_lookup(Plan_root* root) : + Plan_dml(root), + m_table(0), + m_dmlRow(0), + m_query(0) +{ +} + +inline void +Plan_update_lookup::setTable(Plan_table* table) +{ + ctx_assert(table != 0); + m_table = table; +} + +inline void +Plan_update_lookup::setDmlRow(Plan_dml_row* dmlRow) +{ + ctx_assert(dmlRow != 0); + m_dmlRow = dmlRow; +} + +inline void +Plan_update_lookup::setQuery(Plan_query* query) +{ + ctx_assert(query != 0); + m_query = query; +} + +/** + * @class Exec_update_lookup + * @brief Insert in ExecTree + */ +class Exec_update_lookup : public Exec_dml { +public: + class Code : public Exec_dml::Code { + public: + Code(unsigned keyCount); + virtual ~Code(); + protected: + friend class Plan_update_lookup; + friend class Exec_update_lookup; + char* m_tableName; + unsigned m_keyCount; + SqlSpecs m_keySpecs; // key types + NdbAttrId* m_keyId; + Exec_expr** m_keyMatch; // XXX pointers for now + unsigned m_attrCount; + NdbAttrId* m_attrId; + }; + class Data : public Exec_dml::Data { + public: + Data(); + virtual ~Data(); + protected: + friend class Exec_update_lookup; + }; + Exec_update_lookup(Exec_root* root); + virtual ~Exec_update_lookup(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setQuery(Exec_query* query); +protected: + Exec_query* m_query; +}; + +inline +Exec_update_lookup::Code::Code(unsigned keyCount) : + m_tableName(0), + m_keyCount(keyCount), + m_keySpecs(keyCount), + m_keyId(0), + m_keyMatch(0), + m_attrCount(0), + m_attrId(0) +{ +} + +inline +Exec_update_lookup::Data::Data() +{ +} + +inline +Exec_update_lookup::Exec_update_lookup(Exec_root* root) : + Exec_dml(root), + m_query(0) +{ +} + +// children + +inline const Exec_update_lookup::Code& +Exec_update_lookup::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_update_lookup::Data& +Exec_update_lookup::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_update_lookup::setQuery(Exec_query* query) +{ + ctx_assert(query != 0 && m_query == 0); + m_query = query; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_update_scan.cpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_update_scan.cpp new file mode 100644 index 00000000000..9fac1728469 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_update_scan.cpp @@ -0,0 +1,146 @@ +/* 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/StmtArea.hpp> +#include <dictionary/DictTable.hpp> +#include <dictionary/DictColumn.hpp> +#include "Code_dml_column.hpp" +#include "Code_update_scan.hpp" +#include "Code_table.hpp" +#include "Code_root.hpp" + +// Plan_update_scan + +Plan_update_scan::~Plan_update_scan() +{ +} + +Plan_base* +Plan_update_scan::analyze(Ctx& ctx, Ctl& ctl) +{ + ctl.m_dmlRow = m_dmlRow; // row type to convert to + ctx_assert(m_query != 0); + m_query->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + ctx_assert(m_table != 0); + m_table->analyze(ctx, ctl); + if (! ctx.ok()) + return 0; + return this; +} + +void +Plan_update_scan::describe(Ctx& ctx) +{ + stmtArea().setFunction(ctx, "UPDATE WHERE", SQL_DIAG_UPDATE_WHERE); +} + +Exec_base* +Plan_update_scan::codegen(Ctx& ctx, Ctl& ctl) +{ + // generate code for the query + ctx_assert(m_query != 0); + Exec_query* execQuery = static_cast<Exec_query*>(m_query->codegen(ctx, ctl)); + if (! ctx.ok()) + return 0; + ctx_assert(execQuery != 0); + // set up + ctx_assert(m_table != 0); + const ColumnVector& columns = m_table->dmlColumns(); + ctx_assert(columns.size() > 0); + const unsigned attrCount = columns.size() - 1; + // create the code + Exec_update_scan::Code& code = *new Exec_update_scan::Code(); + // updated attributes + code.m_attrCount = attrCount; + code.m_attrId = new NdbAttrId[1 + attrCount]; + code.m_attrId[0] = (NdbAttrId)-1; + for (unsigned i = 1; i <= attrCount; i++) { + Plan_column* column = columns[i]; + ctx_assert(column != 0); + const DictColumn& dictColumn = column->dictColumn(); + code.m_attrId[i] = dictColumn.getAttrId(); + } + // create the exec + Exec_update_scan* exec = new Exec_update_scan(ctl.m_execRoot); + ctl.m_execRoot->saveNode(exec); + exec->setCode(code); + exec->setQuery(execQuery); + return exec; +} + +void +Plan_update_scan::print(Ctx& ctx) +{ + ctx.print(" [update_scan"); + Plan_base* a[] = { m_table, m_query }; + printList(ctx, a, sizeof(a)/sizeof(a[0])); + ctx.print("]"); +} + +// Exec_delete + +Exec_update_scan::Code::~Code() +{ + delete[] m_attrId; +} + +Exec_update_scan::Data::~Data() +{ +} + +Exec_update_scan::~Exec_update_scan() +{ +} + +void +Exec_update_scan::alloc(Ctx& ctx, Ctl& ctl) +{ + // allocate the subquery + ctx_assert(m_query != 0); + m_query->alloc(ctx, ctl); + if (! ctx.ok()) + return; + // create data + Data& data = *new Data; + setData(data); +} + +void +Exec_update_scan::close(Ctx& ctx) +{ + ctx_assert(m_query != 0); + m_query->close(ctx); +} + +void +Exec_update_scan::print(Ctx& ctx) +{ + ctx.print(" [update_scan"); + if (m_code != 0) { + const Code& code = getCode(); + ctx.print(" attrId="); + for (unsigned i = 1; i <= code.m_attrCount; i++) { + if (i > 1) + ctx.print(","); + ctx.print("%u", (unsigned)code.m_attrId[i]); + } + } + Exec_base* a[] = { m_query }; + printList(ctx, a, 1); + ctx.print("]"); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Code_update_scan.hpp b/storage/ndb/src/old_files/client/odbc/codegen/Code_update_scan.hpp new file mode 100644 index 00000000000..d742883e561 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Code_update_scan.hpp @@ -0,0 +1,160 @@ +/* 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_Code_update_scan_hpp +#define ODBC_CODEGEN_Code_update_scan_hpp + +#include <common/common.hpp> +#include "Code_base.hpp" +#include "Code_dml.hpp" +#include "Code_table.hpp" +#include "Code_pred.hpp" +#include "Code_query.hpp" + +/** + * @class Plan_update_scan + * @brief Update in PlanTree + */ +class Plan_update_scan : public Plan_dml { +public: + Plan_update_scan(Plan_root* root); + virtual ~Plan_update_scan(); + Plan_base* analyze(Ctx& ctx, Ctl& ctl); + void describe(Ctx& ctx); + Exec_base* codegen(Ctx& ctx, Ctl& ctl); + void print(Ctx& ctx); + // children + void setTable(Plan_table* table); + void setDmlRow(Plan_dml_row* dmlRow); + void setQuery(Plan_query* query); +protected: + Plan_table* m_table; + Plan_dml_row* m_dmlRow; + Plan_query* m_query; +}; + +inline +Plan_update_scan::Plan_update_scan(Plan_root* root) : + Plan_dml(root), + m_table(0), + m_dmlRow(0), + m_query(0) +{ +} + +// children + +inline void +Plan_update_scan::setTable(Plan_table* table) +{ + ctx_assert(table != 0); + m_table = table; +} + +inline void +Plan_update_scan::setDmlRow(Plan_dml_row* dmlRow) +{ + ctx_assert(dmlRow != 0); + m_dmlRow = dmlRow; +} + +inline void +Plan_update_scan::setQuery(Plan_query* query) +{ + ctx_assert(query != 0); + m_query = query; +} + +/** + * @class Exec_update_scan + * @brief Insert in ExecTree + */ +class Exec_update_scan : public Exec_dml { +public: + class Code : public Exec_dml::Code { + public: + Code(); + virtual ~Code(); + protected: + friend class Plan_update_scan; + friend class Exec_update_scan; + unsigned m_attrCount; + NdbAttrId* m_attrId; + }; + class Data : public Exec_dml::Data { + public: + Data(); + virtual ~Data(); + protected: + friend class Exec_update_scan; + }; + Exec_update_scan(Exec_root* root); + virtual ~Exec_update_scan(); + void alloc(Ctx& ctx, Ctl& ctl); + void execImpl(Ctx& ctx, Ctl& ctl); + void close(Ctx& ctx); + void print(Ctx& ctx); + // children + const Code& getCode() const; + Data& getData() const; + void setQuery(Exec_query* query); +protected: + Exec_query* m_query; +}; + +inline +Exec_update_scan::Code::Code() : + m_attrCount(0), + m_attrId(0) +{ +} + +inline +Exec_update_scan::Data::Data() +{ +} + +inline +Exec_update_scan::Exec_update_scan(Exec_root* root) : + Exec_dml(root), + m_query(0) +{ +} + +// children + +inline const Exec_update_scan::Code& +Exec_update_scan::getCode() const +{ + const Code* code = static_cast<const Code*>(m_code); + return *code; +} + +inline Exec_update_scan::Data& +Exec_update_scan::getData() const +{ + Data* data = static_cast<Data*>(m_data); + return *data; +} + +inline void +Exec_update_scan::setQuery(Exec_query* query) +{ + ctx_assert(query != 0 && m_query == 0); + m_query = query; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/Makefile b/storage/ndb/src/old_files/client/odbc/codegen/Makefile new file mode 100644 index 00000000000..49e5439556d --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/Makefile @@ -0,0 +1,104 @@ +include .defs.mk + +TYPE = * + +NONPIC_ARCHIVE = N + +PIC_ARCHIVE = Y + +ARCHIVE_TARGET = odbccodegen + +SOURCES = \ + SimpleScan.lpp \ + SimpleGram.ypp \ + SimpleParser.cpp \ + CodeGen.cpp \ + Code_base.cpp \ + Code_root.cpp \ + Code_stmt.cpp \ + Code_query.cpp \ + Code_dml.cpp \ + Code_ddl.cpp \ + Code_select.cpp \ + Code_pred.cpp \ + Code_pred_op.cpp \ + Code_comp_op.cpp \ + Code_query_project.cpp \ + Code_query_filter.cpp \ + Code_query_join.cpp \ + Code_query_lookup.cpp \ + Code_query_index.cpp \ + Code_query_scan.cpp \ + Code_query_range.cpp \ + Code_query_sys.cpp \ + Code_query_repeat.cpp \ + Code_query_count.cpp \ + Code_query_sort.cpp \ + Code_query_group.cpp \ + Code_query_distinct.cpp \ + Code_expr_row.cpp \ + Code_expr.cpp \ + Code_expr_op.cpp \ + Code_expr_func.cpp \ + Code_expr_conv.cpp \ + Code_expr_column.cpp \ + Code_expr_const.cpp \ + Code_expr_param.cpp \ + Code_update.cpp \ + Code_update_lookup.cpp \ + Code_update_index.cpp \ + Code_update_scan.cpp \ + Code_set_row.cpp \ + Code_insert.cpp \ + Code_dml_row.cpp \ + Code_dml_column.cpp \ + Code_delete.cpp \ + Code_delete_lookup.cpp \ + Code_delete_index.cpp \ + Code_delete_scan.cpp \ + Code_column.cpp \ + Code_table_list.cpp \ + Code_table.cpp \ + Code_create_table.cpp \ + Code_create_index.cpp \ + Code_create_row.cpp \ + Code_ddl_row.cpp \ + Code_ddl_column.cpp \ + Code_ddl_constr.cpp \ + Code_idx_column.cpp \ + Code_data_type.cpp \ + Code_drop_table.cpp \ + Code_drop_index.cpp + +ifeq ($(NDB_OS),WIN32) +CCFLAGS += -I$(call fixpath,.) + +_libs:: FlexLexer.h unistd.h + +endif + +include ../Extra.mk +include $(NDB_TOP)/Epilogue.mk + +ifeq ($(NDB_OS),LINUX) +FLEXHACK = perl -i -pe 's/\bisatty\b/ouencunbwdb2y1bdc/g' +BISONHACK = perl -i -pe 's/^\s*__attribute__\s*\(\(.*\)\)//' +endif + +ifeq ($(NDB_OS),MACOSX) +FLEXHACK = perl -i -pe 's/\bisatty\b/ouencunbwdb2y1bdc/g' +BISONHACK = perl -i -pe 's/^\s*__attribute__\s*\(\(.*\)\)//' +endif + +ifeq ($(NDB_OS),SOLARIS) +BISONHACK = perl -i -pe 's/^\s*__attribute__\s*\(\(.*\)\)//' +endif + +ifeq ($(NDB_OS),WIN32) +unistd.h: + touch unistd.h + +FlexLexer.h: + cp /usr/include/FlexLexer.h . + +endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/SimpleGram.ypp b/storage/ndb/src/old_files/client/odbc/codegen/SimpleGram.ypp new file mode 100644 index 00000000000..07d8017e5ed --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/SimpleGram.ypp @@ -0,0 +1,1649 @@ +%{ + +#include <NdbApi.hpp> +#include <common/StmtArea.hpp> +#include <common/DataRow.hpp> +#include "CodeGen.hpp" +#include <FlexLexer.h> +#include "SimpleParser.hpp" + +/* redefine globals after headers */ +#define yyparse SimpleParser_yyparse +#if YYDEBUG +#define yydebug SimpleParser_yydebug +#endif + +#define YYLEX_PARAM simpleParserPtr +#define YYPARSE_PARAM simpleParserPtr +#define simpleParser (*static_cast<SimpleParser*>(simpleParserPtr)) + +static int yylex(YYSTYPE* lvalp, void* simpleParserPtr); + +#define yyerror(s) simpleParser.parseError(s) + +#if YYDEBUG +// does not work in bison 1.75 +#undef stderr +#define stderr 0 +#define YYFPRINTF simpleParser.ctx().print +#endif + +// scanner states + +#define pushState(sc) simpleParser.pushState(sc) +#define popState() simpleParser.popState() + +#define StateEval SimpleParser_stateEval +#define StateType SimpleParser_stateType +#define StatePhys SimpleParser_statePhys +extern int SimpleParser_stateEval; +extern int SimpleParser_stateType; +extern int SimpleParser_statePhys; + +struct LimitPair { int off; int cnt; }; + +struct PhysAttr { int storage; int logging; }; + +%} + +%defines +%pure-parser +%verbose + +%union { + Plan_root* m_root; + Plan_stmt* m_stmt; + Plan_select* m_select; + Insert_op m_insert_op; + Plan_insert* m_insert; + Plan_update* m_update; + Plan_delete* m_delete; + Plan_create_table* m_create_table; + Plan_create_index* m_create_index; + NdbDictionary::Object::Type m_index_type; + Plan_create_row* m_create_row; + Plan_ddl_row* m_ddl_row; + Plan_ddl_column* m_ddl_column; + Plan_ddl_constr* m_ddl_constr; + Plan_idx_column* m_idx_column; + Plan_data_type* m_data_type; + Plan_drop_table* m_drop_table; + Plan_drop_index* m_drop_index; + Plan_set_row* m_set_row; + Plan_expr_row* m_expr_row; + bool m_asc_desc; + Plan_pred* m_pred; + Pred_op::Opcode m_pred_opcode; + Comp_op::Opcode m_comp_opcode; + Plan_expr* m_expr; + Expr_op::Opcode m_expr_opcode; + Plan_dml_row* m_dml_row; + Plan_dml_column* m_dml_column; + Plan_table* m_table; + Plan_table_list* m_table_list; + const char* m_string; + struct LimitPair* m_limit; + int m_signed_integer; + bool m_distinct; + struct PhysAttr* m_phys_attr; + NdbDictionary::Object::FragmentType m_storage_attr; + bool m_logging_attr; + SqlType::Type m_sql_type; +} + +/* keywords */ +%token + T_AND + T_ASC + T_AUTO_INCREMENT + T_BIGINT + T_BINARY + T_BLOB + T_BY + T_CHAR + T_CLOB + T_CONSTRAINT + T_CREATE + T_DATETIME + T_DEFAULT + T_DELETE + T_DESC + T_DISTINCT + T_DOUBLE + T_DROP + T_FLOAT + T_FOREIGN + T_FROM + T_GROUP + T_HASH + T_HAVING + T_IN + T_INDEX + T_INSERT + T_INT + T_INTEGER + T_INTO + T_IS + T_KEY + T_LARGE + T_LIKE + T_LIMIT + T_LOGGING + T_LONGBLOB + T_LONGCLOB + T_MEDIUM + T_NOLOGGING + T_NOT + T_NULL + T_OFFSET + T_ON + T_OR + T_ORDER + T_PRECISION + T_PRIMARY + T_REAL + T_REFERENCES + T_ROWNUM + T_SELECT + T_SET + T_SINGLE + T_SMALL + T_SMALLINT + T_STORAGE + T_SYSDATE + T_TABLE + T_UNIQUE + T_UNSIGNED + T_UPDATE + T_VALUES + T_VARBINARY + T_VARCHAR + T_WHERE + T_WRITE + +/* identifiers and constants */ +%token + <m_string> T_IDENTIFIER + <m_string> T_LINTEGER + <m_string> T_LDECIMAL + <m_string> T_LREAL + <m_string> T_STRING + +/* expressions and predicates */ +%token + T_PLUS + T_MINUS + T_TIMES + T_DIVIDE + T_EQ + T_NOTEQ + T_LT + T_LTEQ + T_GT + T_GTEQ + T_QUES + +/* common special symbols */ +%token + T_PERIOD + T_COMMA + T_PARENLEFT + T_PARENRIGHT + T_ASTERISK + T_ASSIGN + +%type <m_root> root +%type <m_stmt> stmt +%type <m_select> stmt_select +%type <m_insert> stmt_insert +%type <m_insert_op> insert_op +%type <m_update> stmt_update +%type <m_delete> stmt_delete +%type <m_create_table> create_table +%type <m_create_index> create_index +%type <m_index_type> index_type +%type <m_create_row> create_row +%type <m_ddl_column> create_column +%type <m_ddl_constr> create_constr +%type <m_idx_column> idx_column +%type <m_data_type> data_type +%type <m_ddl_row> ddl_row +%type <m_ddl_column> ddl_column +%type <m_drop_table> drop_table +%type <m_drop_index> drop_index +%type <m_asc_desc> asc_desc +%type <m_set_row> set_row +%type <m_expr_row> expr_row +%type <m_expr_row> sort_row +%type <m_pred> where_clause +%type <m_expr_row> order_clause +%type <m_pred> pred +%type <m_pred> pred1 +%type <m_pred_opcode> pred1_op +%type <m_pred> pred2 +%type <m_pred_opcode> pred2_op +%type <m_pred> pred3 +%type <m_pred_opcode> pred3_op +%type <m_pred> pred4 +%type <m_comp_opcode> comp_op +%type <m_expr> expr +%type <m_expr> expr1 +%type <m_expr_opcode> expr1_op +%type <m_expr> expr2 +%type <m_expr_opcode> expr2_op +%type <m_expr> expr3 +%type <m_expr_opcode> expr3_op +%type <m_expr> expr4 +%type <m_expr> expr_column +%type <m_dml_row> dml_row +%type <m_dml_column> dml_column +%type <m_expr_row> value_row +%type <m_expr> value_expr +%type <m_table> table +%type <m_table_list> table_list +%type <m_string> dot_identifier +%type <m_limit> limit_clause +%type <m_signed_integer> signed_integer +%type <m_distinct> distinct_clause +%type <m_expr_row> group_clause +%type <m_pred> having_clause +%type <m_phys_attr> phys_attr +%type <m_phys_attr> phys_attr2 +%type <m_storage_attr> storage_attr +%type <m_logging_attr> logging_attr +%type <m_sql_type> blob_type + +%% + +root: + stmt + { + Plan_root* root = simpleParser.root(); + root->setStmt($1); + } + ; +stmt: + stmt_select + { + $$ = $1; + } + | + stmt_insert + { + $$ = $1; + } + | + stmt_update + { + $$ = $1; + } + | + stmt_delete + { + $$ = $1; + } + | + create_table + { + $$ = $1; + } + | + create_index + { + $$ = $1; + } + | + drop_table + { + $$ = $1; + } + | + drop_index + { + $$ = $1; + } + ; +stmt_select: + T_SELECT distinct_clause expr_row T_FROM table_list where_clause group_clause having_clause order_clause limit_clause + { + Plan_root* root = simpleParser.root(); + Plan_select* stmt = new Plan_select(root); + root->saveNode(stmt); + stmt->setDistinct($2); + stmt->setRow($3); + stmt->setList($5); + if ($6 != 0) + stmt->setPred($6); + if ($7 != 0) + stmt->setGroup($7); + if ($8 != 0) + stmt->setHaving($8); + if ($9 != 0) + stmt->setSort($9); + if ($10 != 0) { + stmt->setLimit($10->off, $10->cnt); + delete $10; + } + $$ = stmt; + } + ; +stmt_insert: + insert_op T_INTO table T_VALUES T_PARENLEFT value_row T_PARENRIGHT + { + Plan_root* root = simpleParser.root(); + Plan_insert* stmt = new Plan_insert(root, $1); + root->saveNode(stmt); + stmt->setTable($3); + stmt->setExprRow($6); + $$ = stmt; + } + | + insert_op T_INTO table T_PARENLEFT dml_row T_PARENRIGHT T_VALUES T_PARENLEFT value_row T_PARENRIGHT + { + Plan_root* root = simpleParser.root(); + Plan_insert* stmt = new Plan_insert(root, $1); + root->saveNode(stmt); + stmt->setTable($3); + stmt->setDmlRow($5); + stmt->setExprRow($9); + $$ = stmt; + } + | + insert_op T_INTO table stmt_select + { + Plan_root* root = simpleParser.root(); + Plan_insert* stmt = new Plan_insert(root, $1); + root->saveNode(stmt); + stmt->setTable($3); + stmt->setSelect($4); + $$ = stmt; + } + | + insert_op T_INTO table T_PARENLEFT dml_row T_PARENRIGHT stmt_select + { + Plan_root* root = simpleParser.root(); + Plan_insert* stmt = new Plan_insert(root, $1); + root->saveNode(stmt); + stmt->setTable($3); + stmt->setDmlRow($5); + stmt->setSelect($7); + $$ = stmt; + } + | + insert_op T_INTO table T_SET set_row + { + Plan_root* root = simpleParser.root(); + Plan_insert* stmt = new Plan_insert(root, $1); + root->saveNode(stmt); + stmt->setTable($3); + stmt->setMysqlRow($5); + $$ = stmt; + } + ; +insert_op: + T_INSERT + { + $$ = Insert_op_insert; + } + | + T_WRITE + { + $$ = Insert_op_write; + } + ; +stmt_update: + T_UPDATE table T_SET set_row where_clause + { + Plan_root* root = simpleParser.root(); + Plan_update* stmt = new Plan_update(root); + root->saveNode(stmt); + stmt->setTable($2); + stmt->setRow($4); + if ($5 != 0) + stmt->setPred($5); + $$ = stmt; + } + ; +stmt_delete: + T_DELETE T_FROM table where_clause + { + Plan_root* root = simpleParser.root(); + Plan_delete* stmt = new Plan_delete(root); + root->saveNode(stmt); + stmt->setTable($3); + if ($4 != 0) + stmt->setPred($4); + $$ = stmt; + } + ; +create_table: + T_CREATE T_TABLE dot_identifier T_PARENLEFT create_row T_PARENRIGHT phys_attr + { + Plan_root* root = simpleParser.root(); + Plan_create_table* stmt = new Plan_create_table(root, $3); + root->saveNode(stmt); + delete[] $3; + stmt->setCreateRow($5); + if ($7->storage != -1) + stmt->setFragmentType((NdbDictionary::Object::FragmentType)$7->storage); + if ($7->logging != -1) + stmt->setLogging($7->logging); + delete $7; + $$ = stmt; + } + ; +create_row: + create_column + { + Plan_root* root = simpleParser.root(); + Plan_create_row* createRow = new Plan_create_row(root); + root->saveNode(createRow); + createRow->addColumn($1); + $$ = createRow; + } + | + create_constr + { + Plan_root* root = simpleParser.root(); + Plan_create_row* createRow = new Plan_create_row(root); + root->saveNode(createRow); + createRow->addConstr($1); + $$ = createRow; + } + | + create_row T_COMMA create_column + { + Plan_create_row* createRow = $1; + createRow->addColumn($3); + $$ = createRow; + } + | + create_row T_COMMA create_constr + { + Plan_create_row* createRow = $1; + createRow->addConstr($3); + $$ = createRow; + } + | + create_row T_COMMA create_ignore + { + $$ = $1; + } + ; +create_column: + T_IDENTIFIER { pushState(StateType); } data_type { popState(); } + { + Plan_root* root = simpleParser.root(); + Plan_ddl_column* ddlColumn = new Plan_ddl_column(root, $1); + root->saveNode(ddlColumn); + delete[] $1; + ddlColumn->setType($3); + simpleParser.curr(ddlColumn); + } + create_column_rest + { + $$ = simpleParser.curr((Plan_ddl_column*)0); + } + ; +data_type: + T_CHAR T_PARENLEFT T_LINTEGER T_PARENRIGHT dummy_binary + { + Plan_root* root = simpleParser.root(); + SqlType sqlType(simpleParser.ctx(), SqlType::Char, atoi($3), true); + delete[] $3; + if (! simpleParser.ctx().ok()) { + YYABORT; + } + Plan_data_type* dataType = new Plan_data_type(root, sqlType); + root->saveNode(dataType); + $$ = dataType; + } + | + T_BINARY T_PARENLEFT T_LINTEGER T_PARENRIGHT + { + Plan_root* root = simpleParser.root(); + SqlType sqlType(simpleParser.ctx(), SqlType::Binary, atoi($3), true); + delete[] $3; + if (! simpleParser.ctx().ok()) { + YYABORT; + } + Plan_data_type* dataType = new Plan_data_type(root, sqlType); + root->saveNode(dataType); + $$ = dataType; + } + | + T_VARCHAR T_PARENLEFT T_LINTEGER T_PARENRIGHT dummy_binary + { + Plan_root* root = simpleParser.root(); + SqlType sqlType(simpleParser.ctx(), SqlType::Varchar, atoi($3), true); + delete[] $3; + if (! simpleParser.ctx().ok()) { + YYABORT; + } + Plan_data_type* dataType = new Plan_data_type(root, sqlType); + root->saveNode(dataType); + $$ = dataType; + } + | + T_VARBINARY T_PARENLEFT T_LINTEGER T_PARENRIGHT + { + Plan_root* root = simpleParser.root(); + SqlType sqlType(simpleParser.ctx(), SqlType::Varbinary, atoi($3), true); + delete[] $3; + if (! simpleParser.ctx().ok()) { + YYABORT; + } + Plan_data_type* dataType = new Plan_data_type(root, sqlType); + root->saveNode(dataType); + $$ = dataType; + } + | + T_SMALLINT + { + Plan_root* root = simpleParser.root(); + SqlType sqlType(SqlType::Smallint, true); + Plan_data_type* dataType = new Plan_data_type(root, sqlType); + root->saveNode(dataType); + $$ = dataType; + } + | + T_INTEGER + { + Plan_root* root = simpleParser.root(); + SqlType sqlType(SqlType::Integer, true); + Plan_data_type* dataType = new Plan_data_type(root, sqlType); + root->saveNode(dataType); + $$ = dataType; + } + | + T_INT + { + Plan_root* root = simpleParser.root(); + SqlType sqlType(SqlType::Integer, true); + Plan_data_type* dataType = new Plan_data_type(root, sqlType); + root->saveNode(dataType); + $$ = dataType; + } + | + T_BIGINT + { + Plan_root* root = simpleParser.root(); + SqlType sqlType(SqlType::Bigint, true); + Plan_data_type* dataType = new Plan_data_type(root, sqlType); + root->saveNode(dataType); + $$ = dataType; + } + | + T_REAL + { + Plan_root* root = simpleParser.root(); + SqlType sqlType(SqlType::Real, true); + Plan_data_type* dataType = new Plan_data_type(root, sqlType); + root->saveNode(dataType); + $$ = dataType; + } + | + T_FLOAT + { + Plan_root* root = simpleParser.root(); + SqlType sqlType(SqlType::Double, true); + Plan_data_type* dataType = new Plan_data_type(root, sqlType); + root->saveNode(dataType); + $$ = dataType; + } + | + T_DOUBLE T_PRECISION + { + Plan_root* root = simpleParser.root(); + SqlType sqlType(SqlType::Double, true); + Plan_data_type* dataType = new Plan_data_type(root, sqlType); + root->saveNode(dataType); + $$ = dataType; + } + | + T_DATETIME + { + Plan_root* root = simpleParser.root(); + SqlType sqlType(SqlType::Datetime, true); + Plan_data_type* dataType = new Plan_data_type(root, sqlType); + root->saveNode(dataType); + $$ = dataType; + } + | + blob_type + { + Plan_root* root = simpleParser.root(); + SqlType sqlType($1, true); + Plan_data_type* dataType = new Plan_data_type(root, sqlType); + root->saveNode(dataType); + $$ = dataType; + } + ; +dummy_binary: + /* empty */ + | + T_BINARY + ; +blob_type: + T_BLOB + { + $$ = SqlType::Blob; + } + | + T_LONGBLOB + { + $$ = SqlType::Blob; + } + | + T_CLOB + { + $$ = SqlType::Clob; + } + | + T_LONGCLOB + { + $$ = SqlType::Clob; + } + ; +create_column_rest: + /* empty */ + | + data_constr_list + ; +data_constr_list: + data_constr + | + data_constr_list data_constr + ; +data_constr: + T_NULL + | + T_NOT T_NULL + { + Plan_ddl_column* ddlColumn = simpleParser.curr((Plan_ddl_column*)0); + ddlColumn->setNotNull(); + } + | + T_UNSIGNED + { + Plan_ddl_column* ddlColumn = simpleParser.curr((Plan_ddl_column*)0); + ddlColumn->setUnSigned(); + } + | + T_PRIMARY T_KEY + { + Plan_ddl_column* ddlColumn = simpleParser.curr((Plan_ddl_column*)0); + ddlColumn->setPrimaryKey(); + } + | + T_AUTO_INCREMENT + { + Plan_ddl_column* ddlColumn = simpleParser.curr((Plan_ddl_column*)0); + ddlColumn->setAutoIncrement(); + } + | + T_DEFAULT expr + { + Plan_ddl_column* ddlColumn = simpleParser.curr((Plan_ddl_column*)0); + ddlColumn->setDefaultValue($2); + } + ; +create_constr: + T_PRIMARY T_KEY T_PARENLEFT ddl_row T_PARENRIGHT + { + Plan_root* root = simpleParser.root(); + Plan_ddl_constr* ddlConstr = new Plan_ddl_constr(root); + root->saveNode(ddlConstr); + ddlConstr->setRow($4); + $$ = ddlConstr; + } + | + T_CONSTRAINT dot_identifier T_PRIMARY T_KEY T_PARENLEFT ddl_row T_PARENRIGHT + { + Plan_root* root = simpleParser.root(); + Plan_ddl_constr* ddlConstr = new Plan_ddl_constr(root); + root->saveNode(ddlConstr); + ddlConstr->setRow($6); + $$ = ddlConstr; + } + ; +create_ignore: + T_INDEX dot_identifier T_PARENLEFT ddl_row T_PARENRIGHT + | + T_FOREIGN T_KEY T_PARENLEFT ddl_row T_PARENRIGHT T_REFERENCES dot_identifier T_PARENLEFT ddl_row T_PARENRIGHT + ; +ddl_row: + ddl_column + { + Plan_root* root = simpleParser.root(); + Plan_ddl_row* ddlRow = new Plan_ddl_row(root); + root->saveNode(ddlRow); + ddlRow->addColumn($1); + $$ = ddlRow; + } + | + ddl_row T_COMMA ddl_column + { + Plan_ddl_row* ddlRow = $1; + ddlRow->addColumn($3); + $$ = ddlRow; + } + ; +ddl_column: + T_IDENTIFIER + { + Plan_root* root = simpleParser.root(); + Plan_ddl_column* column = new Plan_ddl_column(root, $1); + root->saveNode(column); + delete[] $1; + $$ = column; + } + ; +create_index: + T_CREATE index_type T_INDEX dot_identifier T_ON table + { + Plan_root* root = simpleParser.root(); + Plan_create_index* stmt = new Plan_create_index(root, $4); + root->saveNode(stmt); + delete[] $4; + stmt->setType($2); + stmt->setTable($6); + simpleParser.curr(stmt); + } + T_PARENLEFT idx_row T_PARENRIGHT phys_attr + { + $$ = simpleParser.curr((Plan_create_index*)0); + if ($11->storage != -1) + $$->setFragmentType((NdbDictionary::Object::FragmentType)$11->storage); + if ($11->logging != -1) + $$->setLogging($11->logging); + delete $11; + } + ; +index_type: + T_HASH + { + $$ = NdbDictionary::Object::HashIndex; + } + | + T_UNIQUE T_HASH + { + $$ = NdbDictionary::Object::UniqueHashIndex; + } + | + /* empty */ + { + $$ = NdbDictionary::Object::OrderedIndex; + } + | + T_UNIQUE + { + $$ = NdbDictionary::Object::UniqueOrderedIndex; + } + ; +idx_row: + idx_column + { + } + | + idx_row T_COMMA idx_column + { + } + ; +idx_column: + T_IDENTIFIER + { + Plan_root* root = simpleParser.root(); + Plan_idx_column* column = new Plan_idx_column(root, $1); + root->saveNode(column); + delete[] $1; + Plan_create_index* stmt = simpleParser.curr((Plan_create_index*)0); + stmt->addColumn(column); + } + ; +phys_attr: + { pushState(StatePhys); } phys_attr2 { popState(); } + { + $$ = $2; + } + ; +phys_attr2: + /* empty */ + { + $$ = new PhysAttr(); + $$->storage = $$->logging = -1; + } + | + phys_attr2 storage_attr + { + if ($1->storage != -1 && $1->storage != $2) { + simpleParser.ctx().pushStatus(Sqlstate::_42000, Error::Gen, "conflicting STORAGE clauses"); + YYABORT; + } + $$->storage = $2; + } + | + phys_attr2 logging_attr + { + if ($1->logging != -1 && $1->logging != $2) { + simpleParser.ctx().pushStatus(Sqlstate::_42000, Error::Gen, "conflicting LOGGING clauses"); + YYABORT; + } + $$->logging = $2; + } + ; +logging_attr: + T_LOGGING + { + $$ = true; + } + | + T_NOLOGGING + { + $$ = false; + } + ; +storage_attr: + T_STORAGE T_PARENLEFT T_SINGLE T_PARENRIGHT + { + $$ = NdbDictionary::Object::FragSingle; + } + | + T_STORAGE T_PARENLEFT T_SMALL T_PARENRIGHT + { + $$ = NdbDictionary::Object::FragAllSmall; + } + | + T_STORAGE T_PARENLEFT T_MEDIUM T_PARENRIGHT + { + $$ = NdbDictionary::Object::FragAllMedium; + } + | + T_STORAGE T_PARENLEFT T_LARGE T_PARENRIGHT + { + $$ = NdbDictionary::Object::FragAllLarge; + } + ; +drop_table: + T_DROP T_TABLE dot_identifier + { + Plan_root* root = simpleParser.root(); + Plan_drop_table* stmt = new Plan_drop_table(root, $3); + root->saveNode(stmt); + delete[] $3; + $$ = stmt; + } + ; +drop_index: + T_DROP T_INDEX dot_identifier + { + Plan_root* root = simpleParser.root(); + Plan_drop_index* stmt = new Plan_drop_index(root, $3); + root->saveNode(stmt); + delete[] $3; + $$ = stmt; + } + | + T_DROP T_INDEX dot_identifier T_ON dot_identifier + { + Plan_root* root = simpleParser.root(); + Plan_drop_index* stmt = new Plan_drop_index(root, $3, $5); + root->saveNode(stmt); + delete[] $3; + delete[] $5; + $$ = stmt; + } + ; +distinct_clause: + /* empty */ + { + $$ = false; + } + | + T_DISTINCT + { + $$ = true; + } + ; +where_clause: + /* empty */ + { + $$ = 0; + } + | + T_WHERE pred + { + $$ = $2; + } + ; +group_clause: + /* empty */ + { + $$ = 0; + } + | + T_GROUP T_BY value_row + { + $$ = $3; + } + ; +having_clause: + /* empty */ + { + $$ = 0; + } + | + T_HAVING pred + { + $$ = $2; + } + ; +order_clause: + /* empty */ + { + $$ = 0; + } + | + T_ORDER T_BY sort_row + { + $$ = $3; + } + ; +limit_clause: + /* empty */ + { + $$ = 0; + } + | + T_LIMIT signed_integer + { + LimitPair* p = new LimitPair; + p->off = 0; + p->cnt = $2; + $$ = p; + } + | + T_LIMIT signed_integer T_COMMA signed_integer + { + LimitPair* p = new LimitPair; + p->off = $2, + p->cnt = $4; + $$ = p; + } + | + T_LIMIT signed_integer T_OFFSET signed_integer + { + LimitPair* p = new LimitPair; + p->off = $4; + p->cnt = $2; + $$ = p; + } + ; +signed_integer: + T_LINTEGER + { + $$ = atoi($1); + delete[] $1; + } + | + T_MINUS T_LINTEGER + { + $$ = (-1) * atoi($2); + delete[] $2; + } + ; +set_row: + dml_column T_ASSIGN expr + { + Plan_root* root = simpleParser.root(); + Plan_set_row* row = new Plan_set_row(root); + root->saveNode(row); + row->addColumn($1); + row->addExpr($3); + $$ = row; + } + | + set_row T_COMMA dml_column T_ASSIGN expr + { + Plan_set_row* row = $1; + row->addColumn($3); + row->addExpr($5); + $$ = row; + } + ; +dml_row: + dml_column + { + Plan_root* root = simpleParser.root(); + Plan_dml_row* row = new Plan_dml_row(root); + root->saveNode(row); + row->addColumn($1); + $$ = row; + } + | + dml_row T_COMMA dml_column + { + Plan_dml_row* row = $1; + row->addColumn($3); + $$ = row; + } + ; +dml_column: + T_IDENTIFIER + { + Plan_root* root = simpleParser.root(); + Plan_dml_column* column = new Plan_dml_column(root, $1); + root->saveNode(column); + delete[] $1; + $$ = column; + } + ; +value_row: + value_expr + { + Plan_root* root = simpleParser.root(); + Plan_expr_row* row = new Plan_expr_row(root); + root->saveNode(row); + row->addExpr($1); + $$ = row; + } + | + value_row T_COMMA value_expr + { + Plan_expr_row* row = $1; + row->addExpr($3); + $$ = row; + } + ; +value_expr: + expr + { + $$ = $1; + } + ; +sort_row: + expr asc_desc + { + Plan_root* root = simpleParser.root(); + Plan_expr_row* row = new Plan_expr_row(root); + root->saveNode(row); + row->addExpr($1, $2); + $$ = row; + } + | + sort_row T_COMMA expr asc_desc + { + Plan_expr_row* row = $1; + row->addExpr($3, $4); + $$ = row; + } + ; +asc_desc: + /* empty */ + { + $$ = true; + } + | + T_ASC + { + $$ = true; + } + | + T_DESC + { + $$ = false; + } + ; +expr_row: + T_ASTERISK + { + Plan_root* root = simpleParser.root(); + Plan_expr_row* row = new Plan_expr_row(root); + root->saveNode(row); + row->setAsterisk(); + $$ = row; + } + | + T_TIMES /* XXX fix scanner state */ + { + Plan_root* root = simpleParser.root(); + Plan_expr_row* row = new Plan_expr_row(root); + root->saveNode(row); + row->setAsterisk(); + $$ = row; + } + | + expr + { + Plan_root* root = simpleParser.root(); + Plan_expr_row* row = new Plan_expr_row(root); + root->saveNode(row); + row->addExpr($1); + $$ = row; + } + | + expr T_IDENTIFIER + { + Plan_root* root = simpleParser.root(); + Plan_expr_row* row = new Plan_expr_row(root); + root->saveNode(row); + row->addExpr($1, BaseString($2)); + $$ = row; + } + | + expr_row T_COMMA expr + { + Plan_expr_row* row = $1; + row->addExpr($3); + $$ = row; + } + | + expr_row T_COMMA expr T_IDENTIFIER + { + Plan_expr_row* row = $1; + row->addExpr($3, BaseString($4)); + $$ = row; + } + ; +pred: + { pushState(StateEval); } pred1 { popState(); } + { + $$ = $2; + } + ; +pred1: + pred2 + { + $$ = $1; + } + | + pred1 pred1_op pred2 + { + Plan_root* root = simpleParser.root(); + Pred_op op($2); + Plan_pred_op* pred = new Plan_pred_op(root, op); + root->saveNode(pred); + pred->setPred(1, $1); + pred->setPred(2, $3); + $$ = pred; + } + ; +pred1_op: + T_OR + { + $$ = Pred_op::Or; + } + ; +pred2: + pred3 + { + $$ = $1; + } + | + pred2 pred2_op pred3 + { + Plan_root* root = simpleParser.root(); + Pred_op op($2); + Plan_pred_op* pred = new Plan_pred_op(root, op); + root->saveNode(pred); + pred->setPred(1, $1); + pred->setPred(2, $3); + $$ = pred; + } + ; +pred2_op: + T_AND + { + $$ = Pred_op::And; + } + ; +pred3: + pred4 + { + $$ = $1; + } + | + pred3_op pred3 + { + Plan_root* root = simpleParser.root(); + Pred_op op($1); + Plan_pred_op* pred = new Plan_pred_op(root, op); + root->saveNode(pred); + pred->setPred(1, $2); + $$ = pred; + } + ; +pred3_op: + T_NOT + { + $$ = Pred_op::Not; + } + ; +pred4: + T_PARENLEFT pred1 T_PARENRIGHT + { + $$ = $2; + } + | + expr1 comp_op expr1 + { + Plan_root* root = simpleParser.root(); + Comp_op op($2); + Plan_comp_op* comp = new Plan_comp_op(root, op); + root->saveNode(comp); + comp->setExpr(1, $1); + comp->setExpr(2, $3); + $$ = comp; + } + | + expr1 T_IS T_NULL + { + Plan_root* root = simpleParser.root(); + Comp_op op(Comp_op::Isnull); + Plan_comp_op* comp = new Plan_comp_op(root, op); + root->saveNode(comp); + comp->setExpr(1, $1); + $$ = comp; + } + | + expr1 T_IS T_NOT T_NULL + { + Plan_root* root = simpleParser.root(); + Comp_op op(Comp_op::Isnotnull); + Plan_comp_op* comp = new Plan_comp_op(root, op); + root->saveNode(comp); + comp->setExpr(1, $1); + $$ = comp; + } + | + expr1 T_IN T_PARENLEFT value_row T_PARENRIGHT + { + Plan_root* root = simpleParser.root(); + Plan_pred* predOut = 0; // hack directly into Or of Eq + Plan_expr* exprLeft = $1; + Plan_expr_row* row = $4; + for (unsigned i = row->getSize(); i >= 1; i--) { + Plan_expr* exprRight = row->getExpr(i); + Plan_comp_op* comp = new Plan_comp_op(root, Comp_op::Eq); + root->saveNode(comp); + comp->setExpr(1, exprLeft); + comp->setExpr(2, exprRight); + if (predOut == 0) { + predOut = comp; + } else { + Plan_pred_op* pred = new Plan_pred_op(root, Pred_op::Or); + root->saveNode(pred); + pred->setPred(1, predOut); + pred->setPred(2, comp); + predOut = pred; + } + } + $$ = predOut; + } + | + expr1 T_NOT T_IN T_PARENLEFT value_row T_PARENRIGHT + { + Plan_root* root = simpleParser.root(); + Plan_pred* predOut = 0; // hack directly into And of Noteq + Plan_expr* exprLeft = $1; + Plan_expr_row* row = $5; + for (unsigned i = row->getSize(); i >= 1; i--) { + Plan_expr* exprRight = row->getExpr(i); + Plan_comp_op* comp = new Plan_comp_op(root, Comp_op::Noteq); + root->saveNode(comp); + comp->setExpr(1, exprLeft); + comp->setExpr(2, exprRight); + if (predOut == 0) { + predOut = comp; + } else { + Plan_pred_op* pred = new Plan_pred_op(root, Pred_op::And); + root->saveNode(pred); + pred->setPred(1, predOut); + pred->setPred(2, comp); + predOut = pred; + } + } + $$ = predOut; + } + ; +comp_op: + T_EQ + { + $$ = Comp_op::Eq; + } + | + T_NOTEQ + { + $$ = Comp_op::Noteq; + } + | + T_LT + { + $$ = Comp_op::Lt; + } + | + T_LTEQ + { + $$ = Comp_op::Lteq; + } + | + T_GT + { + $$ = Comp_op::Gt; + } + | + T_GTEQ + { + $$ = Comp_op::Gteq; + } + | + T_LIKE + { + $$ = Comp_op::Like; + } + | + T_NOT T_LIKE + { + $$ = Comp_op::Notlike; + } + ; +expr: + { pushState(StateEval); } expr1 { popState(); } + { + $$ = $2; + } + ; +expr1: + expr2 + { + $$ = $1; + } + | + expr1 expr1_op expr2 + { + Plan_root* root = simpleParser.root(); + Expr_op op($2); + Plan_expr_op* expr = new Plan_expr_op(root, op); + root->saveNode(expr); + expr->setExpr(1, $1); + expr->setExpr(2, $3); + $$ = expr; + } + ; +expr1_op: + T_PLUS + { + $$ = Expr_op::Add; + } + | + T_MINUS + { + $$ = Expr_op::Subtract; + } + ; +expr2: + expr3 + { + $$ = $1; + } + | + expr2 expr2_op expr3 + { + Plan_root* root = simpleParser.root(); + Expr_op op($2); + Plan_expr_op* expr = new Plan_expr_op(root, op); + root->saveNode(expr); + expr->setExpr(1, $1); + expr->setExpr(2, $3); + $$ = expr; + } + ; +expr2_op: + T_TIMES + { + $$ = Expr_op::Multiply; + } + | + T_DIVIDE + { + $$ = Expr_op::Divide; + } + ; +expr3: + expr4 + { + $$ = $1; + } + | + expr3_op expr3 + { + Plan_root* root = simpleParser.root(); + Expr_op op($1); + Plan_expr_op* expr = new Plan_expr_op(root, op); + root->saveNode(expr); + expr->setExpr(1, $2); + $$ = expr; + } + ; +expr3_op: + T_PLUS + { + $$ = Expr_op::Plus; + } + | + T_MINUS + { + $$ = Expr_op::Minus; + } + ; +expr4: + T_PARENLEFT expr1 T_PARENRIGHT + { + $$ = $2; + } + | + T_IDENTIFIER T_PARENLEFT expr_row T_PARENRIGHT + { + Plan_root* root = simpleParser.root(); + const Expr_func& spec = Expr_func::find($1); + if (spec.m_name == 0) { + simpleParser.ctx().pushStatus(Sqlstate::_42000, Error::Gen, "unknown function %s", $1); + delete[] $1; + YYABORT; + } + Plan_expr_func* func = new Plan_expr_func(root, spec); + root->saveNode(func); + delete[] $1; + func->setArgs($3); + $$ = func; + } + | + T_ROWNUM + { + Plan_root* root = simpleParser.root(); + const Expr_func& spec = Expr_func::find("ROWNUM"); + ctx_assert(spec.m_name != 0); + Plan_expr_func* func = new Plan_expr_func(root, spec); + root->saveNode(func); + func->setArgs(0); + $$ = func; + } + | + T_SYSDATE + { + Plan_root* root = simpleParser.root(); + const Expr_func& spec = Expr_func::find("SYSDATE"); + ctx_assert(spec.m_name != 0); + Plan_expr_func* func = new Plan_expr_func(root, spec); + root->saveNode(func); + func->setArgs(0); + $$ = func; + } + | + expr_column + { + $$ = $1; + } + | + T_STRING + { + Plan_root* root = simpleParser.root(); + LexType lexType(LexType::Char); + Plan_expr_const* expr = new Plan_expr_const(root, lexType, $1); + root->saveNode(expr); + delete[] $1; + $$ = expr; + } + | + T_LINTEGER + { + Plan_root* root = simpleParser.root(); + LexType lexType(LexType::Integer); + Plan_expr_const* expr = new Plan_expr_const(root, lexType, $1); + root->saveNode(expr); + delete[] $1; + $$ = expr; + } + | + T_LDECIMAL + { + Plan_root* root = simpleParser.root(); + LexType lexType(LexType::Float); + Plan_expr_const* expr = new Plan_expr_const(root, lexType, $1); + root->saveNode(expr); + delete[] $1; + $$ = expr; + } + | + T_LREAL + { + Plan_root* root = simpleParser.root(); + LexType lexType(LexType::Float); + Plan_expr_const* expr = new Plan_expr_const(root, lexType, $1); + root->saveNode(expr); + delete[] $1; + $$ = expr; + } + | + T_NULL + { + Plan_root* root = simpleParser.root(); + LexType lexType(LexType::Null); + Plan_expr_const* expr = new Plan_expr_const(root, lexType, ""); + root->saveNode(expr); + $$ = expr; + } + | + T_QUES + { + Plan_root* root = simpleParser.root(); + unsigned paramNumber = simpleParser.paramNumber(); + ctx_assert(paramNumber != 0); + Plan_expr_param* expr = new Plan_expr_param(root, paramNumber); + root->saveNode(expr); + $$ = expr; + } + ; +expr_column: + T_IDENTIFIER + { + Plan_root* root = simpleParser.root(); + Plan_expr_column* column = new Plan_expr_column(root, $1); + root->saveNode(column); + delete[] $1; + $$ = column; + } + | + T_IDENTIFIER T_PERIOD T_IDENTIFIER + { + Plan_root* root = simpleParser.root(); + Plan_expr_column* column = new Plan_expr_column(root, $3); + root->saveNode(column); + delete[] $3; + column->setCname($1); + $$ = column; + } + | + T_IDENTIFIER T_PERIOD T_IDENTIFIER T_PERIOD T_IDENTIFIER + { + Plan_root* root = simpleParser.root(); + BaseString str; + str.append($1); + str.append("."); + str.append($3); + delete[] $1; + delete[] $3; + Plan_expr_column* column = new Plan_expr_column(root, $5); + root->saveNode(column); + delete[] $5; + column->setCname(str); + $$ = column; + } + ; +table_list: + table + { + Plan_root* root = simpleParser.root(); + Plan_table_list* tableList = new Plan_table_list(root); + root->saveNode(tableList); + tableList->addTable($1); + $$ = tableList; + } + | + table_list T_COMMA table + { + Plan_table_list* tableList = $1; + tableList->addTable($3); + $$ = tableList; + } + ; +table: + dot_identifier + { + Plan_root* root = simpleParser.root(); + Plan_table* table = new Plan_table(root, $1); + root->saveNode(table); + delete[] $1; + $$ = table; + } + | + dot_identifier T_IDENTIFIER + { + Plan_root* root = simpleParser.root(); + Plan_table* table = new Plan_table(root, $1); + root->saveNode(table); + delete[] $1; + table->setCname($2); + delete[] $2; + $$ = table; + } + ; +dot_identifier: + T_IDENTIFIER + { + $$ = $1; + } + | + T_IDENTIFIER T_PERIOD T_IDENTIFIER + { + char* s = new char[strlen($1) + 1 + strlen($3) + 1]; + strcpy(s, $1); + strcat(s, "."); + strcat(s, $3); + delete[] $1; + delete[] $3; + $$ = s; + } + ; + +%% + +static int +yylex(YYSTYPE* lvalp, void* simpleParserPtr) +{ + int ret = simpleParser.yylex(); + *lvalp = simpleParser.yylval(); + return ret; +} + +/* vim: set filetype=yacc: */ diff --git a/storage/ndb/src/old_files/client/odbc/codegen/SimpleParser.cpp b/storage/ndb/src/old_files/client/odbc/codegen/SimpleParser.cpp new file mode 100644 index 00000000000..a2418f49e37 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/SimpleParser.cpp @@ -0,0 +1,96 @@ +/* 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> +#include <NdbMutex.h> +#include <common/StmtArea.hpp> +#include <FlexLexer.h> +#include "SimpleParser.hpp" + +SimpleParser::~SimpleParser() +{ +} + +#ifdef NDB_WIN32 +static NdbMutex & parse_mutex = * NdbMutex_Create(); +#else +static NdbMutex parse_mutex = NDB_MUTEX_INITIALIZER; +#endif + +void +SimpleParser::yyparse() +{ + Ctx& ctx = this->ctx(); + NdbMutex_Lock(&parse_mutex); + ctx_log2(("parse: %s", stmtArea().sqlText().c_str())); +#if YYDEBUG + SimpleParser_yydebug = (m_ctx.logLevel() >= 5); +#endif + SimpleParser_yyparse((void*)this); + NdbMutex_Unlock(&parse_mutex); +} + +void +SimpleParser::pushState(int sc) +{ + yy_push_state(sc); + m_stacksize++; +} + +void +SimpleParser::popState() +{ + ctx_assert(m_stacksize > 0); + yy_pop_state(); + m_stacksize--; +} + +void +SimpleParser::parseError(const char* msg) +{ + ctx().pushStatus(Sqlstate::_42000, Error::Gen, "%s at '%*s' position %u", msg, yyleng, yytext, m_parsePos - yyleng); +} + +int +SimpleParser::LexerInput(char* buf, int max_size) +{ + const BaseString& text = stmtArea().sqlText(); + int n = 0; + const char* const t = text.c_str(); + const unsigned m = text.length(); + while (n < max_size && m_textPos < m) { + buf[n++] = t[m_textPos++]; + m_parsePos++; // XXX simple hack + break; + } + return n; +} + +// XXX just a catch-all (scanner should match all input) +void +SimpleParser::LexerOutput(const char* buf, int size) +{ + if (! ctx().ok()) + return; + const char* msg = "unrecognized input"; + ctx().pushStatus(Sqlstate::_42000, Error::Gen, "%s at '%*s' position %u", msg, size, buf, m_parsePos); +} + +void +SimpleParser::LexerError(const char* msg) +{ + ctx().pushStatus(Sqlstate::_42000, Error::Gen, "%s at '%*s' position %u", msg, yyleng, yytext, m_parsePos); +} diff --git a/storage/ndb/src/old_files/client/odbc/codegen/SimpleParser.hpp b/storage/ndb/src/old_files/client/odbc/codegen/SimpleParser.hpp new file mode 100644 index 00000000000..abadae8f905 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/SimpleParser.hpp @@ -0,0 +1,161 @@ +/* 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_SimpleParser_hpp +#define ODBC_CODEGEN_SimpleParser_hpp + +#include <common/common.hpp> +#include "Code_root.hpp" +#include "Code_stmt.hpp" +#include "Code_select.hpp" +#include "Code_pred.hpp" +#include "Code_pred_op.hpp" +#include "Code_comp_op.hpp" +#include "Code_expr_row.hpp" +#include "Code_expr.hpp" +#include "Code_expr_op.hpp" +#include "Code_expr_func.hpp" +#include "Code_expr_column.hpp" +#include "Code_expr_const.hpp" +#include "Code_expr_param.hpp" +#include "Code_update.hpp" +#include "Code_set_row.hpp" +#include "Code_insert.hpp" +#include "Code_dml_row.hpp" +#include "Code_dml_column.hpp" +#include "Code_delete.hpp" +#include "Code_table_list.hpp" +#include "Code_table.hpp" +#include "Code_create_table.hpp" +#include "Code_create_index.hpp" +#include "Code_ddl_row.hpp" +#include "Code_ddl_column.hpp" +#include "Code_ddl_constr.hpp" +#include "Code_data_type.hpp" +#include "Code_drop_table.hpp" +#include "Code_drop_index.hpp" + +#include "SimpleGram.tab.hpp" + +class StmtArea; +class Plan_root; + +class SimpleParser : public yyFlexLexer { +public: + SimpleParser(Ctx& ctx, StmtArea& stmtArea, Plan_root* root); + ~SimpleParser(); + Ctx& ctx(); + StmtArea& stmtArea(); + Plan_root* root(); + void yyparse(); // calls real yyparse + int yylex(); // generated by flex + YYSTYPE yylval(); + void pushState(int sc); // push start condition + void popState(); // pop start condition + unsigned paramNumber() const; + void parseError(const char* msg); + // parser helpers - to avoid creating new Plan tree types + Plan_ddl_column* curr(Plan_ddl_column* p); + Plan_create_index* curr(Plan_create_index* p); +protected: + virtual int LexerInput(char* buf, int max_size); + virtual void LexerOutput(const char* buf, int size); + virtual void LexerError(const char* msg); +private: + Ctx& m_ctx; + StmtArea& m_stmtArea; + Plan_root* const m_root; + unsigned m_textPos; // position in sql text + unsigned m_parsePos; // parse position, to report error + YYSTYPE m_yylval; // token value + BaseString m_string; // storage for edited string token + unsigned m_stacksize; // state stack size + unsigned m_paramNumber; // parameter number + // parser helpers + Plan_ddl_column* m_ddl_column; + Plan_create_index* m_create_index; +}; + +extern int SimpleParser_yyparse(void* simpleParserPtr); +#if YYDEBUG +extern int SimpleParser_yydebug; +#endif + +inline +SimpleParser::SimpleParser(Ctx& ctx, StmtArea& stmtArea, Plan_root* root) : + m_ctx(ctx), + m_stmtArea(stmtArea), + m_root(root), + m_textPos(0), + m_parsePos(0), + m_stacksize(0), + m_paramNumber(0), + // parser helpers + m_ddl_column(0) +{ +} + +inline Ctx& +SimpleParser::ctx() +{ + return m_ctx; +} + +inline StmtArea& +SimpleParser::stmtArea() +{ + return m_stmtArea; +} + +inline Plan_root* +SimpleParser::root() +{ + return m_root; +} + +inline YYSTYPE +SimpleParser::yylval() +{ + return m_yylval; +} + +inline unsigned +SimpleParser::paramNumber() const +{ + return m_paramNumber; +} + +// parser helpers + +inline Plan_ddl_column* +SimpleParser::curr(Plan_ddl_column* p) +{ + if (p != 0) + m_ddl_column = p; + ctx_assert(m_ddl_column != 0); + return m_ddl_column; +} + +inline Plan_create_index* +SimpleParser::curr(Plan_create_index* p) +{ + if (p != 0) + m_create_index = p; + ctx_assert(m_create_index != 0); + return m_create_index; +} + +#endif diff --git a/storage/ndb/src/old_files/client/odbc/codegen/SimpleScan.lpp b/storage/ndb/src/old_files/client/odbc/codegen/SimpleScan.lpp new file mode 100644 index 00000000000..29aa876f669 --- /dev/null +++ b/storage/ndb/src/old_files/client/odbc/codegen/SimpleScan.lpp @@ -0,0 +1,243 @@ +%{ +#include <ctype.h> +#include "SimpleParser.hpp" + +struct SqlKeyword { + const char* m_name; + int m_value; + int m_state; + static const SqlKeyword* find(Ctx& ctx, const char* name, int state); +}; + +%} + +%option c++ +%option yyclass="SimpleParser" +%option stack +%option noyywrap + +space [\040\t\n\r\f] +digit [0-9] +letter [A-Za-z_] +special ("$") +identifier ({letter}({letter}|{digit}|{special})*) +integer {digit}++ +decimal (({digit}*\.{digit}+)|({digit}+\.{digit}*)) +real ((({digit}*\.{digit}+)|({digit}+\.{digit}*)|({digit}+))([Ee][-+]?{digit}+)) + +%s StateEval +%s StateType +%s StatePhys +%x StateString +%x StateQuoted + +%% + +{space} { + } +{identifier} { + const SqlKeyword* key = SqlKeyword::find(m_ctx, (char*)yytext, YYSTATE); + if (key != 0) + return key->m_value; + for (unsigned char* a = (unsigned char*)yytext; *a != 0; a++) { + if (islower(*a)) + *a = toupper(*a); + } + m_yylval.m_string = strcpy(new char[yyleng + 1], yytext); + return T_IDENTIFIER; + } +{integer} { + m_yylval.m_string = strcpy(new char[yyleng + 1], yytext); + return T_LINTEGER; + } +{decimal} { + m_yylval.m_string = strcpy(new char[yyleng + 1], yytext); + return T_LDECIMAL; + } +{real} { + m_yylval.m_string = strcpy(new char[yyleng + 1], yytext); + return T_LREAL; + } +"--".* { + } +"/*" { + int c = 0, d; + while (1) { + d = c; + if ((c = yyinput()) == EOF) { + parseError("unterminated comment"); + yyterminate(); + } + if (d == '*' && c == '/') + break; + } + } +<StateEval>{ +"+" return T_PLUS; +"-" return T_MINUS; +"*" return T_TIMES; +"/" return T_DIVIDE; +"=" return T_EQ; +"!=" return T_NOTEQ; +"^=" return T_NOTEQ; +"<>" return T_NOTEQ; +"<" return T_LT; +"<=" return T_LTEQ; +">" return T_GT; +">=" return T_GTEQ; +"?" m_paramNumber++; return T_QUES; +} + +"." return T_PERIOD; +"," return T_COMMA; +"(" return T_PARENLEFT; +")" return T_PARENRIGHT; +"*" return T_ASTERISK; +"=" return T_ASSIGN; + +"'" { + pushState(StateString); + m_string.assign(""); + } +<StateString>{ +[^']* { + m_string.append(yytext); + } +"''" { + m_string.append("'"); + } +"'" { + m_yylval.m_string = strcpy(new char[m_string.length() + 1], m_string.c_str()); + popState(); + return T_STRING; + } +} + +\" { + pushState(StateQuoted); + m_string.assign(""); + } +<StateQuoted>{ +[^"]* { + m_string.append(yytext); + } +\\\" { + m_string.append("\""); + } +\" { + m_yylval.m_string = strcpy(new char[m_string.length() + 1], m_string.c_str()); + popState(); + return T_IDENTIFIER; + } +} + +%% + +// scan states +int SimpleParser_stateEval = StateEval; +int SimpleParser_stateType = StateType; +int SimpleParser_statePhys = StatePhys; + +// keep sorted + +static const SqlKeyword sqlKeyword[] = { + { "AND", T_AND, -1 }, + { "ASC", T_ASC, -1 }, + { "AUTO_INCREMENT", T_AUTO_INCREMENT, -1 }, + { "BIGINT", T_BIGINT, StateType }, + { "BINARY", T_BINARY, StateType }, + { "BLOB", T_BLOB, StateType }, + { "BY", T_BY, -1 }, + { "CHAR", T_CHAR, StateType }, + { "CLOB", T_CLOB, StateType }, + { "CONSTRAINT", T_CONSTRAINT, -1 }, + { "CREATE", T_CREATE, -1 }, + { "DATETIME", T_DATETIME, StateType }, + { "DEFAULT", T_DEFAULT, -1 }, + { "DELETE", T_DELETE, -1 }, + { "DESC", T_DESC, -1 }, + { "DISTINCT", T_DISTINCT, -1 }, + { "DOUBLE", T_DOUBLE, StateType }, + { "DROP", T_DROP, -1 }, + { "FLOAT", T_FLOAT, StateType }, + { "FOREIGN", T_FOREIGN, -1 }, + { "FROM", T_FROM, -1 }, + { "GROUP", T_GROUP, -1 }, + { "HASH", T_HASH, -1 }, + { "HAVING", T_HAVING, -1 }, + { "IN", T_IN, -1 }, + { "INDEX", T_INDEX, -1 }, + { "INSERT", T_INSERT, -1 }, + { "INT", T_INT, StateType }, + { "INTEGER", T_INTEGER, StateType }, + { "INTO", T_INTO, -1 }, + { "IS", T_IS, -1 }, + { "KEY", T_KEY, -1 }, + { "LARGE", T_LARGE, StatePhys }, + { "LIKE", T_LIKE, -1 }, + { "LIMIT", T_LIMIT, -1 }, + { "LOGGING", T_LOGGING, StatePhys }, + { "LONGBLOB", T_LONGBLOB, StateType }, + { "LONGCLOB", T_LONGCLOB, StateType }, + { "MEDIUM", T_MEDIUM, StatePhys }, + { "NOLOGGING", T_NOLOGGING, StatePhys }, + { "NOT", T_NOT, -1 }, + { "NULL", T_NULL, -1 }, + { "OFFSET", T_OFFSET, -1 }, + { "ON", T_ON, -1 }, + { "OR", T_OR, -1 }, + { "ORDER", T_ORDER, -1 }, + { "PRECISION", T_PRECISION, StateType }, + { "PRIMARY", T_PRIMARY, -1 }, + { "REAL", T_REAL, StateType }, + { "REFERENCES", T_REFERENCES, -1 }, + { "ROWNUM", T_ROWNUM, -1 }, + { "SELECT", T_SELECT, -1 }, + { "SET", T_SET, -1 }, + { "SINGLE", T_SINGLE, StatePhys }, + { "SMALL", T_SMALL, StatePhys }, + { "SMALLINT", T_SMALLINT, StateType }, + { "STORAGE", T_STORAGE, StatePhys }, + { "SYSDATE", T_SYSDATE, -1 }, + { "TABLE", T_TABLE, -1 }, + { "UNIQUE", T_UNIQUE, -1 }, + { "UNSIGNED", T_UNSIGNED, -1 }, + { "UPDATE", T_UPDATE, -1 }, + { "VALUES", T_VALUES, -1 }, + { "VARBINARY", T_VARBINARY, StateType }, + { "VARCHAR", T_VARCHAR, StateType }, + { "WHERE", T_WHERE, -1 }, + { "WRITE", T_WRITE, -1 } +}; + +static const unsigned sqlKeywordCount = sizeof(sqlKeyword) / sizeof(sqlKeyword[0]); + +const SqlKeyword* +SqlKeyword::find(Ctx& ctx, const char* name, int state) +{ + ctx_log4(("find keyword '%s' lex state = %d", name, state)); + const unsigned maxlen = 99; + char buf[maxlen + 1]; + char* a = buf; + const char* b = name; + while (*b != 0) { + if (a >= buf + maxlen) // will not be found + break; + char c = *b++; + if ('a' <= c && c <= 'z') // locale independent + c -= 'a' - 'A'; + *a++ = c; + } + *a = 0; + for (unsigned i = 0; i < sqlKeywordCount; i++) { + const SqlKeyword* key = &sqlKeyword[i]; + if (strcmp(key->m_name, buf) == 0) { + if (key->m_state != -1 && key->m_state != state) + return 0; + return key; + } + } + return 0; +} + +/* vim: set filetype=lex: */ |