Status getQueryColumnsExternal(const std::string& manager_path, const std::string& query, TableColumns& columns) { // Make sure the extension path exists, and is writable. auto status = extensionPathActive(manager_path); if (!status.ok()) { return status; } ExtensionResponse response; try { auto client = EXManagerClient(manager_path); client.get()->getQueryColumns(response, query); } catch (const std::exception& e) { return Status(1, "Extension call failed: " + std::string(e.what())); } // Translate response map: {string: string} to a vector: pair(name, type). for (const auto& column : response.response) { for (const auto& col : column) { columns.push_back( std::make_tuple(col.first, columnTypeName(col.second), DEFAULT)); } } return Status(response.status.code, response.status.message); }
std::string columnDefinition(const PluginResponse& response) { TableColumns columns; for (const auto& column : response) { columns.push_back(make_pair(column.at("name"), column.at("type"))); } return columnDefinition(columns); }
TableColumns columns() const { TableColumns cols; for (int i = 0; i < 20; i++) { cols.push_back({"test_" + std::to_string(i), INTEGER_TYPE}); } return cols; }
Status getQueryColumnsInternal(const std::string& q, TableColumns& columns, sqlite3* db) { // Turn the query into a prepared statement sqlite3_stmt* stmt{nullptr}; auto rc = sqlite3_prepare_v2( db, q.c_str(), static_cast<int>(q.length() + 1), &stmt, nullptr); if (rc != SQLITE_OK || stmt == nullptr) { if (stmt != nullptr) { sqlite3_finalize(stmt); } return Status(1, sqlite3_errmsg(db)); } // Get column count auto num_columns = sqlite3_column_count(stmt); TableColumns results; results.reserve(num_columns); // Get column names and types Status status = Status(); bool unknown_type = false; for (int i = 0; i < num_columns; ++i) { auto col_name = sqlite3_column_name(stmt, i); auto col_type = sqlite3_column_decltype(stmt, i); if (col_name == nullptr) { status = Status(1, "Could not get column type"); break; } if (col_type == nullptr) { // Types are only returned for table columns (not expressions). col_type = "UNKNOWN"; unknown_type = true; } results.push_back(std::make_tuple( col_name, columnTypeName(col_type), ColumnOptions::DEFAULT)); } // An unknown type means we have to parse the plan and SQLite opcodes. if (unknown_type) { QueryPlanner planner(q, db); planner.applyTypes(results); } if (status.ok()) { columns = std::move(results); } sqlite3_finalize(stmt); return status; }
Status ATCConfigParserPlugin::update(const std::string& source, const ParserConfig& config) { auto cv = config.find(kParserKey); if (cv == config.end()) { return Status(1, "No configuration for ATC (Auto Table Construction)"); } auto obj = data_.getObject(); data_.copyFrom(cv->second.doc(), obj); data_.add(kParserKey, obj); const auto& ac_tables = data_.doc()[kParserKey]; auto tables = RegistryFactory::get().registry("table"); auto registered = registeredATCTables(); for (const auto& ac_table : ac_tables.GetObject()) { std::string table_name{ac_table.name.GetString()}; auto params = ac_table.value.GetObject(); std::string query{params.HasMember("query") && params["query"].IsString() ? params["query"].GetString() : ""}; std::string path{params.HasMember("path") && params["path"].IsString() ? params["path"].GetString() : ""}; std::string platform{params.HasMember("platform") && params["platform"].IsString() ? params["platform"].GetString() : ""}; if (query.empty() || path.empty()) { LOG(WARNING) << "ATC Table: " << table_name << " is misconfigured"; continue; } if (!checkPlatform(platform)) { VLOG(1) << "Skipping ATC table: " << table_name << " because platform doesn't match"; continue; } TableColumns columns; std::string columns_value; columns_value.reserve(256); for (const auto& column : params["columns"].GetArray()) { columns.push_back(make_tuple( std::string(column.GetString()), TEXT_TYPE, ColumnOptions::DEFAULT)); columns_value += std::string(column.GetString()) + ","; } registered.erase(table_name); std::string table_settings{table_name + query + columns_value + path}; std::string old_setting; auto s = getDatabaseValue( kPersistentSettings, kDatabaseKeyPrefix + table_name, old_setting); // The ATC table hasn't changed so we skip ahead if (table_settings == old_setting) { continue; } // Remove the old table to replace with the new one s = removeATCTables({table_name}); if (!s.ok()) { LOG(WARNING) << "ATC table overrides core table; Refusing registration"; continue; } s = setDatabaseValue( kPersistentSettings, kDatabaseKeyPrefix + table_name, table_settings); if (!s.ok()) { LOG(WARNING) << "Could not write to database"; continue; } s = tables->add( table_name, std::make_shared<ATCPlugin>(path, columns, query), true); if (!s.ok()) { LOG(WARNING) << s.getMessage(); deleteDatabaseValue(kPersistentSettings, kDatabaseKeyPrefix + table_name); continue; } PluginResponse resp; Registry::call( "sql", "sql", {{"action", "attach"}, {"table", table_name}}, resp); LOG(INFO) << "Registered ATC table: " << table_name; } if (registered.size() > 0) { VLOG(1) << "Removing any ATC tables that were removed in this configuration " "change"; removeATCTables(registered); } return Status(); }