7#include "facilities/Util.h"
8#include "rdbModel/Db/MysqlConnection.h"
9#include "rdbModel/Db/MysqlResults.h"
10#include "rdbModel/Rdb.h"
11#include "rdbModel/RdbException.h"
12#include "rdbModel/Tables/Assertion.h"
13#include "rdbModel/Tables/Column.h"
14#include "rdbModel/Tables/Datatype.h"
15#include "rdbModel/Tables/Table.h"
17#include "xmlBase/Dom.h"
18#include "xmlBase/XmlParser.h"
20#include "facilities/Util.h"
29 int extractSize(
const std::string& sqlString ) {
30 std::string::size_type leftLoc = sqlString.find(
"(" );
31 if ( leftLoc == std::string::npos )
return 0;
33 std::string::size_type rightLoc = sqlString.find(
"," );
34 if ( rightLoc == std::string::npos ) { rightLoc = sqlString.find(
")" ); }
35 std::string numString = sqlString.substr( leftLoc, rightLoc - leftLoc );
39 void addArg(
bool literal,
const std::string
arg, std::string& sqlString ) {
40 if ( literal ) sqlString +=
'"';
42 if ( literal ) sqlString +=
'"';
46 bool compareEnumList(
const std::vector<std::string>& choices, std::string sqlType ) {
48 std::string::size_type locComma = sqlType.find(
"," );
50 while ( locComma != std::string::npos )
53 locComma = sqlType.find(
",", locComma + 1 );
55 unsigned nChoice = choices.size();
56 if ( nChoice != ( nComma + 1 ) )
return false;
57 for (
unsigned iChoice = 0; iChoice < nChoice; iChoice++ )
59 std::string::size_type loc = sqlType.find( choices[iChoice] );
60 if ( loc == std::string::npos )
return false;
67 bool MysqlConnection::m_compileInit =
false;
74 , m_visitorType( VISITORundefined )
77 , m_writeDisabled( false ) {
78 if ( m_out == 0 ) m_out = &std::cout;
79 if ( m_err == 0 ) m_err = &std::cerr;
85 mysql_free_result( m_tempRes );
88 std::cout <<
"close connection ================================" << std::endl;
89 mysql_close( m_mysql );
102 const std::string& password,
const std::string& dbName ) {
104 if ( dbName.size() == 0 )
106 ( *m_err ) <<
"rdbModel::MysqlConnection::open : null db name not allowed!" << std::endl;
113 m_password = password;
116 mysql_init( m_mysql );
121 std::string hostOnly;
123 std::string::size_type colonLoc = host.find(
":" );
124 if ( colonLoc == std::string::npos ) { hostOnly = host; }
127 hostOnly = host.substr( 0, colonLoc );
128 std::string portString = host.substr( colonLoc + 1 );
134 ( *m_err ) <<
"From MysqlConnection::connect. Bad port: " << ex.
getMsg() << std::endl;
140 std::cout <<
"host is:" << hostOnly.c_str() <<
"::use is:: " << user.c_str()
141 <<
":pass is::" << password.c_str() <<
":db is::" << dbName.c_str() << std::endl;
142 MYSQL* connected = mysql_real_connect( m_mysql, hostOnly.c_str(), user.c_str(),
143 password.c_str(), dbName.c_str(), 3306, NULL, 0 );
145 if ( connected != 0 )
147 ( *m_out ) <<
"Successfully connected to MySQL host " << host <<
", database " << dbName
155 ( *m_err ) <<
"Failed to connect to MySQL host " << host
156 <<
"with error:::: " << mysql_error( m_mysql ) << std::endl;
164 using XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument;
165 using XERCES_CPP_NAMESPACE_QUALIFIER DOMElement;
167 DOMDocument* doc = parser.
parse( parms.c_str(),
"mysqlConnection" );
170 ( *m_err ) <<
"parse of connection parameters failed" << std::endl;
174 DOMElement* conn = doc->getDocumentElement();
181 if ( password.size() == 0 )
183 ( *m_out ) <<
"interactive login NYI " << std::endl;
188 return this->
open( host, user, password, dbname );
194 m_matchDbName = matchDbName;
198 m_visitorType = VISITORmatch;
200 unsigned int ret = rdb->
accept(
this );
203 else return m_matchReturn;
215 if ( auto_value ) *auto_value = 0;
218 unsigned nCol = colNames.size();
219 if ( !nCol || ( nCol != values.size() ) )
221 ( *m_err ) <<
" MysqlConnection::insertRow: vector lengths incompatible" << std::endl;
229 ins +=
"insert into " + tableName;
230 ins +=
" set " + colNames[0] +
"='" + values[0] +
"' ";
231 for (
unsigned iCol = 1; iCol < nCol; iCol++ )
232 { ins +=
", " + colNames[iCol] +
"='" + values[iCol] +
"' "; }
235 if ( nullCols->size() > 0 )
237 unsigned nNull = nullCols->size();
238 for (
unsigned iNull = 0; iNull < nNull; iNull++ )
239 { ins +=
", " + ( *nullCols )[iNull] +
"= NULL "; }
243 ( *m_out ) << std::endl <<
"# INSERT string is:" << std::endl;
244 ( *m_out ) << ins << std::endl;
247 if ( m_writeDisabled )
249 ( *m_out ) <<
"write to Db previously disabled; INSERT not sent" << std::endl;
254 int mysqlRet = mysql_query( m_mysql, ins.c_str() );
258 ( *m_out ) <<
"MySQL error during INSERT, code " << mysqlRet << std::endl;
262 if ( auto_value ) { *auto_value = mysql_insert_id( m_mysql ); }
271 unsigned int nCol = colNames.size();
272 if ( nCol != values.size() )
274 ( *m_err ) <<
"rdbModel::mysqlConnection::update: ";
275 ( *m_err ) <<
"Incompatible vector arguments " << std::endl;
279 std::string sqlString =
"UPDATE " + tableName +
" SET ";
280 sqlString += colNames[0] +
" = '" + values[0] +
"'";
281 for (
unsigned int iCol = 1; iCol < nCol; iCol++ )
282 { sqlString +=
"," + colNames[iCol] +
" = '" + values[iCol] +
"'"; }
285 unsigned nNull = nullCols->size();
286 for (
unsigned iNull = 0; iNull < nNull; iNull++ )
287 { sqlString +=
", " + ( *nullCols )[iNull] +
"= NULL "; }
292 sqlString +=
" WHERE ";
294 if ( !ret )
return 0;
296 ( *m_out ) << std::endl <<
"# UPDATE to be issued:" << std::endl;
297 ( *m_out ) << sqlString << std::endl;
299 if ( m_writeDisabled )
301 ( *m_out ) <<
"write to Db previously disabled; UPDATE not sent" << std::endl;
305 int mysqlRet = mysql_query( m_mysql, sqlString.c_str() );
309 ( *m_out ) <<
"rdbModel::MysqlConnection::update: ";
310 ( *m_out ) <<
"MySQL error during UPDATE, code " << mysqlRet << std::endl;
314 my_ulonglong nModLong = mysql_affected_rows( m_mysql );
316 unsigned nMod = nModLong;
323 int rowLimit,
int rowOffset ) {
324 std::string sqlString =
"SELECT ";
325 unsigned nGet = getCols.size();
326 unsigned nOrder = orderCols.size();
328 std::cout <<
"tableName is:" << tableName << std::endl;
332 sqlString += getCols[0];
333 for (
unsigned iGet = 1; iGet < nGet; iGet++ )
336 sqlString += getCols[iGet];
338 sqlString +=
" FROM " + tableName +
" ";
339 std::cout <<
"sqlString is11:" << sqlString << std::endl;
342 sqlString +=
" WHERE ";
344 if ( !ret )
return 0;
347 std::cout <<
"sqlString is22:" << sqlString << std::endl;
364 sqlString +=
" LIMIT ";
365 std::string limitStr;
369 sqlString += limitStr +
",";
373 std::cout <<
"limitStr is:" << limitStr << std::endl;
374 sqlString += limitStr;
377 ( *m_out ) << std::endl <<
" # About to issue SELECT:" << std::endl;
378 ( *m_out ) << sqlString << std::endl;
383 int mysqlRet = mysql_query( m_mysql, sqlString.c_str() );
386 std::string msg =
"rdbModel::MysqlConnection::select: mysql_query error, code ";
387 std::string codeString;
390 ( *m_out ) << std::endl << msg << std::endl;
396 MYSQL_RES* myres = mysql_store_result( m_mysql );
403 ( *m_out ) << std::endl <<
"# About to issue SQL request:" << std::endl;
404 ( *m_out ) << request << std::endl;
408 int mysqlRet = mysql_query( m_mysql, request.c_str() );
409 for ( i = 0; i < 10; i++ )
415 std::string msg =
"rdbModel::MysqlConnection::dbRequest: mysql_query error, code ";
416 std::string codeString;
419 ( *m_out ) << std::endl << i <<
"times not connected++++ " << msg << std::endl;
421 fprintf( stderr,
"mysql_query error %d: %s\n", mysql_errno( m_mysql ),
422 mysql_error( m_mysql ) );
428 mysql_close( m_mysql );
431 bool st =
open( m_host, m_user, m_password, m_dbName );
432 if ( st ==
false )
continue;
433 mysqlRet = mysql_query( m_mysql, request.c_str() );
438 MYSQL_RES* myres = mysql_store_result( m_mysql );
442 if ( mysql_field_count( m_mysql ) == 0 )
448 std::string msg =
"rdbModel::MysqlConnection::dbRequest: expected data; none returned";
449 ( *m_out ) << std::endl << msg << std::endl;
459 if ( !m_compileInit )
462 m_compileInit =
true;
467 ( *m_out ) << std::endl << ex.
getMsg() << std::endl;
475 void MysqlConnection::compileInit() {
502 bool MysqlConnection::compileComparison( Assertion::Operator* op, std::string& sqlString ) {
503 if ( op->getToBe() )
return false;
505 OPTYPE opType = op->getOpType();
509 sqlString += op->getCompareArgs()[0];
516 bool literal0 = ( op->getCompareArgTypes()[0] ==
FIELDTYPElit );
517 bool literal1 = ( op->getCompareArgTypes()[1] ==
FIELDTYPElit );
519 addArg( literal0, op->getCompareArgs()[0], sqlString );
521 addArg( literal1, op->getCompareArgs()[1], sqlString );
530 if ( op->isCompareOp() )
return compileComparison( op, sqlString );
531 if ( op->getToBe() )
return false;
534 const std::vector<Assertion::Operator*>& children = op->getChildren();
535 unsigned nChild = children.size();
546 sqlString +=
"(SELECT * FROM " + op->getTableName();
553 sqlString +=
" WHERE(";
555 ret = compileOperator( children[0], sqlString );
558 std::string msg =
"rdbModel::MysqlConnection::compileOperator failed for operator " +
560 throw RdbException( msg );
564 if ( op->getOpType() ==
OPTYPEexists ) sqlString +=
")";
574 std::string symbol =
opSymbols[op->getOpType()];
576 ret = compileOperator( children[0], sqlString );
580 "rdbModel::MysqlConnection::compileOperator failed for operator " + symbol;
581 throw RdbException( msg );
583 for (
unsigned int iChild = 1; iChild < nChild; iChild++ )
587 ret = compileOperator( children[iChild], sqlString );
591 "rdbModel::MysqlConnection::compileOperator failed for operator " + symbol;
592 throw RdbException( msg );
618 MYSQL_RES* res = mysql_list_tables( m_mysql, 0 );
624 unsigned int nRemote = mysql_num_rows( res );
625 mysql_free_result( res );
627 if ( nRemote < nLocal )
641 const std::string& tName = table->
getName();
646 mysql_free_result( m_tempRes );
649 m_primColName.clear();
651 std::string query =
"SHOW COLUMNS FROM " + tName;
653 ( *m_out ) << std::endl <<
"# About to issue SHOW COLUMNS request :" << std::endl;
654 ( *m_out ) << query << std::endl;
657 int ret = mysql_query( m_mysql, query.c_str() );
664 m_tempRes = mysql_store_result( m_mysql );
673 unsigned int nRow = mysql_num_rows( m_tempRes );
675 for (
unsigned iRow = 0; iRow < nRow; iRow++ )
677 MYSQL_ROW colDescrip = mysql_fetch_row( m_tempRes );
678 std::string name = std::string( colDescrip[0] );
679 std::cout <<
"name is:" << name << std::endl;
680 m_colIx[name] = iRow;
686 std::string myName = col->
getName();
687 if ( m_colIx.find( myName ) == m_colIx.end() )
692 unsigned int ix = m_colIx[myName];
693 mysql_data_seek( m_tempRes,
ix );
694 MYSQL_ROW colDescrip = mysql_fetch_row( m_tempRes );
697 std::string sqlDtype = std::string( colDescrip[1] );
699 if ( !checkDType( dtype, sqlDtype ) )
702 ( *m_out ) <<
"Failed dtype match of col " << myName << std::endl;
707 bool nullable = ( std::string( colDescrip[2] ) == std::string(
"YES" ) );
711 ( *m_out ) <<
"Failed null/not null match of col " << myName << std::endl;
716 if ( std::string( colDescrip[3] ) == std::string(
"PRI" ) ) { m_primColName = myName; }
720 bool autoInc = ( std::string( colDescrip[5] ) == std::string(
"auto_increment" ) );
724 ( *m_out ) <<
"Failed isAutoIncrement match of col " << myName << std::endl;
730 bool MysqlConnection::checkDType(
Datatype* dtype,
const std::string& sqlType ) {
742 if ( sqlType.find( base ) != 0 )
747 Enum* ourEnum = dtype->
getEnum();
750 return compareEnumList( ourEnum->getChoices(), sqlType );
754 if ( sqlType.find( base ) != 0 )
760 if ( sqlSize < dtype->getOutputSize() )
770 if ( sqlType.find( base ) != 0 )
776 if ( !sqlSize ) sqlSize = 1;
778 if ( sqlSize < dtype->getOutputSize() )
787 if ( sqlType !=
"datetime" )
822 if ( sqlType.find( base ) != 0 )
struct st_mysql_res MYSQL_RES
double arg(const EvtComplex &c)
static int stringToInt(const std::string &InStr)
static const char * itoa(int val, std::string &outStr)
Exception class used when converting from string to numeric type.
Operator * getOperator() const
Datatype * getDatatype() const
bool isAutoIncrement() const
const std::string & getName() const
bool nullAllowed() const
Returns true if column may take on value NULL.
int getOutputSize() const
virtual VisitorState visitInterRow(InterRow *)
virtual Visitor::VisitorState visitRdb(Rdb *)
This method says if the visitor is recursive or not.
virtual Visitor::VisitorState visitAssertion(Assertion *)
virtual VisitorState visitQuery(Query *)
virtual VisitorState visitSet(Set *)
virtual bool open(const std::string &host, const std::string &userid, const std::string &password, const std::string &dbName)
virtual ResultHandle * select(const std::string &tableName, const StringVector &getCols, const StringVector &orderCols, const Assertion *where=0, int rowLimit=0, int rowOffset=0)
virtual Visitor::VisitorState visitTable(Table *)
virtual Visitor::VisitorState visitIndex(Index *)
virtual bool compileAssertion(const Assertion *a, std::string &sqlString) const
virtual VisitorState visitSupersede(Supersede *)
virtual ResultHandle * dbRequest(const std::string &request)
virtual VisitorState visitInsertNew(InsertNew *)
virtual ~MysqlConnection()
virtual MATCH matchSchema(Rdb *rdb, bool matchDbName=true)
virtual bool insertRow(const std::string &tableName, const StringVector &colNames, const StringVector &values, int *auto_value=0, const StringVector *nullCols=0)
virtual Visitor::VisitorState visitColumn(Column *)
virtual unsigned int update(const std::string &tableName, const StringVector &colNames, const StringVector &values, const Assertion *where=0, const StringVector *nullCols=0)
MysqlConnection(std::ostream *out=0, std::ostream *errOut=0)
virtual std::string getMsg()
const std::string & getDbName()
unsigned int getNTable() const
void setConnection(Connection *connection)
unsigned int accept(Visitor *v)
This is the recursive accept for the visitor pattern.
const std::string & getName() const
static std::string getAttribute(const DOMElement *elt, const char *attName)
DOMDocument * parse(const char *const filename, const std::string &docType=std::string(""))
Parse an xml file, returning document node if successful.
std::vector< std::string > StringVector
std::string opSymbols[OPTYPElast]