1 #include "otsdaq/TableCore/TableBase.h"
6 #include "otsdaq/TableCore/TableInfoReader.h"
11 #define __MF_SUBJECT__ "TableBase"
13 #define __COUT_HDR__ ("TableBase-" + getTableName() + "\t<> ")
15 const std::string TableBase::GROUP_CACHE_PREPEND =
"GroupCache_";
16 const std::string TableBase::JSON_DOC_PREPEND =
"JSONDoc_";
17 const std::string TableBase::GROUP_METADATA_TABLE_NAME =
"TableGroupMetadata";
26 std::string* accumulatedExceptions)
27 : MAX_VIEWS_IN_CACHE(20)
29 , tableName_(tableName)
31 , mockupTableView_(tableName)
40 std::cout <<
"TableBase Before traceTID=" << traceTID << __E__;
42 traceInit(trace_name(TRACE_NAME, __TRACE_FILE__, buf,
sizeof(buf)), 0);
43 std::cout <<
"TableBase After traceTID=" << traceTID << __E__;
44 __COUT__ <<
"TableBase TRACE reinit and Constructed." << __E__;
49 __SS__ <<
"Do not allow anonymous table view construction!" << __E__;
55 if(tableName_ == TableBase::GROUP_METADATA_TABLE_NAME)
62 if(tableName.substr(0, TableBase::GROUP_CACHE_PREPEND.length()) ==
63 TableBase::GROUP_CACHE_PREPEND ||
64 tableName.substr(0, TableBase::JSON_DOC_PREPEND.length()) ==
65 TableBase::JSON_DOC_PREPEND)
67 __COUTT__ <<
"TableBase for special table '" << tableName <<
"' constructed."
78 __COUT__ <<
"Reading..." << __E__;
81 std::string returnedExceptions = tableInfoReader.read(
this);
84 if(returnedExceptions !=
"")
85 __COUT_ERR__ << returnedExceptions << __E__;
87 if(accumulatedExceptions)
88 *accumulatedExceptions += std::string(
"\n") + returnedExceptions;
92 __SS__ <<
"Failure reading table schema info for table '" << tableName <<
"!' "
93 <<
"Perhaps you need to run otsdaq_convert_config_to_table? Or the XML "
94 "table definition has moved or link broken? or corrupted? Check your "
101 catch(
const std::runtime_error& e)
103 ss <<
"Here was the error:\n" << e.what() << __E__;
109 __COUT_ERR__ <<
"\n" << ss.str();
110 if(accumulatedExceptions)
111 *accumulatedExceptions += std::string(
"\n") + ss.str();
117 __COUT__ <<
"Initializing..." << __E__;
121 getMockupViewP()->
init();
123 __COUT__ <<
"Init." << __E__;
125 catch(std::runtime_error&
128 if(accumulatedExceptions)
129 *accumulatedExceptions += std::string(
"\n") + e.what();
141 : MAX_VIEWS_IN_CACHE(1)
143 , tableName_(specialTableName)
144 , activeTableView_(0)
145 , mockupTableView_(specialTableName)
154 std::cout <<
"TableBase Before traceTID=" << traceTID << __E__;
156 traceInit(trace_name(TRACE_NAME, __TRACE_FILE__, buf,
sizeof(buf)), 0);
157 std::cout <<
"TableBase After traceTID=" << traceTID << __E__;
158 __COUT__ <<
"TableBase TRACE reinit and Constructed." << __E__;
161 __COUT__ <<
"Special table '" << tableName_ <<
"' constructed. " << specialTable
165 if(tableName_ == TableBase::GROUP_METADATA_TABLE_NAME)
174 __COUTT__ <<
"Special table '" << tableName_ <<
"' constructing..." << __E__;
187 std::vector<TableViewColumnInfo>* colInfo = getMockupViewP()->getColumnsInfoP();
201 TableViewColumnInfo::DATATYPE_STRING,
208 TableViewColumnInfo::TYPE_COMMENT,
209 TableViewColumnInfo::COL_NAME_COMMENT,
210 "COMMENT_DESCRIPTION",
211 TableViewColumnInfo::DATATYPE_STRING,
218 TableViewColumnInfo::TYPE_AUTHOR,
221 TableViewColumnInfo::DATATYPE_STRING,
229 "GROUP_CREATION_TIME",
230 TableViewColumnInfo::DATATYPE_TIME,
237 setActiveView(tmpVersion);
241 __COUTT__ <<
"Special table '" << tableName_ <<
"' constructed." << __E__;
257 std::string TableBase::getTypeId() {
return typeid(
this).name(); }
266 void TableBase::reset(
bool keepTemporaryVersions)
270 if(keepTemporaryVersions)
281 if(!activeTableView_)
283 __COUT_ERR__ <<
"ERROR: No active view set" << __E__;
286 activeTableView_->print(out);
294 if(!isStored(version))
298 mockupTableView_, version, mockupTableView_.getAuthor());
300 if(!isStored(version))
302 __SS__ <<
"IMPOSSIBLE ERROR: trimCache() is deleting the "
303 "latest view version "
304 << version <<
"!" << __E__;
310 __SS__ <<
"View to fill with mockup already exists: " << version
311 <<
". Cannot overwrite!" << __E__;
326 if(trimSize == (
unsigned int)-1)
333 time_t stalestTime = -1;
336 if(!viewPair.first.isTemporaryVersion())
338 if(stalestTime == -1 || viewPair.second.getLastAccessTime() < stalestTime)
340 versionToDelete = viewPair.first;
341 stalestTime = viewPair.second.getLastAccessTime();
349 __SS__ <<
"Can NOT have a stored view with an invalid version!" << __E__;
353 eraseView(versionToDelete);
368 if(it->first.isTemporaryVersion())
371 if(activeTableView_ &&
384 eraseView(targetVersion);
389 __SS__ <<
"Temporary trim target was a persistent version: " << targetVersion
411 __SS__ <<
"needleVersion does not exist: " << needleVersion << __E__;
415 const TableView* needleView = &(needleIt->second);
416 unsigned int rows = needleView->getNumberOfRows();
417 unsigned int cols = needleView->getNumberOfColumns();
420 unsigned int potentialMatchCount = 0;
425 __COUTTV__(needleVersion);
426 __COUTTV__(ignoreVersion);
432 auto viewPairReverseIterator =
tableViews_.rbegin();
433 for(; viewPairReverseIterator !=
tableViews_.rend(); ++viewPairReverseIterator)
435 __COUTTV__(viewPairReverseIterator->first);
436 if(viewPairReverseIterator->first == needleVersion)
438 __COUTVS__(2, viewPairReverseIterator->first);
439 if(viewPairReverseIterator->first == ignoreVersion)
441 __COUTVS__(2, viewPairReverseIterator->first);
442 if(viewPairReverseIterator->first.isTemporaryVersion())
444 __COUTVS__(2, viewPairReverseIterator->first);
445 if(viewPairReverseIterator->second.getNumberOfRows() != rows)
447 __COUTVS__(2, viewPairReverseIterator->first);
448 if(viewPairReverseIterator->second.getDataColumnSize() != cols ||
449 viewPairReverseIterator->second.getSourceColumnMismatch() != 0)
452 ++potentialMatchCount;
453 __COUTT__ <<
"Checking version... " << viewPairReverseIterator->first << __E__;
461 match = viewPairReverseIterator->second.getSourceColumnNames().size() ==
462 needleView->getSourceColumnNames().size();
463 __COUTTV__(viewPairReverseIterator->second.getSourceColumnNames().size());
464 __COUTTV__(needleView->getSourceColumnNames().size());
467 for(
auto& haystackColName :
468 viewPairReverseIterator->second.getSourceColumnNames())
469 if(needleView->getSourceColumnNames().find(haystackColName) ==
470 needleView->getSourceColumnNames().end())
472 __COUT__ <<
"Found column name mismatch for '" << haystackColName
473 <<
"'... So allowing same data!" << __E__;
482 for(
auto& srcCol : viewPairReverseIterator->second.getSourceColumnNames())
483 __COUTT__ <<
"compare Col #" << i++ <<
" " << srcCol << __E__;
485 for(
auto& srcCol : needleView->getSourceColumnNames())
486 __COUTT__ <<
"source Col #" << i++ <<
" " << srcCol << __E__;
506 for(
unsigned int row = 0; match && row < rows; ++row)
508 for(
unsigned int col = 0; col < cols - 2;
510 if(viewPairReverseIterator->second.getDataView()[row][col] !=
511 needleView->getDataView()[row][col])
516 <<
"Value name mismatch " << col <<
":"
517 << viewPairReverseIterator->second.getDataView()[row][col] <<
"["
518 << viewPairReverseIterator->second.getDataView()[row][col].size()
520 <<
" vs " << needleView->getDataView()[row][col] <<
"["
521 << needleView->getDataView()[row][col].size() <<
"]" << __E__;
528 __COUT_INFO__ <<
"Duplicate version found: " << viewPairReverseIterator->first
530 return viewPairReverseIterator->first;
534 __COUT__ <<
"No duplicates found in " << potentialMatchCount <<
" potential matches."
545 std::stringstream* diffReport ,
546 std::map<std::string , std::vector<std::string /* colName */>>*
547 v1ModifiedRecords )
const
549 __COUTT__ <<
"Diffing version... " << v1 <<
" vs " << v2 << __E__;
554 __SS__ <<
"Version v" << v1 <<
" does not exist." << __E__;
561 __SS__ <<
"Version v" << v2 <<
" does not exist." << __E__;
565 const TableView* view1 = &(v1It->second);
566 const TableView* view2 = &(v2It->second);
567 unsigned int rows1 = view1->getNumberOfRows();
568 unsigned int cols1 = view1->getNumberOfColumns();
570 bool noDifference =
true;
578 if(view1->getSourceColumnNames().size() != view2->getSourceColumnNames().size())
580 __COUT__ <<
"Found column count mismatch for '"
581 << view1->getSourceColumnNames().size() <<
" vs "
582 << view2->getSourceColumnNames().size() << __E__;
585 *diffReport <<
"<li>Found column count mismatch. The v" << v1
586 <<
" column count is <b>'" << view1->getSourceColumnNames().size()
587 <<
"'</b> and the v" << v2 <<
" column count is <b>'"
588 << view2->getSourceColumnNames().size() <<
"'</b>." << __E__;
590 noDifference =
false;
595 for(
auto& colName1 : view1->getSourceColumnNames())
596 if(view2->getSourceColumnNames().find(colName1) ==
597 view2->getSourceColumnNames().end())
599 __COUT__ <<
"Found column name mismatch for '" << colName1 << __E__;
602 *diffReport <<
"<li>Found column name mismatch. The v" << v1
603 <<
" column <b>'" << colName1 <<
"'</b> was not found in v"
604 << v2 <<
"." << __E__;
606 noDifference =
false;
610 for(
auto& colName2 : view2->getSourceColumnNames())
611 if(view1->getSourceColumnNames().find(colName2) ==
612 view1->getSourceColumnNames().end())
614 __COUT__ <<
"Found column name mismatch for '" << colName2 << __E__;
617 *diffReport <<
"<li>Found column name mismatch. The v" << v1
618 <<
" does not have column <b>'" << colName2
619 <<
"'</b> that was found in v" << v2 <<
"." << __E__;
621 noDifference =
false;
626 if(rows1 != view2->getNumberOfRows())
628 __COUT__ <<
"Found row count mismatch for '" << rows1 <<
" vs "
629 << view2->getNumberOfRows() << __E__;
632 *diffReport <<
"<li>Found row count mismatch. The v" << v1
633 <<
" row count is <b>'" << rows1 <<
"'</b> and the v" << v2
634 <<
" row count is <b>'" << view2->getNumberOfRows() <<
"'</b>."
637 noDifference =
false;
643 std::set<std::string > uidSet1, uidSet2;
644 for(
unsigned int row = 0; row < rows1; ++row)
645 uidSet1.insert(view1->getDataView()[row][view1->
getColUID()]);
646 for(
unsigned int row = 0; row < view2->getNumberOfRows(); ++row)
647 uidSet2.insert(view2->getDataView()[row][view2->
getColUID()]);
649 for(
auto& uid1 : uidSet1)
650 if(uidSet2.find(uid1) == uidSet2.end())
652 __COUT__ <<
"Found record name mismatch for '" << uid1 << __E__;
655 *diffReport <<
"<li>Found record name mismatch. The v" << v1
656 <<
" record <b>'" << uid1 <<
"'</b> was not found in v" << v2
659 noDifference =
false;
663 for(
auto& uid2 : uidSet2)
664 if(uidSet1.find(uid2) == uidSet1.end())
666 __COUT__ <<
"Found record name mismatch for '" << uid2 << __E__;
669 *diffReport <<
"<li>Found record name mismatch. v" << v1
670 <<
" does not have record <b>'" << uid2
671 <<
"'</b> that was found in v" << v2 <<
"." << __E__;
673 noDifference =
false;
678 unsigned int row2, col2;
679 for(
unsigned int row = 0; row < rows1 && row < view2->getNumberOfRows(); ++row)
683 if(view1->getDataView()[row][view1->
getColUID()] !=
684 view2->getDataView()[row2][view2->
getColUID()])
686 bool foundUid2 =
false;
688 for(row2 = 0; row2 < view2->getNumberOfRows(); ++row2)
689 if(view1->getDataView()[row][view1->
getColUID()] ==
690 view2->getDataView()[row2][view2->
getColUID()])
695 __COUTT__ <<
"Found row ? '" << foundUid2 <<
" " << row <<
"," << row2
701 __COUTT__ <<
"Found row "
702 <<
" " << row <<
"," << row2 << __E__;
703 for(
unsigned int col = 0;
704 col < cols1 - 2 && col < view2->getNumberOfColumns() - 2;
709 if(view1->getColumnInfo(col).getName() !=
710 view2->getColumnInfo(col2).getName())
712 bool foundCol2 =
false;
714 for(col2 = 0; col2 < view2->getNumberOfColumns() - 2; ++col2)
715 if(view1->getColumnInfo(col).getName() ==
716 view2->getColumnInfo(col2).getName())
722 __COUTT__ <<
"Found column ? '" << foundCol2 <<
" " << col <<
"," << col2
728 __COUTT__ <<
"Found column "
729 <<
" " << col <<
"," << col2 << __E__;
730 if(view1->getDataView()[row][col] != view2->getDataView()[row2][col2])
732 __COUT__ <<
"Found column value mismatch for '" << row <<
"," << col
733 <<
" " << view1->getDataView()[row][col] << __E__;
736 *diffReport <<
"<li><b>" << view1->getColumnInfo(col).getName()
737 <<
"</b> value mismatch at v" << v1 <<
" {UID,r,c}:{<b>"
738 << view1->getDataView()[row][view1->
getColUID()]
739 <<
"</b>," << row <<
"," << col <<
"}: <b>'"
740 << view1->getDataView()[row][col] <<
"'</b> vs value in v"
741 << v2 <<
": <b>'" << view2->getDataView()[row2][col2]
742 <<
"'</b>." << __E__;
744 noDifference =
false;
748 if(v1ModifiedRecords)
749 (*v1ModifiedRecords)[view1->getDataView()[row][view1->
getColUID()]]
750 .push_back(view1->getColumnInfo(col).getName());
755 if(noDifference && diffReport)
756 *diffReport <<
"<li>No difference found between v" << v1 <<
" and v" << v2 <<
"."
763 void TableBase::changeVersionAndActivateView(
TableVersion temporaryVersion,
769 __SS__ <<
"ERROR: Temporary view version " << temporaryVersion
770 <<
" doesn't exists!" << __E__;
775 __SS__ <<
"ERROR: Attempting to create an invalid version " << version
776 <<
"! Did you really run out of versions? (this should never happen)"
782 __COUT_WARN__ <<
"WARNING: View version " << version
783 <<
" already exists! Overwriting." << __E__;
787 emplacePair.first->second.copy(tmpIt->second, version, tmpIt->second.getAuthor());
788 setActiveView(version);
789 eraseView(temporaryVersion);
793 bool TableBase::isStored(
const TableVersion& version)
const
801 if(!isStored(version))
804 if(activeTableView_ &&
817 const std::string& TableBase::getTableDescription(
void)
const
819 return tableDescription_;
825 return getView().getVersion();
833 std::set<TableVersion> retSet = getStoredVersions();
834 if(retSet.size() && !retSet.rbegin()->isTemporaryVersion())
836 return tableViews_.find(*(retSet.rbegin()))->second.getNumberOfColumns() !=
837 mockupTableView_.getNumberOfColumns();
844 std::set<TableVersion> TableBase::getStoredVersions(
void)
const
846 std::set<TableVersion> retSet;
848 retSet.emplace(configs.first);
860 if(viewPair.first.isTemporaryVersion())
862 else if(viewPair.first.isInvalid())
872 __COUT__ <<
"There is an invalid version now!.. where did it come from?"
886 if(version != TableVersion::INVALID)
891 __SS__ <<
"Table '" << tableName_ <<
"' does not have version v" << version
892 <<
" in the cache." << __E__;
896 if(!activeTableView_)
898 __SS__ <<
"There is no active table view setup! Please check your system "
903 return *activeTableView_;
911 if(version != TableVersion::INVALID)
916 __SS__ <<
"Table '" << tableName_ <<
"' does not have version v" << version
917 <<
" in the cache." << __E__;
921 if(!activeTableView_)
923 __SS__ <<
"There is no active table view setup! Please check your system "
928 return activeTableView_;
932 TableView* TableBase::getMockupViewP(
void) {
return &mockupTableView_; }
938 void TableBase::setTableDescription(
const std::string& tableDescription)
940 tableDescription_ = tableDescription;
955 if(!isStored(version))
960 __SS__ <<
"\nsetActiveView() ERROR: View with version " << version
961 <<
" has never been stored before!" << __E__;
967 if(
tableViews_.at(version).getVersion() != version)
969 __SS__ <<
"Something has gone very wrong with the version handling!" << __E__;
988 const std::string& author,
989 const std::string& mergeApproach ,
990 std::map<std::pair<std::string /*original table*/, std::string /*original uidB*/>,
991 std::string >& uidConversionMap,
993 std::pair<std::string ,
994 std::pair<std::string /*group linkid*/, std::string /*original gidB*/>>,
995 std::string >& groupidConversionMap,
996 bool fillRecordConversionMaps,
997 bool applyRecordConversionMaps,
998 bool generateUniqueDataColumns ,
999 std::stringstream* mergeReport )
1001 __COUT__ <<
"mergeViews starting..." << __E__;
1013 if(!(mergeApproach ==
"Rename" || mergeApproach ==
"Replace" ||
1014 mergeApproach ==
"Skip"))
1016 __SS__ <<
"Error! Invalid merge approach '" << mergeApproach <<
".'" << __E__;
1021 if(sourceViewA.getNumberOfColumns() != mockupTableView_.getNumberOfColumns())
1023 __SS__ <<
"Error! Number of Columns of source view A must match destination "
1025 <<
"Dimension of source is [" << sourceViewA.getNumberOfColumns()
1026 <<
"] and of destination mockup is ["
1027 << mockupTableView_.getNumberOfColumns() <<
"]." << __E__;
1031 if(sourceViewB.getNumberOfColumns() != mockupTableView_.getNumberOfColumns())
1033 __SS__ <<
"Error! Number of Columns of source view B must match destination "
1035 <<
"Dimension of source is [" << sourceViewB.getNumberOfColumns()
1036 <<
"] and of destination mockup is ["
1037 << mockupTableView_.getNumberOfColumns() <<
"]." << __E__;
1043 sourceViewA.print();
1044 sourceViewB.print();
1047 (*mergeReport) <<
"\n'" << mergeApproach <<
"'-Merging table '" <<
getTableName()
1048 <<
"' A=v" << sourceViewA.getVersion() <<
" with B=v"
1049 << sourceViewB.getVersion() << __E__;
1051 if(fillRecordConversionMaps && mergeApproach ==
"Rename")
1053 __COUT__ <<
"Filling record conversion map." << __E__;
1063 unsigned int uniqueId;
1064 std::string uniqueIdString, uniqueIdBase;
1065 char indexString[1000];
1067 unsigned int numericStartIndex;
1070 for(
unsigned int cb = 0; cb < sourceViewB.getNumberOfColumns(); ++cb)
1073 if(!(sourceViewA.getColumnInfo(cb).
isUID() ||
1074 sourceViewA.getColumnInfo(cb).
isGroupID()))
1077 __COUT__ <<
"Have an ID column: " << cb <<
" "
1078 << sourceViewA.getColumnInfo(cb).getType() << __E__;
1081 if(sourceViewA.getColumnInfo(cb).getType() !=
1082 sourceViewB.getColumnInfo(cb).getType() ||
1083 sourceViewA.getColumnInfo(cb).getType() !=
1084 mockupTableView_.getColumnInfo(cb).getType())
1086 __SS__ <<
"Error! " << sourceViewA.getColumnInfo(cb).getType()
1088 <<
" of source view A must match source B and destination mock-up "
1090 <<
" Column of source B is ["
1091 << sourceViewA.getColumnInfo(cb).getType()
1092 <<
"] and of destination mockup is ["
1093 << mockupTableView_.getColumnInfo(cb).getType() <<
"]." << __E__;
1099 std::vector<std::string >
1102 if(sourceViewA.getColumnInfo(cb).
isGroupID())
1107 for(
const auto& bGroupid : bGroupids)
1109 if(aGroupids.find(bGroupid) == aGroupids.end())
1113 __COUT__ <<
"found conflict: " <<
getTableName() <<
"/" << bGroupid
1118 const std::string& str = bGroupid;
1119 numericStartIndex = str.size();
1122 while(numericStartIndex - 1 < str.size() &&
1123 str[numericStartIndex - 1] >=
'0' &&
1124 str[numericStartIndex - 1] <=
'9')
1125 --numericStartIndex;
1127 if(numericStartIndex < str.size())
1129 uniqueId = atoi(str.substr(numericStartIndex).c_str()) + 1;
1130 uniqueIdBase = str.substr(0, numericStartIndex);
1138 __COUTV__(uniqueIdBase);
1139 __COUTV__(uniqueId);
1144 sprintf(indexString,
"%u", uniqueId);
1145 uniqueIdString = uniqueIdBase + indexString;
1146 __COUTV__(uniqueIdString);
1150 if(aGroupids.find(uniqueIdString) != aGroupids.end())
1152 if(!found && bGroupids.find(uniqueIdString) != bGroupids.end())
1154 if(!found && bGroupids.find(uniqueIdString) != bGroupids.end())
1156 for(ra = 0; !found && ra < localConvertedIds.size(); ++ra)
1157 if(localConvertedIds[ra] == uniqueIdString)
1163 sprintf(indexString,
"%u", uniqueId);
1164 uniqueIdString = uniqueIdBase + indexString;
1165 __COUTV__(uniqueIdString);
1169 if(aGroupids.find(uniqueIdString) != aGroupids.end())
1172 bGroupids.find(uniqueIdString) != bGroupids.end())
1175 bGroupids.find(uniqueIdString) != bGroupids.end())
1177 for(ra = 0; !found && ra < localConvertedIds.size(); ++ra)
1178 if(localConvertedIds[ra] == uniqueIdString)
1184 __COUTV__(uniqueIdString);
1186 groupidConversionMap
1187 [std::pair<std::string ,
1188 std::pair<std::string ,
1191 std::pair<std::string ,
1194 bGroupid))] = uniqueIdString;
1195 localConvertedIds.push_back(uniqueIdString);
1202 <<
"Found conflicting B groupID for linkIndex '"
1204 <<
"' and renamed '" << bGroupid <<
"' to '" << uniqueIdString
1215 for(
unsigned int rb = 0; rb < sourceViewB.getNumberOfRows(); ++rb)
1219 for(ra = 0; ra < sourceViewA.getDataView().size(); ++ra)
1231 __COUT__ <<
"found conflict: " <<
getTableName() <<
"/"
1232 << sourceViewB.getDataView()[rb][cb] << __E__;
1236 const std::string& str = sourceViewB.getDataView()[rb][cb];
1237 numericStartIndex = str.size();
1240 while(numericStartIndex - 1 < str.size() &&
1241 str[numericStartIndex - 1] >=
'0' &&
1242 str[numericStartIndex - 1] <=
'9')
1243 --numericStartIndex;
1245 if(numericStartIndex < str.size())
1247 uniqueId = atoi(str.substr(numericStartIndex).c_str()) + 1;
1248 uniqueIdBase = str.substr(0, numericStartIndex);
1256 __COUTV__(uniqueIdBase);
1257 __COUTV__(uniqueId);
1262 sprintf(indexString,
"%u", uniqueId);
1263 uniqueIdString = uniqueIdBase + indexString;
1264 __COUTV__(uniqueIdString);
1268 for(ra = 0; !found && ra < sourceViewA.getDataView().size(); ++ra)
1271 for(ra = 0; !found && ra < sourceViewB.getDataView().size(); ++ra)
1277 for(ra = 0; !found && ra < localConvertedIds.size(); ++ra)
1278 if(localConvertedIds[ra] == uniqueIdString)
1284 sprintf(indexString,
"%u", uniqueId);
1285 uniqueIdString = uniqueIdBase + indexString;
1286 __COUTV__(uniqueIdString);
1290 for(ra = 0; !found && ra < sourceViewA.getDataView().size();
1294 for(ra = 0; !found && ra < sourceViewB.getDataView().size();
1301 for(ra = 0; !found && ra < localConvertedIds.size(); ++ra)
1302 if(localConvertedIds[ra] == uniqueIdString)
1308 __COUTV__(uniqueIdString);
1310 uidConversionMap[std::pair<std::string ,
1314 localConvertedIds.push_back(uniqueIdString);
1319 (*mergeReport) <<
"\t"
1320 <<
"Found conflicting B UID and renamed '"
1322 << uniqueIdString <<
"'" << __E__;
1333 __COUT__ <<
"Not filling record conversion map." << __E__;
1335 if(!applyRecordConversionMaps)
1337 __COUT__ <<
"Not applying record conversion map." << __E__;
1342 __COUT__ <<
"Applying record conversion map." << __E__;
1350 __COUT__ <<
"Merging from (A) " << sourceViewA.getTableName() <<
"_v"
1351 << sourceViewA.getVersion() <<
" and (B) " << sourceViewB.getTableName()
1352 <<
"_v" << sourceViewB.getVersion() <<
" to " <<
getTableName() <<
"_v"
1353 << destinationVersion <<
" with approach '" << mergeApproach <<
".'"
1365 .copy(sourceViewA, destinationVersion, author));
1367 unsigned int destRow, destSize = destinationView->getDataView().size();
1370 std::map<std::pair<std::string , std::string >,
1371 std::string >::iterator uidConversionIt;
1372 std::map<std::pair<std::string ,
1373 std::pair<std::string ,
1375 std::string >::iterator groupidConversionIt;
1378 std::pair<
unsigned int ,
unsigned int > linkPair;
1382 unsigned int colUID = mockupTableView_.
getColUID();
1385 for(
unsigned int rb = 0; rb < sourceViewB.getNumberOfRows(); ++rb)
1387 if(mergeApproach ==
"Rename")
1397 destRow = destinationView->
copyRows(
1403 generateUniqueDataColumns );
1407 for(cb = 0; cb < sourceViewB.getNumberOfColumns(); ++cb)
1413 __COUT__ <<
"Checking UID link... col=" << cb << __E__;
1417 if((uidConversionIt = uidConversionMap.find(
1418 std::pair<std::string ,
1422 rb, linkPair.second)))) != uidConversionMap.end())
1424 __COUT__ <<
"Found entry to remap: "
1425 << sourceViewB.getDataView()[rb][linkPair.second]
1426 <<
" ==> " << uidConversionIt->second << __E__;
1431 <<
"Found entry to remap [r,c]=[" << rb <<
"," << cb
1434 << sourceViewB.getDataView()[rb][linkPair.second]
1435 <<
" ==> [" << destRow <<
"," << linkPair.second
1436 << uidConversionIt->second << __E__;
1438 uidConversionIt->second, destRow, linkPair.second);
1443 __COUT__ <<
"Checking GroupID link... col=" << cb << __E__;
1447 if((groupidConversionIt = groupidConversionMap.find(
1448 std::pair<std::string ,
1449 std::pair<std::string ,
1452 std::pair<std::string ,
1456 rb, linkPair.second))))) !=
1457 groupidConversionMap.end())
1459 __COUT__ <<
"Found entry to remap: "
1460 << sourceViewB.getDataView()[rb][linkPair.second]
1461 <<
" ==> " << groupidConversionIt->second << __E__;
1466 <<
"Found entry to remap [r,c]=[" << rb <<
"," << cb
1469 << sourceViewB.getDataView()[rb][linkPair.second]
1470 <<
" ==> [" << destRow <<
"," << linkPair.second
1471 <<
"] " << groupidConversionIt->second << __E__;
1473 groupidConversionIt->second, destRow, linkPair.second);
1476 else if(sourceViewB.getColumnInfo(cb).
isUID())
1478 __COUT__ <<
"Checking UID... col=" << cb << __E__;
1479 if((uidConversionIt = uidConversionMap.find(
1480 std::pair<std::string ,
1484 uidConversionMap.end())
1486 __COUT__ <<
"Found entry to remap: "
1487 << sourceViewB.getDataView()[rb][cb] <<
" ==> "
1488 << uidConversionIt->second << __E__;
1493 <<
"Found entry to remap [r,c]=[" << rb <<
"," << cb
1495 <<
": " << sourceViewB.getDataView()[rb][cb]
1496 <<
" ==> [" << destRow <<
"," << cb <<
"] "
1497 << uidConversionIt->second << __E__;
1499 uidConversionIt->second, destRow, cb);
1502 else if(sourceViewB.getColumnInfo(cb).
isGroupID())
1504 __COUT__ <<
"Checking GroupID... col=" << cb << __E__;
1505 if((groupidConversionIt = groupidConversionMap.find(
1506 std::pair<std::string ,
1507 std::pair<std::string ,
1510 std::pair<std::string ,
1514 groupidConversionMap.end())
1516 __COUT__ <<
"Found entry to remap: "
1517 << sourceViewB.getDataView()[rb][cb] <<
" ==> "
1518 << groupidConversionIt->second << __E__;
1523 <<
"Found entry to remap [r,c]=[" << rb <<
"," << cb
1524 <<
"]" << sourceViewB.getDataView()[rb][cb]
1525 <<
" ==> [" << destRow <<
"," << cb <<
"] "
1526 << groupidConversionIt->second << __E__;
1528 groupidConversionIt->second, destRow, cb);
1535 if(strb.size() >
getTableName().size() + 2 && strb[0] ==
'/')
1538 __COUT__ <<
"Checking col" << cb <<
" " << strb << __E__;
1541 for(
const auto& mapPairToPair : uidConversionMap)
1543 if((stri = strb.find(mapPairToPair.first.first +
"/" +
1544 mapPairToPair.first.second)) !=
1547 __COUT__ <<
"Found a text link match (stri=" << stri
1549 << (mapPairToPair.first.first +
"/" +
1550 mapPairToPair.first.second)
1551 <<
" ==> " << mapPairToPair.second << __E__;
1555 strb.substr(0, stri) +
1556 (mapPairToPair.first.first +
"/" +
1557 mapPairToPair.first.second) +
1559 (mapPairToPair.first.first +
"/" +
1560 mapPairToPair.first.second)
1566 <<
"Found entry to remap: "
1567 << sourceViewB.getDataView()[rb][cb] <<
" ==> "
1568 << destinationView->getDataView()[destRow][cb]
1574 <<
"Found entry to remap [r,c]=[" << rb <<
","
1576 << sourceViewB.getDataView()[rb][cb]
1577 <<
" ==> [" << destRow <<
"," << cb <<
"] "
1578 << destinationView->getDataView()[destRow][cb]
1594 for(destRow = 0; destRow < destSize; ++destRow)
1603 __COUT__ <<
"No " << mergeApproach <<
" conflict: " << __E__;
1605 if(mergeApproach ==
"replace" || mergeApproach ==
"skip")
1610 author, sourceViewB, rb, 1 );
1619 __COUT__ <<
"found " << mergeApproach
1620 <<
" conflict: " << sourceViewB.getDataView()[rb][colUID] << __E__;
1622 if(mergeApproach ==
"replace")
1627 <<
"Found UID conflict, replacing A with B record row=" << rb
1628 <<
" " << sourceViewB.getDataView()[rb][colUID] << __E__;
1638 destinationView->
copyRows(author, sourceViewB, rb, 1 );
1640 else if(mergeApproach ==
"skip")
1645 <<
"Found UID conflict, skipping B record row=" << rb <<
" "
1646 << sourceViewB.getDataView()[rb][colUID] << __E__;
1650 destinationView->print();
1654 __COUT_ERR__ <<
"Failed to merge " << sourceViewA.getTableName() <<
"_v"
1655 << sourceViewA.getVersion() <<
" and " << sourceViewB.getTableName()
1656 <<
"_v" << sourceViewB.getVersion() <<
" into " <<
getTableName()
1657 <<
"_v" << destinationVersion << __E__;
1658 __COUT_WARN__ <<
"Deleting the failed destination version " << destinationVersion
1660 eraseView(destinationVersion);
1664 return destinationVersion;
1677 const std::string& author,
1678 bool looseColumnMatching )
1681 if(!looseColumnMatching &&
1682 sourceView.getNumberOfColumns() != mockupTableView_.getNumberOfColumns())
1684 __SS__ <<
"Error! Number of Columns of source view must match destination "
1686 <<
"Dimension of source is [" << sourceView.getNumberOfColumns()
1687 <<
"] and of destination mockup is ["
1688 << mockupTableView_.getNumberOfColumns() <<
"]." << __E__;
1696 __SS__ <<
"Error! Asked to copy a view with a conflicting version: "
1697 << destinationVersion << __E__;
1704 __COUT__ <<
"Copying from " << sourceView.getTableName() <<
"_v"
1705 << sourceView.getVersion() <<
" to " <<
getTableName() <<
"_v"
1706 << destinationVersion << __E__;
1711 tableViews_.at(destinationVersion).copy(sourceView, destinationVersion, author);
1715 __COUT_ERR__ <<
"Failed to copy from " << sourceView.getTableName() <<
"_v"
1716 << sourceView.getVersion() <<
" to " <<
getTableName() <<
"_v"
1717 << destinationVersion << __E__;
1718 __COUT_WARN__ <<
"Deleting the failed destination version " << destinationVersion
1720 eraseView(destinationVersion);
1724 return destinationVersion;
1745 while(isStored(tmpVersion) &&
1748 if(isStored(tmpVersion) || tmpVersion.
isInvalid())
1750 __SS__ <<
"Invalid destination temporary version: " << destTemporaryViewVersion
1751 <<
". Expected next temporary version < " << tmpVersion << __E__;
1755 if(sourceViewVersion ==
1756 TableVersion::INVALID ||
1759 if(sourceViewVersion != -1)
1761 __SS__ <<
"ERROR: sourceViewVersion " << sourceViewVersion <<
" not found. "
1762 <<
"Invalid source version. Version requested is not stored (yet?) or "
1767 __COUTT__ <<
"Using Mock-up view" << __E__;
1770 .copy(mockupTableView_, tmpVersion, mockupTableView_.getAuthor());
1785 <<
"createTemporaryView() Source view failed init(). "
1786 <<
"This is being ignored (hopefully the new copy is being fixed)."
1811 __SS__ <<
"Invalid destination temporary version: " << tmpVersion << __E__;
1834 __SS__ <<
"Invalid destination next version: " << tmpVersion << __E__;
1849 __SS__ <<
getTableName() <<
":: Error! Temporary version not found!" << __E__;
1862 unsigned int tablePos = (
unsigned int)std::string::npos;
1864 ((tablePos = str.find(
"Table")) != str.size() - strlen(
"Table") ||
1866 (
unsigned int)std::string::npos))
1871 std::string capsStr =
"";
1872 for(
unsigned int c = 0; c < str.size(); ++c)
1873 if(str[c] >=
'A' && str[c] <=
'Z')
1877 (c && str[c - 1] >=
'a' &&
1878 str[c - 1] <=
'z') ||
1879 (c && str[c - 1] >=
'A' &&
1880 str[c - 1] <=
'Z' &&
1881 c + 1 < str.size() && str[c + 1] >=
'a' && str[c + 1] <=
'z') ||
1882 (c && str[c - 1] >=
'0' &&
1883 str[c - 1] <=
'9' &&
1884 c + 1 < str.size() && str[c + 1] >=
'a' && str[c + 1] <=
'z'))
1888 else if(str[c] >=
'a' && str[c] <=
'z')
1889 capsStr += char(str[c] - 32);
1890 else if(str[c] >=
'0' && str[c] <=
'9')
1895 if((str.substr(0, TableBase::GROUP_CACHE_PREPEND.length()) ==
1896 TableBase::GROUP_CACHE_PREPEND ||
1897 str.substr(0, TableBase::JSON_DOC_PREPEND.length()) ==
1898 TableBase::JSON_DOC_PREPEND) &&
1905 std::stringstream ss;
1906 ss << __COUT_HDR_FL__
1907 <<
"TableBase::convertToCaps: Invalid character found in name (allowed: "
1909 << str <<
"'" << __E__;
1910 TLOG(TLVL_ERROR) << ss.str();
const std::string & getTableName(void) const
Getters.
std::map< TableVersion, TableView > tableViews_
TableVersion createTemporaryView(TableVersion sourceViewVersion=TableVersion(), TableVersion destTemporaryViewVersion=TableVersion::getNextTemporaryVersion())
source of -1, from MockUp, else from valid view version
void setupMockupView(TableVersion version)
bool diffTwoVersions(TableVersion v1, TableVersion v2, std::stringstream *diffReport=0, std::map< std::string, std::vector< std::string >> *v1ModifiedRecords=0) const
TableBase(bool specialTable, const std::string &specialTableName)
void trimTemporary(TableVersion targetVersion=TableVersion())
TableVersion mergeViews(const TableView &sourceViewA, const TableView &sourceViewB, TableVersion destinationVersion, const std::string &author, const std::string &mergeApproach, std::map< std::pair< std::string, std::string >, std::string > &uidConversionMap, std::map< std::pair< std::string, std::pair< std::string, std::string > >, std::string > &groupidConversionMap, bool fillRecordConversionMaps, bool applyRecordConversionMaps, bool generateUniqueDataColumns=false, std::stringstream *mergeRepoert=nullptr)
unsigned int getNumberOfStoredViews(void) const
TableVersion checkForDuplicate(TableVersion needleVersion, TableVersion ignoreVersion=TableVersion()) const
bool isActive(void)
isActive
static std::string convertToCaps(std::string &str, bool isConfigName=false)
TableView * getTemporaryView(TableVersion temporaryVersion)
const unsigned int MAX_VIEWS_IN_CACHE
TableVersion getNextVersion(void) const
const TableVersion & getViewVersion(void) const
always the active one
TableVersion copyView(const TableView &sourceView, TableVersion destinationVersion, const std::string &author, bool looseColumnMatching=false)
bool latestAndMockupColumnNumberMismatch(void) const
void setTableName(const std::string &tableName)
Setters.
void print(std::ostream &out=std::cout) const
always prints active view
void specialMetaTableConstructor(void)
Methods.
TableVersion getNextTemporaryVersion(void) const
void trimCache(unsigned int trimSize=-1)
bool isInvalid(void) const
isInvalid
static TableVersion getNextVersion(const TableVersion &version=TableVersion())
bool isTemporaryVersion(void) const
static TableVersion getNextTemporaryVersion(const TableVersion &version=TableVersion())
bool isChildLinkUID(void) const
static const std::string DATATYPE_NUMBER
std::string getChildLinkIndex(void) const
getChildLinkIndex
bool isChildLink(void) const
bool isUID(void) const
isUID
bool isGroupID(void) const
static const std::string TYPE_UID
NOTE: Do NOT put '-' in static const TYPEs because it will mess up javascript handling in the web gui...
bool isChildLinkGroupID(void) const
void setValueAsString(const std::string &value, unsigned int row, unsigned int col)
bool getChildLink(const unsigned int &col, bool &isGroup, std::pair< unsigned int, unsigned int > &linkPair) const
unsigned int copyRows(const std::string &author, const TableView &src, unsigned int srcOffsetRow=0, unsigned int srcRowsToCopy=(unsigned int) -1, unsigned int destOffsetRow=(unsigned int) -1, unsigned char generateUniqueDataColumns=false, const std::string &baseNameAutoUID="")
std::string getValueAsString(unsigned int row, unsigned int col, bool convertEnvironmentVariables=true) const
std::set< std::string > getSetOfGroupIDs(const std::string &childLinkIndex, unsigned int row=-1) const
unsigned int getColUID(void) const
unsigned int addRow(const std::string &author="", unsigned char incrementUniqueData=false, const std::string &baseNameAutoUID="", unsigned int rowToAdd=(unsigned int) -1, std::string childLinkIndex="", std::string groupId="")
static std::string mapToString(const std::map< std::string, T > &mapToReturn, const std::string &primaryDelimeter=", ", const std::string &secondaryDelimeter=": ")
static std::string stackTrace(void)