Logo Search packages:      
Sourcecode: bayonne version File versions  Download package

mysql.cpp

// Copyright (C) 2000 Open Source Telecom Corporation.
//  
// 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 <server.h>
#include <cc++/process.h>
#include <mysql.h>

#ifdef      CCXX_NAMESPACES
namespace ost {
using namespace std;
#endif

#define     SYM_SQLDRIVER     "sql.driver"
#define     SYM_ROWS    "sql.rows"
#define     SYM_COLS    "sql.cols"
#define     SYM_DATABASE      "sql.database"
#define     SYM_SQLERROR      "sql.error"
#define SYM_INSERTID    "sql.insertid"

class MySQLTrunk : public TrunkImage
{
private:
      friend class MySQLModule;

      void characters(const unsigned char *text, unsigned len) {};
      void startElement(const unsigned char *name, const unsigned char **attrib) {};
      void endElement(const unsigned char *name) {};
      bool loader(Trunk *trk, trunkdata_t *data);
      char *mystr(const char *temp);

      MySQLTrunk();
      ~MySQLTrunk();
};

class MySQLModule : private Module, public Keydata, public Mutex
{
private:
      friend class MySQLTrunk;
      MYSQL **conn;
      unsigned int nbConn;

      modtype_t getType(void)
            {return MODULE_SQL;};

      char *getName(void)
            {return "sql";};

      TrunkImage *getXML(void)
            {return (TrunkImage *)new MySQLTrunk;};

      char *dispatch(Trunk *trunk);

