statement caching fixw
[csql.git] / src / sql / SqlStatement.cxx
blobbc91ba8f8719f6436db924d2f3a860afe8419daa
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 void SqlStatement::setParamValues(AbsSqlStatement *sqlStmt, int parampos, DataType type, int length, void *value)
44 switch(type)
46 case typeInt:
47 sqlStmt->setIntParam(parampos, *(int*)value);
48 break;
49 case typeLong:
50 sqlStmt->setLongParam(parampos, *(long*)value);
51 break;
52 case typeLongLong:
53 sqlStmt->setLongLongParam(parampos, *(long long*)value);
54 break;
55 case typeShort:
56 sqlStmt->setShortParam(parampos, *(short*)value);
57 break;
58 case typeByteInt:
59 sqlStmt->setByteIntParam(parampos, *(char*)value);
60 break;
61 case typeDouble:
62 sqlStmt->setDoubleParam(parampos, *(double*)value);
63 break;
64 case typeFloat:
65 sqlStmt->setFloatParam(parampos, *(float*)value);
66 break;
67 case typeDate:
68 sqlStmt->setDateParam(parampos, *(Date*)value);
69 break;
70 case typeTime:
71 sqlStmt->setTimeParam(parampos, *(Time*)value);
72 break;
73 case typeTimeStamp:
74 sqlStmt->setTimeStampParam(parampos, *(TimeStamp*)value);
75 break;
76 case typeVarchar:
77 case typeString:
79 sqlStmt->setStringParam(parampos, (char*)value);
80 break;
82 case typeBinary:
83 sqlStmt->setBinaryParam(parampos, (char *) value, length);
84 break;
85 default:
86 printf("unknown type\n");
87 break;
89 return;
92 void *SqlStatement::fillBindBuffer(TDBInfo tdbName, DataType type, void *&valBuf, int length, int nRecords)
94 BindBuffer *bBuf = NULL;
95 switch(type)
97 case typeDate:
98 bBuf = new BindBuffer();
99 bBuf->csql = valBuf;
100 bBuf->type = typeDate;
101 bBuf->length = sizeof(DATE_STRUCT);
102 bBuf->targetdb = malloc(nRecords * bBuf->length);
103 memset(bBuf->targetdb, 0, nRecords * bBuf->length);
104 valBuf = bBuf->targetdb;
105 break;
106 case typeTime:
107 bBuf = new BindBuffer();
108 bBuf->csql = valBuf;
109 bBuf->type = typeTime;
110 bBuf->length = sizeof(TIME_STRUCT);
111 bBuf->targetdb = malloc(nRecords * bBuf->length);
112 memset(bBuf->targetdb, 0, nRecords * bBuf->length);
113 valBuf = bBuf->targetdb;
114 break;
115 case typeTimeStamp:
116 bBuf = new BindBuffer();
117 bBuf->csql = valBuf;
118 bBuf->type = typeTimeStamp;
119 bBuf->length = sizeof(TIMESTAMP_STRUCT);
120 bBuf->targetdb = malloc(nRecords * bBuf->length);
121 memset(bBuf->targetdb, 0, nRecords * bBuf->length);
122 valBuf = bBuf->targetdb;
123 break;
124 case typeLongLong:
126 if( tdbName == postgres)
128 bBuf = new BindBuffer();
129 bBuf->type = typeLongLong;
130 bBuf->length = 40;
131 bBuf->csql = valBuf;
132 int size = nRecords*AllDataType::size(typeString,bBuf->length);
133 bBuf->targetdb = malloc(size);
134 memset(bBuf->targetdb, 0, size);
135 valBuf = bBuf->targetdb;
136 break;
137 }else
139 bBuf = new BindBuffer();
140 bBuf->type = type;
141 bBuf->csql = valBuf;
142 bBuf->length = length;
143 break;
146 case typeVarchar:
147 case typeString:
149 bBuf = new BindBuffer();
150 bBuf->type = typeString;
151 bBuf->csql = valBuf;
152 bBuf->length = length;
153 break;
155 default:
156 bBuf = new BindBuffer();
157 bBuf->type = type;
158 bBuf->csql = valBuf;
159 bBuf->length = length;
160 break;
162 bBuf->nullData = (SQLLEN *) malloc(nRecords * sizeof(SQLLEN));
163 for (int i = 0; i < nRecords; i++) bBuf->nullData[i] = SQL_NTS;
164 return bBuf;
168 List SqlStatement::getTableNameList()
170 return pData.getTableNameList();
172 SqlStatement::SqlStatement()
174 innerStmt = NULL;
175 sqlCon = NULL;
176 stmt = NULL;
177 isPrepd = false;
178 isCachedStmt=false;
179 isMgmtStatement = false;
180 sqlStmtString = NULL;
181 dontCache = false;
183 void SqlStatement::setConnection(AbsSqlConnection *conn)
185 sqlCon = (SqlConnection*)conn;
186 con = conn;
189 void SqlStatement::setSqlConnection(SqlConnection *conn)
191 sqlCon = conn;
194 DbRetVal SqlStatement::executeDirect(char *str)
196 DbRetVal rv = OK;
197 int rows = 0;
198 rv = prepare(str);
199 if (rv != OK) return rv;
200 rv = execute(rows);
201 if (rv != OK) return rv;
202 return rv;
205 void SqlStatement::setStmtString(char *ststr)
207 if (sqlStmtString) { ::free(sqlStmtString); sqlStmtString=NULL; }
208 sqlStmtString = (char*) malloc(strlen(ststr)+1);
209 strcpy(sqlStmtString, ststr);
212 DbRetVal SqlStatement::prepare()
214 return prepareInt(sqlStmtString);
217 DbRetVal SqlStatement::prepare(char *stmtstr)
219 if (sqlStmtString) { ::free(sqlStmtString); sqlStmtString=NULL;}
220 sqlStmtString = (char*) malloc(strlen(stmtstr)+1);
221 strcpy(sqlStmtString, stmtstr);
222 return prepareInt(stmtstr);
225 DbRetVal SqlStatement::prepareInt(char *stmtstr)
227 DbRetVal rv = OK;
228 if (! sqlCon->isConnectionOpen()) {
229 printError(ErrNotOpen, "Connection not open");
230 return ErrNotOpen;
232 SqlStatement *cachedStmt = sqlCon->findInCache(stmtstr);
233 if (cachedStmt)
235 *this = *cachedStmt;
236 this->stmt->setParsedData(&this->pData);
237 isCachedStmt=true;
238 logFine(Conf::logger,"GOT STMT FROM CACHE: %s %x", stmtstr, cachedStmt);
239 return OK;
241 // take mutex here
242 int ret = ProcessManager::prepareMutex.tryLock(10, 1000);
243 if (ret != 0)
245 printError(ErrLockTimeOut, "Unable to get prepare mutex");
246 return ErrLockTimeOut;
249 DatabaseManager *dbMgr = sqlCon->getConnObject().getDatabaseManager();
250 if (isPrepared()) free();
251 lexInput = stmtstr;
252 parsedData = &pData;
254 yy_buffer_state *yy_buffer= yy_scan_string(stmtstr);
255 int rc = yyparse();
256 if (yy_buffer) yy_delete_buffer(yy_buffer);
257 if (rc != 0)
259 free();
260 parsedData = NULL;
261 ProcessManager::prepareMutex.releaseLock(-1, false);
262 return ErrSyntaxError;
264 if( parsedData->getStmtType() == MgmtStatement)
266 isPrepd = true;
267 parsedData = NULL;
268 isMgmtStatement = true;
269 ProcessManager::prepareMutex.releaseLock(-1, false);
270 logFine(Conf::logger,"PREPARE: %s %x", stmtstr, stmt);
271 return OK;
273 stmt = StatementFactory::getStatement(parsedData);
274 stmt->setDbMgr(dbMgr);
275 if( parsedData->getStmtType() == UserStatement)
277 UserManager* userMgr = sqlCon->getConnObject().getUserManager();
278 UserTblStatement *ustmt = (UserTblStatement *)stmt;
279 ustmt->setUserManager(userMgr,sqlCon->getConnObject().getUserName());
281 rv = stmt->resolve();
282 if (rv != OK)
284 free();
285 parsedData = NULL;
286 ProcessManager::prepareMutex.releaseLock(-1, false);
287 return rv;
289 isPrepd = true;
290 if (!isCachedStmt && Conf::config.getStmtCacheSize() && !getDontCache()) {
291 if (stmt->noOfParamFields() > 0) {
292 isCachedStmt = true;
293 sqlCon->addToCache(this, stmtstr);
294 } else if (Conf::config.useCacheNoParam()) {
295 if (parsedData->getCacheWorthy()) {
296 isCachedStmt = true;
297 sqlCon->addToCache(this, stmtstr);
300 } else { printf("stmtstring '%s' not cached\n", stmtstr); }
301 parsedData = NULL;
302 ProcessManager::prepareMutex.releaseLock(-1, false);
303 return OK;
306 char* SqlStatement::getTableName()
308 return pData.getTableName();
311 bool SqlStatement::isSelect()
313 if ((pData.getStmtType() == SelectStatement) || (pData.getStmtType() == MetaStatement)) return true;
314 return false;
317 bool SqlStatement::isPrepared() { return isPrepd; }
319 DbRetVal SqlStatement::execute(int &rowsAffected)
321 DbRetVal rv = OK;
322 if (! sqlCon->isConnectionOpen()) {
323 printError(ErrNotOpen, "Connection not open");
324 return ErrNotOpen;
326 if (! isPrepared()) {
327 printError(ErrNotPrepared, "Statement Not Prepared");
328 return ErrNotPrepared;
330 if( isMgmtStatement )
332 flushCacheStmt();
333 logFiner(Conf::logger,"EXECUTE: %x", stmt);
334 return OK;
336 rv = stmt->execute(rowsAffected);
337 if (rv == ErrAlready && pData.getStmtType() == SelectStatement )
338 { //if previous scan is not closed, close it
339 SelStatement *selStmt = (SelStatement*) stmt;
340 selStmt->close();
341 rv = stmt->execute(rowsAffected);
343 logFiner(Conf::logger,"EXECUTE: %x", stmt);
344 return rv;
347 void* SqlStatement::fetch()
349 if (! sqlCon->isConnectionOpen()) {
350 printError(ErrNotOpen, "Connection not open");
351 return NULL;
353 if (! isPrepared()) {
354 printError(ErrNotPrepared, "Statement Not Prepared");
355 return NULL;
357 if (pData.getStmtType() == SelectStatement ) {
358 SelStatement *selStmt = (SelStatement*) stmt;
359 return selStmt->fetch();
361 else if(pData.getStmtType() == MetaStatement){
362 MetadataStatement *metaStmt = (MetadataStatement*) stmt;
363 return metaStmt->fetch();
365 else { return NULL;}
368 void* SqlStatement::fetch(DbRetVal &rv)
370 if (! sqlCon->isConnectionOpen()) {
371 printError(ErrNotOpen, "Connection not open");
372 rv = ErrNoConnection;
373 return NULL;
375 if (! isPrepared()) {
376 printError(ErrNotPrepared, "Statement Not Prepared");
377 return NULL;
379 if (pData.getStmtType() == SelectStatement ) {
380 SelStatement *selStmt = (SelStatement*) stmt;
381 return selStmt->fetch(rv);
383 else if(pData.getStmtType() == MetaStatement){
384 MetadataStatement *metaStmt = (MetadataStatement*) stmt;
385 return metaStmt->fetch(rv);
387 else { return NULL;}
390 void* SqlStatement::fetchAndPrint(bool SQL)
392 if (! sqlCon->isConnectionOpen()) {
393 printError(ErrNotOpen, "Connection not open");
394 return NULL;
396 if (! isPrepared()) {
397 printError(ErrNotPrepared, "Statement Not Prepared");
398 return NULL;
400 if (pData.getStmtType() != SelectStatement) return NULL;
401 SelStatement *selStmt = (SelStatement*) stmt;
402 return selStmt->fetchAndPrint(SQL);
405 DbRetVal SqlStatement::bindParam(int pos, void* value)
407 DbRetVal rv = OK;
408 rv = stmt->setParam(pos, value);
409 return rv;
412 DbRetVal SqlStatement::bindField(int pos, void* value)
414 DbRetVal rv = OK;
415 if (pData.getStmtType() == SelectStatement ) {
416 SelStatement *selStmt = (SelStatement*) stmt;
417 return selStmt->setBindField(pos, value);
419 else if(pData.getStmtType() == MetaStatement){
420 MetadataStatement *metaStmt = (MetadataStatement*) stmt;
421 return metaStmt->setBindField(pos, value);
423 else { return ErrBadCall;}
425 void* SqlStatement::next()
427 if (pData.getStmtType() == SelectStatement ) {
428 SelStatement *selStmt = (SelStatement*) stmt;
429 return( (void*) selStmt->next() );
431 else if(pData.getStmtType() == MetaStatement){
432 MetadataStatement *metaStmt = (MetadataStatement*) stmt;
433 return( (void*) metaStmt->next() );
435 else { return 0;}
438 bool SqlStatement::isFldNull(int pos)
440 if (pData.getStmtType() != SelectStatement) return 0;
441 SelStatement *selStmt = (SelStatement*) stmt;
442 return (selStmt->isFldNull(pos));
444 bool SqlStatement::isFldNull(char *name)
446 if (pData.getStmtType() != SelectStatement) return 0;
447 SelStatement *selStmt = (SelStatement*) stmt;
448 return (selStmt->isFldNull(name));
450 DbRetVal SqlStatement::close()
452 if (pData.getStmtType() == SelectStatement ) {
453 SelStatement *selStmt = (SelStatement*) stmt;
454 logFinest(Conf::logger,"CLOSE: %x", stmt);
455 return selStmt->close();
457 else if(pData.getStmtType() == MetaStatement){
458 MetadataStatement *selStmt = (MetadataStatement*) stmt;
459 logFinest(Conf::logger,"CLOSE: %x", stmt);
460 return selStmt->close();
462 else { return OK;}
465 void* SqlStatement::getParamValuePtr( int pos )
467 //if (pData.getStmtType() != SelectStatement) return 0;
468 DmlStatement *dmlStmt = (DmlStatement*) stmt;
469 return( (void*) dmlStmt->getParamValuePtr( pos ) );
472 char* SqlStatement::getFieldName( int pos )
474 if (pData.getStmtType() == SelectStatement ) {
475 SelStatement *selStmt = (SelStatement*) stmt;
476 return( (char*) selStmt->getFieldName( pos ) );
478 else if(pData.getStmtType() == MetaStatement){
479 MetadataStatement *selStmt = (MetadataStatement*) stmt;
480 return( (char*) selStmt->getFieldName( pos ) );
482 else { return 0;}
485 DataType SqlStatement::getFieldType( int pos )
487 if (pData.getStmtType() == SelectStatement ) {
488 SelStatement *selStmt = (SelStatement*) stmt;
489 return( (DataType) selStmt->getFieldType( pos ) );
491 else if(pData.getStmtType() == MetaStatement){
492 MetadataStatement *selStmt = (MetadataStatement*) stmt;
493 return( (DataType) selStmt->getFieldType( pos ) );
495 else { return typeUnknown;}
497 int SqlStatement::getFieldLength( int pos )
499 if (pData.getStmtType() == SelectStatement ) {
500 SelStatement *selStmt = (SelStatement*) stmt;
501 return( (int) selStmt->getFieldLength( pos ) );
503 else if(pData.getStmtType() == MetaStatement){
504 MetadataStatement *selStmt = (MetadataStatement*) stmt;
505 return( (int) selStmt->getFieldLength( pos ) );
507 else { return 0;}
510 void* SqlStatement::getFieldValuePtr( int pos )
512 if (pData.getStmtType() == SelectStatement ) {
513 SelStatement *selStmt = (SelStatement*) stmt;
514 return( (void*) selStmt->getFieldValuePtr( pos ) );
516 else if(pData.getStmtType() == MetaStatement){
517 MetadataStatement *selStmt = (MetadataStatement*) stmt;
518 return( (void*) selStmt->getFieldValuePtr( pos ) );
520 else { return 0;}
522 void* SqlStatement::getFieldValuePtr( char *name )
524 if (pData.getStmtType() == SelectStatement ) {
525 SelStatement *selStmt = (SelStatement*) stmt;
526 return( (void*) selStmt->getFieldValuePtr( name ) );
528 else if(pData.getStmtType() == MetaStatement){
529 MetadataStatement *selStmt = (MetadataStatement*) stmt;
530 return( (void*) selStmt->getFieldValuePtr( name ) );
532 else { return NULL;}
535 int SqlStatement::noOfProjFields()
537 if (pData.getStmtType() == SelectStatement ) {
538 SelStatement *selStmt = (SelStatement*) stmt;
539 return selStmt->noOfProjFields();
541 else if(pData.getStmtType() == MetaStatement){
542 MetadataStatement *selStmt = (MetadataStatement*) stmt;
543 return selStmt->noOfProjFields();
545 else { return 0;}
548 void SqlStatement::getProjFieldType(int *data)
550 if (pData.getStmtType() == SelectStatement ) {
551 SelStatement *selStmt = (SelStatement*) stmt;
552 return( selStmt->getProjFieldType(data) );
554 else if(pData.getStmtType() == MetaStatement){
555 MetadataStatement *selStmt = (MetadataStatement*) stmt;
556 return( selStmt->getProjFieldType(data) );
562 int SqlStatement::noOfParamFields()
564 if (NULL == stmt) return 0;
565 else return stmt->noOfParamFields();
568 DbRetVal SqlStatement::getProjFldInfo (int projpos, FieldInfo *&fInfo)
570 DbRetVal rv = OK;
571 if (pData.getStmtType() == SelectStatement ) {
572 SelStatement *selStmt = (SelStatement*) stmt;
573 rv = selStmt->getProjFldInfo(projpos, fInfo);
575 else if(pData.getStmtType() == MetaStatement){
576 MetadataStatement *selStmt = (MetadataStatement*) stmt;
577 rv = selStmt->getProjFldInfo(projpos, fInfo);
578 } else { return ErrBadCall;}
579 return rv;
582 DbRetVal SqlStatement::getParamFldInfo (int parampos, FieldInfo *&fInfo)
584 DbRetVal rv = OK;
585 if (pData.getStmtType() ==SelectStatement ||
586 pData.getStmtType() ==InsertStatement ||
587 pData.getStmtType() ==UpdateStatement ||
588 pData.getStmtType() ==DeleteStatement)
591 DmlStatement *dmlStmt = (DmlStatement*) stmt;
592 rv = dmlStmt->getParamFldInfo(parampos, fInfo);
594 return rv;
597 DbRetVal SqlStatement::free()
599 logFinest(Conf::logger,"FREE: %x", stmt);
600 if (isCachedStmt) {
601 stmt=NULL;
602 pData.init();
603 isPrepd = false;
604 if (sqlStmtString) {
605 sqlCon->setStmtNotInUse(sqlStmtString);
606 ::free(sqlStmtString); sqlStmtString=NULL;
608 isCachedStmt = false;
609 return OK;
611 if(stmt) delete stmt;
612 stmt = NULL;
613 pData.reset();
614 isMgmtStatement = false;
615 isPrepd = false;
616 isCachedStmt = false;
617 if (sqlStmtString) { ::free(sqlStmtString); sqlStmtString=NULL; }
618 return OK;
621 void SqlStatement::setNull(int pos)
623 stmt->setNull(pos);
625 void SqlStatement::setShortParam(int paramPos, short value)
627 stmt->setShortParam(paramPos, value);
629 void SqlStatement::setIntParam(int paramPos, int value)
631 stmt->setIntParam(paramPos, value);
633 void SqlStatement::setLongParam(int paramPos, long value)
635 stmt->setLongParam(paramPos, value);
637 void SqlStatement::setLongLongParam(int paramPos, long long value)
639 stmt->setLongLongParam(paramPos, value);
641 void SqlStatement::setByteIntParam(int paramPos, ByteInt value)
643 stmt->setByteIntParam(paramPos, value);
645 void SqlStatement::setFloatParam(int paramPos, float value)
647 stmt->setFloatParam(paramPos, value);
649 void SqlStatement::setDoubleParam(int paramPos, double value)
651 stmt->setDoubleParam(paramPos, value);
653 void SqlStatement::setStringParam(int paramPos, char *value)
655 stmt->setStringParam(paramPos, value);
657 void SqlStatement::setDateParam(int paramPos, Date value)
659 stmt->setDateParam(paramPos, value);
661 void SqlStatement::setTimeParam(int paramPos, Time value)
663 stmt->setTimeParam(paramPos, value);
665 void SqlStatement::setTimeStampParam(int paramPos, TimeStamp value)
667 stmt->setTimeStampParam(paramPos, value);
669 void SqlStatement::setBinaryParam(int paramPos, void *value, int length)
671 stmt->setBinaryParam(paramPos, value, length);
673 int SqlStatement::getFldPos(char *name)
675 return stmt->getFldPos(name);
677 long long SqlStatement::getLastInsertedVal(DbRetVal &rv)
679 return stmt->getLastInsertedVal(rv);
681 List SqlStatement::getAllTableNames(DbRetVal &ret)
683 DatabaseManager *dbMgr = NULL;
684 List tbNmList;
685 dbMgr=sqlCon->getConnObject().getDatabaseManager();
686 int rv = ret;
687 if(dbMgr != NULL) tbNmList = dbMgr->getAllTableNames(&rv);
688 ret = (DbRetVal) rv;
689 return tbNmList;
692 List SqlStatement::getAllUserNames(DbRetVal &ret)
694 UserManager *urMgr = NULL;
695 List urNmList;
696 urMgr=sqlCon->getConnObject().getUserManager();
697 int rv = ret;
698 if(urMgr != NULL)
699 urNmList = urMgr->getAllUserNames(&rv);
700 ret = (DbRetVal) rv;
701 return urNmList;
703 List SqlStatement::getFieldNameList(const char *tblName, DbRetVal &rv)
705 List fldNameList;
706 if (isPrepared()) {
707 fldNameList = stmt->getFieldNameList(tblName, rv);
708 return fldNameList;
710 DatabaseManager *dbMgr = sqlCon->getConnObject().getDatabaseManager();
711 Table *table = dbMgr->openTable(tblName);
712 if (NULL == table) {
713 List dummyList;
714 printError(ErrLockTimeOut, "Unable to open table %s", tblName);
715 return dummyList;
717 fldNameList = table->getFieldNameList();
718 dbMgr->closeTable(table);
719 return fldNameList;
721 DbRetVal SqlStatement::getFieldInfo(const char *tblName, const char *fldName, FieldInfo *&info)
723 DbRetVal rv = OK;
724 if (isPrepared()) {
725 rv = stmt->getFieldInfo(tblName, fldName, info);
726 return rv;
728 DatabaseManager *dbMgr = sqlCon->getConnObject().getDatabaseManager();
729 Table *table = dbMgr->openTable(tblName);
730 if (NULL == table) {
731 printError(ErrLockTimeOut, "Unable to open table %s", tblName);
732 return ErrLockTimeOut;
734 rv = table->getFieldInfo(fldName, info);
735 dbMgr->closeTable(table);
736 return rv;
738 void SqlStatement::setLoading(bool flag)
740 if (pData.getStmtType() == InsertStatement||
741 pData.getStmtType() == UpdateStatement||
742 pData.getStmtType() == DeleteStatement)
744 DmlStatement *dmlStmt = (DmlStatement*) stmt;
745 dmlStmt->setLoading(flag);
747 return;
750 int SqlStatement::getNoOfPagesForTable(char *tblName)
752 DatabaseManager *dbMgr = sqlCon->getConnObject().getDatabaseManager();
753 DatabaseManagerImpl *dbMgrImpl = (DatabaseManagerImpl *)dbMgr;
754 return dbMgrImpl->getNoOfPagesForTable(tblName);
757 DbRetVal SqlStatement::loadRecords(char *tblName, void *buf)
759 DatabaseManager *dbMgr = sqlCon->getConnObject().getDatabaseManager();
760 DatabaseManagerImpl *dbMgrImpl = (DatabaseManagerImpl *)dbMgr;
761 return dbMgrImpl->loadRecords(tblName, (char *) buf);
764 DbRetVal SqlStatement::pasteRecords(char *tblName, void *buffer)
766 DatabaseManager *dbMgr = sqlCon->getConnObject().getDatabaseManager();
767 DatabaseManagerImpl *dbMgrImpl = (DatabaseManagerImpl *)dbMgr;
768 return dbMgrImpl->pasteRecords(tblName, buffer);
770 void SqlStatement::flushCacheStmt()
772 return sqlCon->flushCacheStmt();
775 void SqlStatement::resetStmtString() {
776 sqlStmtString=NULL;
778 //-------------------------------------------------------------------
780 static void sigTermHandler(int sig)
782 ListIterator iter= SqlConnection::connList.getIterator();
783 SqlConnection *conn = NULL;
784 while (iter.hasElement())
786 conn = (SqlConnection*) iter.nextElement();
787 conn->flushCacheStmt();
788 if (conn->isConnectionOpen()) conn->disconnect();
790 exit(0);
793 DbRetVal SqlConnection::connect (char *user, char * pass)
795 DbRetVal ret = conn.open(user, pass);
796 if (ret != OK) return ret;
797 if (ret == OK) isConnOpen = true;
798 if (!isInit) initialize();
799 connList.append(this);
800 DbRetVal rv = OK;
801 #if (defined MMDB && EMBED)
802 os::signal(SIGINT, sigTermHandler);
803 os::signal(SIGTERM, sigTermHandler);
804 if (Conf::config.useDurability() && !firstThread) {
805 rv = recoverCsqlDB();
806 if (rv != OK) {
807 printError(ErrSysInternal, "Recovery Failed");
808 return rv;
810 firstThread = true;
812 rollback(); //for drop table execute in redo log
813 #endif
814 return ret;
817 void SqlConnection::flushCacheStmt()
819 ListIterator iter = cachedStmts.getIterator();
820 while (iter.hasElement()) {
821 CachedStmtNode* node = (CachedStmtNode*) iter.nextElement();
822 //do not delete when the statement is currently in use.
823 //otherwise it leads to illegal memory access when application
824 //calls any method on this statement
825 if (node->inUse) continue;
826 //if (node->inUse) node->inUse = 0;
827 free(node->sqlString);
828 node->sqlStmt->setCachedStmt(false);
829 node->sqlStmt->free();
830 delete node->sqlStmt;
831 delete node;
833 cachedStmts.reset();
834 return;
837 void SqlConnection::setStmtNotInUse(char *stmtstr)
839 ListIterator iter = cachedStmts.getIterator();
840 int inputStmtLen = strlen(stmtstr);
841 CachedStmtNode *node = NULL;
842 while ((node = (CachedStmtNode*)iter.nextElement()) != NULL)
844 if (node->stmtLength == inputStmtLen)
846 if (0 == strcmp(node->sqlString, stmtstr))
848 node->inUse =0;
849 return;
855 SqlStatement* SqlConnection::findInCache(char *stmtstr)
857 ListIterator iter = cachedStmts.getIterator();
858 int inputStmtLen = strlen(stmtstr);
859 CachedStmtNode *node = NULL;
860 while ((node = (CachedStmtNode*)iter.nextElement()) != NULL)
862 if (node->stmtLength == inputStmtLen)
864 if (0 == strcmp(node->sqlString, stmtstr))
866 logFiner(Conf::logger, "Statement Retrieved From Cache %x\n",
867 node->sqlStmt);
868 node->hits++;
869 node->inUse = 1;
870 return node->sqlStmt;
874 return NULL;
877 void SqlConnection::addToCache(SqlStatement *sqlStmt, char* stmtString)
879 SqlStatement *stmt = new SqlStatement();
880 *stmt= *sqlStmt;
881 CachedStmtNode *node = new CachedStmtNode();
882 node->sqlStmt = stmt;
883 node->stmtLength = strlen(stmtString);
884 node->sqlString = (char*)malloc(node->stmtLength+1);
885 node->inUse=1;
886 strcpy(node->sqlString, stmtString);
887 if (cachedStmts.size() >= Conf::config.getStmtCacheSize())
889 removeLeastUsed();
891 node->sqlStmt->resetStmtString();
892 cachedStmts.append(node);
893 logFiner(Conf::logger, "Statement added To Cache %x\n", node->sqlStmt);
894 logFinest(Conf::logger, "Statement added To Cache %s\n", node->sqlString);
895 return ;
898 void SqlConnection::removeLeastUsed()
900 ListIterator iter = cachedStmts.getIterator();
901 CachedStmtNode *node = NULL, *toRemove =NULL;
902 int lowHits = 0;
903 bool firstCall = true;
904 while((node = (CachedStmtNode*) iter.nextElement()) != NULL)
906 if (firstCall) {
907 firstCall = false;
908 lowHits = node->hits;
909 toRemove = node; //if cache size is 1
910 continue;
912 if (lowHits >= node->hits) toRemove = node;
914 cachedStmts.remove(toRemove);
915 //TODO::check whether there is memory leak for list elements
916 logFiner(Conf::logger, "Statement removed from Cache %x\n", toRemove->sqlStmt);
917 logFinest(Conf::logger, "Statement removed from Cache %s\n", toRemove->sqlString);
918 delete toRemove; toRemove = NULL;
919 return;
922 SqlConnection::~SqlConnection()
924 flushCacheStmt();
925 if (isConnOpen) disconnect();
926 innerConn = NULL;
929 static void sigUsr1Handler(int sig)
931 ListIterator iter= SqlConnection::connList.getIterator();
932 SqlConnection *conn = NULL;
933 while (iter.hasElement())
935 conn = (SqlConnection*) iter.nextElement();
936 conn->flushCacheStmt();
938 os::signal(SIGCSQL1, sigUsr1Handler);
939 return;
942 static void exithandler(void)
944 ListIterator iter= SqlConnection::connList.getIterator();
945 SqlConnection *conn = NULL;
946 while (iter.hasElement())
948 conn = (SqlConnection*) iter.nextElement();
949 conn->flushCacheStmt();
950 conn->disconnect();
953 void SqlConnection::displayStmtCache()
955 ListIterator iter = cachedStmts.getIterator();
956 CachedStmtNode *node = NULL;
957 printf("STATEMENT CACHE START \n");
958 while ((node = (CachedStmtNode*)iter.nextElement()) != NULL)
960 node->display();
962 printf("STATEMENT CACHE END\n");
965 void SqlConnection::initialize()
967 os::signal(SIGCSQL1, sigUsr1Handler);
968 #if (defined MMDB && defined EMBED)
969 os::atexit(exithandler);
970 #endif
971 isInit = true;
974 #if (defined MMDB && defined EMBED)
976 DbRetVal SqlConnection::recoverCsqlDB()
978 DbRetVal rv = OK;
979 char dbRedoFileName[MAX_FILE_LEN];
980 char dbChkptSchema[MAX_FILE_LEN];
981 char dbChkptMap[MAX_FILE_LEN];
982 char dbChkptData[MAX_FILE_LEN];
983 char dbBackupFile[MAX_FILE_LEN];
984 char cmd[IDENTIFIER_LENGTH];
985 //check for check point file if present recover
986 sprintf(dbChkptSchema, "%s/db.chkpt.schema1", Conf::config.getDbFile());
987 if (FILE *file = fopen(dbChkptSchema, "r")) {
988 fclose(file);
989 sprintf(cmd, "cp -f %s %s/db.chkpt.schema", dbChkptSchema,
990 Conf::config.getDbFile());
991 int ret = system(cmd);
992 if (ret != 0) return ErrOS;
994 sprintf(dbChkptMap, "%s/db.chkpt.map1", Conf::config.getDbFile());
995 if (FILE *file = fopen(dbChkptMap, "r")) {
996 fclose(file);
997 sprintf(cmd, "cp -f %s %s/db.chkpt.map", dbChkptMap,
998 Conf::config.getDbFile());
999 int ret = system(cmd);
1000 if (ret != 0) return ErrOS;
1002 int chkptID= Database::getCheckpointID();
1003 sprintf(dbChkptData, "%s/db.chkpt.data%d", Conf::config.getDbFile(),
1004 chkptID);
1005 sprintf(dbBackupFile, "%s/db.chkpt.data1", Conf::config.getDbFile());
1006 FILE *fl = NULL;
1007 if (!Conf::config.useMmap() && (fl = fopen(dbBackupFile, "r"))) {
1008 fclose(fl);
1009 sprintf(cmd, "cp %s/db.chkpt.data1 %s", Conf::config.getDbFile(),
1010 dbChkptData);
1011 int ret = system(cmd);
1012 if (ret != 0) return ErrOS;
1014 if (FILE *file = fopen(dbChkptData, "r")) {
1015 fclose(file);
1016 rv = recoverSystemAndUserDB();
1017 if (rv != OK) return rv;
1020 //check for redo log file if present apply redo logs
1021 sprintf(dbRedoFileName, "%s/csql.db.cur", Conf::config.getDbFile());
1022 if (FILE *file = fopen(dbRedoFileName, "r"))
1024 fclose(file);
1025 rv = (DbRetVal) applyRedoLogs(dbRedoFileName);
1026 if (rv != OK) return rv;
1027 DatabaseManager *dbMgr = getConnObject().getDatabaseManager();
1028 rv = dbMgr->checkPoint();
1029 if (rv != OK)
1031 printError(ErrSysInternal, "checkpoint failed after redo log apply");
1032 return ErrOS;
1035 return OK;
1038 DbRetVal SqlConnection::recoverSystemAndUserDB()
1040 DbRetVal rv = OK;
1041 char schFile[1024];
1042 sprintf(schFile, "%s/db.chkpt.schema", Conf::config.getDbFile());
1043 if (FILE *file = fopen(schFile, "r")) {
1044 rv = applySchemaFile(file);
1045 if (rv != OK) { fclose(file); return rv; }
1047 DatabaseManager *dbMgr = getConnObject().getDatabaseManager();
1048 rv = dbMgr->recover();
1049 return rv;
1052 DbRetVal SqlConnection::applySchemaFile(FILE *fp)
1054 char buf[8192];
1055 char eof;
1056 DbRetVal rv = OK;
1057 SqlStatement *stmt = new SqlStatement();
1058 while ((eof = getQueryFromSchemaFile(fp,buf)) != EOF) {
1059 stmt->setConnection(this);
1060 rv = stmt->prepare(buf);
1061 if (rv != OK) { delete stmt; return rv; }
1062 int rows = 0;
1063 stmt->execute(rows);
1064 if (rv != OK) { stmt->free(); delete stmt; return rv; }
1066 delete stmt;
1067 return OK;
1070 char SqlConnection::getQueryFromSchemaFile(FILE *fp, char *buf)
1072 char c, *bufBegin=buf;
1073 int charCnt=0;
1074 while( (c=(char ) fgetc(fp)) != EOF && c != ';')
1076 *buf++ = c; charCnt++;
1077 if( charCnt == SQL_STMT_LEN ) {
1078 printf("SQL Statement length is greater than %d. "
1079 "Ignoring the statement.\n", SQL_STMT_LEN );
1080 *bufBegin++ =';';
1081 *bufBegin ='\0';
1082 return 0;
1085 *buf++ = ';';
1086 *buf = '\0';
1087 return c;
1090 int SqlConnection::applyRedoLogs(char *redoFile)
1092 struct stat st;
1093 DbRetVal rv = OK;
1094 int fd = open(redoFile, O_RDONLY);
1095 if (-1 == fd) { return OK; }
1096 if (fstat(fd, &st) == -1) {
1097 printError(ErrSysInternal, "Unable to retrieve undo log file size");
1098 close(fd);
1099 return 1;
1101 if (st.st_size ==0) {
1102 printError(ErrNote, "No Redo logs found during recovery");
1103 SqlStatement::readAndPopulateStmts(this, stmtBuckets);
1104 close(fd);
1105 return OK;
1107 void *startAddr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
1108 if (MAP_FAILED == startAddr) {
1109 printf("Unable to read undo log file:mmap failed.\n");
1110 return 2;
1113 rv = SqlStatement::readAndPopulateStmts(this, stmtBuckets);
1114 if (OK != rv)
1116 printf("Unable to read stmt log file\n");
1117 return 2;
1120 char *iter = (char*)startAddr;
1121 void *value = NULL;
1122 int logType, eType;
1123 int stmtID;
1124 int txnID;
1125 int len, ret, retVal =0;
1126 int loglen;
1127 char stmtString[SQL_STMT_LEN];
1128 while(true) {
1129 if (iter - (char*)startAddr >= st.st_size) break;
1130 logType = *(int*)iter;
1131 if (logType == -1) { //prepare
1132 iter = iter + sizeof(int);
1133 txnID = *(int*) iter; iter += sizeof(int);
1134 loglen = *(int*) iter; iter += sizeof(int);
1135 stmtID = *(int*)iter;
1136 iter = iter + sizeof(int);
1137 len = *(int*)iter;
1138 iter = iter + sizeof(int);
1139 strncpy(stmtString, iter, len);
1140 iter = iter + len;
1141 AbsSqlStatement *stmt = SqlFactory::createStatement(CSqlDirect);
1142 SqlStatement *sqlStmt = (SqlStatement *)stmt;
1143 stmt->setConnection(this);
1144 rv = stmt->prepare(stmtString);
1145 if (rv != OK) {
1146 printError(ErrSysInternal, "unable to prepare stmt:%s", stmtString);
1147 retVal=1;
1148 break;
1150 sqlStmt->setLoading(true);
1151 SqlStatement::addToHashTable(stmtID, stmt, stmtBuckets, stmtString);
1153 else if(logType == -2) { //commit
1154 beginTrans();
1155 iter = iter + sizeof(int);
1156 txnID = *(int*) iter; iter += sizeof(int);
1157 loglen = *(int*) iter; iter += sizeof(int);
1158 char *curPtr = iter;
1159 while(true) {
1160 if (iter - (char*)startAddr >= st.st_size) {
1161 //file end reached
1162 retVal=0;
1163 break;
1165 stmtID = *(int*)iter;
1166 iter = iter + sizeof(int);
1167 eType = *(int*)iter;
1168 AbsSqlStatement *stmt =
1169 SqlStatement::getStmtFromHashTable(stmtID,stmtBuckets);
1170 if (NULL == stmt) {
1171 printError(ErrSysInternal,
1172 "Unable to find in stmt hashtable");
1173 retVal=2;
1174 break;
1176 if (0 == eType) { //execute type
1177 iter = iter + sizeof(int);
1178 rv = stmt->execute(ret);
1179 if (rv != OK) {
1180 printError(ErrSysInternal, "unable to execute");
1181 retVal=2;
1182 break;
1184 if (*(int*)iter <0) break;
1185 } else if ( 1 == eType) { //set type
1186 iter=iter+sizeof(int);
1187 int pos = *(int*) iter;
1188 iter=iter+sizeof(int);
1189 int isNull = *(int *)iter;
1190 iter = iter + sizeof(int);
1191 if (isNull == 0) {
1192 DataType type = (DataType)(*(int*)iter);
1193 iter=iter+sizeof(int);
1194 int len = *(int*) iter;
1195 iter=iter+sizeof(int);
1196 value = iter;
1197 iter=iter+len;
1198 SqlStatement::setParamValues(stmt, pos,
1199 type, len, value);
1200 } else stmt->setNull(pos);
1201 if (*(int*)iter <0) break;
1204 commit();
1206 else if(logType == -3) { //free
1207 iter = iter + sizeof(int);
1208 txnID = *(int*) iter; iter += sizeof(int);
1209 loglen = *(int*) iter; iter += sizeof(int);
1210 stmtID = *(int*)iter;
1211 iter = iter + sizeof(int);
1212 AbsSqlStatement *stmt = SqlStatement::getStmtFromHashTable(stmtID,
1213 stmtBuckets);
1214 if (stmt) {
1215 stmt->free();
1216 SqlStatement::removeFromHashTable(stmtID,stmtBuckets);
1217 } else { printError(ErrSysInternal, "statement not found for %d\n",stmtID);}
1219 else if(logType == -4) { //prepare and execute
1220 iter = iter + sizeof(int);
1221 txnID = *(int*) iter; iter += sizeof(int);
1222 loglen = *(int*) iter; iter += sizeof(int);
1223 stmtID = *(int*)iter;
1224 iter = iter + sizeof(int);
1225 len = *(int*)iter;
1226 iter = iter + sizeof(int);
1227 strncpy(stmtString, iter, len);
1228 stmtString[len+1] ='\0';
1229 iter = iter + len;
1230 AbsSqlStatement *stmt = SqlFactory::createStatement(CSqlDirect);
1231 if ( NULL == stmt) {
1232 printError(ErrSysInternal, "unable to prepare:%s", stmtString);
1233 retVal=3;
1234 break;
1236 stmt->setConnection(this);
1237 rv = stmt->prepare(stmtString);
1238 if (rv != OK) {
1239 printError(ErrSysInternal, "unable to prepare:%s", stmtString);
1240 retVal=4;
1241 break;
1243 rv = stmt->execute(ret);
1244 if (rv != OK) {
1245 if (strlen(stmtString) > 6 &&
1246 ( (strncasecmp(stmtString,"CREATE", 6) == 0) ||
1247 (strncasecmp(stmtString,"DROP", 4) == 0) ||
1248 (strncasecmp(stmtString,"RENAME", 6) == 0) ||
1249 (strncasecmp(stmtString,"ALTER", 5) == 0) )) {
1250 continue;
1252 printError(ErrSysInternal, "unable to execute %s", stmtString);
1253 retVal=5;
1254 break;
1256 stmt->free();
1257 }else{
1258 printError(ErrSysInternal, "Redo log file corrupted: logType:%d", logType);
1259 retVal=6;
1260 break;
1263 munmap((char*)startAddr, st.st_size);
1264 close(fd);
1265 SqlStatement::filterAndWriteStmtLogs(stmtBuckets);
1266 SqlStatement::freeAllStmtHandles(stmtBuckets);
1267 return retVal;
1269 #endif