statement caching modifications and cache stmt display
[csql.git] / src / sql / SqlStatement.cxx
blob77bdf88f63d3dbd6a521a2ba6cb4b34e24c14e84
1 /***************************************************************************
2 * Copyright (C) 2007 by Prabakaran Thirumalai *
3 * praba_tuty@yahoo.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 #include <os.h>
21 #include <Statement.h>
22 #include <SqlStatement.h>
23 #include <dmllex.h>
25 char *lexInput;
26 extern ParsedData *parsedData;
28 int yyparse ();
29 bool SqlConnection::isInit = false;
30 #if (defined MMDB && defined EMBED)
31 bool SqlConnection::firstThread = false;
32 GlobalUniqueID SqlConnection::UID;
33 #endif
34 List SqlConnection::connList;
36 SqlStatement::~SqlStatement()
38 if (sqlStmtString) { ::free(sqlStmtString); sqlStmtString=NULL;}
39 if (isPrepd) { free(); isPrepd = false; }
42 List SqlStatement::getTableNameList()
44 return pData.getTableNameList();
46 SqlStatement::SqlStatement()
48 innerStmt = NULL;
49 sqlCon = NULL;
50 stmt = NULL;
51 isPrepd = false;
52 isCachedStmt=false;
53 isMgmtStatement = false;
54 sqlStmtString = NULL;
56 void SqlStatement::setConnection(AbsSqlConnection *conn)
58 sqlCon = (SqlConnection*)conn;
59 con = conn;
62 void SqlStatement::setSqlConnection(SqlConnection *conn)
64 sqlCon = conn;
67 DbRetVal SqlStatement::executeDirect(char *str)
69 DbRetVal rv = OK;
70 int rows = 0;
71 rv = prepare(str);
72 if (rv != OK) return rv;
73 rv = execute(rows);
74 if (rv != OK) return rv;
75 return rv;
77 void SqlStatement::setStmtString(char *ststr)
79 if (sqlStmtString) { ::free(sqlStmtString); sqlStmtString=NULL; }
80 sqlStmtString = (char*) malloc(strlen(ststr)+1);
81 strcpy(sqlStmtString, ststr);
84 DbRetVal SqlStatement::prepare()
86 return prepareInt(sqlStmtString);
89 DbRetVal SqlStatement::prepare(char *stmtstr)
91 if (sqlStmtString) { ::free(sqlStmtString); sqlStmtString=NULL;}
92 sqlStmtString = (char*) malloc(strlen(stmtstr)+1);
93 strcpy(sqlStmtString, stmtstr);
94 return prepareInt(stmtstr);
97 DbRetVal SqlStatement::prepareInt(char *stmtstr)
99 DbRetVal rv = OK;
100 if (! sqlCon->isConnectionOpen()) {
101 printError(ErrNotOpen, "Connection not open");
102 return ErrNotOpen;
104 SqlStatement *cachedStmt = sqlCon->findInCache(stmtstr);
105 if (cachedStmt)
107 *this = *cachedStmt;
108 this->stmt->setParsedData(&this->pData);
109 isCachedStmt=true;
110 logFine(Conf::logger,"GOT STMT FROM CACHE: %s %x", stmtstr, cachedStmt);
111 return OK;
113 // take mutex here
114 int ret = ProcessManager::prepareMutex.tryLock(10, 1000);
115 if (ret != 0)
117 printError(ErrLockTimeOut, "Unable to get prepare mutex");
118 return ErrLockTimeOut;
121 DatabaseManager *dbMgr = sqlCon->getConnObject().getDatabaseManager();
122 if (isPrepared()) free();
123 lexInput = stmtstr;
124 parsedData = &pData;
126 yy_buffer_state *yy_buffer= yy_scan_string(stmtstr);
127 int rc = yyparse();
128 if (yy_buffer) yy_delete_buffer(yy_buffer);
129 if (rc != 0)
131 free();
132 parsedData = NULL;
133 ProcessManager::prepareMutex.releaseLock(-1, false);
134 return ErrSyntaxError;
136 if( parsedData->getStmtType() == MgmtStatement)
138 isPrepd = true;
139 parsedData = NULL;
140 isMgmtStatement = true;
141 ProcessManager::prepareMutex.releaseLock(-1, false);
142 logFine(Conf::logger,"PREPARE: %s %x", stmtstr, stmt);
143 return OK;
145 stmt = StatementFactory::getStatement(parsedData);
146 stmt->setDbMgr(dbMgr);
147 if( parsedData->getStmtType() == UserStatement)
149 UserManager* userMgr = sqlCon->getConnObject().getUserManager();
150 UserTblStatement *ustmt = (UserTblStatement *)stmt;
151 ustmt->setUserManager(userMgr,sqlCon->getConnObject().getUserName());
153 rv = stmt->resolve();
154 if (rv != OK)
156 free();
157 parsedData = NULL;
158 ProcessManager::prepareMutex.releaseLock(-1, false);
159 return rv;
161 isPrepd = true;
162 if (!isCachedStmt && Conf::config.getStmtCacheSize()) {
163 if (stmt->noOfParamFields() > 0) {
164 isCachedStmt = true;
165 sqlCon->addToCache(this, stmtstr);
166 }else if (Conf::config.useCacheNoParam())
168 if (parsedData->getCacheWorthy())
170 isCachedStmt = true;
171 sqlCon->addToCache(this, stmtstr);
175 parsedData = NULL;
176 ProcessManager::prepareMutex.releaseLock(-1, false);
177 return OK;
180 char* SqlStatement::getTableName()
182 return pData.getTableName();
185 bool SqlStatement::isSelect()
187 if ((pData.getStmtType() == SelectStatement) || (pData.getStmtType() == MetaStatement)) return true;
188 return false;
191 bool SqlStatement::isPrepared() { return isPrepd; }
193 DbRetVal SqlStatement::execute(int &rowsAffected)
195 DbRetVal rv = OK;
196 if (! sqlCon->isConnectionOpen()) {
197 printError(ErrNotOpen, "Connection not open");
198 return ErrNotOpen;
200 if (! isPrepared()) {
201 printError(ErrNotPrepared, "Statement Not Prepared");
202 return ErrNotPrepared;
204 if( isMgmtStatement )
206 flushCacheStmt();
207 logFiner(Conf::logger,"EXECUTE: %x", stmt);
208 return OK;
210 rv = stmt->execute(rowsAffected);
211 if (rv == ErrAlready && pData.getStmtType() == SelectStatement )
212 { //if previous scan is not closed, close it
213 SelStatement *selStmt = (SelStatement*) stmt;
214 selStmt->close();
215 rv = stmt->execute(rowsAffected);
217 logFiner(Conf::logger,"EXECUTE: %x", stmt);
218 return rv;
221 void* SqlStatement::fetch()
223 if (! sqlCon->isConnectionOpen()) {
224 printError(ErrNotOpen, "Connection not open");
225 return NULL;
227 if (! isPrepared()) {
228 printError(ErrNotPrepared, "Statement Not Prepared");
229 return NULL;
231 if (pData.getStmtType() == SelectStatement ) {
232 SelStatement *selStmt = (SelStatement*) stmt;
233 return selStmt->fetch();
235 else if(pData.getStmtType() == MetaStatement){
236 MetadataStatement *metaStmt = (MetadataStatement*) stmt;
237 return metaStmt->fetch();
239 else { return NULL;}
242 void* SqlStatement::fetch(DbRetVal &rv)
244 if (! sqlCon->isConnectionOpen()) {
245 printError(ErrNotOpen, "Connection not open");
246 rv = ErrNoConnection;
247 return NULL;
249 if (! isPrepared()) {
250 printError(ErrNotPrepared, "Statement Not Prepared");
251 return NULL;
253 if (pData.getStmtType() == SelectStatement ) {
254 SelStatement *selStmt = (SelStatement*) stmt;
255 return selStmt->fetch(rv);
257 else if(pData.getStmtType() == MetaStatement){
258 MetadataStatement *metaStmt = (MetadataStatement*) stmt;
259 return metaStmt->fetch(rv);
261 else { return NULL;}
264 void* SqlStatement::fetchAndPrint(bool SQL)
266 if (! sqlCon->isConnectionOpen()) {
267 printError(ErrNotOpen, "Connection not open");
268 return NULL;
270 if (! isPrepared()) {
271 printError(ErrNotPrepared, "Statement Not Prepared");
272 return NULL;
274 if (pData.getStmtType() != SelectStatement) return NULL;
275 SelStatement *selStmt = (SelStatement*) stmt;
276 return selStmt->fetchAndPrint(SQL);
279 DbRetVal SqlStatement::bindParam(int pos, void* value)
281 DbRetVal rv = OK;
282 rv = stmt->setParam(pos, value);
283 return rv;
286 DbRetVal SqlStatement::bindField(int pos, void* value)
288 DbRetVal rv = OK;
289 if (pData.getStmtType() == SelectStatement ) {
290 SelStatement *selStmt = (SelStatement*) stmt;
291 return selStmt->setBindField(pos, value);
293 else if(pData.getStmtType() == MetaStatement){
294 MetadataStatement *metaStmt = (MetadataStatement*) stmt;
295 return metaStmt->setBindField(pos, value);
297 else { return ErrBadCall;}
299 void* SqlStatement::next()
301 if (pData.getStmtType() == SelectStatement ) {
302 SelStatement *selStmt = (SelStatement*) stmt;
303 return( (void*) selStmt->next() );
305 else if(pData.getStmtType() == MetaStatement){
306 MetadataStatement *metaStmt = (MetadataStatement*) stmt;
307 return( (void*) metaStmt->next() );
309 else { return 0;}
312 bool SqlStatement::isFldNull(int pos)
314 if (pData.getStmtType() != SelectStatement) return 0;
315 SelStatement *selStmt = (SelStatement*) stmt;
316 return (selStmt->isFldNull(pos));
318 bool SqlStatement::isFldNull(char *name)
320 if (pData.getStmtType() != SelectStatement) return 0;
321 SelStatement *selStmt = (SelStatement*) stmt;
322 return (selStmt->isFldNull(name));
324 DbRetVal SqlStatement::close()
326 if (pData.getStmtType() == SelectStatement ) {
327 SelStatement *selStmt = (SelStatement*) stmt;
328 logFinest(Conf::logger,"CLOSE: %x", stmt);
329 return selStmt->close();
331 else if(pData.getStmtType() == MetaStatement){
332 MetadataStatement *selStmt = (MetadataStatement*) stmt;
333 logFinest(Conf::logger,"CLOSE: %x", stmt);
334 return selStmt->close();
336 else { return OK;}
339 void* SqlStatement::getParamValuePtr( int pos )
341 //if (pData.getStmtType() != SelectStatement) return 0;
342 DmlStatement *dmlStmt = (DmlStatement*) stmt;
343 return( (void*) dmlStmt->getParamValuePtr( pos ) );
346 char* SqlStatement::getFieldName( int pos )
348 if (pData.getStmtType() == SelectStatement ) {
349 SelStatement *selStmt = (SelStatement*) stmt;
350 return( (char*) selStmt->getFieldName( pos ) );
352 else if(pData.getStmtType() == MetaStatement){
353 MetadataStatement *selStmt = (MetadataStatement*) stmt;
354 return( (char*) selStmt->getFieldName( pos ) );
356 else { return 0;}
359 DataType SqlStatement::getFieldType( int pos )
361 if (pData.getStmtType() == SelectStatement ) {
362 SelStatement *selStmt = (SelStatement*) stmt;
363 return( (DataType) selStmt->getFieldType( pos ) );
365 else if(pData.getStmtType() == MetaStatement){
366 MetadataStatement *selStmt = (MetadataStatement*) stmt;
367 return( (DataType) selStmt->getFieldType( pos ) );
369 else { return typeUnknown;}
371 int SqlStatement::getFieldLength( int pos )
373 if (pData.getStmtType() == SelectStatement ) {
374 SelStatement *selStmt = (SelStatement*) stmt;
375 return( (int) selStmt->getFieldLength( pos ) );
377 else if(pData.getStmtType() == MetaStatement){
378 MetadataStatement *selStmt = (MetadataStatement*) stmt;
379 return( (int) selStmt->getFieldLength( pos ) );
381 else { return 0;}
384 void* SqlStatement::getFieldValuePtr( int pos )
386 if (pData.getStmtType() == SelectStatement ) {
387 SelStatement *selStmt = (SelStatement*) stmt;
388 return( (void*) selStmt->getFieldValuePtr( pos ) );
390 else if(pData.getStmtType() == MetaStatement){
391 MetadataStatement *selStmt = (MetadataStatement*) stmt;
392 return( (void*) selStmt->getFieldValuePtr( pos ) );
394 else { return 0;}
396 void* SqlStatement::getFieldValuePtr( char *name )
398 if (pData.getStmtType() == SelectStatement ) {
399 SelStatement *selStmt = (SelStatement*) stmt;
400 return( (void*) selStmt->getFieldValuePtr( name ) );
402 else if(pData.getStmtType() == MetaStatement){
403 MetadataStatement *selStmt = (MetadataStatement*) stmt;
404 return( (void*) selStmt->getFieldValuePtr( name ) );
406 else { return NULL;}
409 int SqlStatement::noOfProjFields()
411 if (pData.getStmtType() == SelectStatement ) {
412 SelStatement *selStmt = (SelStatement*) stmt;
413 return selStmt->noOfProjFields();
415 else if(pData.getStmtType() == MetaStatement){
416 MetadataStatement *selStmt = (MetadataStatement*) stmt;
417 return selStmt->noOfProjFields();
419 else { return 0;}
422 void SqlStatement::getProjFieldType(int *data)
424 if (pData.getStmtType() == SelectStatement ) {
425 SelStatement *selStmt = (SelStatement*) stmt;
426 return( selStmt->getProjFieldType(data) );
428 else if(pData.getStmtType() == MetaStatement){
429 MetadataStatement *selStmt = (MetadataStatement*) stmt;
430 return( selStmt->getProjFieldType(data) );
436 int SqlStatement::noOfParamFields()
438 return stmt->noOfParamFields();
441 DbRetVal SqlStatement::getProjFldInfo (int projpos, FieldInfo *&fInfo)
443 DbRetVal rv = OK;
444 if (pData.getStmtType() == SelectStatement ) {
445 SelStatement *selStmt = (SelStatement*) stmt;
446 rv = selStmt->getProjFldInfo(projpos, fInfo);
448 else if(pData.getStmtType() == MetaStatement){
449 MetadataStatement *selStmt = (MetadataStatement*) stmt;
450 rv = selStmt->getProjFldInfo(projpos, fInfo);
451 } else { return ErrBadCall;}
452 return rv;
455 DbRetVal SqlStatement::getParamFldInfo (int parampos, FieldInfo *&fInfo)
457 DbRetVal rv = OK;
458 if (pData.getStmtType() ==SelectStatement ||
459 pData.getStmtType() ==InsertStatement ||
460 pData.getStmtType() ==UpdateStatement ||
461 pData.getStmtType() ==DeleteStatement)
464 DmlStatement *dmlStmt = (DmlStatement*) stmt;
465 rv = dmlStmt->getParamFldInfo(parampos, fInfo);
467 return rv;
470 DbRetVal SqlStatement::free()
472 logFinest(Conf::logger,"FREE: %x", stmt);
473 if (isCachedStmt) {
474 stmt=NULL;
475 pData.init();
476 isPrepd = false;
477 if (sqlStmtString) sqlCon->setStmtNotInUse(sqlStmtString);
478 if (sqlStmtString) { ::free(sqlStmtString); sqlStmtString=NULL; }
479 isCachedStmt = false;
480 return OK;
482 if(stmt) delete stmt;
483 stmt = NULL;
484 pData.reset();
485 isMgmtStatement = false;
486 isPrepd = false;
487 isCachedStmt = false;
488 if (sqlStmtString) { ::free(sqlStmtString); sqlStmtString=NULL; }
489 return OK;
492 void SqlStatement::setNull(int pos)
494 stmt->setNull(pos);
496 void SqlStatement::setShortParam(int paramPos, short value)
498 stmt->setShortParam(paramPos, value);
500 void SqlStatement::setIntParam(int paramPos, int value)
502 stmt->setIntParam(paramPos, value);
504 void SqlStatement::setLongParam(int paramPos, long value)
506 stmt->setLongParam(paramPos, value);
508 void SqlStatement::setLongLongParam(int paramPos, long long value)
510 stmt->setLongLongParam(paramPos, value);
512 void SqlStatement::setByteIntParam(int paramPos, ByteInt value)
514 stmt->setByteIntParam(paramPos, value);
516 void SqlStatement::setFloatParam(int paramPos, float value)
518 stmt->setFloatParam(paramPos, value);
520 void SqlStatement::setDoubleParam(int paramPos, double value)
522 stmt->setDoubleParam(paramPos, value);
524 void SqlStatement::setStringParam(int paramPos, char *value)
526 stmt->setStringParam(paramPos, value);
528 void SqlStatement::setDateParam(int paramPos, Date value)
530 stmt->setDateParam(paramPos, value);
532 void SqlStatement::setTimeParam(int paramPos, Time value)
534 stmt->setTimeParam(paramPos, value);
536 void SqlStatement::setTimeStampParam(int paramPos, TimeStamp value)
538 stmt->setTimeStampParam(paramPos, value);
540 void SqlStatement::setBinaryParam(int paramPos, void *value, int length)
542 stmt->setBinaryParam(paramPos, value, length);
544 int SqlStatement::getFldPos(char *name)
546 return stmt->getFldPos(name);
548 long long SqlStatement::getLastInsertedVal(DbRetVal &rv)
550 return stmt->getLastInsertedVal(rv);
552 List SqlStatement::getAllTableNames(DbRetVal &ret)
554 DatabaseManager *dbMgr = NULL;
555 List tbNmList;
556 dbMgr=sqlCon->getConnObject().getDatabaseManager();
557 int rv = ret;
558 if(dbMgr != NULL)
559 tbNmList = dbMgr->getAllTableNames(&rv);
560 ret = (DbRetVal) rv;
561 return tbNmList;
564 List SqlStatement::getAllUserNames(DbRetVal &ret)
566 UserManager *urMgr = NULL;
567 List urNmList;
568 urMgr=sqlCon->getConnObject().getUserManager();
569 int rv = ret;
570 if(urMgr != NULL)
571 urNmList = urMgr->getAllUserNames(&rv);
572 ret = (DbRetVal) rv;
573 return urNmList;
575 List SqlStatement::getFieldNameList(const char *tblName)
577 DatabaseManager *dbMgr = sqlCon->getConnObject().getDatabaseManager();
578 Table *table = dbMgr->openTable(tblName);
579 if (NULL == table) {
580 List dummyList;
581 printError(ErrLockTimeOut, "Unable to open table %s", tblName);
582 return dummyList;
584 List fldNameList = table->getFieldNameList();
585 dbMgr->closeTable(table);
586 return fldNameList;
588 DbRetVal SqlStatement::getFieldInfo(const char *tblName, const char *fldName, FieldInfo *&info)
590 DatabaseManager *dbMgr = sqlCon->getConnObject().getDatabaseManager();
591 Table *table = dbMgr->openTable(tblName);
592 if (NULL == table) {
593 printError(ErrLockTimeOut, "Unable to open table %s", tblName);
594 return ErrLockTimeOut;
596 DbRetVal rv = table->getFieldInfo(fldName, info);
597 dbMgr->closeTable(table);
598 return OK;
600 void SqlStatement::setLoading(bool flag)
602 if (pData.getStmtType() == InsertStatement||
603 pData.getStmtType() == UpdateStatement||
604 pData.getStmtType() == DeleteStatement)
606 DmlStatement *dmlStmt = (DmlStatement*) stmt;
607 dmlStmt->setLoading(flag);
609 return;
612 int SqlStatement::getNoOfPagesForTable(char *tblName)
614 DatabaseManager *dbMgr = sqlCon->getConnObject().getDatabaseManager();
615 DatabaseManagerImpl *dbMgrImpl = (DatabaseManagerImpl *)dbMgr;
616 return dbMgrImpl->getNoOfPagesForTable(tblName);
619 DbRetVal SqlStatement::loadRecords(char *tblName, void *buf)
621 DatabaseManager *dbMgr = sqlCon->getConnObject().getDatabaseManager();
622 DatabaseManagerImpl *dbMgrImpl = (DatabaseManagerImpl *)dbMgr;
623 return dbMgrImpl->loadRecords(tblName, (char *) buf);
626 DbRetVal SqlStatement::pasteRecords(char *tblName, void *buffer)
628 DatabaseManager *dbMgr = sqlCon->getConnObject().getDatabaseManager();
629 DatabaseManagerImpl *dbMgrImpl = (DatabaseManagerImpl *)dbMgr;
630 return dbMgrImpl->pasteRecords(tblName, buffer);
632 void SqlStatement::flushCacheStmt()
634 return sqlCon->flushCacheStmt();
636 void SqlStatement::resetStmtString() {
637 sqlStmtString=NULL;
639 //-------------------------------------------------------------------
641 static void sigTermHandler(int sig)
643 ListIterator iter= SqlConnection::connList.getIterator();
644 SqlConnection *conn = NULL;
645 while (iter.hasElement())
647 conn = (SqlConnection*) iter.nextElement();
648 conn->flushCacheStmt();
649 if (conn->isConnectionOpen()) conn->disconnect();
651 exit(0);
654 DbRetVal SqlConnection::connect (char *user, char * pass)
656 DbRetVal ret = conn.open(user, pass);
657 if (ret != OK) return ret;
658 if (ret == OK) isConnOpen = true;
659 if (!isInit) initialize();
660 connList.append(this);
661 DbRetVal rv = OK;
662 #if (defined MMDB && EMBED)
663 os::signal(SIGINT, sigTermHandler);
664 os::signal(SIGTERM, sigTermHandler);
665 if (Conf::config.useDurability() && !firstThread) {
666 rv = recoverCsqlDB();
667 if (rv != OK) {
668 printError(ErrSysInternal, "Recovery Failed");
669 return rv;
671 firstThread = true;
673 rollback(); //for drop table execute in redo log
674 #endif
675 return ret;
678 void SqlConnection::flushCacheStmt()
680 ListIterator iter = cachedStmts.getIterator();
681 while (iter.hasElement()) {
682 CachedStmtNode* node = (CachedStmtNode*) iter.nextElement();
683 //do not delete when the statement is currently in use.
684 //otherwise it leads to illegal memory access when application
685 //calls any method on this statement
686 if (node->inUse) continue;
687 free(node->sqlString);
688 node->sqlStmt->setCachedStmt(false);
689 node->sqlStmt->free();
690 delete node->sqlStmt;
691 delete node;
693 cachedStmts.reset();
694 return;
697 void SqlConnection::setStmtNotInUse(char *stmtstr)
699 ListIterator iter = cachedStmts.getIterator();
700 int inputStmtLen = strlen(stmtstr);
701 CachedStmtNode *node = NULL;
702 while ((node = (CachedStmtNode*)iter.nextElement()) != NULL)
704 if (node->stmtLength == inputStmtLen)
706 if (0 == strcmp(node->sqlString, stmtstr))
708 node->inUse =0;
714 SqlStatement* SqlConnection::findInCache(char *stmtstr)
716 ListIterator iter = cachedStmts.getIterator();
717 int inputStmtLen = strlen(stmtstr);
718 CachedStmtNode *node = NULL;
719 while ((node = (CachedStmtNode*)iter.nextElement()) != NULL)
721 if (node->stmtLength == inputStmtLen)
723 if (0 == strcmp(node->sqlString, stmtstr))
725 logFiner(Conf::logger, "Statement Retrieved From Cache %x\n",
726 node->sqlStmt);
727 node->hits++;
728 node->inUse = 1;
729 return node->sqlStmt;
733 return NULL;
735 void SqlConnection::addToCache(SqlStatement *sqlStmt, char* stmtString)
737 SqlStatement *stmt = new SqlStatement();
738 *stmt= *sqlStmt;
739 CachedStmtNode *node = new CachedStmtNode();
740 node->sqlStmt = stmt;
741 node->stmtLength = strlen(stmtString);
742 node->sqlString = (char*)malloc(node->stmtLength+1);
743 node->inUse=1;
744 strcpy(node->sqlString, stmtString);
745 if (cachedStmts.size() >= Conf::config.getStmtCacheSize())
747 removeLeastUsed();
749 node->sqlStmt->resetStmtString();
750 cachedStmts.append(node);
751 logFiner(Conf::logger, "Statement added To Cache %x\n", node->sqlStmt);
752 logFinest(Conf::logger, "Statement added To Cache %s\n", node->sqlString);
753 return ;
755 void SqlConnection::removeLeastUsed()
757 ListIterator iter = cachedStmts.getIterator();
758 CachedStmtNode *node = NULL, *toRemove =NULL;
759 int lowHits = 0;
760 bool firstCall = true;
761 while((node = (CachedStmtNode*) iter.nextElement()) != NULL)
763 if (firstCall) {
764 firstCall = false;
765 lowHits = node->hits;
766 toRemove = node; //if cache size is 1
767 continue;
769 if (lowHits >= node->hits) toRemove = node;
771 cachedStmts.remove(toRemove);
772 //TODO::check whether there is memory leak for list elements
773 logFiner(Conf::logger, "Statement removed from Cache %x\n", toRemove->sqlStmt);
774 logFinest(Conf::logger, "Statement removed from Cache %s\n", toRemove->sqlString);
775 return;
777 SqlConnection::~SqlConnection()
779 flushCacheStmt();
780 if (isConnOpen) disconnect();
781 innerConn = NULL;
784 static void sigUsr1Handler(int sig)
786 ListIterator iter= SqlConnection::connList.getIterator();
787 SqlConnection *conn = NULL;
788 while (iter.hasElement())
790 conn = (SqlConnection*) iter.nextElement();
791 conn->flushCacheStmt();
793 os::signal(SIGCSQL1, sigUsr1Handler);
794 return;
797 static void exithandler(void)
799 ListIterator iter= SqlConnection::connList.getIterator();
800 SqlConnection *conn = NULL;
801 while (iter.hasElement())
803 conn = (SqlConnection*) iter.nextElement();
804 conn->flushCacheStmt();
805 conn->disconnect();
808 void SqlConnection::displayStmtCache()
810 ListIterator iter = cachedStmts.getIterator();
811 CachedStmtNode *node = NULL;
812 printf("STATEMENT CACHE START \n");
813 while ((node = (CachedStmtNode*)iter.nextElement()) != NULL)
815 node->display();
817 printf("STATEMENT CACHE END\n");
820 void SqlConnection::initialize()
822 os::signal(SIGCSQL1, sigUsr1Handler);
823 #if (defined MMDB && defined EMBED)
824 os::atexit(exithandler);
825 #endif
826 isInit = true;
829 #if (defined MMDB && defined EMBED)
830 DbRetVal SqlConnection::recoverCsqlDB()
832 DbRetVal rv = OK;
833 char dbRedoFileName[MAX_FILE_LEN];
834 char dbChkptSchema[MAX_FILE_LEN];
835 char dbChkptMap[MAX_FILE_LEN];
836 char dbChkptData[MAX_FILE_LEN];
837 char dbBackupFile[MAX_FILE_LEN];
838 char cmd[IDENTIFIER_LENGTH];
839 //check for check point file if present recover
840 sprintf(dbChkptSchema, "%s/db.chkpt.schema1", Conf::config.getDbFile());
841 if (FILE *file = fopen(dbChkptSchema, "r")) {
842 fclose(file);
843 sprintf(cmd, "cp -f %s %s/db.chkpt.schema", dbChkptSchema,
844 Conf::config.getDbFile());
845 int ret = system(cmd);
846 if (ret != 0) return ErrOS;
848 sprintf(dbChkptMap, "%s/db.chkpt.map1", Conf::config.getDbFile());
849 if (FILE *file = fopen(dbChkptMap, "r")) {
850 fclose(file);
851 sprintf(cmd, "cp -f %s %s/db.chkpt.map", dbChkptMap,
852 Conf::config.getDbFile());
853 int ret = system(cmd);
854 if (ret != 0) return ErrOS;
856 int chkptID= Database::getCheckpointID();
857 sprintf(dbChkptData, "%s/db.chkpt.data%d", Conf::config.getDbFile(),
858 chkptID);
859 sprintf(dbBackupFile, "%s/db.chkpt.data1", Conf::config.getDbFile());
860 FILE *fl = NULL;
861 if (!Conf::config.useMmap() && (fl = fopen(dbBackupFile, "r"))) {
862 fclose(fl);
863 sprintf(cmd, "cp %s/db.chkpt.data1 %s", Conf::config.getDbFile(),
864 dbChkptData);
865 int ret = system(cmd);
866 if (ret != 0) return ErrOS;
868 if (FILE *file = fopen(dbChkptData, "r")) {
869 fclose(file);
870 rv = recoverSystemAndUserDB();
873 //check for redo log file if present apply redo logs
874 sprintf(dbRedoFileName, "%s/csql.db.cur", Conf::config.getDbFile());
875 if (FILE *file = fopen(dbRedoFileName, "r"))
877 fclose(file);
878 applyRedoLogs(dbRedoFileName);
879 DatabaseManager *dbMgr = getConnObject().getDatabaseManager();
880 rv = dbMgr->checkPoint();
881 if (rv != OK)
883 printError(ErrSysInternal, "checkpoint failed after redo log apply");
884 return ErrOS;
887 return OK;
890 DbRetVal SqlConnection::recoverSystemAndUserDB()
892 DbRetVal rv = OK;
893 char schFile[1024];
894 sprintf(schFile, "%s/db.chkpt.schema", Conf::config.getDbFile());
895 if (FILE *file = fopen(schFile, "r")) {
896 applySchemaFile(file);
898 DatabaseManager *dbMgr = getConnObject().getDatabaseManager();
899 dbMgr->recover();
900 return OK;
903 DbRetVal SqlConnection::applySchemaFile(FILE *fp)
905 char buf[8192];
906 char eof;
907 SqlStatement *stmt = new SqlStatement();
908 while ((eof = getQueryFromSchemaFile(fp,buf)) != EOF) {
909 stmt->setConnection(this);
910 stmt->prepare(buf);
911 int rows = 0;
912 stmt->execute(rows);
914 delete stmt;
915 return OK;
918 char SqlConnection::getQueryFromSchemaFile(FILE *fp, char *buf)
920 char c, *bufBegin=buf;
921 int charCnt=0;
922 while( (c=(char ) fgetc(fp)) != EOF && c != ';')
924 *buf++ = c; charCnt++;
925 if( charCnt == SQL_STMT_LEN ) {
926 printf("SQL Statement length is greater than %d. "
927 "Ignoring the statement.\n", SQL_STMT_LEN );
928 *bufBegin++ =';';
929 *bufBegin ='\0';
930 return 0;
933 *buf++ = ';';
934 *buf = '\0';
935 return c;
938 void SqlConnection::addToHashTable(int stmtID, AbsSqlStatement* sHdl)
940 int bucketNo = stmtID % STMT_BUCKET_SIZE;
941 StmtBucket *buck = (StmtBucket *) stmtBuckets;
942 StmtBucket *stmtBucket = &buck[bucketNo];
943 StmtNode *node = new StmtNode();
944 node->stmtId = stmtID;
945 node->stmt = sHdl;
946 stmtBucket->bucketList.append(node);
947 return;
950 void SqlConnection::removeFromHashTable(int stmtID)
952 int bucketNo = stmtID % STMT_BUCKET_SIZE;
953 StmtBucket *buck = (StmtBucket *) stmtBuckets;
954 StmtBucket *stmtBucket = &buck[bucketNo];
955 StmtNode *node = NULL;
956 ListIterator it = stmtBucket->bucketList.getIterator();
957 while(it.hasElement()) {
958 node = (StmtNode *) it.nextElement();
959 if(stmtID == node->stmtId) break;
961 it.reset();
962 stmtBucket->bucketList.remove(node);
963 return;
966 AbsSqlStatement *SqlConnection::getStmtFromHashTable(int stmtId)
968 int bucketNo = stmtId % STMT_BUCKET_SIZE;
969 StmtBucket *buck = (StmtBucket *) stmtBuckets;
970 StmtBucket *stmtBucket = &buck[bucketNo];
971 StmtNode *node = NULL;
972 ListIterator it = stmtBucket->bucketList.getIterator();
973 while(it.hasElement()) {
974 node = (StmtNode *) it.nextElement();
975 if(stmtId == node->stmtId) {
976 return node->stmt;
979 return NULL;
982 void setParam(AbsSqlStatement *stmt, int pos, DataType type , int length, void *value)
984 switch(type)
986 case typeInt:
987 stmt->setIntParam(pos, *(int*)value);
988 break;
989 case typeLong:
990 stmt->setLongParam(pos, *(long*) value);
991 break;
992 case typeLongLong:
993 stmt->setLongLongParam(pos, *(long long*)value);
994 break;
995 case typeShort:
996 stmt->setShortParam(pos, *(short*)value);
997 break;
998 case typeByteInt:
999 stmt->setByteIntParam(pos, *(ByteInt*)value);
1000 break;
1001 case typeDouble:
1002 stmt->setDoubleParam(pos, *(double*)value);
1003 break;
1004 case typeFloat:
1005 stmt->setFloatParam(pos, *(float*)value);
1006 break;
1007 case typeDate:
1008 stmt->setDateParam(pos, *(Date*)value);
1009 break;
1010 case typeTime:
1011 stmt->setTimeParam(pos, *(Time*)value);
1012 break;
1013 case typeTimeStamp:
1014 stmt->setTimeStampParam(pos, *(TimeStamp*)value);
1015 break;
1016 case typeString:
1017 case typeVarchar:
1018 stmt->setStringParam(pos, (char*)value);
1019 break;
1020 case typeBinary:
1021 stmt->setBinaryParam(pos, value, length);
1022 break;
1023 default:
1024 printf("unknown type\n");
1025 break;
1027 return;
1030 int SqlConnection::applyRedoLogs(char *redoFile)
1032 struct stat st;
1033 DbRetVal rv = OK;
1034 int fd = open(redoFile, O_RDONLY);
1035 if (-1 == fd) { return OK; }
1036 if (fstat(fd, &st) == -1) {
1037 printError(ErrSysInternal, "Unable to retrieve undo log file size");
1038 close(fd);
1039 return 1;
1041 if (st.st_size ==0) {
1042 close(fd);
1043 return OK;
1045 void *startAddr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
1046 if (MAP_FAILED == startAddr) {
1047 printf("Unable to read undo log file:mmap failed.\n");
1048 return 2;
1050 stmtBuckets = malloc (STMT_BUCKET_SIZE * sizeof(StmtBucket));
1051 memset(stmtBuckets, 0, STMT_BUCKET_SIZE * sizeof(StmtBucket));
1053 char *iter = (char*)startAddr;
1054 void *value = NULL;
1055 int logType, eType;
1056 int stmtID;
1057 int txnID;
1058 int len, ret, retVal =0;
1059 int loglen;
1060 char stmtString[SQL_STMT_LEN];
1061 //printf("size of file %d\n", st.st_size);
1062 while(true) {
1063 //printf("OFFSET HERE %d\n", iter - (char*)startAddr);
1064 if (iter - (char*)startAddr >= st.st_size) break;
1065 logType = *(int*)iter;
1066 if (logType == -1) { //prepare
1067 iter = iter + sizeof(int);
1068 txnID = *(int*) iter; iter += sizeof(int);
1069 loglen = *(int*) iter; iter += sizeof(int);
1070 stmtID = *(int*)iter;
1071 iter = iter + sizeof(int);
1072 len = *(int*)iter;
1073 iter = iter + sizeof(int);
1074 strncpy(stmtString, iter, len);
1075 iter = iter + len;
1076 //printf("PREPARE:%d %d %s\n", stmtID, len, stmtString);
1077 AbsSqlStatement *st = SqlFactory::createStatement(CSqlDirect);
1078 SqlStatement *stmt = (SqlStatement *)st;
1079 stmt->setConnection(this);
1080 rv = stmt->prepare(stmtString);
1081 if (rv != OK) {
1082 printError(ErrSysInternal, "unable to prepare stmt:%s", stmtString);
1083 retVal=1;
1084 break;
1086 stmt->prepare(stmtString);
1087 SqlStatement *sqlStmt = (SqlStatement*)stmt;
1088 sqlStmt->setLoading(true);
1089 addToHashTable(stmtID, stmt);
1091 else if(logType == -2) { //commit
1092 beginTrans();
1093 iter = iter + sizeof(int);
1094 txnID = *(int*) iter; iter += sizeof(int);
1095 loglen = *(int*) iter; iter += sizeof(int);
1096 char *curPtr = iter;
1097 while(true) {
1098 //printf("Iter length %d\n", iter - curPtr);
1099 if (iter - (char*)startAddr >= st.st_size) {
1100 //file end reached
1101 //printf("Redo log file end\n");
1102 retVal=0;
1103 break;
1105 stmtID = *(int*)iter;
1106 //printf("stmtid %d\n", stmtID);
1107 iter = iter + sizeof(int);
1108 eType = *(int*)iter;
1109 //printf("eType is %d\n", eType);
1110 AbsSqlStatement *stmt = getStmtFromHashTable(stmtID);
1111 if (0 == eType) { //execute type
1112 iter = iter + sizeof(int);
1113 //printf("EXEC: %d\n", stmtID);
1114 if (stmt) {
1115 rv = stmt->execute(ret);
1116 if (rv != OK) {
1117 printError(ErrSysInternal, "unable to execute");
1118 retVal=2;
1119 break;
1121 } else {
1122 printError(ErrSysInternal, "statement not found for %d\n",stmtID);
1124 if (*(int*)iter <0) break;
1125 } else if ( 1 == eType) { //set type
1126 iter=iter+sizeof(int);
1127 int pos = *(int*) iter;
1128 iter=iter+sizeof(int);
1129 DataType type = (DataType)(*(int*)iter);
1130 iter=iter+sizeof(int);
1131 int len = *(int*) iter;
1132 iter=iter+sizeof(int);
1133 value = iter;
1134 //AllDataType::printVal(value, type, len);
1135 iter=iter+len;
1136 //printf("SET: %d %d %d %d\n", stmtID, pos, type, len);
1137 setParam(stmt, pos, type, len, value);
1138 if (*(int*)iter <0) break;
1141 commit();
1143 else if(logType == -3) { //free
1144 iter = iter + sizeof(int);
1145 txnID = *(int*) iter; iter += sizeof(int);
1146 loglen = *(int*) iter; iter += sizeof(int);
1147 stmtID = *(int*)iter;
1148 iter = iter + sizeof(int);
1149 AbsSqlStatement *stmt = getStmtFromHashTable(stmtID);
1150 if (stmt) {
1151 stmt->free();
1152 removeFromHashTable(stmtID);
1153 } else { printError(ErrSysInternal, "statement not found for %d\n",stmtID);}
1155 else if(logType == -4) { //prepare and execute
1156 iter = iter + sizeof(int);
1157 txnID = *(int*) iter; iter += sizeof(int);
1158 loglen = *(int*) iter; iter += sizeof(int);
1159 stmtID = *(int*)iter;
1160 iter = iter + sizeof(int);
1161 len = *(int*)iter;
1162 iter = iter + sizeof(int);
1163 strncpy(stmtString, iter, len);
1164 stmtString[len+1] ='\0';
1165 iter = iter + len;
1166 //printf("CREATE:%d %d %s\n", stmtID, len, stmtString);
1167 AbsSqlStatement *stmt = SqlFactory::createStatement(CSqlDirect);
1168 if ( NULL == stmt) {
1169 printError(ErrSysInternal, "unable to prepare:%s", stmtString);
1170 retVal=3;
1171 break;
1173 stmt->setConnection(this);
1174 rv = stmt->prepare(stmtString);
1175 if (rv != OK) {
1176 printError(ErrSysInternal, "unable to prepare:%s", stmtString);
1177 retVal=4;
1178 break;
1180 rv = stmt->execute(ret);
1181 if (rv != OK) {
1182 if (strlen(stmtString) > 6 &&
1183 ( (strncasecmp(stmtString,"CREATE", 6) == 0) ||
1184 (strncasecmp(stmtString,"DROP", 4) == 0)) ) {
1185 // conn->disconnect();
1186 // return OK;
1187 continue;
1189 printError(ErrSysInternal, "unable to execute %s", stmtString);
1190 retVal=5;
1191 break;
1193 stmt->free();
1194 }else{
1195 printError(ErrSysInternal, "Redo log file corrupted: logType:%d", logType);
1196 retVal=6;
1197 break;
1200 munmap((char*)startAddr, st.st_size);
1201 close(fd);
1202 //freeAllStmtHandles();
1203 return retVal;
1205 #endif