      void connect(Trunk *trunk);
      void detach(Trunk *trunk);
public:
      MySQLModule();
} mysql;

MySQLModule::MySQLModule() : Module(), Keydata("/bayonne/sql"), Mutex(), conn(NULL), nbConn(0)
{
      static Keydata::Define keydefs[] = {
      {"database", "bayonne"},
      {"port", "3306"},
      {NULL, NULL}};

      const char *cp;

      slog(Slog::levelDebug) << "load: mysql module" << endl;
      load(keydefs);
      driver->addModule(this);
      addSession();

      cp = getLast("host");
      if(cp)
            Process::setEnv("MYSQL_HOST", cp, true);

      cp = getLast("port");
      if(cp)
            Process::setEnv("MYSQL_PORT", cp, true);

      slog(Slog::levelDebug) << "sql: loading mysql driver" << endl;
}

void MySQLModule::connect(Trunk *trunk)
{
      char buf[256];
      const char *dbname, *user, *password, *host;
      MYSQL *cnx;
      unsigned int port, boucle;
      enterMutex();
      unsigned int id = trunk->getId();
      if (nbConn <= id) {
            if (nbConn == 0) {
                  conn = (MYSQL **)malloc(sizeof(MYSQL *) * (id + 1));
            }
            else {
                  conn = (MYSQL **)realloc(conn, sizeof(MYSQL *) * (id + 1));
            }
            for (boucle = nbConn ; boucle < id + 1 ; boucle++) {
                  conn[boucle] = NULL;
            }
            nbConn = id + 1;
      }
      cnx = conn[id];
      leaveMutex();
      if(cnx == NULL)
      {
            dbname = getLast("database");
            user = getLast("user");
            password = getLast("password");
            host = getLast("host");
            port = atoi(getLast("port"));

            slog(Slog::levelDebug) << "sql: connecting database (" << id << ")" << endl;

            cnx = (MYSQL *)malloc(sizeof(MYSQL));
            mysql_init(cnx);
            mysql_options(cnx, MYSQL_READ_DEFAULT_GROUP, "Bayonne");
            if(!mysql_real_connect(cnx, host, user, password,
                        NULL, port, NULL, 0))
            {
                  slog(Slog::levelError) << "sql: failed to connect: " <<
                        mysql_error(cnx) << endl;
                  free(cnx);
            }
            enterMutex();
            conn[id] = cnx;
            leaveMutex();
      }
      trunk->setConst(SYM_SQLDRIVER, "mysql");
      trunk->setConst(SYM_DATABASE, getLast("database"));
      trunk->setSymbol(SYM_ROWS, 10);
      trunk->setSymbol(SYM_COLS, 10);
      trunk->setSymbol(SYM_SQLERROR, 64);
      trunk->setSymbol(SYM_INSERTID, 10);
}

void MySQLModule::detach(Trunk *trunk)
{
      const char *cp = trunk->getSymbol(SYM_SQLDRIVER);
      if(!cp)
            return;

      if(stricmp(cp, "mysql"))
            return;

      enterMutex();
      unsigned int id = trunk->getId();
      if (conn[id] != NULL) {
            mysql_close(conn[id]);
            free(conn[id]);
            conn[id] = NULL;
            slog(Slog::levelDebug) << "sql: disconnecting database" << endl;
      }
      leaveMutex();
}

char *MySQLModule::dispatch(Trunk *trunk)
{
            trunkdata_t *data = getData(trunk);
        const char *key, *sql = trunk->getKeyword("query");
      const char *db = trunk->getKeyword("database");
      const char *mem = trunk->getMember();
      char *table = trunk->getKeyword("table"), *opt, *tag, *cp;
      char cols[256], vals[256];
      Line *line = trunk->getScript();
      unsigned len = 0, clen = 0, vlen = 0, argc = 0;

        key = trunk->getKeyword("maxTime");
        if(!key)
                key = "60s";
      if(!mem)
            mem = "none";
      if(!db)
            db = getLast("database");

      data->load.timeout = getSecTimeout(key);

      if(!sql && !stricmp(mem, "insert"))
      {
            if(!table)
                  table = trunk->getValue(NULL);
            if(!table)
                  return "insert-table-missing";

            while(argc < line->argc && clen < sizeof(cols) - 1 && vlen < sizeof(vals) - 1)
            {
                  opt = line->args[argc++];
                  if(*opt == '%')
                  {
                        tag = ++opt;
                        opt = trunk->getSymbol(opt);
                  }
                  else if(*opt == '=' && stricmp(opt, "=table") && stricmp(opt, "=maxTime"))
                  {
                        tag = ++opt;
                        opt = trunk->getContent(line->args[argc++]);
                  }     
                  else
                        continue;
                  
                  if(clen)
                        cols[clen++] = ',';
                  if(vlen)
                        vals[vlen++] = ',';
                  snprintf(cols + clen, sizeof(cols) - clen, "%s", tag);
                  clen = strlen(cols);
                  snprintf(vals + vlen, sizeof(vals) - vlen, "\'%s\'", opt);
                  vlen = strlen(vals);          
            }
            cols[clen] = 0;
            vals[vlen] = 0;
            snprintf(data->load.filepath, 250, 
                  "insert into %s (%s) values (%s)", table, cols, vals);
            len = strlen(data->load.filepath);
      }
      else while(!sql && len < 256 && NULL != (cp = trunk->getValue(NULL)))
      {
            snprintf(data->load.filepath + len, 256 - len, "%s", cp);
            len = strlen(data->load.filepath);
      }
      if(!sql && data->load.filepath)
            sql = data->load.filepath;

        data->load.attach = false;
        data->load.post = false;
            data->load.section = "";
      data->load.fail = NULL;
        key = trunk->getKeyword("maxTime");
        if(!key)
                key = "60s";
        data->load.timeout = getSecTimeout(key);
        data->load.parent = NULL;
        data->load.gosub = false;
        data->load.url = sql;
        data->load.vars = NULL;
        data->load.userid[0] = 0;
      data->load.database = db;
      mysql.connect(trunk);
        return NULL;
}

MySQLTrunk::MySQLTrunk() : TrunkImage()
{
}

MySQLTrunk::~MySQLTrunk()
{
      purge();
}

bool MySQLTrunk::loader(Trunk *trunk, trunkdata_t *data)
{
      int status;
      const char *sql = data->load.url;
      const char *db = data->load.database;
      const char *dvr = trunk->getSymbol(SYM_SQLDRIVER);
      unsigned rows, cols, row, col;
      const char **argv;
      char val[10];
      const char *errmsg;
      char iid[100];
      MYSQL_RES *result;
      MYSQL *cnx;
      unsigned int id = trunk->getId();

      if(!dvr)
            mysql.connect(trunk);

      trunk->setSymbol(SYM_ROWS, "0");
      trunk->setSymbol(SYM_COLS, "0");
      trunk->setSymbol(SYM_SQLERROR, "");
      trunk->setSymbol(SYM_INSERTID, "0");

      if(stricmp(dvr, "mysql"))
      {
            trunk->setSymbol(SYM_SQLERROR, "invalid-driver");
            return false;
      }

      mysql.enterMutex();
      cnx = mysql.conn[id];
      mysql.leaveMutex();
      if(mysql.nbConn <= id)
      {
            trunk->setSymbol(SYM_SQLERROR, "no-database");
            return false;
      }
      if(cnx == NULL)
      {
            trunk->setSymbol(SYM_SQLERROR, "no-database");
            return false;
      }

      if(mysql_ping(cnx) != 0)
      {
            trunk->setSymbol(SYM_SQLERROR, "server-died");
            mysql.enterMutex();
            mysql_close(mysql.conn[id]);
            mysql.conn[id] = NULL;
            mysql.leaveMutex();
            return false;
      }

      if(mysql_select_db(cnx, db) != 0)
      {
            errmsg = mysql_error(cnx);
            slog(Slog::levelCritical) << "sql: " << errmsg << endl;
            trunk->setSymbol(SYM_SQLERROR, errmsg);
            return false;
      }

      if(mysql_real_query(cnx, sql, strlen(sql)) != 0)
      {
            errmsg = mysql_error(cnx);
            slog(Slog::levelCritical) << "sql: " << errmsg << endl;
            trunk->setSymbol(SYM_SQLERROR, errmsg);
            return false;
      }


      result = mysql_store_result(cnx);
      if(result)
      {
            cols = mysql_num_fields(result);
            rows = mysql_num_rows(result);
      }
      else
      {
            if(mysql_field_count(cnx) == 0)
            {
                  // query doesn't return data
                  sprintf(iid, "%d", mysql_insert_id(cnx));
                  trunk->setSymbol(SYM_INSERTID, iid);
                  trunk->setSymbol(SYM_ROWS, mysql_affected_rows(cnx));
                  //    mysql_free_result(result);
                  return true;
            }
            else
            {
                  errmsg = mysql_error(cnx);
                  slog(Slog::levelCritical) << "sql: " << errmsg << endl;
                  trunk->setSymbol(SYM_SQLERROR, errmsg);
                  return false;
            }
      }
      
      getCompile("#header");
      argv = (const char **)MemPager::alloc(sizeof(char *) * (cols + 1));
      col = 0;

      MYSQL_FIELD *field;
      while(field = mysql_fetch_field(result))
      {
            argv[col] = mystr(field->name);
            ++col;
      }
      argv[col] = NULL;
      addCompile(0, "data", argv);

      putCompile(main);

      getCompile("#sql");

      row = 0;
      MYSQL_ROW sqlrow;
      while(sqlrow = mysql_fetch_row(result))
      {
            col = 0;
            while(col < cols)
            {
                  argv[col] = mystr(sqlrow[col]);
                  ++col;
            }
            argv[col] = NULL;
            addCompile(0, "data", argv);
            ++row;
      }

      putCompile(current);

      mysql_free_result(result);

      trunk->setData("#sql");
      snprintf(val, sizeof(val), "%d", rows);
      trunk->setSymbol(SYM_ROWS, val);
      snprintf(val, sizeof(val), "%d", cols);
      trunk->setSymbol(SYM_COLS, val);
      return true;
}

char *MySQLTrunk::mystr(const char *temp)
{
      char *nt;
      unsigned len;

      if(!temp)
            return "";

      len = strlen(temp);

      while(len && isspace(temp[len - 1]))
            --len;

        nt = (char *)MemPager::alloc(len + 1);
        strncpy(nt, temp, len);
      nt[len] = 0;
        return nt;
}

#ifdef      CCXX_NAMESPACES
};
#endif

Generated by  Doxygen 1.6.0   Back to index