r20408 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r20407‎ | r20408 | r20409 >
Date:21:40, 13 March 2007
Author:river
Status:old
Tags:
Comment:
MaxDB client
Modified paths:
  • /trunk/skirmish/config.mk.sample (modified) (history)
  • /trunk/skirmish/db.cc (modified) (history)
  • /trunk/skirmish/maxdb.cc (added) (history)
  • /trunk/skirmish/maxdb.h (added) (history)
  • /trunk/skirmish/rules.mk (modified) (history)

Diff [purge]

Index: trunk/skirmish/db.cc
@@ -22,6 +22,10 @@
2323 # include "odbc.h"
2424 #endif
2525
 26+#ifdef SKIRMISH_MAXDB
 27+# include "maxdb.h"
 28+#endif
 29+
2630 namespace db {
2731
2832 connection::connection()
@@ -67,6 +71,10 @@
6872 #ifdef SKIRMISH_ODBC
6973 ("odbc", construct<odbc::connection>)
7074 #endif
 75+#ifdef SKIRMISH_MAXDB
 76+ ("maxdb", construct<maxdb::connection>)
 77+ ("sapdb", construct<maxdb::connection>)
 78+#endif
7179 ;
7280
7381 schemelist_t::iterator it = schemes.find(type);
Index: trunk/skirmish/maxdb.cc
@@ -0,0 +1,293 @@
 2+#include <iostream>
 3+#include <boost/lexical_cast.hpp>
 4+#include <boost/format.hpp>
 5+#include <boost/algorithm/string/case_conv.hpp>
 6+#include <unistd.h>
 7+
 8+#include "maxdb.h"
 9+
 10+namespace maxdb {
 11+
 12+connection::connection(std::string const &desc)
 13+ : runtime(0)
 14+ , env(0)
 15+ , conn(0)
 16+{
 17+ /* desc is "user[/password]@[host[/database]]" */
 18+ std::string::size_type i;
 19+ std::string userpart;
 20+ std::string dbpart;
 21+ std::string d;
 22+
 23+ d = desc.substr(desc.find(':') + 1);
 24+
 25+ if ((i = d.find('@')) != std::string::npos) {
 26+ userpart = d.substr(0, i);
 27+ dbpart = d.substr(i + 1);
 28+ } else
 29+ userpart = d;
 30+
 31+ if ((i = userpart.find('/')) != std::string::npos) {
 32+ user = userpart.substr(0, i);
 33+ password = userpart.substr(i + 1);
 34+ } else {
 35+ user = userpart;
 36+ char *p = getpass("Enter password: ");
 37+ if (p)
 38+ password = p;
 39+ }
 40+
 41+ if ((i = dbpart.find('/')) != std::string::npos) {
 42+ host = dbpart.substr(0, i);
 43+ dbname = dbpart.substr(i + 1);
 44+ } else
 45+ host = dbpart;
 46+}
 47+
 48+connection::~connection()
 49+{
 50+ close();
 51+}
 52+
 53+void
 54+connection::open(void)
 55+{
 56+ char err[1024];
 57+ if ((runtime = SQLDBC::GetClientRuntime(err, sizeof(err))) == NULL)
 58+ throw db::error(err);
 59+ env = new SQLDBC::SQLDBC_Environment(runtime);
 60+ conn = env->createConnection();
 61+ if (conn->connect(host.c_str(), dbname.c_str(), user.c_str(), password.c_str()) != SQLDBC_OK)
 62+ throw db::error(error(conn->error()));
 63+}
 64+
 65+void
 66+connection::close(void)
 67+{
 68+ delete env;
 69+}
 70+
 71+std::string
 72+connection::error(SQLDBC::SQLDBC_ErrorHndl &err)
 73+{
 74+ return str(boost::format("%d:%s:%s") % err.getErrorCode() % err.getSQLState() % err.getErrorText());
 75+}
 76+
 77+db::resultptr
 78+connection::execute_sql(std::string const &sql)
 79+{
 80+ db::resultptr r = prepare_sql(sql);
 81+ r->execute();
 82+ return r;
 83+}
 84+
 85+db::resultptr
 86+connection::prepare_sql(std::string const &sql)
 87+{
 88+ return db::resultptr(new result(this, sql));
 89+}
 90+
 91+result::result(connection *conn, std::string const &q)
 92+ : stmt(0)
 93+ , conn(conn)
 94+ , sql(q)
 95+{
 96+std::cout << "q = ["<<q<<"]\n";
 97+ if ((stmt = conn->conn->createPreparedStatement()) == NULL)
 98+ throw db::error(conn->error(conn->conn->error()));
 99+ if (stmt->prepare(q.c_str(), q.size(), SQLDBC_StringEncodingUTF8) != SQLDBC_OK)
 100+ throw db::error(conn->error(stmt->error()));
 101+ if (!stmt->isQuery())
 102+ return;
 103+
 104+ SQLDBC::SQLDBC_ParameterMetaData *pmd = stmt->getParameterMetaData();
 105+ SQLDBC_Int2 nparams = pmd->getParameterCount();
 106+ SQLDBC_Length namelen;
 107+ for (int i = 1; i <= nparams; ++i) {
 108+#if 0
 109+ if (pmd->getParameterName(i, NULL, SQLDBC_StringEncodingUTF8, 0, &namelen) != SQLDBC_DATA_TRUNC)
 110+ throw db::error("could not retrieve parameter length");
 111+#endif
 112+ std::vector<char> paramname(namelen + 1);
 113+std::cout << "namelen = " << namelen << '\n';
 114+ if (pmd->getParameterName(i, &paramname[0], SQLDBC_StringEncodingUTF8, paramname.size() + 1, &namelen) != SQLDBC_OK)
 115+ throw db::error("could not retrieve parameter name");
 116+ param p;
 117+ p.name.assign(&paramname[0], &paramname[0] + namelen);
 118+ p.pos = i;
 119+std::cout << "i = " << i << " nparams = " << nparams << " name = [" << p.name << "] len = " << namelen << "\n";
 120+ params.push_back(p);
 121+ }
 122+}
 123+
 124+void
 125+result::execute(void)
 126+{
 127+ if (stmt->execute() != SQLDBC_OK)
 128+ throw db::error(conn->error(stmt->error()));
 129+
 130+ SQLDBC::SQLDBC_ResultSetMetaData *md = stmt->getResultSetMetaData();
 131+ if (md == NULL)
 132+ return;
 133+
 134+ int ncols = md->getColumnCount();
 135+ fields.resize(ncols);
 136+ for (int i = 0; i < ncols; ++i) {
 137+ int colsize = md->getColumnLength(i + 1);
 138+ fields[i].size = colsize;
 139+ fields[i].data.resize(colsize + 1);
 140+
 141+ SQLDBC_Retcode r;
 142+ std::vector<char> name(256);
 143+ SQLDBC_Length namelen;
 144+ r = md->getColumnName(i + 1, &name[0], SQLDBC_StringEncodingUTF8, name.size(), &namelen);
 145+ if (r != SQLDBC_OK && r != SQLDBC_DATA_TRUNC)
 146+ throw db::error(conn->error(stmt->error()));
 147+ if (r == SQLDBC_DATA_TRUNC) {
 148+ name.resize(namelen + 1);
 149+ if (md->getColumnName(i + 1, &name[0], SQLDBC_StringEncodingUTF8, name.size(), &namelen)
 150+ != SQLDBC_OK)
 151+ throw db::error(conn->error(stmt->error()));
 152+ }
 153+ fields[i].name.assign(&name[0], &name[0] + namelen);
 154+ }
 155+
 156+ res = stmt->getResultSet();
 157+}
 158+
 159+void
 160+result::bind(std::string const &key, std::string const &value)
 161+{
 162+ for (int i = 0; i < params.size(); ++i) {
 163+ if (params[i].name != key)
 164+ return;
 165+ SQLDBC_Length len = value.size();
 166+ if (stmt->bindParameter(params[i].pos, SQLDBC_HOSTTYPE_UTF8,
 167+ (void *)value.data(), &len, value.size(), SQLDBC_FALSE) != SQLDBC_OK)
 168+ throw db::error(conn->error(stmt->error()));
 169+ return;
 170+ }
 171+ throw db::error(str(boost::format("parameter \"%s\" does not exist in statement") % key));
 172+}
 173+
 174+result::~result()
 175+{
 176+}
 177+
 178+bool
 179+result::empty(void)
 180+{
 181+ return fields.size() == 0;
 182+}
 183+
 184+int
 185+result::num_fields(void)
 186+{
 187+ return fields.size();
 188+}
 189+
 190+int
 191+result::affected_rows(void)
 192+{
 193+ return 0; /* XXX */
 194+}
 195+
 196+result_row *
 197+result::next_row(void)
 198+{
 199+ switch (res->next()) {
 200+ case SQLDBC_OK:
 201+ break;
 202+ case SQLDBC_NO_DATA_FOUND:
 203+ return NULL;
 204+ case SQLDBC_NOT_OK:
 205+ throw db::error(conn->error(res->error()));
 206+ }
 207+
 208+ for (int i = 0; i < fields.size(); ++i) {
 209+ if (res->getObject(i + 1, SQLDBC_HOSTTYPE_UTF8, &fields[i].data[0],
 210+ &fields[i].len, fields[i].size + 1, SQLDBC_TRUE) != SQLDBC_OK)
 211+ throw db::error(conn->error(res->error()));
 212+ }
 213+ return new result_row(this);
 214+}
 215+
 216+result_row::result_row(result *er)
 217+ : er(er)
 218+{
 219+}
 220+
 221+std::string
 222+result_row::string_value(int col)
 223+{
 224+ if (er->fields[col].len == SQLDBC_NULL_DATA)
 225+ return "NULL";
 226+ return std::string(&er->fields[col].data[0], &er->fields[col].data[er->fields[col].len]);
 227+
 228+}
 229+
 230+std::string
 231+result::field_name(int col)
 232+{
 233+ return fields[col].name;
 234+}
 235+
 236+std::vector<db::table>
 237+connection::describe_tables(std::string const &schema)
 238+{
 239+ std::string n = boost::algorithm::to_upper_copy(schema);
 240+
 241+ db::resultptr r;
 242+ if (schema.empty())
 243+ r = prepare_sql("SELECT owner, table_name FROM all_tables");
 244+ else {
 245+ r = prepare_sql("SELECT owner, table_name FROM all_tables WHERE owner = :towner");
 246+ r->bind(":towner", n);
 247+ }
 248+ r->execute();
 249+
 250+ std::vector<std::pair<std::string, std::string> > names;
 251+
 252+ std::vector<db::table> ret;
 253+ result::iterator it = r->begin(), end = r->end();
 254+ for (; it != end; ++it) {
 255+ names.push_back(std::pair<std::string, std::string>(
 256+ it->string_value(0), it->string_value(1)));
 257+ }
 258+
 259+ for (int i = 0; i < names.size(); ++i) {
 260+ ret.push_back(describe_table(names[i].first, names[i].second));
 261+ }
 262+
 263+ return ret;
 264+}
 265+
 266+db::table
 267+connection::describe_table(std::string const &schema, std::string const &name)
 268+{
 269+ db::table ret;
 270+ ret.name = name;
 271+ ret.schema = schema;
 272+
 273+ db::resultptr r = prepare_sql(
 274+ "SELECT column_name, data_type, nullable FROM all_tab_columns WHERE owner = :tabowner AND table_name = :name");
 275+ std::string n = boost::algorithm::to_upper_copy(name);
 276+ std::string o = boost::algorithm::to_upper_copy(schema);
 277+
 278+ r->bind(":name", n);
 279+ r->bind(":tabowner", o);
 280+ r->execute();
 281+
 282+ result::iterator it = r->begin(), end = r->end();
 283+ for (; it != end; ++it) {
 284+ db::column c;
 285+ c.name = it->string_value(0);
 286+ c.type = it->string_value(1);
 287+ c.nullable = it->string_value(2) == "Y";
 288+ ret.columns.push_back(c);
 289+ }
 290+
 291+ return ret;
 292+}
 293+
 294+} // namespace maxdb
Property changes on: trunk/skirmish/maxdb.cc
___________________________________________________________________
Added: svn:keywords
1295 + Id Revision
Index: trunk/skirmish/maxdb.h
@@ -0,0 +1,84 @@
 2+#ifndef MAXDB_H
 3+#define MAXDB_H
 4+
 5+#include <string>
 6+#include <vector>
 7+
 8+#include "db.h"
 9+#include <SQLDBC.h>
 10+
 11+namespace maxdb {
 12+
 13+struct result;
 14+struct connection;
 15+
 16+struct maxdbfield {
 17+ std::string name;
 18+ SQLDBC_Length size;
 19+ SQLDBC_Length len;
 20+ std::vector<char> data;
 21+};
 22+
 23+struct result_row : db::result_row {
 24+ result_row(result *er);
 25+
 26+ std::string string_value(int col);
 27+
 28+ result *er;
 29+};
 30+
 31+struct param {
 32+ std::string name;
 33+ int pos;
 34+};
 35+
 36+struct result : db::result {
 37+ result(connection *, std::string const &);
 38+ ~result();
 39+
 40+ void bind(std::string const &, std::string const &);
 41+ void execute(void);
 42+
 43+ bool empty(void);
 44+ int num_fields(void);
 45+ int affected_rows(void);
 46+ std::string field_name(int col);
 47+
 48+ result_row *next_row(void);
 49+
 50+ std::string sql;
 51+ std::vector<maxdbfield> fields;
 52+ connection *conn;
 53+ SQLDBC::SQLDBC_PreparedStatement *stmt;
 54+ SQLDBC::SQLDBC_ResultSet *res;
 55+ std::vector<param> params;
 56+};
 57+
 58+struct connection : db::connection {
 59+ connection(std::string const &desc);
 60+ ~connection();
 61+
 62+ void open(void);
 63+ void close(void);
 64+
 65+ std::string error(SQLDBC::SQLDBC_ErrorHndl &);
 66+
 67+ db::resultptr execute_sql(std::string const &);
 68+ db::resultptr prepare_sql(std::string const &);
 69+
 70+ std::vector<db::table> describe_tables(std::string const &);
 71+ db::table describe_table(std::string const &, std::string const &);
 72+
 73+private:
 74+ friend class result;
 75+
 76+ SQLDBC_IRuntime *runtime;
 77+ SQLDBC::SQLDBC_Environment *env;
 78+ SQLDBC::SQLDBC_Connection *conn;
 79+
 80+ std::string host, dbname, user, password;
 81+};
 82+
 83+} // namespace oracle
 84+
 85+#endif
Property changes on: trunk/skirmish/maxdb.h
___________________________________________________________________
Added: svn:keywords
186 + Id Revision
Index: trunk/skirmish/config.mk.sample
@@ -24,3 +24,9 @@
2525 # Build ODBC client (currently requires unixODBC)
2626 BUILD_ODBC = YES
2727 # BUILD_ODBC = NO
 28+
 29+# Build MaxDB (requires MaxDB SDK)
 30+BUILD_MAXDB = YES
 31+# BUILD_MAXDB = NO
 32+
 33+MAXDB_ROOT = /opt/sdb
Index: trunk/skirmish/rules.mk
@@ -27,6 +27,13 @@
2828 DB_SRCS += odbc.cc
2929 endif
3030
 31+ifeq ($(BUILD_MAXDB),YES)
 32+INCLUDES += -I$(MAXDB_ROOT)/programs/sdk/sqldbc/incl
 33+CPPFLAGS += -DSKIRMISH_MAXDB
 34+LIBS += -L$(MAXDB_ROOT)/programs/lib -lSQLDBC
 35+DB_SRCS += maxdb.cc
 36+endif
 37+
3138 .cc.o:
3239 $(CXX) $(CPPFLAGS) $(INCLUDES) $(CXXFLAGS) -c $<
3340