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 ***************************************************************************/
18 #include <SqlFactory.h>
19 #include <SqlStatement.h>
20 #include <SqlOdbcConnection.h>
21 #include <SqlOdbcStatement.h>
23 AbsSqlConnection
*conn
=NULL
;
24 AbsSqlStatement
*stmt
=NULL
;
25 DataType pkFldType
= typeUnknown
;
29 printf("Usage: cacheverify [-U username] [-P passwd] -t tablename [-p] [-f]\n");
30 printf(" username -> username to connect with csql.\n");
31 printf(" passwd -> password for the above username to connect with csql.\n");
32 printf(" tablename -> cached table name in csql from target db.\n");
33 printf(" p -> verification at primary key field level\n");
34 printf(" f -> verification at record level\n");
35 printf(" ? -> help\n");
39 typedef struct PrimaryKeyField
{
45 typedef struct FldVal
{
58 int cmpIntPkFldVal (const void *pkfv1
, const void *pkfv2
)
60 PrimKeyFldVal
*p1
= (PrimKeyFldVal
*)pkfv1
;
61 PrimKeyFldVal
*p2
= (PrimKeyFldVal
*)pkfv2
;
63 result
=AllDataType::compareVal(&p1
->val
,&p2
->val
,OpLessThan
,pkFldType
);
64 if (result
) return -1;
68 int cmpStringPkFldVal (const void *pkfv1
, const void *pkfv2
)
70 PrimKeyFldVal
*p1
= (PrimKeyFldVal
*)pkfv1
;
71 PrimKeyFldVal
*p2
= (PrimKeyFldVal
*)pkfv2
;
72 char *val1
= (char *) &p1
->val
;
73 char *val2
= (char *) &p2
->val
;
74 if (strcmp(val1
, val2
) < 0) return -1;
78 int cmpIntRecord (const void *pkfv1
, const void *pkfv2
)
80 Record
*p1
= (Record
*)pkfv1
;
81 Record
*p2
= (Record
*)pkfv2
;
82 if (AllDataType::compareVal(&p1
->val
, &p2
->val
, OpLessThan
, pkFldType
))
87 int cmpStringRecord (const void *pkfv1
, const void *pkfv2
)
89 Record
*p1
= (Record
*)pkfv1
;
90 Record
*p2
= (Record
*)pkfv2
;
91 char *val1
= (char *) &p1
->val
;
92 char *val2
= (char *) &p2
->val
;
93 if (strcmp(val1
, val2
) < 0) return -1;
97 DbRetVal
verifyCount(const char *tblName
, long numTuples
)
99 char statement
[SQL_STMT_LEN
];
100 AbsSqlConnection
*adConn
= SqlFactory::createConnection(CSqlAdapter
);
101 DbRetVal rv
= adConn
->connect(I_USER
,I_PASS
);
102 if (rv
!= OK
) { delete adConn
; return ErrSysInit
; }
103 AbsSqlStatement
*adStmt
= SqlFactory::createStatement(CSqlAdapter
);
104 adStmt
->setConnection(adConn
);
107 sprintf(statement
, "select count(*) from %s;", tblName
);
108 rv
= adConn
->beginTrans();
109 rv
= adStmt
->prepare(statement
);
112 adConn
->disconnect();
114 printError(rv
, "Prepare failed");
117 SqlOdbcConnection
*adcon
= (SqlOdbcConnection
*)adConn
;
118 adStmt
->bindField(1, &count1
);
119 rv
= adStmt
->execute(rows
);
123 adConn
->disconnect();
125 printError(rv
, "Execute failed");
128 if (adStmt
->fetch()== NULL
) {
131 adConn
->disconnect();
133 printError(ErrSysInternal
, "Fetch failed");
134 return ErrSysInternal
;
138 printf("\nNumber of Records:\n");
139 printf("-------------------+-------------------+-------------------+\n");
140 printf(" Data | In CSQL | In TargetDB |\n");
141 printf("-------------------+-------------------+-------------------+\n");
142 printf(" No. Of Records | %-6ld | %-6ld |\n", numTuples
, count1
);
143 printf("-------------------+-------------------+-------------------+\n");
145 adConn
->disconnect();
150 DbRetVal
verifyMismatchingRecords(const char *tblName
, int option
)
152 char csqlstatement
[SQL_STMT_LEN
];
153 char tdbstatement
[SQL_STMT_LEN
];
154 AbsSqlConnection
*trgtDbCon
= SqlFactory::createConnection(CSqlAdapter
);
155 DbRetVal rv
= trgtDbCon
->connect(I_USER
,I_PASS
);
160 AbsSqlStatement
*trgtDbStmt
= SqlFactory::createStatement(CSqlAdapter
);
161 trgtDbStmt
->setConnection(trgtDbCon
);
163 char fieldName
[IDENTIFIER_LENGTH
];
165 SqlOdbcStatement
*ostmt
= (SqlOdbcStatement
*) trgtDbStmt
;
166 ostmt
->getPrimaryKeyFieldName((char*)tblName
, fieldName
);
167 if (fieldName
[0] == '\0') {
169 trgtDbCon
->disconnect();
171 printError(ErrSysInternal
, "Primary key does not exist on table %s", tblName
);
174 printf("\nPrimary key field name is \'%s\'\n", fieldName
);
177 //will work for single field primary keys
178 //composite need to be worked out
179 FieldInfo
*fInfo
= new FieldInfo();
180 ((SqlStatement
*)stmt
)->getFieldInfo(tblName
, fieldName
, fInfo
);
181 pkFldType
= fInfo
->type
;
183 if (pkFldType
== typeString
)
184 pkFldLen
= os::align(fInfo
->length
+ 1);
186 pkFldLen
= fInfo
->length
;
188 void *pkval
= AllDataType::alloc(pkFldType
, pkFldLen
);
189 memset(pkval
, 0, pkFldLen
);
190 //List for primary key field values present in csql server
192 List valListInTrgtDb
;
196 sprintf(csqlstatement
, "select %s from %s;", fieldName
, tblName
);
197 sprintf(tdbstatement
, "select %s from %s where %s=?;", fieldName
, tblName
, fieldName
);
198 rv
= stmt
->prepare(csqlstatement
);
201 trgtDbCon
->disconnect();
204 printError(rv
, "Prepare failed");
207 rv
= trgtDbStmt
->prepare(tdbstatement
);
210 trgtDbCon
->disconnect();
213 printError(rv
, "Prepare failed");
216 stmt
->bindField(1, pkval
);
217 trgtDbStmt
->bindField(1, pkval
);
218 rv
= conn
->beginTrans();
223 trgtDbCon
->disconnect();
225 printError(rv
, "BeginTrans failed");
228 rv
= stmt
->execute(rows
);
233 trgtDbCon
->disconnect();
235 printError(ErrSysInternal
, "Execute failed");
238 rv
= trgtDbCon
->beginTrans();
239 int pkFldValSize
= sizeof(PrimKeyFldVal
) - 1 + pkFldLen
;
240 while(stmt
->fetch(rv
) != NULL
&& rv
== OK
) {
241 PrimKeyFldVal
*pkFldVal
= (PrimKeyFldVal
*) malloc (pkFldValSize
);
242 memset(pkFldVal
, 0, pkFldValSize
);
243 AllDataType::copyVal(&pkFldVal
->val
, pkval
, pkFldType
, pkFldLen
);
244 pkFldVal
->inCsql
= true;
245 pkFldVal
->inTrgtDb
= true;
246 SqlStatement::setParamValues(trgtDbStmt
,1, pkFldType
,pkFldLen
,pkval
);
247 trgtDbStmt
->execute(rows
);
248 if (trgtDbStmt
->fetch(rv
) != NULL
) {
249 sameInBothDb
.append(pkFldVal
);
251 pkFldVal
->inTrgtDb
= false;
252 missingList
.append(pkFldVal
);
262 // List for primary key field values present in target DB
263 sprintf(tdbstatement
, "select %s from %s;", fieldName
, tblName
);
264 sprintf(csqlstatement
, "select %s from %s where %s=?;", fieldName
, tblName
, fieldName
);
265 rv
= trgtDbCon
->beginTrans();
266 rv
= trgtDbStmt
->prepare(tdbstatement
);
270 printError(rv
, "Prepare failed");
273 stmt
->prepare(csqlstatement
);
274 stmt
->bindField(1, pkval
);
275 trgtDbStmt
->bindField(1, pkval
);
276 rv
= trgtDbStmt
->execute(rows
);
281 trgtDbCon
->disconnect();
283 printError(rv
, "Execute failed\n");
287 while (trgtDbStmt
->fetch() != NULL
) {
288 PrimKeyFldVal
*pkFldVal
= (PrimKeyFldVal
*) malloc (pkFldValSize
);
289 memset(pkFldVal
, 0, pkFldValSize
);
290 AllDataType::copyVal(&pkFldVal
->val
, pkval
, pkFldType
, pkFldLen
);
291 pkFldVal
->inCsql
= true;
292 pkFldVal
->inTrgtDb
= true;
293 SqlStatement::setParamValues(stmt
, 1, pkFldType
, pkFldLen
, pkval
);
295 if (stmt
->fetch(rv
) == NULL
&& rv
==OK
) {
296 pkFldVal
->inCsql
= false;
297 missingList
.append(pkFldVal
);
307 PrimKeyFldVal *pkArr = NULL;
308 ListIterator missIter = missingList.getIterator();
309 int nEitherDb = missingList.size();
311 pkArr = (PrimKeyFldVal *) malloc(nEitherDb * pkFldValSize);
313 char *ptr = (char *)pkArr;
314 while (missIter.hasElement()) {
315 PrimKeyFldVal *elm = (PrimKeyFldVal *)missIter.nextElement();
316 memcpy(ptr, elm, pkFldValSize);
319 if (pkFldType == typeByteInt || pkFldType == typeShort ||
320 pkFldType == typeInt || pkFldType == typeLong ||
321 pkFldType == typeLongLong)
322 qsort (pkArr, nEitherDb, pkFldValSize, cmpIntPkFldVal);
323 else if (pkFldType == typeString)
324 qsort (pkArr, nEitherDb, pkFldValSize, cmpStringPkFldVal);
327 // Sorting the primary key field values present in either of the databases
328 bool missingRecords
= false;
329 printf("\nMissing Records: Marked by \'X\'\n");
330 printf("-------------------+-------------------+-------------------+\n");
331 printf(" Primary Key | In CSQL | In Target DB |\n");
332 printf("-------------------+-------------------+-------------------+\n");
333 /* if (missingList.size()) {
334 char *ptr = (char *) pkArr;
335 missingRecords = true;
336 for (int i = 0; i < nEitherDb; i++) {
337 PrimKeyFldVal *pkFldVal = (PrimKeyFldVal *) ptr;
339 int nChrs = AllDataType::printVal(&pkFldVal->val, pkFldType,
342 while (nChrs-- != 0) printf(" ");
343 if (pkFldVal->inCsql == false) {
346 else if (pkFldVal->inTrgtDb == false) {
351 printf("-------------------+-------------------+-------------------+\n");
354 printf(" No missing Records in either of the databases |\n");
355 printf("-------------------+-------------------+-------------------+\n");
365 ListIterator missIter
= missingList
.getIterator();
366 if (missingList
.size()) {
367 missingRecords
= true;
368 while (missIter
.hasElement()) {
369 PrimKeyFldVal
*pkFldVal
= (PrimKeyFldVal
*) missIter
.nextElement();
371 int nChrs
= AllDataType::printVal(&pkFldVal
->val
, pkFldType
,
374 while (nChrs
-- != 0) printf(" ");
375 if (pkFldVal
->inCsql
== false) {
378 else if (pkFldVal
->inTrgtDb
== false) {
382 printf("-------------------+-------------------+-------------------+\n");
385 printf(" No missing Records in either of the databases |\n");
386 printf("-------------------+-------------------+-------------------+\n");
389 // Need to clean up the mess that is no more required
392 PrimKeyFldVal
*pkFldVal
= NULL
;
393 while ((pkFldVal
= (PrimKeyFldVal
*) missIter
.nextElement()) != NULL
)
398 //statement to fetch the values from the database
399 sprintf(csqlstatement
, "select * from %s where %s = ?;", tblName
, fieldName
);
400 rv
= stmt
->prepare(csqlstatement
);
401 rv
= trgtDbStmt
->prepare(csqlstatement
);
404 trgtDbCon
->disconnect();
406 printError(rv
, "Prepare failed");
410 // need to bind each field with buffer which is list of field values
411 SqlStatement
*sqlStmt
= (SqlStatement
*) stmt
;
412 List fldNameList
= sqlStmt
->getFieldNameList(tblName
, rv
);
413 ListIterator iter
= fldNameList
.getIterator();
414 Identifier
*fname
= NULL
;
415 FieldInfo
*fldInfo
= new FieldInfo();
416 List cfieldValueList
;
417 List tfieldValueList
;
419 // List to hold all the records that are present in both the databases
422 while (iter
.hasElement()) {
423 fname
= (Identifier
*) iter
.nextElement();
426 trgtDbCon
->disconnect();
429 printError(ErrSysFatal
, "Fatal:Field Name list has NULL");
432 rv
= sqlStmt
->getFieldInfo(tblName
, fname
->name
, fldInfo
);
433 if (ErrNotFound
== rv
) {
435 trgtDbCon
->disconnect();
438 printError(ErrSysInternal
, "Field %s does not exist in table", fname
->name
);
439 return ErrSyntaxError
;
441 FldVal
*cfldVal
= new FldVal();
442 FldVal
*tfldVal
= new FldVal();
443 cfldVal
->type
= fldInfo
->type
;
444 tfldVal
->type
= fldInfo
->type
;
445 if(cfldVal
->type
== typeString
)
446 cfldVal
->length
= os::align(fldInfo
->length
+ 1);
447 else cfldVal
->length
= fldInfo
->length
;
448 cfldVal
->value
= AllDataType::alloc(fldInfo
->type
, cfldVal
->length
);
449 tfldVal
->value
= AllDataType::alloc(fldInfo
->type
, cfldVal
->length
);
450 memset(cfldVal
->value
, 0, cfldVal
->length
);
451 memset(tfldVal
->value
, 0, cfldVal
->length
);
452 cfieldValueList
.append(cfldVal
);
453 tfieldValueList
.append(tfldVal
);
454 stmt
->bindField(paramPos
, cfldVal
->value
);
455 trgtDbStmt
->bindField(paramPos
, tfldVal
->value
);
460 while ((fname
=(Identifier
*)iter
.nextElement())!= NULL
) delete fname
;
463 // WHERE parameter should be binded with the primary key field value of the list that is present in both the databases
464 int recSize
= 2 * sizeof(List
) + pkFldLen
;
465 ListIterator sameValIter
= sameInBothDb
.getIterator();
466 PrimKeyFldVal
*sameElem
= NULL
;
467 while((sameElem
= (PrimKeyFldVal
*)sameValIter
.nextElement()) != NULL
) {
469 trgtDbCon
->beginTrans();
470 SqlStatement::setParamValues(stmt
, 1, pkFldType
, pkFldLen
,
472 SqlStatement::setParamValues(trgtDbStmt
, 1, pkFldType
, pkFldLen
,
474 rv
= stmt
->execute(rows
);
475 rv
= trgtDbStmt
->execute(rows
);
478 trgtDbCon
->disconnect();
480 printError(rv
, "Execute failed");
483 if (stmt
->fetch() != NULL
&& trgtDbStmt
->fetch() != NULL
) {
484 Record
*rec
= (Record
*) malloc(recSize
);
485 memset(rec
, 0, recSize
);
486 AllDataType::copyVal(&rec
->val
, &sameElem
->val
,
487 pkFldType
, pkFldLen
);
488 ListIterator cfldValIter
= cfieldValueList
.getIterator();
489 ListIterator tfldValIter
= tfieldValueList
.getIterator();
491 while (cfldValIter
.hasElement() && tfldValIter
.hasElement()) {
492 FldVal
*cfldVal
= (FldVal
*) cfldValIter
.nextElement();
493 FldVal
*tfldVal
= (FldVal
*) tfldValIter
.nextElement();
494 if (AllDataType::compareVal(cfldVal
->value
, tfldVal
->value
, OpEquals
, cfldVal
->type
, cfldVal
->length
) == false) {
495 FldVal
*cfldValue
= new FldVal();
496 FldVal
*tfldValue
= new FldVal();
497 cfldValue
->type
= cfldVal
->type
;
498 tfldValue
->type
= cfldVal
->type
;
499 cfldValue
->length
= cfldVal
->length
;
500 tfldValue
->length
= cfldVal
->length
;
501 cfldValue
->value
= AllDataType::alloc(cfldValue
->type
, cfldValue
->length
);
502 tfldValue
->value
= AllDataType::alloc(cfldValue
->type
, cfldValue
->length
);
503 cfldValue
->pos
= pos
; tfldValue
->pos
= pos
;
504 memset(cfldValue
->value
, 0, cfldValue
->length
);
505 memset(tfldValue
->value
, 0, cfldValue
->length
);
506 AllDataType::cachecopyVal(cfldValue
->value
, cfldVal
->value
, cfldVal
->type
, cfldVal
->length
);
507 AllDataType::cachecopyVal(tfldValue
->value
, tfldVal
->value
, cfldVal
->type
, cfldVal
->length
);
508 rec
->csqlFldValList
.append(cfldValue
);
509 rec
->tdbFldValList
.append(tfldValue
);
513 if (rec
->csqlFldValList
.size()) recordList
.append(rec
);
520 // stmt->free(); // dont free it just yet needed further up
523 // freeing the field value list that is present in both the databases
524 PrimKeyFldVal
*pkFldVal
= NULL
;
525 while ((pkFldVal
= (PrimKeyFldVal
*) sameValIter
.nextElement()) != NULL
)
527 sameInBothDb
.reset();
529 // sort the records based on Primary key that is present in both the databases
530 int size = recordList.size();
531 char *arr = (char *) malloc(size * recSize);
532 memset(arr, 0, size * recSize);
535 ListIterator recIter = recordList.getIterator();
536 while (recIter.hasElement()) {
537 Record *rec = (Record *) recIter.nextElement();
538 memcpy(ptr, rec, recSize);
541 if (pkFldType == typeByteInt || pkFldType == typeShort ||
542 pkFldType == typeInt || pkFldType == typeLong ||
543 pkFldType == typeLongLong)
544 qsort(arr, size, recSize, cmpIntRecord);
545 else if (pkFldType == typeString)
546 qsort(arr, size, recSize, cmpStringRecord);
550 bool isConsistent
= true;
551 printf("\nInconsistent Records for the same key:\n");
552 printf("-------------------+-------------------+-------------------+-------------------+\n");
553 printf(" %-16s | %-16s | %-16s | %-16s |\n", "Primary Key", "Field Name", "In CSQL", "In Trgt DB");
554 printf("-------------------+-------------------+-------------------+-------------------+\n");
556 char *fldname = NULL;
557 for (int i = 0; i < size; i++) {
558 Record *recd = (Record *) ptr;
559 ListIterator csqlIt = recd->csqlFldValList.getIterator();
560 ListIterator trgtDbIt = recd->tdbFldValList.getIterator();
562 while (csqlIt.hasElement() && trgtDbIt.hasElement()) {
563 FldVal *csqlElem = (FldVal *) csqlIt.nextElement();
564 FldVal *trgtDbElem = (FldVal *) trgtDbIt.nextElement();
565 fldname = ((SqlStatement *) stmt)->getFieldName(csqlElem->pos);
566 if (AllDataType::compareVal(csqlElem->value, trgtDbElem->value, OpEquals, csqlElem->type, csqlElem->length) == false) {
567 isConsistent = false;
570 int cnt = AllDataType::printVal(&recd->val,
571 pkFldType, pkFldLen);
573 while (cnt-- != 0) printf(" ");
574 printf("| %-16s | ", fldname);
577 else printf(" | %-16s | ", fldname);
578 int cnt = AllDataType::printVal(csqlElem->value, csqlElem->type, csqlElem->length);
583 cnt = AllDataType::printVal(trgtDbElem->value, trgtDbElem->type, trgtDbElem->length);
593 ListIterator recIter
= recordList
.getIterator();
595 char *fldname
= NULL
;
596 if (recordList
.size()) {
597 isConsistent
= false;
598 while(recIter
.hasElement()) {
599 Record
*recd
= (Record
*) recIter
.nextElement();
600 ListIterator csqlIt
= recd
->csqlFldValList
.getIterator();
601 ListIterator trgtDbIt
= recd
->tdbFldValList
.getIterator();
603 while (csqlIt
.hasElement()) {
604 FldVal
*csqlElem
= (FldVal
*) csqlIt
.nextElement();
605 FldVal
*trgtDbElem
= (FldVal
*) trgtDbIt
.nextElement();
606 fldname
= ((SqlStatement
*) stmt
)->getFieldName(csqlElem
->pos
);
609 int cnt
= AllDataType::printVal(&recd
->val
,
610 pkFldType
, pkFldLen
);
612 while (cnt
-- != 0) printf(" ");
613 printf("| %-16s | ", fldname
);
616 else printf(" | %-16s | ", fldname
);
617 int cnt
= AllDataType::printVal(csqlElem
->value
, csqlElem
->type
, csqlElem
->length
);
619 while (cnt
-- != 0) printf(" ");
621 cnt
= AllDataType::printVal(trgtDbElem
->value
, trgtDbElem
->type
, trgtDbElem
->length
);
623 while (cnt
-- != 0) printf(" ");
629 if (isConsistent
== true && missingRecords
== false)
630 printf(" The data is consistent in both the databases |\n");
631 else if (isConsistent
== true && missingRecords
== true)
632 printf(" The data is consistent for the records with the same key |\n");
633 printf("-------------------+-------------------+-------------------+-------------------+\n");
635 // clean up all the mess before leaving
639 while((itm
= (Record
*) recIter
.nextElement()) != NULL
) {
640 ListIterator cit
= (ListIterator
) itm
->csqlFldValList
.getIterator();
641 ListIterator tit
= (ListIterator
) itm
->tdbFldValList
.getIterator();
642 FldVal
*cfldVal
= NULL
;
643 FldVal
*tfldVal
= NULL
;
644 while( (cfldVal
= (FldVal
*) cit
.nextElement()) != NULL
&&
645 (tfldVal
= (FldVal
*) tit
.nextElement()) != NULL
) {
646 free (cfldVal
->value
);
647 free (tfldVal
->value
);
657 trgtDbCon
->disconnect();
662 int main(int argc
, char **argv
)
664 char username
[IDENTIFIER_LENGTH
];
666 char password
[IDENTIFIER_LENGTH
];
669 char tableName
[IDENTIFIER_LENGTH
];
671 bool tableNameSpecified
= false;
673 while ((c
= getopt(argc
, argv
, "U:P:t:pf?")) != EOF
)
677 case 'U' : { strcpy(username
, argv
[optind
- 1]); opt
=10; break; }
678 case 'P' : { strcpy(password
, argv
[optind
- 1]); opt
=10; break; }
679 case 't' : { strcpy(tableName
, argv
[optind
- 1]);
680 if (opt
==10) opt
= 2;
681 tableNameSpecified
= true;
684 case 'p' : { opt
= 3; break; } //verify at primary key level
685 case 'f' : { opt
= 4; break; } //verify at record level
686 case '?' : { opt
= 10; break; } //print help
696 if (!tableNameSpecified
) {
697 printError(ErrSysInternal
, "Table name is not specified. Check usage with ?");
701 //printf("%s %s \n", username, password);
702 if (username
[0] == '\0' )
704 strcpy(username
, I_USER
);
705 strcpy(password
, I_PASS
);
708 conn
= SqlFactory::createConnection(CSqlDirect
);
709 DbRetVal rv
= conn
->connect(username
, password
);
711 printError(rv
, "Authentication failed");
715 stmt
= SqlFactory::createStatement(CSqlDirect
);
716 stmt
->setConnection(conn
);
718 List tableNameList
= stmt
->getAllTableNames(rv
);
719 ListIterator it
= tableNameList
.getIterator();
720 while (it
.hasElement()) {
721 Identifier
*elem
= (Identifier
*) it
.nextElement();
722 if (strcmp(elem
->name
, tableName
) == 0) {
728 fp
= fopen(Conf::config
.getTableConfigFile(),"r");
733 printError(ErrSysInternal
, "csqltable.conf file does not exist");
736 char tablename
[IDENTIFIER_LENGTH
];
737 char fieldname
[IDENTIFIER_LENGTH
];
738 char condition
[IDENTIFIER_LENGTH
];
739 char field
[IDENTIFIER_LENGTH
];
740 char dsnName
[IDENTIFIER_LENGTH
];
743 bool isCached
= false;
745 fscanf(fp
, "%d %s %s %s %s %s\n", &mode
, tablename
,fieldname
,condition
,field
,dsnName
);
746 if (strcmp(tableName
, tablename
) == 0) {
755 char statement
[SQL_STMT_LEN
];
756 sprintf(statement
, "select count(*) from %s;", tableName
);
757 rv
= stmt
->prepare(statement
);
764 rv
= conn
->beginTrans();
771 stmt
->bindField(1, &numTuples
);
779 void *tuple
= stmt
->fetch(rv
);
784 if (isCached
== false) {
786 printError(ErrSysInternal
, "The table \'%s\' is not cached", tableName
);
793 rv
= verifyCount(tableName
, numTuples
);
802 if (opt
== 3 || opt
== 4) {
803 rv
= verifyCount(tableName
, numTuples
);
810 rv
= verifyMismatchingRecords(tableName
, opt
);