BOSS 8.0.0
BESIII Offline Software System
Loading...
Searching...
No Matches
MysqlConnection.cxx
Go to the documentation of this file.
1// $Header: /bes/bes/BossCvs/Calibration/rdbModel/src/Db/MysqlConnection.cxx,v 1.12 2014/04/18
2// 05:27:35 maqm Exp $
3#ifdef WIN32
4# include <windows.h>
5#endif
6
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"
16
17#include "xmlBase/Dom.h"
18#include "xmlBase/XmlParser.h"
19
20#include "facilities/Util.h"
21#include "mysql.h"
22#include <iostream>
23#include <stdio.h>
24#include <unistd.h>
25namespace {
26
27 // Size specification is of form (m) or (m,d) If no size specification
28 // return 0; else return value of m.
29 int extractSize( const std::string& sqlString ) {
30 std::string::size_type leftLoc = sqlString.find( "(" );
31 if ( leftLoc == std::string::npos ) return 0;
32 leftLoc++; // now is at start of m
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 );
36 return facilities::Util::stringToInt( numString );
37 }
38
39 void addArg( bool literal, const std::string arg, std::string& sqlString ) {
40 if ( literal ) sqlString += '"';
41 sqlString += arg;
42 if ( literal ) sqlString += '"';
43 return;
44 }
45
46 bool compareEnumList( const std::vector<std::string>& choices, std::string sqlType ) {
47 // Number has to be the same.
48 std::string::size_type locComma = sqlType.find( "," );
49 unsigned nComma = 0;
50 while ( locComma != std::string::npos )
51 {
52 nComma++;
53 locComma = sqlType.find( ",", locComma + 1 );
54 }
55 unsigned nChoice = choices.size();
56 if ( nChoice != ( nComma + 1 ) ) return false;
57 for ( unsigned iChoice = 0; iChoice < nChoice; iChoice++ )
58 {
59 std::string::size_type loc = sqlType.find( choices[iChoice] );
60 if ( loc == std::string::npos ) return false;
61 }
62 return true;
63 }
64} // namespace
65
66namespace rdbModel {
67 bool MysqlConnection::m_compileInit = false;
68
69 MysqlConnection::MysqlConnection( std::ostream* out, std::ostream* errOut )
70 : m_mysql( 0 )
71 , m_connected( 0 )
72 , m_out( out )
73 , m_err( errOut )
74 , m_visitorType( VISITORundefined )
75 , m_rdb( 0 )
76 , m_tempRes( 0 )
77 , m_writeDisabled( false ) {
78 if ( m_out == 0 ) m_out = &std::cout;
79 if ( m_err == 0 ) m_err = &std::cerr;
80 }
81
83 if ( m_tempRes )
84 {
85 mysql_free_result( m_tempRes );
86 m_tempRes = 0;
87 }
88 std::cout << "close connection ================================" << std::endl;
89 mysql_close( m_mysql );
90 m_mysql = 0;
91 m_connected = false;
92 return true;
93 }
94
96 close();
97 delete m_mysql;
98 return;
99 }
100
101 bool MysqlConnection::open( const std::string& host, const std::string& user,
102 const std::string& password, const std::string& dbName ) {
103 // , unsigned int port) {
104 if ( dbName.size() == 0 )
105 {
106 ( *m_err ) << "rdbModel::MysqlConnection::open : null db name not allowed!" << std::endl;
107 m_err->flush();
108 return false;
109 }
110 // huangb add
111 m_host = host;
112 m_user = user;
113 m_password = password;
114
115 m_mysql = new MYSQL;
116 mysql_init( m_mysql );
117
118 // 'host' argument is of the form hostname[:port]
119 // That is, port section is optional. If not supplied, use
120 // default port.
121 std::string hostOnly;
122 int port = 0;
123 std::string::size_type colonLoc = host.find( ":" );
124 if ( colonLoc == std::string::npos ) { hostOnly = host; }
125 else
126 {
127 hostOnly = host.substr( 0, colonLoc );
128 std::string portString = host.substr( colonLoc + 1 );
129 try
130 {
131 port = facilities::Util::stringToInt( portString );
132 } catch ( facilities::WrongType ex )
133 {
134 ( *m_err ) << "From MysqlConnection::connect. Bad port: " << ex.getMsg() << std::endl;
135 m_err->flush();
136 return false;
137 }
138 }
139 // mysql_init(m_mysql);
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 );
144
145 if ( connected != 0 )
146 { // Everything is fine. Put out an info message
147 ( *m_out ) << "Successfully connected to MySQL host " << host << ", database " << dbName
148 << std::endl;
149 m_out->flush();
150 m_connected = true;
151 m_dbName = dbName;
152 }
153 else
154 {
155 ( *m_err ) << "Failed to connect to MySQL host " << host
156 << "with error:::: " << mysql_error( m_mysql ) << std::endl;
157 m_err->flush();
158 m_connected = false;
159 }
160 return m_connected;
161 }
162
163 bool MysqlConnection::open( const std::string& parms ) {
164 using XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument;
165 using XERCES_CPP_NAMESPACE_QUALIFIER DOMElement;
166 xmlBase::XmlParser parser;
167 DOMDocument* doc = parser.parse( parms.c_str(), "mysqlConnection" );
168 if ( doc == 0 )
169 {
170 ( *m_err ) << "parse of connection parameters failed" << std::endl;
171 m_err->flush();
172 return false;
173 }
174 DOMElement* conn = doc->getDocumentElement();
175
176 std::string host = xmlBase::Dom::getAttribute( conn, "host" );
177 std::string user = xmlBase::Dom::getAttribute( conn, "user" );
178 std::string password = xmlBase::Dom::getAttribute( conn, "password" );
179 std::string dbname = xmlBase::Dom::getAttribute( conn, "dbname" );
180
181 if ( password.size() == 0 )
182 { // prompt for password?
183 ( *m_out ) << "interactive login NYI " << std::endl;
184 m_out->flush();
185 return false;
186 }
187
188 return this->open( host, user, password, dbname );
189 }
190
191 MATCH MysqlConnection::matchSchema( Rdb* rdb, bool matchDbName ) {
192 if ( !m_connected ) return MATCHnoConnection;
193
194 m_matchDbName = matchDbName;
195
196 // Check global characteristics;
197 // Could do this via Manager; seems a bit artificial, bypass for now
198 m_visitorType = VISITORmatch;
199 m_matchReturn = MATCHequivalent;
200 unsigned int ret = rdb->accept( this );
201
202 if ( ( ret == Visitor::VERROR ) || ( ret == Visitor::VERRORABORT ) ) { return MATCHfail; }
203 else return m_matchReturn;
204 }
205
206 // For each table
207 // compare # of columns
208 // compare datatype description, other attributes of column
209 // compare indices
210
211 bool MysqlConnection::insertRow( const std::string& tableName, const StringVector& colNames,
212 const StringVector& values, int* auto_value,
213 const StringVector* nullCols ) {
214 std::string ins;
215 if ( auto_value ) *auto_value = 0;
216
217 // check that sizes of vectors match
218 unsigned nCol = colNames.size();
219 if ( !nCol || ( nCol != values.size() ) )
220 {
221 ( *m_err ) << " MysqlConnection::insertRow: vector lengths incompatible" << std::endl;
222 m_err->flush();
223 return false;
224 }
225
226 // caller should already have checked for validity and should
227 // have supplied all necessary columns
228
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] + "' "; }
233 if ( nullCols )
234 {
235 if ( nullCols->size() > 0 )
236 {
237 unsigned nNull = nullCols->size();
238 for ( unsigned iNull = 0; iNull < nNull; iNull++ )
239 { ins += ", " + ( *nullCols )[iNull] + "= NULL "; }
240 }
241 }
242
243 ( *m_out ) << std::endl << "# INSERT string is:" << std::endl;
244 ( *m_out ) << ins << std::endl;
245 m_out->flush();
246
247 if ( m_writeDisabled )
248 {
249 ( *m_out ) << "write to Db previously disabled; INSERT not sent" << std::endl;
250 m_out->flush();
251 return true;
252 }
253
254 int mysqlRet = mysql_query( m_mysql, ins.c_str() );
255
256 if ( mysqlRet )
257 {
258 ( *m_out ) << "MySQL error during INSERT, code " << mysqlRet << std::endl;
259 m_out->flush();
260 return false;
261 }
262 if ( auto_value ) { *auto_value = mysql_insert_id( m_mysql ); }
263 return true;
264 }
265
266 unsigned int MysqlConnection::update( const std::string& tableName,
267 const StringVector& colNames,
268 const StringVector& values, const Assertion* where,
269 const StringVector* nullCols ) {
270
271 unsigned int nCol = colNames.size();
272 if ( nCol != values.size() )
273 {
274 ( *m_err ) << "rdbModel::mysqlConnection::update: ";
275 ( *m_err ) << "Incompatible vector arguments " << std::endl;
276 m_err->flush();
277 return 0;
278 }
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] + "'"; }
283 if ( nullCols )
284 {
285 unsigned nNull = nullCols->size();
286 for ( unsigned iNull = 0; iNull < nNull; iNull++ )
287 { sqlString += ", " + ( *nullCols )[iNull] + "= NULL "; }
288 }
289
290 if ( where )
291 {
292 sqlString += " WHERE ";
293 bool ret = compileAssertion( where, sqlString );
294 if ( !ret ) return 0;
295 }
296 ( *m_out ) << std::endl << "# UPDATE to be issued:" << std::endl;
297 ( *m_out ) << sqlString << std::endl;
298 m_out->flush();
299 if ( m_writeDisabled )
300 {
301 ( *m_out ) << "write to Db previously disabled; UPDATE not sent" << std::endl;
302 m_out->flush();
303 return 0;
304 }
305 int mysqlRet = mysql_query( m_mysql, sqlString.c_str() );
306
307 if ( mysqlRet )
308 {
309 ( *m_out ) << "rdbModel::MysqlConnection::update: ";
310 ( *m_out ) << "MySQL error during UPDATE, code " << mysqlRet << std::endl;
311 m_out->flush();
312 return 0;
313 }
314 my_ulonglong nModLong = mysql_affected_rows( m_mysql );
315 // Not much chance that we'll change more rows than will fit in just long
316 unsigned nMod = nModLong;
317 return nMod;
318 }
319
320 ResultHandle* MysqlConnection::select( const std::string& tableName,
321 const StringVector& getCols,
322 const StringVector& orderCols, const Assertion* where,
323 int rowLimit, int rowOffset ) {
324 std::string sqlString = "SELECT ";
325 unsigned nGet = getCols.size();
326 unsigned nOrder = orderCols.size();
327
328 std::cout << "tableName is:" << tableName << std::endl;
329
330 // tableName="metadata_v2r1";
331
332 sqlString += getCols[0];
333 for ( unsigned iGet = 1; iGet < nGet; iGet++ )
334 {
335 sqlString += ",";
336 sqlString += getCols[iGet];
337 }
338 sqlString += " FROM " + tableName + " ";
339 std::cout << "sqlString is11:" << sqlString << std::endl;
340 if ( where != 0 )
341 {
342 sqlString += " WHERE ";
343 bool ret = compileAssertion( where, sqlString );
344 if ( !ret ) return 0;
345 }
346
347 std::cout << "sqlString is22:" << sqlString << std::endl;
348
349 /*maqm if (nOrder > 0 ) {
350 sqlString += " ORDER BY " + orderCols[0];
351 for (unsigned iOrder = 1; iOrder < nOrder; iOrder++) {
352 sqlString += ",";
353 sqlString += orderCols[iOrder];
354 }
355 }
356 */
357 // sqlString ="SELECT ser_no FROM metadata_v2r1 WHERE ((completion='OK') AND
358 // (instrument='LAT') AND (calib_type='MDC_t0') AND (flavor='vanilla'))";
359 if ( rowLimit > 0 )
360 {
361 // SQL format is LIMIT offset,limit or
362 // LIMIT limit or
363 // LIMIT limit OFFSET offset [don't use this one]
364 sqlString += " LIMIT ";
365 std::string limitStr;
366 if ( rowOffset > 0 )
367 {
368 facilities::Util::itoa( rowOffset, limitStr );
369 sqlString += limitStr + ",";
370 }
371 limitStr.clear();
372 facilities::Util::itoa( rowLimit, limitStr );
373 std::cout << "limitStr is:" << limitStr << std::endl;
374 sqlString += limitStr;
375 }
376
377 ( *m_out ) << std::endl << " # About to issue SELECT:" << std::endl;
378 ( *m_out ) << sqlString << std::endl;
379 m_out->flush();
380 // maqm add
381 // sqlString="SELECT ser_no FROM metadata_v2r1";
382
383 int mysqlRet = mysql_query( m_mysql, sqlString.c_str() );
384 if ( mysqlRet )
385 {
386 std::string msg = "rdbModel::MysqlConnection::select: mysql_query error, code ";
387 std::string codeString;
388 facilities::Util::itoa( mysqlRet, codeString );
389 msg += codeString;
390 ( *m_out ) << std::endl << msg << std::endl;
391 m_out->flush();
392 throw RdbException( msg, mysqlRet );
393 return 0;
394 }
395
396 MYSQL_RES* myres = mysql_store_result( m_mysql );
397 MysqlResults* results = new MysqlResults( myres );
398 return results;
399 }
400
401 ResultHandle* MysqlConnection::dbRequest( const std::string& request ) {
402
403 ( *m_out ) << std::endl << "# About to issue SQL request:" << std::endl;
404 ( *m_out ) << request << std::endl;
405 m_out->flush();
406
407 int i = 0;
408 int mysqlRet = mysql_query( m_mysql, request.c_str() );
409 for ( i = 0; i < 10; i++ )
410 {
411 // int mysqlRet = mysql_query(m_mysql, request.c_str());
412 if ( mysqlRet )
413 {
414 // not connected
415 std::string msg = "rdbModel::MysqlConnection::dbRequest: mysql_query error, code ";
416 std::string codeString;
417 facilities::Util::itoa( mysqlRet, codeString );
418 msg += codeString;
419 ( *m_out ) << std::endl << i << "times not connected++++ " << msg << std::endl;
420 m_out->flush();
421 fprintf( stderr, "mysql_query error %d: %s\n", mysql_errno( m_mysql ),
422 mysql_error( m_mysql ) );
423 if ( i >= 9 )
424 {
425 throw RdbException( msg, mysqlRet );
426 return 0;
427 }
428 mysql_close( m_mysql );
429 m_mysql = 0;
430 sleep( 100 );
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() );
434 }
435 else { break; }
436 }
437
438 MYSQL_RES* myres = mysql_store_result( m_mysql );
439 if ( !myres )
440 {
441 // Was it supposed to return data?
442 if ( mysql_field_count( m_mysql ) == 0 )
443 { // no data expected
444 return 0;
445 }
446 else
447 {
448 std::string msg = "rdbModel::MysqlConnection::dbRequest: expected data; none returned";
449 ( *m_out ) << std::endl << msg << std::endl;
450 m_out->flush();
451 throw RdbException( msg );
452 return 0;
453 }
454 }
455 return new MysqlResults( myres );
456 }
457
458 bool MysqlConnection::compileAssertion( const Assertion* a, std::string& sqlString ) const {
459 if ( !m_compileInit )
460 {
461 compileInit();
462 m_compileInit = true;
463 }
464 try
465 { return compileOperator( a->getOperator(), sqlString ); } catch ( RdbException ex )
466 {
467 ( *m_out ) << std::endl << ex.getMsg() << std::endl;
468 m_out->flush();
469 return false;
470 }
471 }
472
473 std::string opSymbols[OPTYPElast];
474
475 void MysqlConnection::compileInit() {
476 opSymbols[OPTYPEor] = " OR ";
477 opSymbols[OPTYPEand] = " AND ";
478 opSymbols[OPTYPEnot] = " NOT ";
479 opSymbols[OPTYPEexists] = "EXISTS ";
480 opSymbols[OPTYPEisNull] = " IS NULL";
481 opSymbols[OPTYPEequal] = "=";
487 return;
488 }
489
490 /*
491 Need significant changes here to deal with which="toBe" case
492 In that case, the output isn't going to be SQL; in fact, it's
493 not clear what it should be, exactly!
494 */
495
496 /** Result is appended to caller-supplied string
497 Convention is to use " " around literal values
498 Note no verification is done here; that operator is in fact a comparison
499 or isNull operator. This is called internally only and that check will
500 have been done before invoking this routine.
501 */
502 bool MysqlConnection::compileComparison( Assertion::Operator* op, std::string& sqlString ) {
503 if ( op->getToBe() ) return false; // can't compile
504
505 OPTYPE opType = op->getOpType();
506 if ( opType == OPTYPEisNull )
507 {
508 sqlString += "(";
509 sqlString += op->getCompareArgs()[0];
510 sqlString += opSymbols[opType];
511 sqlString += ")";
512 return true;
513 }
514 sqlString += "(";
515
516 bool literal0 = ( op->getCompareArgTypes()[0] == FIELDTYPElit );
517 bool literal1 = ( op->getCompareArgTypes()[1] == FIELDTYPElit );
518
519 addArg( literal0, op->getCompareArgs()[0], sqlString );
520 sqlString += opSymbols[opType];
521 addArg( literal1, op->getCompareArgs()[1], sqlString );
522 sqlString += ")";
523
524 return true;
525 }
526
527 bool MysqlConnection::compileOperator( Assertion::Operator* op, std::string& sqlString ) {
528
529 // maqm std::cout<<"in compileOperator() sqlString is00:"<<sqlString<<std::endl;
530 if ( op->isCompareOp() ) return compileComparison( op, sqlString );
531 if ( op->getToBe() ) return false; // can't compile in this case
532 bool ret = true;
533
534 const std::vector<Assertion::Operator*>& children = op->getChildren();
535 unsigned nChild = children.size();
536
537 // For single-child operators NOT, exists, operator symbol
538 // goes 1st, then operand
539 if ( nChild <= 1 )
540 { // operator goes first
541 sqlString += opSymbols[op->getOpType()];
542
543 // more special handling for EXISTS
544 if ( op->getOpType() == OPTYPEexists )
545 {
546 sqlString += "(SELECT * FROM " + op->getTableName();
547 if ( !nChild )
548 { // done
549 sqlString += ")";
550 return ret;
551 }
552 // else EXISTS child is object of a WHERE clause
553 sqlString += " WHERE(";
554 }
555 ret = compileOperator( children[0], sqlString );
556 if ( !ret )
557 {
558 std::string msg = "rdbModel::MysqlConnection::compileOperator failed for operator " +
559 opSymbols[op->getOpType()];
560 throw RdbException( msg );
561 }
562
563 // Have an extra closing ")" for EXISTS with WHERE clause
564 if ( op->getOpType() == OPTYPEexists ) sqlString += ")";
565
566 return ret;
567 }
568
569 // Otherwise put operator symbols between adjacent children.
570
571 // First open parentheses
572 sqlString += "(";
573
574 std::string symbol = opSymbols[op->getOpType()];
575
576 ret = compileOperator( children[0], sqlString );
577 if ( !ret )
578 {
579 std::string msg =
580 "rdbModel::MysqlConnection::compileOperator failed for operator " + symbol;
581 throw RdbException( msg );
582 }
583 for ( unsigned int iChild = 1; iChild < nChild; iChild++ )
584 {
585 sqlString += symbol;
586
587 ret = compileOperator( children[iChild], sqlString );
588 if ( !ret )
589 {
590 std::string msg =
591 "rdbModel::MysqlConnection::compileOperator failed for operator " + symbol;
592 throw RdbException( msg );
593 }
594 }
595 // Finally close paren.
596 sqlString += ")";
597 return ret;
598 }
599
600 // Satisfy Visitor interface. For now the only visitor is the
601 // one to check whether remote and local db descriptions match or
602 // are at least compatible enough to be used.
604
605 if ( m_matchDbName )
606 {
607 if ( m_dbName != rdb->getDbName() )
608 {
609 m_matchReturn = MATCHfail;
610 return Visitor::VDONE;
611 }
612 }
613
614 unsigned int nLocal = rdb->getNTable();
615
616 // Null pointer for 2nd argument means "list all tables"
617
618 MYSQL_RES* res = mysql_list_tables( m_mysql, 0 );
619 if ( !res )
620 {
621 m_matchReturn = MATCHfail;
623 }
624 unsigned int nRemote = mysql_num_rows( res );
625 mysql_free_result( res );
626
627 if ( nRemote < nLocal )
628 {
629 m_matchReturn = MATCHfail;
630 return Visitor::VDONE;
631 }
632 else if ( nRemote > nLocal ) m_matchReturn = MATCHcompatible;
633
634 // Tell Rdb about this
635 rdb->setConnection( this );
636
637 return Visitor::VCONTINUE;
638 }
639
641 const std::string& tName = table->getName();
642
643 // Result set will have all fields for the table
644 if ( m_tempRes )
645 {
646 mysql_free_result( m_tempRes );
647 m_tempRes = 0;
648 }
649 m_primColName.clear();
650
651 std::string query = "SHOW COLUMNS FROM " + tName;
652
653 ( *m_out ) << std::endl << "# About to issue SHOW COLUMNS request :" << std::endl;
654 ( *m_out ) << query << std::endl;
655 m_out->flush();
656
657 int ret = mysql_query( m_mysql, query.c_str() );
658 if ( ret )
659 {
660 m_matchReturn = MATCHfail;
662 }
663
664 m_tempRes = mysql_store_result( m_mysql );
665 if ( !m_tempRes )
666 {
667 m_matchReturn = MATCHfail;
669 }
670 // Result set is a table with fields "Field"(the name) "Type" "Null"(yes
671 // or no) "Key" "Default", "Extra"
672 // Make it easier for accept(Column* ) to find relevant information
673 unsigned int nRow = mysql_num_rows( m_tempRes );
674 m_colIx.clear();
675 for ( unsigned iRow = 0; iRow < nRow; iRow++ )
676 {
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;
681 }
682 return Visitor::VCONTINUE;
683 }
684
686 std::string myName = col->getName();
687 if ( m_colIx.find( myName ) == m_colIx.end() )
688 {
689 m_matchReturn = MATCHfail;
691 }
692 unsigned int ix = m_colIx[myName];
693 mysql_data_seek( m_tempRes, ix );
694 MYSQL_ROW colDescrip = mysql_fetch_row( m_tempRes );
695
696 // Type
697 std::string sqlDtype = std::string( colDescrip[1] );
698 Datatype* dtype = col->getDatatype();
699 if ( !checkDType( dtype, sqlDtype ) )
700 {
701 m_matchReturn = MATCHfail;
702 ( *m_out ) << "Failed dtype match of col " << myName << std::endl;
704 }
705
706 // Null
707 bool nullable = ( std::string( colDescrip[2] ) == std::string( "YES" ) );
708 if ( nullable != col->nullAllowed() )
709 {
710 m_matchReturn = MATCHfail;
711 ( *m_out ) << "Failed null/not null match of col " << myName << std::endl;
713 }
714 // Key (PRI for primary, MUL if first in a multiple-field key
715 // Save primary key info, if any
716 if ( std::string( colDescrip[3] ) == std::string( "PRI" ) ) { m_primColName = myName; }
717
718 // Field 4 is default
719 // Extra (may say auto_increment)
720 bool autoInc = ( std::string( colDescrip[5] ) == std::string( "auto_increment" ) );
721 if ( autoInc != col->isAutoIncrement() )
722 {
723 m_matchReturn = MATCHfail;
724 ( *m_out ) << "Failed isAutoIncrement match of col " << myName << std::endl;
726 }
727 return Visitor::VCONTINUE;
728 }
729
730 bool MysqlConnection::checkDType( Datatype* dtype, const std::string& sqlType ) {
731 std::string base;
732 int sqlSize;
733 if ( dtype->getType() != Datatype::TYPEenum ) { sqlSize = extractSize( sqlType ); }
734
735 // Cases char, varchar, enum and datetime are handled entirely within
736 // the switch statement, but most do the bulk of the work in
737 // common, after the switch.
738 switch ( dtype->getType() )
739 {
740 case Datatype::TYPEenum: {
741 base = "enum";
742 if ( sqlType.find( base ) != 0 )
743 {
744 m_matchReturn = MATCHfail;
745 return false;
746 }
747 Enum* ourEnum = dtype->getEnum();
748 // Finally compare local list of choices to those listed in sqlType
749 // Local list is a vector; in sqlType they're quoted, comma separated
750 return compareEnumList( ourEnum->getChoices(), sqlType );
751 }
753 base = "varchar";
754 if ( sqlType.find( base ) != 0 )
755 {
756 m_matchReturn = MATCHfail;
757 return false;
758 }
759 // size in db must be at least as large as size in Col.
760 if ( sqlSize < dtype->getOutputSize() )
761 {
762 m_matchReturn = MATCHfail;
763 return false;
764 }
765 else if ( sqlSize > dtype->getOutputSize() ) { m_matchReturn = MATCHcompatible; }
766 return true;
767 }
768 case Datatype::TYPEchar: {
769 base = "char";
770 if ( sqlType.find( base ) != 0 )
771 {
772 m_matchReturn = MATCHfail;
773 return false;
774 }
775 // For char datatype unspecified size is equivalent to size=1
776 if ( !sqlSize ) sqlSize = 1;
777 // size in db must be at least as large as size in Col.
778 if ( sqlSize < dtype->getOutputSize() )
779 {
780 m_matchReturn = MATCHfail;
781 return false;
782 }
783 else if ( sqlSize > dtype->getOutputSize() ) { m_matchReturn = MATCHcompatible; }
784 return true;
785 }
787 if ( sqlType != "datetime" )
788 {
789 m_matchReturn = MATCHfail;
790 return false;
791 }
792 return true;
793 }
794
796 base = "timestamp";
797 break;
798 }
799 case Datatype::TYPEint: {
800 base = "int";
801 break;
802 }
804 base = "mediumint";
805 break;
806 }
808 base = "smallint";
809 break;
810 }
813 base = "double";
814 break;
815 }
816 default: { // Indicates bad xml file input. Applications
817 // should have exited already
818 m_matchReturn = MATCHfail;
819 return false;
820 }
821 } // end switch
822 if ( sqlType.find( base ) != 0 )
823 {
824 m_matchReturn = MATCHfail;
825 return false;
826 }
827 // Now check size. It's only for display, so mismatch is not failure
828 if ( sqlSize != dtype->getOutputSize() ) { m_matchReturn = MATCHcompatible; }
829
830 return true;
831 }
832
834 return Visitor::VCONTINUE;
835 // might put something real here later
836 }
837
841
845
849
851
853
857
858} // end namespace rdbModel
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.
bool isAutoIncrement() const
Definition Column.cxx:33
bool nullAllowed() const
Returns true if column may take on value NULL.
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 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)
void setConnection(Connection *connection)
Definition Rdb.cxx:42
unsigned int accept(Visitor *v)
This is the recursive accept for the visitor pattern.
Definition Rdb.cxx:98
static std::string getAttribute(const DOMElement *elt, const char *attName)
Definition Dom.cxx:199
DOMDocument * parse(const char *const filename, const std::string &docType=std::string(""))
Parse an xml file, returning document node if successful.
#define ix(i)
std::string opSymbols[OPTYPElast]