1 /***************************************************************************
2 * Copyright (C) 2007 by www.databasecache.com *
3 * Contact: praba_tuty@databasecache.com *
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. *
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. *
15 ***************************************************************************/
16 #include<CacheTableLoader.h>
18 DbRetVal
CacheTableLoader::addToCacheTableFile(bool isDirect
)
21 fp
= fopen(Conf::config
.getTableConfigFile(),"a");
23 printError(ErrSysInit
, "Invalid path/filename in TABLE_CONFIG_FILE.\nTable will not be"
24 "recovered in case of crash");
27 //TODO::if already table present in the file, it means that the
28 //table is replicated. in this case change mode from
29 //2 to 3 (repl to replcache)
30 if( strcmp(fieldName
,"")==0 ){ strcpy(fieldName
,"NULL"); }
33 if((strcmp(conditionVal
,"")!=0)&&(strcmp(fieldlistVal
,"")!=0))
35 fprintf(fp
,"%d:%s %s %s %s\n",6,tableName
,fieldName
,conditionVal
,fieldlistVal
);
37 else if((strcmp(conditionVal
,"")!=0)&&(strcmp(fieldlistVal
,"")==0))
39 strcpy(fieldlistVal
,"NULL");
40 fprintf(fp
,"%d:%s %s %s %s\n",6,tableName
,fieldName
,conditionVal
,fieldlistVal
);
42 else if((strcmp(conditionVal
,"")==0)&&(strcmp(fieldlistVal
,"")!=0))
44 strcpy(conditionVal
,"NULL");
45 fprintf(fp
,"%d:%s %s %s %s\n",6,tableName
,fieldName
,conditionVal
,fieldlistVal
);
49 strcpy(fieldlistVal
,"NULL");
50 strcpy(conditionVal
,"NULL");
51 fprintf(fp
,"%d:%s %s %s %s\n",5,tableName
,fieldName
,conditionVal
,fieldlistVal
);
56 if((strcmp(conditionVal
,"")!=0)&&(strcmp(fieldlistVal
,"")!=0))
58 fprintf(fp
,"%d:%s %s %s %s\n",2,tableName
,fieldName
,conditionVal
,fieldlistVal
);
60 else if((strcmp(conditionVal
,"")!=0)&&(strcmp(fieldlistVal
,"")==0))
62 strcpy(fieldlistVal
,"NULL");
63 fprintf(fp
,"%d:%s %s %s %s\n",2,tableName
,fieldName
,conditionVal
,fieldlistVal
);
65 else if((strcmp(conditionVal
,"")==0)&&(strcmp(fieldlistVal
,"")!=0))
67 strcpy(conditionVal
,"NULL");
68 fprintf(fp
,"%d:%s %s %s %s\n",2,tableName
,fieldName
,conditionVal
,fieldlistVal
);
72 strcpy(fieldlistVal
,"NULL");
73 strcpy(conditionVal
,"NULL");
74 fprintf(fp
,"%d:%s %s %s %s\n",1,tableName
,fieldName
,conditionVal
,fieldlistVal
);
82 DbRetVal
CacheTableLoader::removeFromCacheTableFile()
85 char tmpFileName
[MAX_FILE_PATH_LEN
];
86 sprintf(tmpFileName
, "%s.tmp", Conf::config
.getTableConfigFile());
87 tmpfp
= fopen(tmpFileName
,"w");
89 printError(ErrSysInit
, "Invalid path/filename in TABLE_CONFIG_FILE.\n");
92 fp
= fopen(Conf::config
.getTableConfigFile(),"r");
94 printError(ErrSysInit
, "csqltable.conf file does not exist");
97 char tablename
[IDENTIFIER_LENGTH
];
98 char fieldname
[IDENTIFIER_LENGTH
];
99 char condition
[IDENTIFIER_LENGTH
];
100 char field
[IDENTIFIER_LENGTH
];
104 fscanf(fp
, "%d:%s %s %s %s\n", &mode
, tablename
,fieldname
,condition
,field
);
105 if (strcmp (tablename
, tableName
) == 0) continue;
106 fprintf(tmpfp
, "%d:%s %s %s %s\n", mode
, tablename
,fieldname
,condition
,field
);
110 char sysCommand
[MAX_FILE_PATH_LEN
* 2];
111 sprintf(sysCommand
, "mv %s %s", tmpFileName
, Conf::config
.getTableConfigFile());
112 int ret
= system(sysCommand
);
115 printError(ErrSysInit
, "Check csqltable.conf file permission. unable to remove %s from file", tableName
);
121 // new function is added by: Jitendra
122 DbRetVal
CacheTableLoader :: isTablePresent()
127 rv
= conn
.open(userName
,password
);
128 if(rv
!=OK
) return ErrSysInit
;
129 // check for CACHE_TABLE variable
132 fp
= fopen(Conf :: config
.getTableConfigFile(),"r");
135 printError(ErrSysInit
, "cachetable.conf file does not exist");
140 char tablename
[IDENTIFIER_LENGTH
];
141 char condition
[IDENTIFIER_LENGTH
];
142 char fieldname
[IDENTIFIER_LENGTH
];
143 char field
[IDENTIFIER_LENGTH
];
148 tablename
[0] = '\0'; condition
[0] = '\0';
149 fscanf(fp
,"%d:%s %s %s %s\n",&mode
,tablename
,fieldname
,condition
,field
);
151 if(strcmp(tableName
,tablename
)==0)
163 DbRetVal
CacheTableLoader::load(bool tabDefinition
)
166 DbRetVal rv
= conn
.open(userName
, password
);
167 if (rv
!= OK
) return ErrSysInit
;
168 // check for CACHE_TABLE variable
171 DatabaseManager
*dbMgr
= (DatabaseManager
*) conn
.getDatabaseManager();
172 if (dbMgr
== NULL
) { printError(ErrSysInit
, "Auth failed\n"); return ErrSysInit
; }
173 if (tabDefinition
== false) {
174 Table
*tbl
= dbMgr
->openTable(tableName
);
179 if (tbl
->numTuples()) {
180 printError(ErrNotEmpty
, "The table '\%s\' is not empty", tableName
);
181 dbMgr
->closeTable(tbl
);
186 conn
.startTransaction();
187 rv
= load(dbMgr
, tabDefinition
);
193 DbRetVal
CacheTableLoader::load(DatabaseManager
*dbMgr
, bool tabDefinition
)
196 sprintf(dsn
, "DSN=%s;", Conf::config
.getDSN());
197 SQLCHAR outstr
[1024];
198 SQLSMALLINT outstrlen
;
204 retValue
= SQLAllocHandle (SQL_HANDLE_ENV
, SQL_NULL_HANDLE
, &henv
);
205 if (retValue
) {printError(ErrSysInit
, "Unable to allocate ODBC handle \n"); return ErrSysInit
; }
206 SQLSetEnvAttr(henv
, SQL_ATTR_ODBC_VERSION
, (void *) SQL_OV_ODBC3
, 0);
207 retValue
= SQLAllocHandle (SQL_HANDLE_DBC
, henv
, &hdbc
);
208 if (retValue
) {printError(ErrSysInit
, "Unable to allocate ODBC handle \n"); return ErrSysInit
; }
209 retValue
= SQLDriverConnect(hdbc
, NULL
, (SQLCHAR
*)dsn
, SQL_NTS
,
210 outstr
, sizeof(outstr
), &outstrlen
,
211 SQL_DRIVER_NOPROMPT
);
212 if (SQL_SUCCEEDED(retValue
)) {
213 printDebug(DM_Gateway
, "Connected to target database using dsn = %s\n", dsn
);
215 fprintf(stderr
, "Failed to connect to target database\n");
219 retValue
=SQLAllocHandle (SQL_HANDLE_STMT
, hdbc
, &hstmt
);
220 if (retValue
) {printError(ErrSysInit
, "Unable to allocate ODBC handle \n"); return ErrSysInit
; }
223 if(((strcmp(conditionVal
,"")==0) || (strcmp(conditionVal
,"NULL")==0)) && ((strcmp(fieldlistVal
,"")==0) || (strcmp(fieldlistVal
,"NULL")==0)))
225 sprintf(stmtBuf
, "SELECT * FROM %s;", tableName
);
227 else if(((strcmp(conditionVal
,"")!=0) || (strcmp(conditionVal
,"NULL")!=0)) && ((strcmp(fieldlistVal
,"")==0) || (strcmp(fieldlistVal
,"NULL")==0)))
229 sprintf(stmtBuf
,"SELECT * FROM %s where %s;",tableName
,conditionVal
);
232 else if(((strcmp(conditionVal
,"")==0) || (strcmp(conditionVal
,"NULL")==0)) && ((strcmp(fieldlistVal
,"")!=0) || (strcmp(fieldlistVal
,"NULL")!=0)))
234 sprintf(stmtBuf
,"SELECT %s FROM %s;",fieldlistVal
,tableName
);
237 sprintf(stmtBuf
,"SELECT %s FROM %s where %s;",fieldlistVal
,tableName
,conditionVal
);
239 retValue
= SQLPrepare (hstmt
, (unsigned char *) stmtBuf
, SQL_NTS
);
240 if (retValue
) {printError(ErrSysInit
, "Unable to Prepare ODBC statement \n"); return ErrSysInit
; }
244 retValue
= SQLNumResultCols (hstmt
, &totalFields
);
245 if (retValue
) {printError(ErrSysInit
, "Unable to retrieve ODBC total columns\n"); return ErrSysInit
; }
247 UCHAR colName
[IDENTIFIER_LENGTH
];
255 icol
= 1; colNameMax
= IDENTIFIER_LENGTH
;
256 char columnname
[IDENTIFIER_LENGTH
];
257 char indexname
[IDENTIFIER_LENGTH
];
258 short type
; short unique
;
260 retValue
=SQLAllocHandle (SQL_HANDLE_STMT
, hdbc
, &hstmtmeta
);
263 printError(ErrSysInit
, "Unable to allocate ODBC handle \n");
266 retValue
=SQLPrimaryKeys(hstmtmeta
, NULL
, SQL_NTS
, NULL
, SQL_NTS
, (SQLCHAR
*) tableName
, SQL_NTS
);
267 retValue
= SQLBindCol(hstmtmeta
, 4, SQL_C_CHAR
,columnname
, 129,NULL
);
268 HashIndexInitInfo
*inf
= new HashIndexInitInfo();
269 bool isPriIndex
=false;
270 char indname
[IDENTIFIER_LENGTH
];
271 if(SQLFetch( hstmtmeta
) == SQL_SUCCESS
)
273 inf
->list
.append(columnname
);
274 while( SQLFetch( hstmtmeta
) == SQL_SUCCESS
)
276 inf
->list
.append(columnname
);
278 inf
->indType
= hashIndex
;
279 inf
->bucketSize
= 10007;
280 inf
->isUnique
= true; inf
->isPrimary
= true;
281 strcpy(inf
->tableName
, tableName
);
282 strcpy(indexname
,"PRIMARY");
283 sprintf(indname
, "%s_%s", tableName
, indexname
);
287 bool iskeyfieldExist
=true;
288 if(isPriIndex
&& (strcmp(fieldlistVal
,"")!=0) && (strcmp(fieldlistVal
,"NULL")!=0))
290 inf
->list
.resetIter();
291 while ((name
=inf
->list
.nextFieldName())!=NULL
)
293 iskeyfieldExist
=isFieldExist(name
);
294 if(!iskeyfieldExist
) { break; }
296 }else if(!isPriIndex
){iskeyfieldExist
= false;}
297 if(((strcmp(fieldName
,"")!=0) && (strcmp(fieldName
,"NULL")!=0)) && !(isFieldExist(fieldName
)))
299 if(Conf::config
.useTwoWayCache() && (strcmp(fieldlistVal
,"")!=0) && (strcmp(fieldlistVal
,"NULL")!=0))
301 printError(ErrSysInit
, "Bidirectonal caching fail for no primary key in %s \n", tableName
);
306 if(!iskeyfieldExist
&& ((strcmp(fieldName
,"")==0) || (strcmp(fieldName
,"NULL")==0)))
308 if(Conf::config
.useTwoWayCache())
310 printError(ErrSysInit
, "Bidirectonal caching fail for no primary key in %s \n", tableName
);
314 while (icol
<= totalFields
) {
315 retValue
= SQLDescribeCol(hstmt
, icol
, colName
, colNameMax
,
316 &nameLength
, &colType
, &colLength
,
318 if (retValue
) {printError(ErrSysInit
, "Unable to retrieve ODBC column info\n"); return ErrSysInit
; }
320 printDebug(DM_Gateway
, "Describe Column %s %d %d \n", colName
, colType
, colLength
);
324 inf
->list
.resetIter();
325 while ((name
=inf
->list
.nextFieldName())!=NULL
)
327 if(0==strcmp((char*)colName
,name
))
329 tabDef
.addField((char*)colName
, AllDataType::convertFromSQLType(colType
), colLength
+1, NULL
, true);
334 if(!isPriFld
){tabDef
.addField((char*)colName
, AllDataType::convertFromSQLType(colType
), colLength
+1); }
337 tabDef
.addField((char*)colName
, AllDataType::convertFromSQLType(colType
), colLength
+1, NULL
, true);
339 rv
= dbMgr
->createTable(tableName
, tabDef
);
342 printError(ErrSysInit
, "Table creation failed in csql for %s\n", tableName
);
347 rv
= dbMgr
->createIndex(indname
, inf
);
350 printError(ErrSysInit
, "Index creation failed in csql for %s\n", tableName
);
357 if(Conf::config
.useTwoWayCache() && iskeyfieldExist
)
359 printError(ErrSysInit
, "Bidirectonal caching fail for no primary key in %s \n", tableName
);
363 retValue
= SQLCloseCursor(hstmtmeta
);
364 retValue
= SQLStatistics(hstmtmeta
, NULL
, 0, NULL
, SQL_NTS
,
365 (SQLCHAR
*) tableName
, SQL_NTS
, SQL_INDEX_ALL
, SQL_QUICK
);
366 retValue
= SQLBindCol(hstmtmeta
, 4, SQL_C_SHORT
,
368 retValue
= SQLBindCol(hstmtmeta
, 6, SQL_C_CHAR
,
369 indexname
, 129, NULL
);
370 retValue
= SQLBindCol(hstmtmeta
, 7, SQL_C_SHORT
,
372 retValue
= SQLBindCol(hstmtmeta
, 9, SQL_C_CHAR
,
373 columnname
, 129,NULL
);
374 while ((retValue
= SQLFetch(hstmtmeta
)) == SQL_SUCCESS
)
375 { //if (type != SQL_TABLE_STAT)
377 printDebug(DM_Gateway
, "Column: %-18s Index Name: %-18s unique:%hd type:%hd\n",
378 columnname
, indexname
, unique
, type
);
380 bool isPrimary
=false;
381 inf
->list
.resetIter();
382 while ((name
=inf
->list
.nextFieldName())!=NULL
)
384 if(0==strcmp(columnname
,name
))
390 if(isPrimary
){continue;}
392 HashIndexInitInfo
*info
= new HashIndexInitInfo();
393 info
->indType
= hashIndex
;
394 info
->bucketSize
= 10007;
395 info
->list
.append(columnname
);
396 if (!unique
) {info
->isUnique
= true; info
->isPrimary
= false;}
397 strcpy(info
->tableName
, tableName
);
399 sprintf(indname
, "%s_%s", tableName
, indexname
);
400 rv
= dbMgr
->createIndex(indname
, info
);
403 printError(ErrSysInit
, "Index creation failed in csql for %s\n", tableName
);
409 printError(ErrSysInit
,"CSQL does not support this index type\n");
413 }// while meta data fetch for index creation
414 SQLCloseCursor (hstmtmeta
);
415 SQLFreeHandle (SQL_HANDLE_STMT
, hstmtmeta
);
417 Table
*table
= dbMgr
->openTable(tableName
);
419 printError(ErrSysInit
,"unable to open table %s\n", tableName
);
420 dbMgr
->closeTable(table
);
421 if (tabDefinition
) dbMgr
->dropTable(tableName
);
425 table
->setUndoLogging(false);
426 //rv = table->lock(false); //no need to release this lock as it is upgrade from S to X
429 dbMgr
->closeTable(table
);
430 if (tabDefinition
) dbMgr
->dropTable(tableName
);
434 List fNameList
= table
->getFieldNameList();
435 ListIterator fNameIter
= fNameList
.getIterator();
436 FieldInfo
*info
= new FieldInfo();
437 int fcount
=1; void *valBuf
; int fieldsize
=0;
438 Identifier
*elem
= NULL
;
442 while (fNameIter
.hasElement()) {
443 elem
= (Identifier
*) fNameIter
.nextElement();
444 table
->getFieldInfo((const char*)elem
->name
, info
);
445 valBuf
= AllDataType::alloc(info
->type
, info
->length
);
446 table
->bindFld(elem
->name
, valBuf
);
451 fieldsize
= info
->length
;
454 bBuf
= new BindBuffer();
456 bBuf
->type
= typeDate
;
457 fieldsize
= sizeof(DATE_STRUCT
);
458 bBuf
->targetdb
= malloc(fieldsize
);
459 valBuf
= bBuf
->targetdb
;
460 valBufList
.append(bBuf
);
463 bBuf
= new BindBuffer();
465 bBuf
->type
= typeTime
;
466 fieldsize
= sizeof(TIME_STRUCT
);
467 bBuf
->targetdb
= malloc(fieldsize
);
468 valBuf
= bBuf
->targetdb
;
469 valBufList
.append(bBuf
);
472 bBuf
= new BindBuffer();
474 bBuf
->type
= typeTimeStamp
;
475 fieldsize
= sizeof(TIMESTAMP_STRUCT
);
476 bBuf
->targetdb
= malloc(fieldsize
);
477 valBuf
= bBuf
->targetdb
;
478 valBufList
.append(bBuf
);
481 retValue
= SQLBindCol (hstmt
, fcount
++, AllDataType::convertToSQLType(info
->type
),
482 valBuf
, fieldsize
, NULL
);
483 if (retValue
) {printError(ErrSysInit
, "Unable to bind columns in ODBC\n"); return ErrSysInit
; }
486 retValue
= SQLExecute (hstmt
);
487 if (retValue
) {printError(ErrSysInit
, "Unable to execute ODBC statement\n"); return ErrSysInit
; }
490 retValue
= SQLFetch (hstmt
);
492 ListIterator bindIter
= valBufList
.getIterator();
493 while (bindIter
.hasElement()) {
494 bBuf
= (BindBuffer
*) bindIter
.nextElement();
495 switch (bBuf
->type
) {
497 Date
*dtCSQL
= (Date
*) bBuf
->csql
;
498 DATE_STRUCT
*dtTarget
= (DATE_STRUCT
*) bBuf
->targetdb
;
499 dtCSQL
->set(dtTarget
->year
,dtTarget
->month
,dtTarget
->day
);
503 Time
*dtCSQL
= (Time
*) bBuf
->csql
;
504 TIME_STRUCT
*dtTarget
= (TIME_STRUCT
*) bBuf
->targetdb
;
505 dtCSQL
->set(dtTarget
->hour
,dtTarget
->minute
,dtTarget
->second
);
508 case typeTimeStamp
: {
509 TimeStamp
*dtCSQL
= (TimeStamp
*) bBuf
->csql
;
510 TIMESTAMP_STRUCT
*dtTarget
= (TIMESTAMP_STRUCT
*) bBuf
->targetdb
;
511 dtCSQL
->setDate(dtTarget
->year
,dtTarget
->month
,dtTarget
->day
);
512 dtCSQL
->setTime(dtTarget
->hour
,dtTarget
->minute
,dtTarget
->second
, dtTarget
->fraction
);
517 table
->insertTuple();
519 //TODO::leak:: valBufList and its targetdb buffer
521 dbMgr
->closeTable(table
);
522 SQLCloseCursor (hstmt
);
523 SQLFreeHandle (SQL_HANDLE_STMT
, hstmt
);
524 SQLDisconnect (hdbc
);
525 SQLFreeHandle (SQL_HANDLE_DBC
, hdbc
);
526 SQLFreeHandle (SQL_HANDLE_ENV
, henv
);
530 DbRetVal
CacheTableLoader::reload()
532 DbRetVal rv
= unload(false);
533 if (rv
!= OK
) return rv
;
538 DbRetVal
CacheTableLoader::unload(bool tabDefinition
)
541 DbRetVal rv
= conn
.open(userName
, password
);
542 if (rv
!= OK
) return ErrSysInit
;
544 if (isTableCached() != OK
) {
545 printError(ErrNotCached
, "The table \'%s\' is not cached", tableName
);
548 DatabaseManager
*dbMgr
= (DatabaseManager
*) conn
.getDatabaseManager();
549 if (dbMgr
== NULL
) { printError(ErrSysInit
, "Auth failed\n"); return ErrSysInit
; }
552 Table
*table
= dbMgr
->openTable(tableName
);
553 if (table
== NULL
) { conn
.close(); return ErrBadCall
; }
554 rv
= conn
.startTransaction();
555 if (rv
!= OK
) { dbMgr
->closeTable(table
); conn
.close(); return ErrBadCall
; }
558 dbMgr
->closeTable(table
);
562 rv
= dbMgr
->dropTable(tableName
);
569 DbRetVal
CacheTableLoader::refresh()
574 DbRetVal
CacheTableLoader::recoverAllCachedTables()
578 DbRetVal rv
= conn
.open(userName
, password
);
579 if(rv
!=OK
) return ErrSysInit
;
581 //Note: if connection is not open, configuration veriables may be incorrect
583 fp
= fopen(Conf::config
.getTableConfigFile(),"r");
585 printError(ErrSysInit
, "cachetable.conf file does not exist");
589 //TODO::take exclusive lock on database
590 char tablename
[IDENTIFIER_LENGTH
];
591 char fieldname
[IDENTIFIER_LENGTH
];
592 char condition
[IDENTIFIER_LENGTH
];
593 char field
[IDENTIFIER_LENGTH
];
598 fscanf(fp
, "%d:%s %s %s %s\n", &mode
, tablename
,fieldname
,condition
,field
);
599 //if (mode ==2 ) //just replicated table and not cached
601 printDebug(DM_Gateway
, "Recovering Table from target db: %s\n", tablename
);
602 setCondition(condition
);
604 setFieldName(fieldname
);
605 setFieldListVal(field
);
606 printf("Recovering table %s %s %s\n", tablename
,condition
,field
);
608 if (rv
!= OK
) return rv
;
614 DbRetVal
CacheTableLoader::isTableCached()
617 char tmpFileName
[MAX_FILE_PATH_LEN
];
618 fp
= fopen(Conf::config
.getTableConfigFile(),"r");
620 printError(ErrSysInit
, "csqltable.conf file does not exist");
623 char tablename
[IDENTIFIER_LENGTH
];
624 char fieldname
[IDENTIFIER_LENGTH
];
625 char condition
[IDENTIFIER_LENGTH
];
626 char field
[IDENTIFIER_LENGTH
];
630 fscanf(fp
, "%d:%s %s %s %s\n", &mode
, tablename
,fieldname
,condition
,field
);
631 if (strcmp (tablename
, tableName
) == 0) {
640 int CacheTableLoader::getTableMode(char *tabname
)
643 fp
= fopen(Conf::config
.getTableConfigFile(),"r");
645 printError(ErrSysInit
, "cachetable.conf file does not exist");
649 char tablename
[IDENTIFIER_LENGTH
];
650 char fieldname
[IDENTIFIER_LENGTH
];
651 char condition
[IDENTIFIER_LENGTH
];
652 char field
[IDENTIFIER_LENGTH
];
656 fscanf(fp
,"%d:%s %s %s %s\n",&mode
,tablename
,fieldname
,fieldname
,condition
);
657 if(0==strcmp(tabname
,tablename
)){
667 bool CacheTableLoader::isFieldExist(char *fieldname
)
669 char tmpfieldname
[IDENTIFIER_LENGTH
];
671 while(fieldlistVal
[j
]!=0)
673 if(fieldlistVal
[j
] != ',')
674 tmpfieldname
[i
++]=fieldlistVal
[j
++];
677 tmpfieldname
[i
]='\0';
678 if(strcmp(fieldname
,tmpfieldname
)==0)
683 tmpfieldname
[i
]='\0';
684 if(strcmp(fieldname
,tmpfieldname
)==0)