statement caching for select statement with no parameter and with predicates. Bu
[csql.git] / src / sql / SqlStatement.cxx
blob737e57f80e59ddb9162f68ca412971ced78fb711
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 ();
30 SqlStatement::~SqlStatement()
32 if (isPrepd) { free(); isPrepd = false; }
35 List SqlStatement::getTableNameList()
37 return pData.getTableNameList();
39 SqlStatement::SqlStatement()
41 innerStmt = NULL;
42 sqlCon = NULL;
43 stmt = NULL;
44 isPrepd = false;
45 isCachedStmt=false;
46 isMgmtStatement = false;
48 void SqlStatement::setConnection(AbsSqlConnection *conn)
50 sqlCon = (SqlConnection*)conn;
51 con = conn;
54 void SqlStatement::setSqlConnection(SqlConnection *conn)
56 sqlCon = conn;
59 DbRetVal SqlStatement::executeDirect(char *str)
61 DbRetVal rv = OK;
62 int rows = 0;
63 rv = prepare(str);
64 if (rv != OK) return rv;
65 rv = execute(rows);
66 if (rv != OK) return rv;
67 return rv;
70 DbRetVal SqlStatement::prepare(char *stmtstr)
72 DbRetVal rv = OK;
73 if (! sqlCon->isConnectionOpen()) {
74 printError(ErrNotOpen, "Connection not open");
75 return ErrNotOpen;
77 SqlStatement *cachedStmt = sqlCon->findInCache(stmtstr);
78 if (cachedStmt)
80 *this = *cachedStmt;
81 this->stmt->setParsedData(&this->pData);
82 logFine(Conf::logger,"GOT STMT FROM CACHE: %s %x", stmtstr, cachedStmt);
83 return OK;
85 // take mutex here
86 DatabaseManager *dbMgr = sqlCon->getConnObject().getDatabaseManager();
87 Database *sysdb = ((DatabaseManagerImpl *)dbMgr)->sysDb();
88 int tries = Conf::config.getMutexRetries();
89 struct timeval timeout;
90 timeout.tv_sec = Conf::config.getMutexSecs();
91 timeout.tv_usec = Conf::config.getMutexUSecs();
93 while (true) {
94 rv = sysdb->getPrepareStmtMutex();
95 if (rv == OK) break;
96 tries--;
97 if (tries == 0) {
98 printError(rv,
99 "Unable to get prepare statement mutex after %d tries", Conf::config.getMutexRetries());
100 return rv;
102 os::select(0, 0, 0, 0, &timeout);
105 if (isPrepared()) free();
106 lexInput = stmtstr;
107 parsedData = &pData;
109 yy_buffer_state *yy_buffer= yy_scan_string(stmtstr);
110 int rc = yyparse();
111 if (yy_buffer) yy_delete_buffer(yy_buffer);
112 if (rc != 0)
114 free();
115 parsedData = NULL;
116 //yyrestart(yyin);
117 sysdb->releasePrepareStmtMutex();
118 return ErrSyntaxError;
120 if( parsedData->getStmtType() == MgmtStatement)
122 isPrepd = true;
123 parsedData = NULL;
124 isMgmtStatement = true;
125 sysdb->releasePrepareStmtMutex();
126 logFine(Conf::logger,"PREPARE: %s %x", stmtstr, stmt);
127 return OK;
129 stmt = StatementFactory::getStatement(parsedData);
130 stmt->setDbMgr(dbMgr);
131 if( parsedData->getStmtType() == UserStatement)
133 UserManager* userMgr = sqlCon->getConnObject().getUserManager();
134 UserTblStatement *ustmt = (UserTblStatement *)stmt;
135 ustmt->setUserManager(userMgr,sqlCon->getConnObject().getUserName());
137 rv = stmt->resolve();
138 if (rv != OK)
140 free();
141 parsedData = NULL;
142 //yyrestart(yyin);
143 sysdb->releasePrepareStmtMutex();
144 return rv;
146 parsedData = NULL;
147 //yyrestart(yyin);
148 sysdb->releasePrepareStmtMutex();
149 isPrepd = true;
150 if (Conf::config.getStmtCacheSize()) {
151 if (stmt->noOfParamFields() > 0) {
152 isCachedStmt = true;
153 sqlCon->addToCache(this, stmtstr);
154 return OK;
156 if (Conf::config.useCacheNoParam())
158 if (parsedData->getCacheWorthy())
160 isCachedStmt = true;
161 sqlCon->addToCache(this, stmtstr);
162 return OK;
166 return OK;
169 char* SqlStatement::getTableName()
171 return pData.getTableName();
174 bool SqlStatement::isSelect()
176 if ((pData.getStmtType() == SelectStatement) || (pData.getStmtType() == MetaStatement)) return true;
177 return false;
180 bool SqlStatement::isPrepared() { return isPrepd; }
182 DbRetVal SqlStatement::execute(int &rowsAffected)
184 DbRetVal rv = OK;
185 if (! sqlCon->isConnectionOpen()) {
186 printError(ErrNotOpen, "Connection not open");
187 return ErrNotOpen;
189 if (! isPrepared()) {
190 printError(ErrNotPrepared, "Statement Not Prepared");
191 return ErrNotPrepared;
193 if( isMgmtStatement )
195 flushCacheStmt();
196 logFiner(Conf::logger,"EXECUTE: %x", stmt);
197 return OK;
199 rv = stmt->execute(rowsAffected);
200 if (rv == ErrAlready && pData.getStmtType() == SelectStatement )
201 { //if previous scan is not closed, close it
202 SelStatement *selStmt = (SelStatement*) stmt;
203 selStmt->close();
204 rv = stmt->execute(rowsAffected);
206 logFiner(Conf::logger,"EXECUTE: %x", stmt);
207 return rv;
210 void* SqlStatement::fetch()
212 if (! sqlCon->isConnectionOpen()) {
213 printError(ErrNotOpen, "Connection not open");
214 return NULL;
216 if (! isPrepared()) {
217 printError(ErrNotPrepared, "Statement Not Prepared");
218 return NULL;
220 if (pData.getStmtType() == SelectStatement ) {
221 SelStatement *selStmt = (SelStatement*) stmt;
222 return selStmt->fetch();
224 else if(pData.getStmtType() == MetaStatement){
225 MetadataStatement *metaStmt = (MetadataStatement*) stmt;
226 return metaStmt->fetch();
228 else { return NULL;}
231 void* SqlStatement::fetch(DbRetVal &rv)
233 if (! sqlCon->isConnectionOpen()) {
234 printError(ErrNotOpen, "Connection not open");
235 return NULL;
237 if (! isPrepared()) {
238 printError(ErrNotPrepared, "Statement Not Prepared");
239 return NULL;
241 if (pData.getStmtType() == SelectStatement ) {
242 SelStatement *selStmt = (SelStatement*) stmt;
243 return selStmt->fetch(rv);
245 else if(pData.getStmtType() == MetaStatement){
246 MetadataStatement *metaStmt = (MetadataStatement*) stmt;
247 return metaStmt->fetch(rv);
249 else { return NULL;}
252 void* SqlStatement::fetchAndPrint(bool SQL)
254 if (! sqlCon->isConnectionOpen()) {
255 printError(ErrNotOpen, "Connection not open");
256 return NULL;
258 if (! isPrepared()) {
259 printError(ErrNotPrepared, "Statement Not Prepared");
260 return NULL;
262 if (pData.getStmtType() != SelectStatement) return NULL;
263 SelStatement *selStmt = (SelStatement*) stmt;
264 return selStmt->fetchAndPrint(SQL);
267 DbRetVal SqlStatement::bindParam(int pos, void* value)
269 DbRetVal rv = OK;
270 rv = stmt->setParam(pos, value);
271 return rv;
274 DbRetVal SqlStatement::bindField(int pos, void* value)
276 DbRetVal rv = OK;
277 if (pData.getStmtType() == SelectStatement ) {
278 SelStatement *selStmt = (SelStatement*) stmt;
279 return selStmt->setBindField(pos, value);
281 else if(pData.getStmtType() == MetaStatement){
282 MetadataStatement *metaStmt = (MetadataStatement*) stmt;
283 return metaStmt->setBindField(pos, value);
285 else { return ErrBadCall;}
287 void* SqlStatement::next()
289 if (pData.getStmtType() == SelectStatement ) {
290 SelStatement *selStmt = (SelStatement*) stmt;
291 return( (void*) selStmt->next() );
293 else if(pData.getStmtType() == MetaStatement){
294 MetadataStatement *metaStmt = (MetadataStatement*) stmt;
295 return( (void*) metaStmt->next() );
297 else { return 0;}
300 bool SqlStatement::isFldNull(int pos)
302 if (pData.getStmtType() != SelectStatement) return 0;
303 SelStatement *selStmt = (SelStatement*) stmt;
304 return (selStmt->isFldNull(pos));
306 bool SqlStatement::isFldNull(char *name)
308 if (pData.getStmtType() != SelectStatement) return 0;
309 SelStatement *selStmt = (SelStatement*) stmt;
310 return (selStmt->isFldNull(name));
312 DbRetVal SqlStatement::close()
314 if (pData.getStmtType() == SelectStatement ) {
315 SelStatement *selStmt = (SelStatement*) stmt;
316 logFinest(Conf::logger,"CLOSE: %x", stmt);
317 return selStmt->close();
319 else if(pData.getStmtType() == MetaStatement){
320 MetadataStatement *selStmt = (MetadataStatement*) stmt;
321 logFinest(Conf::logger,"CLOSE: %x", stmt);
322 return selStmt->close();
324 else { return OK;}
327 void* SqlStatement::getParamValuePtr( int pos )
329 //if (pData.getStmtType() != SelectStatement) return 0;
330 DmlStatement *dmlStmt = (DmlStatement*) stmt;
331 return( (void*) dmlStmt->getParamValuePtr( pos ) );
334 char* SqlStatement::getFieldName( int pos )
336 if (pData.getStmtType() == SelectStatement ) {
337 SelStatement *selStmt = (SelStatement*) stmt;
338 return( (char*) selStmt->getFieldName( pos ) );
340 else if(pData.getStmtType() == MetaStatement){
341 MetadataStatement *selStmt = (MetadataStatement*) stmt;
342 return( (char*) selStmt->getFieldName( pos ) );
344 else { return 0;}
347 DataType SqlStatement::getFieldType( int pos )
349 if (pData.getStmtType() == SelectStatement ) {
350 SelStatement *selStmt = (SelStatement*) stmt;
351 return( (DataType) selStmt->getFieldType( pos ) );
353 else if(pData.getStmtType() == MetaStatement){
354 MetadataStatement *selStmt = (MetadataStatement*) stmt;
355 return( (DataType) selStmt->getFieldType( pos ) );
357 else { return typeUnknown;}
359 int SqlStatement::getFieldLength( int pos )
361 if (pData.getStmtType() == SelectStatement ) {
362 SelStatement *selStmt = (SelStatement*) stmt;
363 return( (int) selStmt->getFieldLength( pos ) );
365 else if(pData.getStmtType() == MetaStatement){
366 MetadataStatement *selStmt = (MetadataStatement*) stmt;
367 return( (int) selStmt->getFieldLength( pos ) );
369 else { return 0;}
372 void* SqlStatement::getFieldValuePtr( int pos )
374 if (pData.getStmtType() == SelectStatement ) {
375 SelStatement *selStmt = (SelStatement*) stmt;
376 return( (void*) selStmt->getFieldValuePtr( pos ) );
378 else if(pData.getStmtType() == MetaStatement){
379 MetadataStatement *selStmt = (MetadataStatement*) stmt;
380 return( (void*) selStmt->getFieldValuePtr( pos ) );
382 else { return 0;}
384 void* SqlStatement::getFieldValuePtr( char *name )
386 if (pData.getStmtType() == SelectStatement ) {
387 SelStatement *selStmt = (SelStatement*) stmt;
388 return( (void*) selStmt->getFieldValuePtr( name ) );
390 else if(pData.getStmtType() == MetaStatement){
391 MetadataStatement *selStmt = (MetadataStatement*) stmt;
392 return( (void*) selStmt->getFieldValuePtr( name ) );
394 else { return NULL;}
397 int SqlStatement::noOfProjFields()
399 if (pData.getStmtType() == SelectStatement ) {
400 SelStatement *selStmt = (SelStatement*) stmt;
401 return selStmt->noOfProjFields();
403 else if(pData.getStmtType() == MetaStatement){
404 MetadataStatement *selStmt = (MetadataStatement*) stmt;
405 return selStmt->noOfProjFields();
407 else { return 0;}
410 void SqlStatement::getProjFieldType(int *data)
412 if (pData.getStmtType() == SelectStatement ) {
413 SelStatement *selStmt = (SelStatement*) stmt;
414 return( selStmt->getProjFieldType(data) );
416 else if(pData.getStmtType() == MetaStatement){
417 MetadataStatement *selStmt = (MetadataStatement*) stmt;
418 return( selStmt->getProjFieldType(data) );
424 int SqlStatement::noOfParamFields()
426 return stmt->noOfParamFields();
429 DbRetVal SqlStatement::getProjFldInfo (int projpos, FieldInfo *&fInfo)
431 DbRetVal rv = OK;
432 if (pData.getStmtType() == SelectStatement ) {
433 SelStatement *selStmt = (SelStatement*) stmt;
434 rv = selStmt->getProjFldInfo(projpos, fInfo);
436 else if(pData.getStmtType() == MetaStatement){
437 MetadataStatement *selStmt = (MetadataStatement*) stmt;
438 rv = selStmt->getProjFldInfo(projpos, fInfo);
439 } else { return ErrBadCall;}
440 return rv;
443 DbRetVal SqlStatement::getParamFldInfo (int parampos, FieldInfo *&fInfo)
445 DbRetVal rv = OK;
446 if (pData.getStmtType() ==SelectStatement ||
447 pData.getStmtType() ==InsertStatement ||
448 pData.getStmtType() ==UpdateStatement ||
449 pData.getStmtType() ==DeleteStatement)
452 DmlStatement *dmlStmt = (DmlStatement*) stmt;
453 rv = dmlStmt->getParamFldInfo(parampos, fInfo);
455 return rv;
458 DbRetVal SqlStatement::free()
460 logFinest(Conf::logger,"FREE: %x", stmt);
461 if (isCachedStmt) {
462 stmt=NULL;
463 pData.init();
464 isPrepd = false;
465 return OK;
467 if(stmt) delete stmt;
468 stmt = NULL;
469 pData.reset();
470 isMgmtStatement = false;
471 isPrepd = false;
472 return OK;
475 void SqlStatement::setNull(int pos)
477 stmt->setNull(pos);
479 void SqlStatement::setShortParam(int paramPos, short value)
481 stmt->setShortParam(paramPos, value);
483 void SqlStatement::setIntParam(int paramPos, int value)
485 stmt->setIntParam(paramPos, value);
487 void SqlStatement::setLongParam(int paramPos, long value)
489 stmt->setLongParam(paramPos, value);
491 void SqlStatement::setLongLongParam(int paramPos, long long value)
493 stmt->setLongLongParam(paramPos, value);
495 void SqlStatement::setByteIntParam(int paramPos, ByteInt value)
497 stmt->setByteIntParam(paramPos, value);
499 void SqlStatement::setFloatParam(int paramPos, float value)
501 stmt->setFloatParam(paramPos, value);
503 void SqlStatement::setDoubleParam(int paramPos, double value)
505 stmt->setDoubleParam(paramPos, value);
507 void SqlStatement::setStringParam(int paramPos, char *value)
509 stmt->setStringParam(paramPos, value);
511 void SqlStatement::setDateParam(int paramPos, Date value)
513 stmt->setDateParam(paramPos, value);
515 void SqlStatement::setTimeParam(int paramPos, Time value)
517 stmt->setTimeParam(paramPos, value);
519 void SqlStatement::setTimeStampParam(int paramPos, TimeStamp value)
521 stmt->setTimeStampParam(paramPos, value);
523 void SqlStatement::setBinaryParam(int paramPos, void *value, int length)
525 stmt->setBinaryParam(paramPos, value, length);
527 int SqlStatement::getFldPos(char *name)
529 return stmt->getFldPos(name);
531 List SqlStatement::getAllTableNames(DbRetVal &ret)
533 DatabaseManager *dbMgr = NULL;
534 List tbNmList;
535 dbMgr=sqlCon->getConnObject().getDatabaseManager();
536 int rv = ret;
537 if(dbMgr != NULL)
538 tbNmList = dbMgr->getAllTableNames(&rv);
539 ret = (DbRetVal) rv;
540 return tbNmList;
543 List SqlStatement::getAllUserNames(DbRetVal &ret)
545 UserManager *urMgr = NULL;
546 List urNmList;
547 urMgr=sqlCon->getConnObject().getUserManager();
548 int rv = ret;
549 if(urMgr != NULL)
550 urNmList = urMgr->getAllUserNames(&rv);
551 ret = (DbRetVal) rv;
552 return urNmList;
554 List SqlStatement::getFieldNameList(const char *tblName)
556 DatabaseManager *dbMgr = sqlCon->getConnObject().getDatabaseManager();
557 Table *table = dbMgr->openTable(tblName);
558 List fldNameList = table->getFieldNameList();
559 dbMgr->closeTable(table);
560 return fldNameList;
562 DbRetVal SqlStatement::getFieldInfo(const char *tblName, const char *fldName, FieldInfo *&info)
564 DatabaseManager *dbMgr = sqlCon->getConnObject().getDatabaseManager();
565 Table *table = dbMgr->openTable(tblName);
566 DbRetVal rv = table->getFieldInfo(fldName, info);
567 dbMgr->closeTable(table);
568 return OK;
570 void SqlStatement::setLoading(bool flag)
572 if (pData.getStmtType() == InsertStatement||
573 pData.getStmtType() == UpdateStatement||
574 pData.getStmtType() == DeleteStatement)
576 DmlStatement *dmlStmt = (DmlStatement*) stmt;
577 dmlStmt->setLoading(flag);
579 return;
582 int SqlStatement::getNoOfPagesForTable(char *tblName)
584 DatabaseManager *dbMgr = sqlCon->getConnObject().getDatabaseManager();
585 DatabaseManagerImpl *dbMgrImpl = (DatabaseManagerImpl *)dbMgr;
586 return dbMgrImpl->getNoOfPagesForTable(tblName);
589 DbRetVal SqlStatement::loadRecords(char *tblName, void *buf)
591 DatabaseManager *dbMgr = sqlCon->getConnObject().getDatabaseManager();
592 DatabaseManagerImpl *dbMgrImpl = (DatabaseManagerImpl *)dbMgr;
593 return dbMgrImpl->loadRecords(tblName, (char *) buf);
596 DbRetVal SqlStatement::pasteRecords(char *tblName, void *buffer)
598 DatabaseManager *dbMgr = sqlCon->getConnObject().getDatabaseManager();
599 DatabaseManagerImpl *dbMgrImpl = (DatabaseManagerImpl *)dbMgr;
600 return dbMgrImpl->pasteRecords(tblName, buffer);
602 void SqlStatement::flushCacheStmt()
604 return sqlCon->flushCacheStmt();
606 //-------------------------------------------------------------------
607 void SqlConnection::flushCacheStmt()
609 ListIterator iter = cachedStmts.getIterator();
610 while (iter.hasElement()) {
611 CachedStmtNode* node = (CachedStmtNode*) iter.nextElement();
612 free(node->sqlString);
613 node->sqlStmt->setCachedStmt(false);
614 node->sqlStmt->free();
615 delete node->sqlStmt;
616 delete node;
618 cachedStmts.reset();
619 return;
622 SqlStatement* SqlConnection::findInCache(char *stmtstr)
624 ListIterator iter = cachedStmts.getIterator();
625 int inputStmtLen = strlen(stmtstr);
626 CachedStmtNode *node = NULL;
627 while ((node = (CachedStmtNode*)iter.nextElement()) != NULL)
629 if (node->stmtLength == inputStmtLen)
631 if (0 == strcmp(node->sqlString, stmtstr))
633 logFiner(Conf::logger, "Statement Retrieved From Cache %x\n",
634 node->sqlStmt);
635 node->hits++;
636 return node->sqlStmt;
640 return NULL;
642 void SqlConnection::addToCache(SqlStatement *sqlStmt, char* stmtString)
644 SqlStatement *stmt = new SqlStatement();
645 *stmt= *sqlStmt;
646 CachedStmtNode *node = new CachedStmtNode();
647 node->sqlStmt = stmt;
648 node->stmtLength = strlen(stmtString);
649 node->sqlString = (char*)malloc(node->stmtLength+1);
650 strcpy(node->sqlString, stmtString);
651 if (cachedStmts.size() >= Conf::config.getStmtCacheSize())
653 removeLeastUsed();
655 cachedStmts.append(node);
656 logFiner(Conf::logger, "Statement added To Cache %x\n", node->sqlStmt);
657 logFinest(Conf::logger, "Statement added To Cache %s\n", node->sqlString);
658 return ;
660 void SqlConnection::removeLeastUsed()
662 ListIterator iter = cachedStmts.getIterator();
663 CachedStmtNode *node = NULL, *toRemove =NULL;
664 int lowHits = 0;
665 bool firstCall = true;
666 while((node = (CachedStmtNode*) iter.nextElement()) != NULL)
668 if (firstCall) {
669 firstCall = false;
670 lowHits = node->hits;
671 toRemove = node; //if cache size is 1
672 continue;
674 if (lowHits >= node->hits) toRemove = node;
676 cachedStmts.remove(toRemove);
677 logFiner(Conf::logger, "Statement removed from Cache %x\n", toRemove->sqlStmt);
678 logFinest(Conf::logger, "Statement removed from Cache %s\n", toRemove->sqlString);
679 return;
681 SqlConnection::~SqlConnection()
683 innerConn = NULL;
684 flushCacheStmt();
685 if (isConnOpen) disconnect();