File indexing completed on 2024-05-19 05:42:12
0001 // ct_lvtmdb_soci_reader.h -*-C++-*- 0002 0003 /* 0004 // Copyright 2023 Codethink Ltd <codethink@codethink.co.uk> 0005 // SPDX-License-Identifier: Apache-2.0 0006 // 0007 // Licensed under the Apache License, Version 2.0 (the "License"); 0008 // you may not use this file except in compliance with the License. 0009 // You may obtain a copy of the License at 0010 // 0011 // http://www.apache.org/licenses/LICENSE-2.0 0012 // 0013 // Unless required by applicable law or agreed to in writing, software 0014 // distributed under the License is distributed on an "AS IS" BASIS, 0015 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 0016 // See the License for the specific language governing permissions and 0017 // limitations under the License. 0018 */ 0019 0020 #include <ct_lvtmdb_soci_helper.h> 0021 #include <ct_lvtmdb_soci_reader.h> 0022 #include <ct_lvtshr_graphenums.h> 0023 0024 #include <filesystem> 0025 #include <optional> 0026 0027 #include <soci/soci-backend.h> 0028 #include <soci/soci.h> 0029 #include <soci/sqlite3/soci-sqlite3.h> 0030 0031 #include <ct_lvtmdb_componentobject.h> 0032 #include <ct_lvtmdb_errorobject.h> 0033 #include <ct_lvtmdb_fieldobject.h> 0034 #include <ct_lvtmdb_fileobject.h> 0035 #include <ct_lvtmdb_functionobject.h> 0036 #include <ct_lvtmdb_methodobject.h> 0037 #include <ct_lvtmdb_namespaceobject.h> 0038 #include <ct_lvtmdb_packageobject.h> 0039 #include <ct_lvtmdb_repositoryobject.h> 0040 #include <ct_lvtmdb_typeobject.h> 0041 #include <ct_lvtmdb_variableobject.h> 0042 0043 using namespace Codethink::lvtmdb; 0044 0045 namespace { 0046 0047 struct Maps { 0048 std::map<std::string, RepositoryObject *> repositoryMap; 0049 std::map<std::string, PackageObject *> packageMap; 0050 std::map<int, ComponentObject *> componentMap; 0051 std::map<int, FileObject *> filesMap; 0052 std::map<std::string, NamespaceObject *> namespaceMap; 0053 std::map<int, VariableObject *> variableMap; 0054 std::map<int, FunctionObject *> functionMap; 0055 std::map<int, TypeObject *> userDefinedTypeMap; 0056 std::map<int, FieldObject *> fieldMap; 0057 std::map<int, MethodObject *> methodMap; 0058 }; 0059 0060 void loadRepositories(ObjectStore& store, soci::session& db, Maps& map) 0061 { 0062 soci::rowset<soci::row> rowset = (db.prepare << "select name, disk_path from source_repository"); 0063 for (const auto& row : rowset) { 0064 const auto name = row.get<std::string>(0); 0065 const auto path = row.get<std::string>(1); 0066 auto *repo = store.getOrAddRepository(name, path); 0067 map.repositoryMap[name] = repo; 0068 } 0069 } 0070 0071 struct PackageQueryParams { 0072 int id = 0; 0073 0074 soci::indicator parent_ind = soci::indicator::i_null; 0075 std::string parent_qualified_name; 0076 0077 soci::indicator repository_ind = soci::indicator::i_null; 0078 std::string repository_name; 0079 0080 std::string name; 0081 std::string qualified_name; 0082 std::string path; 0083 }; 0084 0085 // This loads the packages in order so we don't need to worry about having 0086 // not loaded the parent yet. 0087 void loadPackages(ObjectStore& store, soci::session& db, Maps& maps, std::optional<int> parent_id) 0088 { 0089 // soci prepared statements didn't work for null vs value, neither with std::optional.' 0090 std::string query = 0091 R"(select 0092 sp.id, 0093 pp.qualified_name as parent_name, 0094 sp.name, 0095 sp.qualified_name, 0096 sp.disk_path, 0097 re.name 0098 from 0099 source_package sp 0100 left join 0101 source_package pp on sp.parent_id = pp.id 0102 left join 0103 source_repository re on sp.source_repository_id = re.id 0104 where sp.parent_id is )" 0105 + (parent_id.has_value() ? std::to_string(parent_id.value()) : "NULL"); 0106 0107 PackageQueryParams params; 0108 soci::statement st = (db.prepare << query, 0109 soci::into(params.id), 0110 soci::into(params.parent_qualified_name, params.parent_ind), 0111 soci::into(params.name), 0112 soci::into(params.qualified_name), 0113 soci::into(params.path), 0114 soci::into(params.repository_name, params.repository_ind)); 0115 0116 st.execute(); 0117 std::vector<int> current_parents; 0118 while (st.fetch()) { 0119 PackageObject *parent = nullptr; 0120 if (params.parent_ind == soci::indicator::i_ok) { 0121 parent = maps.packageMap[params.parent_qualified_name]; 0122 } 0123 0124 RepositoryObject *repository = nullptr; 0125 if (params.repository_ind == soci::indicator::i_ok) { 0126 repository = maps.repositoryMap[params.repository_name]; 0127 } 0128 0129 PackageObject *pkg = store.getOrAddPackage(params.qualified_name, params.name, params.path, parent, repository); 0130 current_parents.push_back(params.id); 0131 maps.packageMap[params.qualified_name] = pkg; 0132 0133 if (parent) { 0134 auto lock = parent->rwLock(); 0135 (void) lock; 0136 parent->addChild(pkg); 0137 } 0138 } 0139 0140 for (const auto current_parent : current_parents) { 0141 loadPackages(store, db, maps, current_parent); 0142 } 0143 } 0144 0145 struct ComponentQueryParams { 0146 int id = 0; 0147 std::string packageQualifiedName; 0148 std::string qualifiedName; 0149 std::string name; 0150 }; 0151 0152 void loadComponents(ObjectStore& store, soci::session& db, Maps& maps) 0153 { 0154 // soci prepared statements didn't work for null vs value, neither with std::optional.' 0155 std::string query = R"(select 0156 sc.id, 0157 sc.qualified_name, 0158 sc.name, 0159 sp.qualified_name as package_name 0160 from 0161 source_component sc 0162 left join 0163 source_package sp on sc.package_id = sp.id)"; 0164 0165 ComponentQueryParams params; 0166 soci::statement st = (db.prepare << query, 0167 soci::into(params.id), 0168 soci::into(params.qualifiedName), 0169 soci::into(params.name), 0170 soci::into(params.packageQualifiedName)); 0171 0172 st.execute(); 0173 while (st.fetch()) { 0174 PackageObject *package = maps.packageMap[params.packageQualifiedName]; 0175 auto *comp = store.getOrAddComponent(params.qualifiedName, params.name, package); 0176 maps.componentMap[params.id] = comp; 0177 0178 auto lock = package->rwLock(); 0179 (void) lock; 0180 package->addComponent(comp); 0181 } 0182 } 0183 0184 struct FileQueryParams { 0185 int id = 0; 0186 std::string package_qualified_name; 0187 int component_id = 0; 0188 std::string name; 0189 std::string qualifiedName; 0190 int is_header = false; // bool. 0191 std::string hash; 0192 }; 0193 0194 void loadFiles(ObjectStore& store, soci::session& db, Maps& maps) 0195 { 0196 std::string query = R"(select 0197 sf.id, 0198 sp.qualified_name as package_name, 0199 sf.component_id, 0200 sf.name, 0201 sf.qualified_name, 0202 sf.is_header, 0203 sf.hash 0204 from 0205 source_file sf 0206 left join 0207 source_package sp on sf.package_id = sp.id)"; 0208 0209 FileQueryParams params; 0210 soci::statement st = (db.prepare << query, 0211 soci::into(params.id), 0212 soci::into(params.package_qualified_name), 0213 soci::into(params.component_id), 0214 soci::into(params.name), 0215 soci::into(params.qualifiedName), 0216 soci::into(params.is_header), 0217 soci::into(params.hash)); 0218 0219 st.execute(); 0220 while (st.fetch()) { 0221 PackageObject *package = maps.packageMap[params.package_qualified_name]; 0222 ComponentObject *comp = maps.componentMap[params.component_id]; 0223 auto *fileObj = 0224 store.getOrAddFile(params.qualifiedName, params.name, params.is_header, params.hash, package, comp); 0225 0226 auto lock = comp->rwLock(); 0227 (void) lock; 0228 comp->addFile(fileObj); 0229 maps.filesMap[params.id] = fileObj; 0230 } 0231 } 0232 0233 /* this is a 1-1 mapping of the Sql schema. it clearly shows that we should 0234 * change this table to have the file_id instead of the file_name. 0235 */ 0236 struct ErrorQueryParams { 0237 int id = 0; 0238 int error_kind = 0; 0239 std::string fully_qualified_name; 0240 std::string error_message; 0241 std::string file_name; 0242 }; 0243 0244 void loadErrors(ObjectStore& store, soci::session& db, Maps& maps) 0245 { 0246 std::string query = "select id, error_kind, fully_qualified_name, error_message, file_name from error_messages"; 0247 ErrorQueryParams params; 0248 soci::statement st = (db.prepare << query, 0249 soci::into(params.id), 0250 soci::into(params.error_kind), 0251 soci::into(params.fully_qualified_name), 0252 soci::into(params.error_message), 0253 soci::into(params.file_name)); 0254 0255 st.execute(); 0256 while (st.fetch()) { 0257 // I see no need to store the errors on a map, just load it directly. 0258 auto kind = static_cast<MdbUtil::ErrorKind>(params.error_kind); 0259 store.getOrAddError(kind, params.fully_qualified_name, params.error_message, params.file_name); 0260 } 0261 } 0262 0263 struct NamespaceQueryParams { 0264 int id = 0; 0265 soci::indicator parent_qualified_name_ind = soci::indicator::i_null; 0266 std::string parent_qualified_name; 0267 std::string name; 0268 std::string qualified_name; 0269 }; 0270 0271 void loadNamespaces(ObjectStore& store, soci::session& db, Maps& maps, std::optional<int> parent_id) 0272 { 0273 std::string query = 0274 R"(select 0275 ns.id, 0276 ns.name, 0277 ns.qualified_name, 0278 pns.qualified_name 0279 from namespace_declaration ns 0280 left join namespace_declaration pns on ns.parent_id = pns.id 0281 where ns.parent_id is )" 0282 + (parent_id.has_value() ? std::to_string(parent_id.value()) : "NULL"); 0283 0284 NamespaceQueryParams params; 0285 soci::statement st = (db.prepare << query, 0286 soci::into(params.id), 0287 soci::into(params.name), 0288 soci::into(params.qualified_name), 0289 soci::into(params.parent_qualified_name, params.parent_qualified_name_ind)); 0290 0291 st.execute(); 0292 std::vector<int> current_parents; 0293 while (st.fetch()) { 0294 NamespaceObject *parent = nullptr; 0295 if (params.parent_qualified_name_ind == soci::indicator::i_ok) { 0296 parent = maps.namespaceMap[params.parent_qualified_name]; 0297 } 0298 0299 auto *ns = store.getOrAddNamespace(params.qualified_name, params.name, parent); 0300 current_parents.push_back(params.id); 0301 maps.namespaceMap[params.qualified_name] = ns; 0302 } 0303 0304 for (const auto current_parent : current_parents) { 0305 loadNamespaces(store, db, maps, current_parent); 0306 } 0307 } 0308 0309 struct VariableQueryParams { 0310 int id = 0; 0311 soci::indicator ns_qual_name_ind = soci::indicator::i_null; 0312 std::string ns_qual_name; 0313 std::string name; 0314 std::string qualified_name; 0315 std::string signature; 0316 int is_global = 0; // bool. 0317 }; 0318 0319 void loadVariables(ObjectStore& store, soci::session& db, Maps& maps) 0320 { 0321 std::string query = 0322 R"(select 0323 va.id, 0324 va.name, 0325 va.qualified_name, 0326 va.signature, 0327 va.is_global, 0328 ns.qualified_name 0329 from 0330 variable_declaration va 0331 left join 0332 namespace_declaration ns on ns.id = va.namespace_id 0333 )"; 0334 0335 VariableQueryParams params; 0336 soci::statement st = (db.prepare << query, 0337 soci::into(params.id), 0338 soci::into(params.name), 0339 soci::into(params.qualified_name), 0340 soci::into(params.signature), 0341 soci::into(params.is_global), 0342 soci::into(params.ns_qual_name, params.ns_qual_name_ind)); 0343 0344 st.execute(); 0345 0346 while (st.fetch()) { 0347 NamespaceObject *ns = nullptr; 0348 if (params.ns_qual_name_ind != soci::indicator::i_null) { 0349 ns = maps.namespaceMap[params.ns_qual_name]; 0350 } 0351 0352 auto *variableObj = 0353 store.getOrAddVariable(params.qualified_name, params.name, params.signature, params.is_global, ns); 0354 maps.variableMap[params.id] = variableObj; 0355 } 0356 } 0357 0358 struct FunctionQueryParams { 0359 int id = 0; 0360 soci::indicator ns_qual_name_ind = soci::indicator::i_null; 0361 std::string ns_qual_name; 0362 std::string name; 0363 std::string qualified_name; 0364 std::string signature; 0365 std::string rtype; 0366 std::string template_params; 0367 }; 0368 0369 void loadFunctions(ObjectStore& store, soci::session& db, Maps& maps) 0370 { 0371 std::string query = 0372 R"(select 0373 fn.id, 0374 fn.name, 0375 fn.qualified_name, 0376 fn.signature, 0377 fn.return_type, 0378 fn.template_parameters, 0379 ns.qualified_name 0380 from 0381 function_declaration fn 0382 left join 0383 namespace_declaration ns on ns.id = fn.namespace_id 0384 )"; 0385 0386 FunctionQueryParams params; 0387 soci::statement st = (db.prepare << query, 0388 soci::into(params.id), 0389 soci::into(params.name), 0390 soci::into(params.qualified_name), 0391 soci::into(params.signature), 0392 soci::into(params.rtype), 0393 soci::into(params.template_params), 0394 soci::into(params.ns_qual_name, params.ns_qual_name_ind)); 0395 0396 st.execute(); 0397 0398 while (st.fetch()) { 0399 NamespaceObject *ns = nullptr; 0400 if (params.ns_qual_name_ind != soci::indicator::i_null) { 0401 ns = maps.namespaceMap[params.ns_qual_name]; 0402 } 0403 0404 auto *functionObj = store.getOrAddFunction(params.qualified_name, 0405 params.name, 0406 params.signature, 0407 params.rtype, 0408 params.template_params, 0409 ns); 0410 maps.functionMap[params.id] = functionObj; 0411 } 0412 } 0413 0414 struct UserDefinedTypeQueryParams { 0415 int id = 0; 0416 soci::indicator parent_ns_qual_name_ind = soci::indicator::i_null; 0417 std::string parent_ns_qual_name; 0418 0419 soci::indicator class_namespace_ind = soci::indicator::i_null; 0420 int class_namespace_id = 0; 0421 0422 soci::indicator parent_package_ind = soci::indicator::i_null; 0423 std::string package_qualified_name; 0424 std::string name; 0425 std::string qualified_name; 0426 int kind = 0; 0427 int access = 0; 0428 }; 0429 0430 void loadUserDefinedTypes(ObjectStore& store, soci::session& db, Maps& maps, std::optional<int> parent_id) 0431 { 0432 // soci prepared statements didn't work for null vs value, neither with std::optional.' 0433 std::string query = 0434 R"(select 0435 cd.id, 0436 cd.class_namespace_id, 0437 sp.qualified_name as package_name, 0438 cd.name, 0439 cd.qualified_name, 0440 cd.kind, 0441 cd.access, 0442 ns.qualified_name 0443 from 0444 class_declaration cd 0445 left join 0446 source_package sp on sp.id = cd.parent_package_id 0447 left join 0448 namespace_declaration ns on ns.id = cd.parent_namespace_id 0449 where class_namespace_id is )" 0450 + (parent_id.has_value() ? std::to_string(parent_id.value()) : "NULL"); 0451 0452 UserDefinedTypeQueryParams params; 0453 soci::statement st = (db.prepare << query, 0454 soci::into(params.id), 0455 soci::into(params.class_namespace_id, params.class_namespace_ind), 0456 soci::into(params.package_qualified_name, params.parent_package_ind), 0457 soci::into(params.name), 0458 soci::into(params.qualified_name), 0459 soci::into(params.kind), 0460 soci::into(params.access), 0461 soci::into(params.parent_ns_qual_name, params.parent_ns_qual_name_ind)); 0462 0463 st.execute(); 0464 std::vector<int> current_parents; 0465 while (st.fetch()) { 0466 NamespaceObject *parent_ns = nullptr; 0467 if (params.parent_ns_qual_name_ind == soci::indicator::i_ok) { 0468 parent_ns = maps.namespaceMap[params.parent_ns_qual_name]; 0469 } 0470 0471 TypeObject *parent_class = nullptr; 0472 if (params.class_namespace_ind == soci::indicator::i_ok) { 0473 parent_class = maps.userDefinedTypeMap[params.class_namespace_id]; 0474 } 0475 0476 PackageObject *parent_pkg = nullptr; 0477 if (params.parent_package_ind == soci::indicator::i_ok) { 0478 parent_pkg = maps.packageMap[params.package_qualified_name]; 0479 } 0480 0481 auto kind = static_cast<Codethink::lvtshr::UDTKind>(params.kind); 0482 // TODO: Move CDBUtil::AccessSpecifier to lvtmdb. 0483 auto accessSpecifier = static_cast<Codethink::lvtshr::AccessSpecifier>(params.access); 0484 0485 auto *udt = store.getOrAddType(params.qualified_name, 0486 params.name, 0487 kind, 0488 accessSpecifier, 0489 parent_ns, 0490 parent_pkg, 0491 parent_class); 0492 maps.userDefinedTypeMap[params.id] = udt; 0493 current_parents.push_back(params.id); 0494 0495 if (parent_pkg) { 0496 auto lock = parent_pkg->rwLock(); 0497 (void) lock; 0498 parent_pkg->addType(udt); 0499 } 0500 if (parent_ns) { 0501 auto lock = parent_ns->rwLock(); 0502 (void) lock; 0503 parent_ns->addType(udt); 0504 } 0505 if (parent_class) { 0506 auto lock = parent_class->rwLock(); 0507 (void) lock; 0508 parent_class->addChild(udt); 0509 } 0510 } 0511 0512 for (const int id : current_parents) { 0513 loadUserDefinedTypes(store, db, maps, id); 0514 } 0515 } 0516 0517 struct FieldQueryParams { 0518 int id = 0; 0519 int class_id = 0; 0520 std::string name; 0521 std::string qualified_name; 0522 std::string signature; 0523 int access = 0; 0524 int is_static = false; // bool. 0525 }; 0526 0527 void loadFields(ObjectStore& store, soci::session& db, Maps& maps) 0528 { 0529 std::string query = 0530 "select id, class_id, name, qualified_name, signature, access, is_static from " 0531 "field_declaration"; 0532 0533 FieldQueryParams params; 0534 soci::statement st = (db.prepare << query, 0535 soci::into(params.id), 0536 soci::into(params.class_id), 0537 soci::into(params.name), 0538 soci::into(params.qualified_name), 0539 soci::into(params.signature), 0540 soci::into(params.access), 0541 soci::into(params.is_static)); 0542 0543 st.execute(); 0544 0545 while (st.fetch()) { 0546 TypeObject *parent = maps.userDefinedTypeMap[params.class_id]; 0547 auto accessSpecifier = static_cast<Codethink::lvtshr::AccessSpecifier>(params.access); 0548 auto *field = store.getOrAddField(params.qualified_name, 0549 params.name, 0550 params.signature, 0551 accessSpecifier, 0552 params.is_static, 0553 parent); 0554 maps.fieldMap[params.id] = field; 0555 } 0556 } 0557 0558 struct MethodQueryParams { 0559 int id = 0; 0560 soci::indicator class_ind = soci::indicator::i_null; 0561 int class_id = 0; 0562 std::string name; 0563 std::string qualified_name; 0564 std::string signature; 0565 std::string rtype; 0566 std::string template_parameters; 0567 int access = 0; 0568 int is_virtual = false; 0569 int is_pure = false; 0570 int is_static = false; 0571 soci::indicator const_ind = soci::indicator::i_null; 0572 int is_const = false; 0573 }; 0574 0575 void loadMethods(ObjectStore& store, soci::session& db, Maps& maps) 0576 { 0577 std::string query = 0578 "select id, class_id, name, qualified_name, signature, return_type " 0579 " template_parameters, access, is_virtual, is_pure, is_static, is_const from " 0580 "method_declaration"; 0581 0582 MethodQueryParams params; 0583 soci::statement st = (db.prepare << query, 0584 soci::into(params.id), 0585 soci::into(params.class_id), 0586 soci::into(params.name), 0587 soci::into(params.qualified_name), 0588 soci::into(params.signature), 0589 soci::into(params.rtype), 0590 soci::into(params.template_parameters), 0591 soci::into(params.access), 0592 soci::into(params.is_virtual), 0593 soci::into(params.is_pure), 0594 soci::into(params.is_static), 0595 0596 // This looks like it's a bug on soci. `is_const` 0597 // is defined as "NOT NULL" but soci is fetching 0598 // a null value. 0599 soci::into(params.is_const, params.const_ind)); 0600 0601 st.execute(); 0602 0603 while (st.fetch()) { 0604 TypeObject *parent = maps.userDefinedTypeMap[params.class_id]; 0605 auto accessSpecifier = static_cast<Codethink::lvtshr::AccessSpecifier>(params.access); 0606 0607 // This looks like it's a bug on soci. `is_const` 0608 // is defined as "NOT NULL" but soci is fetching 0609 // a null value. 0610 if (params.const_ind == soci::indicator::i_null) { 0611 params.is_const = false; 0612 } 0613 0614 auto *method = store.getOrAddMethod(params.qualified_name, 0615 params.name, 0616 params.signature, 0617 params.rtype, 0618 params.template_parameters, 0619 accessSpecifier, 0620 params.is_virtual, 0621 params.is_pure, 0622 params.is_static, 0623 params.is_const, 0624 parent); 0625 maps.methodMap[params.id] = method; 0626 } 0627 } 0628 0629 void loadPackageRelations(ObjectStore& store, soci::session& db, Maps& maps) 0630 { 0631 const std::string query = R"( 0632 select 0633 target.qualified_name 0634 from 0635 dependencies dep 0636 left join 0637 source_package target on target_id = target.id 0638 where dep.source_id = ( 0639 select id 0640 from source_package 0641 where qualified_name = :s 0642 ) )"; 0643 0644 // Those are all the *database* connections but I guess there's more. 0645 for (const auto& [qualified_name, _] : maps.packageMap) { 0646 (void) _; 0647 0648 PackageObject *source = maps.packageMap[qualified_name]; 0649 std::string target_qual_name; 0650 soci::statement st = (db.prepare << query, soci::into(target_qual_name), soci::use(qualified_name)); 0651 st.execute(); 0652 while (st.fetch()) { 0653 PackageObject *target = maps.packageMap[target_qual_name]; 0654 PackageObject::addDependency(target, source); 0655 } 0656 } 0657 } 0658 0659 void loadComponentRelations(ObjectStore& store, soci::session& db, const Maps& maps) 0660 { 0661 for (const auto& [id, source] : maps.componentMap) { 0662 int target_id = 0; 0663 soci::statement st = (db.prepare << "select target_id from component_relation where source_id = :s", 0664 soci::into(target_id), 0665 soci::use(id)); 0666 st.execute(); 0667 while (st.fetch()) { 0668 ComponentObject *target = maps.componentMap.at(target_id); 0669 ComponentObject::addDependency(source, target); 0670 } 0671 } 0672 } 0673 0674 void loadFileRelations(ObjectStore& store, soci::session& db, const Maps& maps) 0675 { 0676 const std::string query_1 = R"(select target_id from includes where source_id = :s)"; 0677 const std::string query_2 = 0678 R"(select 0679 ns.qualified_name 0680 from namespace_source_file nsf 0681 left join 0682 namespace_declaration ns on ns.id = nsf.namespace_id 0683 where nsf.source_file_id = :s)"; 0684 0685 for (const auto& [source_id, source] : maps.filesMap) { 0686 int target_id = 0; 0687 soci::statement st = (db.prepare << query_1, soci::into(target_id), soci::use(source_id)); 0688 st.execute(); 0689 while (st.fetch()) { 0690 FileObject *target = maps.filesMap.at(target_id); 0691 FileObject::addIncludeRelation(source, target); 0692 } 0693 0694 std::string ns_qual_name; 0695 soci::statement st2 = (db.prepare << query_2, soci::into(ns_qual_name), soci::use(source_id)); 0696 st2.execute(); 0697 while (st2.fetch()) { 0698 NamespaceObject *target = maps.namespaceMap.at(ns_qual_name); 0699 { 0700 auto lock = source->rwLock(); 0701 source->addNamespace(target); 0702 } 0703 { 0704 auto lock = target->rwLock(); 0705 target->addFile(source); 0706 } 0707 } 0708 } 0709 } 0710 0711 void loadUserDefinedTypeRelations(ObjectStore& store, soci::session& db, const Maps& maps) 0712 { 0713 for (const auto& [source_id, source] : maps.userDefinedTypeMap) { 0714 // uses_in_the_interface. 0715 int target_id = 0; 0716 soci::statement st = (db.prepare << "select target_id from uses_in_the_interface where source_id = :s", 0717 soci::into(target_id), 0718 soci::use(source_id)); 0719 st.execute(); 0720 while (st.fetch()) { 0721 TypeObject *target = maps.userDefinedTypeMap.at(target_id); 0722 TypeObject::addUsesInTheInterface(source, target); 0723 } 0724 0725 // uses_in_the_implementation 0726 target_id = 0; 0727 st = (db.prepare << "select target_id from uses_in_the_implementation where source_id = :s", 0728 soci::into(target_id), 0729 soci::use(source_id)); 0730 st.execute(); 0731 while (st.fetch()) { 0732 TypeObject *target = maps.userDefinedTypeMap.at(target_id); 0733 TypeObject::addUsesInTheImplementation(source, target); 0734 } 0735 0736 // class_hierarchy 0737 target_id = 0; 0738 st = (db.prepare << "select target_id from class_hierarchy where source_id = :s", 0739 soci::into(target_id), 0740 soci::use(source_id)); 0741 st.execute(); 0742 while (st.fetch()) { 0743 TypeObject *target = maps.userDefinedTypeMap.at(target_id); 0744 TypeObject::addIsARelationship(source, target); 0745 } 0746 0747 // components 0748 target_id = 0; 0749 st = (db.prepare << "select component_id from udt_component where udt_id = :s", 0750 soci::into(target_id), 0751 soci::use(source_id)); 0752 st.execute(); 0753 while (st.fetch()) { 0754 ComponentObject *target = maps.componentMap.at(target_id); 0755 { 0756 auto lock = target->rwLock(); 0757 (void) lock; 0758 target->addType(source); 0759 } 0760 { 0761 auto lock = source->rwLock(); 0762 (void) lock; 0763 source->addComponent(target); 0764 } 0765 } 0766 0767 // source files. 0768 target_id = 0; 0769 st = (db.prepare << "select source_file_id from class_source_file where class_id = :s", 0770 soci::into(target_id), 0771 soci::use(source_id)); 0772 st.execute(); 0773 while (st.fetch()) { 0774 FileObject *target = maps.filesMap.at(target_id); 0775 { 0776 auto lock = target->rwLock(); 0777 (void) lock; 0778 target->addType(source); 0779 } 0780 { 0781 auto lock = source->rwLock(); 0782 (void) lock; 0783 source->addFile(target); 0784 } 0785 } 0786 } 0787 } 0788 0789 void loadFieldRelations(ObjectStore& store, soci::session& db, const Maps& maps) 0790 { 0791 for (const auto& [source_id, source] : maps.fieldMap) { 0792 int target_id = 0; 0793 soci::statement st = (db.prepare << "select type_class_id from field_type where field_id = :s", 0794 soci::into(target_id), 0795 soci::use(source_id)); 0796 st.execute(); 0797 while (st.fetch()) { 0798 TypeObject *target = maps.userDefinedTypeMap.at(target_id); 0799 { 0800 auto lock = target->rwLock(); 0801 (void) lock; 0802 target->addField(source); 0803 } 0804 { 0805 auto lock = source->rwLock(); 0806 (void) lock; 0807 source->addType(target); 0808 } 0809 } 0810 } 0811 } 0812 0813 void loadMethodRelations(ObjectStore& store, soci::session& db, const Maps& maps) 0814 { 0815 for (const auto& [source_id, source] : maps.methodMap) { 0816 int target_id = 0; 0817 soci::statement st = (db.prepare << "select type_class_id from method_argument_class where method_id = :s", 0818 soci::into(target_id), 0819 soci::use(source_id)); 0820 st.execute(); 0821 while (st.fetch()) { 0822 TypeObject *target = maps.userDefinedTypeMap.at(target_id); 0823 auto lock = target->rwLock(); 0824 (void) lock; 0825 target->addMethod(source); 0826 } 0827 } 0828 } 0829 0830 } // end namespace 0831 0832 cpp::result<void, ObjectStore::ReadFromDatabaseError> SociReader::readInto(ObjectStore& store, const std::string& path) 0833 { 0834 auto lock = store.rwLock(); 0835 (void) lock; 0836 0837 if (path != ":memory:") { 0838 if (!std::filesystem::exists(path)) { 0839 return cpp::fail(ObjectStore::ReadFromDatabaseError{"File doesn't exist on disk"}); 0840 } 0841 } 0842 0843 soci::session db; 0844 db.open(*soci::factory_sqlite3(), path); 0845 0846 // Currently there's no version check on lvtmdb.' 0847 // const int version_key = static_cast<int>(SociHelper::Key::Version); 0848 const int db_state_key = static_cast<int>(SociHelper::Key::DatabaseState); 0849 0850 int query_res; 0851 db << "select value from db_option where key = :k", soci::into(query_res), soci::use(db_state_key); 0852 0853 // Load the Repositories 0854 Maps maps; 0855 0856 loadRepositories(store, db, maps); 0857 loadPackages(store, db, maps, std::nullopt); 0858 loadComponents(store, db, maps); 0859 loadFiles(store, db, maps); 0860 loadErrors(store, db, maps); 0861 loadNamespaces(store, db, maps, std::nullopt); 0862 loadVariables(store, db, maps); 0863 loadFunctions(store, db, maps); 0864 loadUserDefinedTypes(store, db, maps, std::nullopt); 0865 loadFields(store, db, maps); 0866 loadMethods(store, db, maps); 0867 0868 // Here we have all the entities, we now need to add the connections between them. 0869 loadPackageRelations(store, db, maps); 0870 loadComponentRelations(store, db, maps); 0871 loadFileRelations(store, db, maps); 0872 loadUserDefinedTypeRelations(store, db, maps); 0873 loadFieldRelations(store, db, maps); 0874 loadMethodRelations(store, db, maps); 0875 return {}; 0876 }