/home/bes3soft/bes3soft/Boss/7.0.2/dist/7.0.2/Calibration/rdbModel/rdbModel-00-01-01/src/Db/MysqlConnection.cxx

Go to the documentation of this file.
00001 // $Header: /bes/bes/BossCvs/Calibration/rdbModel/src/Db/MysqlConnection.cxx,v 1.12 2014/04/18 05:27:35 maqm Exp $
00002 #ifdef  WIN32
00003 #include <windows.h>
00004 #endif
00005 
00006 #include "rdbModel/Db/MysqlConnection.h"
00007 #include "rdbModel/Rdb.h"
00008 #include "rdbModel/Tables/Table.h"
00009 #include "rdbModel/Tables/Assertion.h"
00010 #include "rdbModel/Tables/Column.h"
00011 #include "rdbModel/Tables/Datatype.h"
00012 #include "rdbModel/Db/MysqlResults.h"
00013 #include "rdbModel/RdbException.h"
00014 #include "facilities/Util.h"
00015 
00016 #include "xmlBase/XmlParser.h"
00017 #include "xmlBase/Dom.h"
00018 
00019 #include "mysql.h"
00020 #include <iostream>
00021 #include <stdio.h>
00022 #include <unistd.h>
00023 #include "facilities/Util.h"
00024 namespace {
00025 
00026   // Size specification is of form (m) or (m,d)  If no size specification 
00027   // return 0; else return value of m.
00028   int extractSize(const std::string& sqlString) {
00029     std::string::size_type leftLoc = sqlString.find("(");
00030     if (leftLoc == std::string::npos) return 0;
00031     leftLoc++;           // now is at start of m
00032     std::string::size_type rightLoc = sqlString.find(",");
00033     if (rightLoc == std::string::npos) {
00034       rightLoc = sqlString.find(")");
00035     }
00036     std::string numString = 
00037       sqlString.substr(leftLoc, rightLoc - leftLoc);
00038     return facilities::Util::stringToInt(numString);
00039   }
00040 
00041   void addArg(bool literal, const std::string arg, std::string& sqlString) {
00042     if (literal) sqlString += '"';
00043     sqlString += arg;
00044     if (literal) sqlString += '"';
00045     return;
00046   }
00047 
00048   bool compareEnumList(const std::vector<std::string>& choices, 
00049                        std::string sqlType) {
00050     // Number has to be the same.  
00051     std::string::size_type locComma = sqlType.find(",");
00052     unsigned nComma = 0;
00053     while (locComma != std::string::npos) {
00054       nComma++;
00055       locComma = sqlType.find(",", locComma+1);
00056     }
00057     unsigned nChoice = choices.size();
00058     if (nChoice != (nComma + 1)) return false;
00059     for (unsigned iChoice = 0; iChoice < nChoice; iChoice++) {
00060       std::string::size_type loc = sqlType.find(choices[iChoice]);
00061       if (loc == std::string::npos) return false;
00062     }
00063     return true;
00064   }
00065 }
00066     
00067 namespace rdbModel {
00068   bool   MysqlConnection::m_compileInit = false;
00069 
00070   MysqlConnection::MysqlConnection(std::ostream* out,
00071                                    std::ostream* errOut) :
00072     m_mysql(0), m_connected(0), m_out(out), m_err(errOut),
00073     m_visitorType(VISITORundefined), m_rdb(0), m_tempRes(0),
00074     m_writeDisabled(false)                                   {
00075     if (m_out == 0) m_out = &std::cout;
00076     if (m_err == 0) m_err = &std::cerr;
00077   }
00078 
00079   bool MysqlConnection::close() {
00080     if (m_tempRes) {
00081       mysql_free_result(m_tempRes);
00082       m_tempRes = 0;
00083     }
00084  std::cout<<"close connection ================================"<<std::endl;
00085     mysql_close(m_mysql);
00086     m_mysql = 0;
00087     m_connected = false;
00088     return true;
00089   }
00090 
00091   MysqlConnection::~MysqlConnection() {
00092     close();
00093     delete m_mysql;
00094     return;
00095   }
00096 
00097   bool MysqlConnection::open(const std::string& host, 
00098                              const std::string& user,
00099                              const std::string& password,
00100                              const std::string& dbName) {
00101                              //     , unsigned int       port) {
00102     if (dbName.size() == 0) {
00103       (*m_err) << 
00104         "rdbModel::MysqlConnection::open : null db name not allowed!" <<
00105         std::endl;
00106       m_err->flush();
00107       return false;
00108     } 
00109    //huangb add
00110     m_host = host;
00111     m_user = user;
00112     m_password = password;
00113 
00114     m_mysql = new MYSQL;
00115     mysql_init(m_mysql);
00116 
00117     // 'host' argument is of the form hostname[:port]
00118     //  That is, port section is optional.  If not supplied, use
00119     // default port.
00120     std::string hostOnly;
00121     int port = 0;
00122     std::string::size_type colonLoc = host.find(":");
00123     if (colonLoc == std::string::npos) {
00124       hostOnly = host;
00125     }
00126     else {
00127       hostOnly = host.substr(0, colonLoc);
00128       std::string portString = host.substr(colonLoc+1);
00129       try {
00130         port = facilities::Util::stringToInt(portString);
00131       }
00132       catch (facilities::WrongType ex) {
00133         (*m_err) << "From MysqlConnection::connect.  Bad port: "
00134                  << ex.getMsg() << std::endl;
00135         m_err->flush();
00136         return false;
00137       }
00138 
00139     }
00140     //    mysql_init(m_mysql);
00141     std::cout<<"host is:"<<hostOnly.c_str()<<"::use is:: "<<user.c_str()<<":pass is::"<<password.c_str()<<":db is::"<<dbName.c_str()<<std::endl;
00142     MYSQL *connected = mysql_real_connect(m_mysql, hostOnly.c_str(),  
00143                                           user.c_str(),
00144                                           password.c_str(), dbName.c_str(),
00145                                           3306, NULL, 0);
00146 
00147     if (connected != 0) {  // Everything is fine.  Put out an info message
00148       (*m_out) << "Successfully connected to MySQL host " << 
00149         host << ", database " << dbName << std::endl;
00150       m_out->flush();
00151       m_connected = true;
00152       m_dbName = dbName;
00153     }
00154     else {
00155       (*m_err) <<  "Failed to connect to MySQL host " << host <<
00156         "with error:::: " << mysql_error(m_mysql) << std::endl;
00157       m_err->flush();
00158       m_connected = false;
00159     }
00160     return m_connected;
00161   }
00162 
00163   bool MysqlConnection::open(const std::string& parms) {
00164     using XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument;
00165     using XERCES_CPP_NAMESPACE_QUALIFIER DOMElement;
00166     xmlBase::XmlParser parser;
00167     DOMDocument* doc = parser.parse(parms.c_str(), "mysqlConnection");
00168     if (doc == 0) {
00169       (*m_err) << "parse of connection parameters failed" << std::endl;
00170       m_err->flush();
00171       return false;
00172     }
00173     DOMElement*  conn = doc->getDocumentElement();
00174     
00175     std::string host = xmlBase::Dom::getAttribute(conn, "host");
00176     std::string user = xmlBase::Dom::getAttribute(conn, "user");
00177     std::string password = xmlBase::Dom::getAttribute(conn, "password");
00178     std::string dbname = xmlBase::Dom::getAttribute(conn, "dbname");
00179 
00180     if (password.size() == 0 ) { // prompt for password?
00181       (*m_out) << "interactive login NYI " << std::endl;
00182       m_out->flush();
00183       return false;
00184     }
00185 
00186     return this->open(host, user, password, dbname);
00187   }
00188 
00189 
00190 
00191   MATCH MysqlConnection::matchSchema(Rdb *rdb, bool matchDbName) {
00192     if (!m_connected) return MATCHnoConnection;
00193 
00194     m_matchDbName = matchDbName;
00195 
00196     // Check global characteristics; 
00197     // Could do this via Manager; seems a bit artificial, bypass for now
00198     m_visitorType = VISITORmatch;
00199     m_matchReturn = MATCHequivalent;
00200     unsigned int ret = rdb->accept(this);
00201 
00202     if ((ret == Visitor::VERROR) || (ret == Visitor::VERRORABORT)) {
00203       return MATCHfail;
00204     }
00205     else return m_matchReturn;
00206   }
00207 
00208 
00209 
00210     // For each table
00211     //         compare # of columns
00212     //         compare datatype description, other attributes of column
00213     //         compare indices
00214 
00215 
00216   bool MysqlConnection::insertRow(const std::string& tableName, 
00217                                   const StringVector& colNames, 
00218                                   const StringVector& values,
00219                                   int* auto_value,
00220                                   const StringVector* nullCols) {
00221     std::string ins;
00222     if (auto_value) *auto_value = 0;
00223 
00224     // check that sizes of vectors match
00225     unsigned  nCol = colNames.size();    
00226     if (!nCol || (nCol != values.size()  ) ) {
00227       (*m_err) << " MysqlConnection::insertRow: vector lengths incompatible"
00228                 << std::endl;
00229       m_err->flush();
00230       return false;
00231     }
00232 
00233     // caller should already have checked for validity and should
00234     // have supplied all necessary columns
00235 
00236     ins += "insert into " + tableName;
00237     ins += " set " + colNames[0] + "='" + values[0] + "' ";
00238     for (unsigned iCol = 1; iCol < nCol; iCol++) {
00239       ins += ", " + colNames[iCol] + "='" + values[iCol] + "' ";
00240     }
00241     if (nullCols) {
00242       if (nullCols->size() > 0) {
00243         unsigned nNull = nullCols->size();
00244         for (unsigned iNull = 0; iNull < nNull; iNull++) {
00245           ins += ", " + (*nullCols)[iNull] + "= NULL ";
00246         }
00247       }
00248     }
00249 
00250     (*m_out) << std::endl << "# INSERT string is:" << std::endl;
00251     (*m_out) << ins << std::endl;
00252     m_out->flush();
00253 
00254     if (m_writeDisabled) {
00255       (*m_out) << "write to Db previously disabled; INSERT not sent"
00256                << std::endl;
00257       m_out->flush();
00258       return true;
00259     }
00260 
00261     int mysqlRet = mysql_query(m_mysql, ins.c_str());
00262 
00263     if (mysqlRet) {
00264       (*m_out) << "MySQL error during INSERT, code " << mysqlRet << std::endl;
00265       m_out->flush();
00266       return false;
00267     }
00268     if (auto_value) {
00269       *auto_value = mysql_insert_id(m_mysql);
00270     }
00271     return true;
00272   }
00273 
00274 
00275   unsigned int MysqlConnection::update(const std::string& tableName, 
00276                                        const StringVector& colNames, 
00277                                        const StringVector& values,
00278                                        const Assertion* where,
00279                                        const StringVector* nullCols) {
00280 
00281     unsigned int nCol = colNames.size();
00282     if (nCol != values.size()) {
00283       (*m_err) << "rdbModel::mysqlConnection::update: ";
00284       (*m_err) << "Incompatible vector arguments " << std::endl;
00285       m_err->flush();
00286       return 0;
00287     }
00288     std::string sqlString = "UPDATE " + tableName + " SET ";
00289     sqlString += colNames[0] + " = '" + values[0] + "'";
00290     for (unsigned int iCol = 1; iCol < nCol; iCol++) {
00291       sqlString += "," + colNames[iCol] + " = '" + values[iCol] + "'";
00292     }
00293     if (nullCols) {
00294       unsigned nNull = nullCols->size();
00295       for (unsigned iNull = 0; iNull < nNull; iNull++) {
00296         sqlString += ", " + (*nullCols)[iNull] + "= NULL ";
00297       }
00298     }
00299 
00300     if (where) {
00301       sqlString += " WHERE ";
00302       bool ret = compileAssertion(where, sqlString);
00303       if (!ret) return 0;
00304     }
00305     (*m_out) << std::endl << "#  UPDATE to be issued:" << std::endl;
00306     (*m_out) << sqlString << std::endl;
00307     m_out->flush();
00308     if (m_writeDisabled) {
00309       (*m_out) << "write to Db previously disabled; UPDATE not sent"
00310                << std::endl;
00311       m_out->flush();
00312       return 0;
00313     }
00314     int mysqlRet = mysql_query(m_mysql, sqlString.c_str());
00315 
00316     if (mysqlRet) {
00317       (*m_out) << "rdbModel::MysqlConnection::update: ";
00318       (*m_out) << "MySQL error during UPDATE, code " << mysqlRet << std::endl;
00319       m_out->flush();
00320       return 0;
00321     }
00322     my_ulonglong nModLong = mysql_affected_rows(m_mysql);
00323     // Not much chance that we'll change more rows than will fit in just long
00324     unsigned nMod = nModLong;
00325     return nMod;
00326 
00327 
00328   }
00329 
00330   ResultHandle* MysqlConnection::select(const std::string& tableName,
00331                                         const StringVector& getCols,
00332                                         const StringVector& orderCols,
00333                                         const Assertion* where,
00334                                         int   rowLimit,
00335                                         int   rowOffset) {
00336     std::string sqlString = "SELECT ";
00337     unsigned nGet = getCols.size();
00338     unsigned nOrder = orderCols.size();
00339 
00340      std::cout<<"tableName is:"<<tableName<<std::endl;
00341 
00342 //     tableName="metadata_v2r1";
00343        
00344     sqlString += getCols[0];
00345     for (unsigned iGet = 1; iGet < nGet; iGet++) {
00346       sqlString += ",";
00347       sqlString += getCols[iGet];
00348     }
00349     sqlString +=  " FROM " + tableName +  " ";
00350      std::cout<<"sqlString is11:"<<sqlString<<std::endl;
00351    if (where != 0) {
00352       sqlString += " WHERE ";
00353       bool ret = compileAssertion(where, sqlString);
00354       if (!ret) return 0;
00355     }
00356    
00357     std::cout<<"sqlString is22:"<<sqlString<<std::endl;
00358   
00359     /*maqm  if (nOrder > 0 ) {
00360       sqlString += " ORDER BY " + orderCols[0]; 
00361       for (unsigned iOrder = 1; iOrder < nOrder; iOrder++) {
00362         sqlString += ",";
00363         sqlString += orderCols[iOrder];
00364       }
00365     }
00366    */ 
00367 //     sqlString ="SELECT ser_no FROM metadata_v2r1  WHERE ((completion='OK') AND (instrument='LAT') AND (calib_type='MDC_t0') AND (flavor='vanilla'))";
00368     if (rowLimit > 0) {
00369       // SQL format is LIMIT offset,limit      or
00370       //               LIMIT limit             or
00371       //               LIMIT limit   OFFSET offset  [don't use this one]
00372       sqlString += " LIMIT ";
00373       std::string limitStr;
00374       if (rowOffset > 0) {
00375         facilities::Util::itoa(rowOffset, limitStr);
00376         sqlString += limitStr + ",";
00377       }
00378       limitStr.clear();
00379       facilities::Util::itoa(rowLimit, limitStr);
00380        std::cout<<"limitStr is:"<<limitStr<<std::endl;
00381       sqlString += limitStr;
00382     }
00383 
00384     (*m_out) << std::endl << " # About to issue SELECT:" << std::endl;
00385     (*m_out) << sqlString << std::endl;
00386     m_out->flush();
00387    //maqm add
00388 //     sqlString="SELECT ser_no FROM metadata_v2r1";
00389 
00390      
00391     int mysqlRet = mysql_query(m_mysql, sqlString.c_str());
00392     if (mysqlRet) {
00393       std::string msg = 
00394         "rdbModel::MysqlConnection::select: mysql_query error, code ";
00395       std::string codeString;
00396       facilities::Util::itoa(mysqlRet, codeString);
00397       msg += codeString;
00398       (*m_out) << std::endl << msg << std::endl;
00399       m_out->flush();
00400       throw RdbException(msg, mysqlRet);
00401       return 0;
00402     }
00403 
00404     MYSQL_RES *myres = mysql_store_result(m_mysql);
00405     MysqlResults* results = new MysqlResults(myres);
00406     return results;
00407   }
00408 
00409   ResultHandle* MysqlConnection::dbRequest(const std::string& request) {
00410 
00411     (*m_out) << std::endl << "# About to issue SQL request:" << std::endl;
00412     (*m_out) << request << std::endl;
00413     m_out->flush();
00414     
00415     int i=0;
00416     int mysqlRet = mysql_query(m_mysql, request.c_str());
00417     for (i=0;i<10;i++) {
00418     //  int mysqlRet = mysql_query(m_mysql, request.c_str());
00419       if (mysqlRet) {  
00420         //not connected
00421         std::string msg = 
00422           "rdbModel::MysqlConnection::dbRequest: mysql_query error, code ";
00423         std::string codeString;
00424         facilities::Util::itoa(mysqlRet, codeString);
00425         msg += codeString;
00426         (*m_out) << std::endl <<i<<"times not connected++++ "<< msg << std::endl;
00427         m_out->flush();
00428         fprintf(stderr, "mysql_query error %d: %s\n",mysql_errno(m_mysql),mysql_error(m_mysql));
00429         if (i>=9){
00430          throw RdbException(msg, mysqlRet);
00431           return 0;
00432         }
00433          mysql_close(m_mysql);
00434          m_mysql = 0;
00435          sleep(100);
00436          bool st = open(m_host,m_user,m_password,m_dbName);
00437          if(st==false) continue;
00438         mysqlRet = mysql_query(m_mysql, request.c_str());
00439       }else{
00440         break;
00441       }
00442     }
00443    
00444 
00445     MYSQL_RES *myres = mysql_store_result(m_mysql);
00446     if (!myres) {
00447       // Was it supposed to return data?
00448       if (mysql_field_count(m_mysql) == 0) { // no data expected
00449         return 0;
00450       }
00451       else {
00452         std::string msg =
00453           "rdbModel::MysqlConnection::dbRequest: expected data; none returned";
00454         (*m_out) << std::endl << msg << std::endl;
00455         m_out->flush();
00456         throw RdbException(msg);
00457         return 0;
00458       }
00459     }
00460     return new MysqlResults(myres);
00461   }
00462 
00463   bool MysqlConnection::compileAssertion(const Assertion* a, 
00464       std::string& sqlString) const {
00465     if (!m_compileInit) {
00466       compileInit();
00467       m_compileInit = true;
00468     }
00469     try {
00470       return compileOperator(a->getOperator(), sqlString);
00471     }
00472     catch (RdbException ex) {
00473       (*m_out) << std::endl << ex.getMsg() << std::endl;
00474       m_out->flush();
00475       return false;
00476     }
00477   }
00478 
00479   std::string opSymbols[OPTYPElast];
00480 
00481   void MysqlConnection::compileInit() {
00482     opSymbols[OPTYPEor] = " OR ";
00483     opSymbols[OPTYPEand] = " AND ";
00484     opSymbols[OPTYPEnot] = " NOT ";
00485     opSymbols[OPTYPEexists] = "EXISTS ";
00486     opSymbols[OPTYPEisNull] = " IS NULL";
00487     opSymbols[OPTYPEequal] = "=";
00488     opSymbols[OPTYPEnotEqual] = "<>";
00489     opSymbols[OPTYPElessThan] = "<";
00490     opSymbols[OPTYPEgreaterThan] = ">";
00491     opSymbols[OPTYPElessOrEqual] = "<=";
00492     opSymbols[OPTYPEgreaterOrEqual] = ">=";
00493     return;
00494   }
00495 
00496 
00497 
00498   /*  
00499       Need significant changes here to deal with which="toBe" case
00500       In that case, the output isn't going to be SQL; in fact, it's
00501       not clear what it should be, exactly!
00502    */
00503 
00510   bool MysqlConnection::compileComparison(Assertion::Operator* op, 
00511       std::string& sqlString) {
00512     if (op->getToBe()) return false;  // can't compile
00513 
00514     OPTYPE opType = op->getOpType();
00515     if (opType == OPTYPEisNull) {
00516       sqlString +="(";
00517       sqlString += op->getCompareArgs()[0];
00518       sqlString += opSymbols[opType];
00519       sqlString += ")";
00520       return true;
00521     }
00522     sqlString += "(";
00523 
00524     bool literal0 = (op->getCompareArgTypes()[0] == FIELDTYPElit);
00525     bool literal1 = (op->getCompareArgTypes()[1] == FIELDTYPElit);
00526 
00527     addArg(literal0, op->getCompareArgs()[0], sqlString);
00528     sqlString += opSymbols[opType];
00529     addArg(literal1, op->getCompareArgs()[1], sqlString);
00530     sqlString += ")";
00531 
00532     return true;
00533   }
00534 
00535   bool MysqlConnection::compileOperator(Assertion::Operator* op, 
00536       std::string &sqlString) {
00537 
00538     //maqm     std::cout<<"in compileOperator() sqlString is00:"<<sqlString<<std::endl;
00539     if (op->isCompareOp() ) return compileComparison(op, sqlString);
00540     if (op->getToBe()) return false;  // can't compile in this case
00541     bool ret = true;
00542 
00543     const std::vector<Assertion::Operator*>& children = op->getChildren();
00544     unsigned nChild = children.size();
00545 
00546     // For single-child operators NOT,  exists, operator symbol
00547     // goes 1st, then operand
00548     if (nChild <= 1) { // operator goes first
00549       sqlString += opSymbols[op->getOpType()];
00550 
00551       // more special handling for EXISTS
00552       if (op->getOpType() == OPTYPEexists) {
00553         sqlString += "(SELECT * FROM " + op->getTableName();
00554         if (!nChild) {     // done
00555           sqlString += ")";
00556           return ret;
00557         }
00558         // else EXISTS child is object of a WHERE clause 
00559         sqlString += " WHERE(";
00560       }
00561       ret = compileOperator(children[0], sqlString);
00562       if (!ret) {
00563         std::string msg = 
00564           "rdbModel::MysqlConnection::compileOperator failed for operator "
00565           + opSymbols[op->getOpType()];
00566         throw RdbException(msg);
00567       }
00568 
00569       // Have an extra closing ")" for EXISTS with WHERE clause
00570       if (op->getOpType() == OPTYPEexists)       sqlString += ")";
00571 
00572 
00573       return ret;
00574     }
00575 
00576     // Otherwise put operator symbols between adjacent children.
00577 
00578     // First open parentheses
00579     sqlString += "(";
00580 
00581     std::string symbol = opSymbols[op->getOpType()];
00582 
00583     ret = compileOperator(children[0], sqlString);
00584     if (!ret) {
00585       std::string msg = 
00586         "rdbModel::MysqlConnection::compileOperator failed for operator "
00587         + symbol;
00588       throw RdbException(msg);
00589     }
00590     for (unsigned int iChild = 1; iChild < nChild; iChild++) {
00591       sqlString += symbol;
00592 
00593       ret = compileOperator(children[iChild], sqlString);
00594       if (!ret) {
00595         std::string msg = 
00596           "rdbModel::MysqlConnection::compileOperator failed for operator "
00597           + symbol;
00598         throw RdbException(msg);
00599       }
00600     }
00601     // Finally close paren.
00602     sqlString += ")";
00603     return ret;
00604   }
00605 
00606   // Satisfy Visitor interface.  For now the only visitor is the
00607   // one to check whether remote and local db descriptions match or
00608   // are at least compatible enough to be used.
00609   Visitor::VisitorState MysqlConnection::visitRdb(Rdb *rdb) {
00610 
00611     if (m_matchDbName) {
00612       if (m_dbName != rdb->getDbName()) {
00613         m_matchReturn = MATCHfail;
00614         return Visitor::VDONE;
00615       }
00616     }
00617 
00618     unsigned int nLocal = rdb->getNTable();
00619 
00620     // Null pointer for 2nd argument means "list all tables"
00621 
00622     MYSQL_RES* res = mysql_list_tables(m_mysql, 0);
00623     if (!res) {
00624       m_matchReturn = MATCHfail;
00625       return Visitor::VERRORABORT;
00626     }
00627     unsigned int nRemote = mysql_num_rows(res);
00628     mysql_free_result(res);
00629 
00630     if (nRemote < nLocal) {
00631       m_matchReturn = MATCHfail;
00632       return Visitor::VDONE;
00633     }
00634     else if (nRemote > nLocal) m_matchReturn = MATCHcompatible;
00635 
00636     // Tell Rdb about this 
00637     rdb->setConnection(this);
00638 
00639     return Visitor::VCONTINUE;
00640   }
00641 
00642   Visitor::VisitorState MysqlConnection::visitTable(Table* table) {
00643     const std::string& tName = table->getName();
00644 
00645     // Result set will have all fields for the table
00646     if (m_tempRes) {
00647       mysql_free_result(m_tempRes);
00648       m_tempRes = 0;
00649     }
00650     m_primColName.clear();
00651 
00652     std::string query = "SHOW COLUMNS FROM " + tName;
00653 
00654     (*m_out) << std::endl << "# About to issue SHOW COLUMNS request :" 
00655       << std::endl;
00656     (*m_out) << query << std::endl;
00657     m_out->flush();
00658 
00659     int ret = mysql_query(m_mysql, query.c_str());
00660     if (ret) {
00661       m_matchReturn = MATCHfail;
00662       return Visitor::VERRORABORT;
00663     }
00664 
00665     m_tempRes = mysql_store_result(m_mysql);
00666     if (!m_tempRes) {
00667       m_matchReturn = MATCHfail;
00668       return Visitor::VERRORABORT;
00669     }
00670     // Result set is a table with fields "Field"(the name) "Type" "Null"(yes
00671     // or no) "Key" "Default", "Extra"  
00672     // Make it easier for accept(Column* ) to find relevant information
00673     unsigned int nRow = mysql_num_rows(m_tempRes);
00674     m_colIx.clear();
00675     for (unsigned iRow = 0; iRow < nRow; iRow++) {
00676       MYSQL_ROW colDescrip = mysql_fetch_row(m_tempRes);
00677       std::string name = std::string(colDescrip[0]);
00678       std::cout<<"name is:"<<name<<std::endl;
00679       m_colIx[name] = iRow;
00680     }
00681     return Visitor::VCONTINUE;
00682 
00683   }
00684 
00685   Visitor::VisitorState MysqlConnection::visitColumn(Column* col) {
00686     std::string myName = col->getName();
00687     if (m_colIx.find(myName) == m_colIx.end()) {
00688       m_matchReturn = MATCHfail;
00689       return Visitor::VERRORABORT;
00690     }
00691     unsigned int ix = m_colIx[myName];
00692     mysql_data_seek(m_tempRes, ix);
00693     MYSQL_ROW colDescrip = mysql_fetch_row(m_tempRes);
00694 
00695     // Type
00696     std::string sqlDtype = std::string(colDescrip[1]);
00697     Datatype* dtype = col->getDatatype();
00698     if (!checkDType(dtype, sqlDtype)) {
00699       m_matchReturn = MATCHfail;
00700       (*m_out) << "Failed dtype match of col " << myName << std::endl;
00701       return Visitor::VERRORABORT;
00702     }
00703 
00704     // Null
00705     bool nullable = (std::string(colDescrip[2]) == std::string("YES"));
00706     if (nullable != col->nullAllowed()) {
00707       m_matchReturn = MATCHfail;
00708       (*m_out) << "Failed null/not null match of col " << myName << std::endl;
00709       return Visitor::VERRORABORT;
00710     }
00711     // Key (PRI for primary, MUL if first in a multiple-field key
00712     // Save primary key info, if any
00713     if (std::string(colDescrip[3]) == std::string("PRI")) {
00714       m_primColName = myName;
00715     }
00716 
00717     // Field 4 is default
00718     // Extra (may say auto_increment)
00719     bool autoInc = 
00720       (std::string(colDescrip[5]) == std::string("auto_increment"));
00721     if (autoInc != col->isAutoIncrement()) {
00722       m_matchReturn = MATCHfail;
00723       (*m_out) << "Failed isAutoIncrement match of col " << myName << std::endl;
00724       return Visitor::VERRORABORT;
00725     }
00726     return Visitor::VCONTINUE;
00727   }
00728 
00729   bool MysqlConnection::checkDType(Datatype* dtype, 
00730       const std::string& sqlType) {
00731     std::string base;
00732     int sqlSize;
00733     if (dtype->getType() != Datatype::TYPEenum) {
00734       sqlSize = extractSize(sqlType);
00735     }
00736 
00737     // Cases  char, varchar, enum and datetime are handled entirely within
00738     // the switch statement, but most do the bulk of the work in
00739     // common, after the switch.
00740     switch (dtype->getType()) {
00741       case Datatype::TYPEenum: {
00742                                  base = "enum";
00743                                  if (sqlType.find(base) != 0) {
00744                                    m_matchReturn = MATCHfail;
00745                                    return false;
00746                                  }
00747                                  Enum* ourEnum = dtype->getEnum();
00748                                  // Finally compare local list of choices to those listed in sqlType
00749                                  // Local list is a vector; in sqlType they're quoted, comma separated
00750                                  return compareEnumList(ourEnum->getChoices(), sqlType);
00751                                }
00752       case Datatype::TYPEvarchar: {
00753                                     base = "varchar";
00754                                     if (sqlType.find(base) != 0) {
00755                                       m_matchReturn = MATCHfail;
00756                                       return false;
00757                                     }
00758                                     // size in db must be at least as large as size in Col.
00759                                     if (sqlSize < dtype->getOutputSize()) {
00760                                       m_matchReturn = MATCHfail;
00761                                       return false;
00762                                     }
00763                                     else if (sqlSize > dtype->getOutputSize()) {
00764                                       m_matchReturn = MATCHcompatible;
00765                                     }
00766                                     return true;
00767                                   }
00768       case Datatype::TYPEchar: {
00769                                  base = "char";
00770                                  if (sqlType.find(base) != 0) {
00771                                    m_matchReturn = MATCHfail;
00772                                    return false;
00773                                  }
00774                                  //  For char datatype unspecified size is equivalent to size=1
00775                                  if (!sqlSize) sqlSize = 1;
00776                                  // size in db must be at least as large as size in Col.
00777                                  if (sqlSize < dtype->getOutputSize()) {
00778                                    m_matchReturn = MATCHfail;
00779                                    return false;
00780                                  }
00781                                  else if (sqlSize > dtype->getOutputSize()) {
00782                                    m_matchReturn = MATCHcompatible;
00783                                  }
00784                                  return true;
00785                                }
00786       case Datatype::TYPEdatetime: {
00787                                      if (sqlType != "datetime") {
00788                                        m_matchReturn = MATCHfail;
00789                                        return false;
00790                                      }
00791                                      return true;
00792                                    }
00793 
00794 
00795       case Datatype::TYPEtimestamp: {
00796                                       base = "timestamp";
00797                                       break;
00798                                     }
00799       case Datatype::TYPEint: {
00800                                 base = "int";
00801                                 break;
00802                               }
00803       case Datatype::TYPEmediumint: {
00804                                       base = "mediumint";
00805                                       break;
00806                                     }
00807       case Datatype::TYPEsmallint: {
00808                                      base = "smallint";
00809                                      break;
00810                                    }
00811       case Datatype::TYPEreal: 
00812       case Datatype::TYPEdouble: {
00813                                    base = "double";
00814                                    break;
00815                                  }
00816       default: {  // Indicates bad xml file input.  Applications
00817                  //should have exited already
00818                  m_matchReturn = MATCHfail;
00819                  return false;
00820                }
00821     }     // end switch
00822     if (sqlType.find(base) != 0) {
00823       m_matchReturn = MATCHfail;
00824       return false;
00825     }
00826     // Now check size.  It's only for display, so mismatch is not failure
00827     if (sqlSize != dtype->getOutputSize()) {
00828       m_matchReturn = MATCHcompatible;
00829     }
00830 
00831     return true;
00832   }
00833 
00834 
00835 
00836   Visitor::VisitorState MysqlConnection::visitIndex(Index* ) {
00837     return Visitor::VCONTINUE;
00838     // might put something real here later
00839   }
00840 
00841   Visitor::VisitorState MysqlConnection::visitAssertion(Assertion*) {
00842     return Visitor::VCONTINUE;
00843   }
00844 
00845   Visitor::VisitorState MysqlConnection::visitInsertNew(InsertNew*) {
00846     return Visitor::VCONTINUE;
00847   }
00848 
00849   Visitor::VisitorState MysqlConnection::visitSupersede(Supersede*) {
00850     return Visitor::VCONTINUE;
00851   }
00852 
00853   Visitor::VisitorState MysqlConnection::visitQuery(Query*) {
00854     return Visitor::VCONTINUE;
00855   }
00856 
00857   Visitor::VisitorState MysqlConnection::visitSet(Set*) {
00858     return Visitor::VCONTINUE;
00859   }
00860 
00861   Visitor::VisitorState MysqlConnection::visitInterRow(InterRow*) {
00862     return Visitor::VCONTINUE;
00863   }
00864 
00865 
00866   } // end namespace rdbModel

Generated on Tue Nov 29 22:57:56 2016 for BOSS_7.0.2 by  doxygen 1.4.7