ClickHouse/src/TableFunctions/TableFunctionSQLite.cpp

105 lines
3.2 KiB
C++
Raw Normal View History

#include <TableFunctions/TableFunctionSQLite.h>
#if USE_SQLITE
#include <Common/Exception.h>
#include <Common/quoteString.h>
2021-07-13 09:39:36 +00:00
#include <Databases/SQLite/fetchSQLiteTableStructure.h>
#include "registerTableFunctions.h"
#include <Interpreters/evaluateConstantExpression.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTLiteral.h>
#include <TableFunctions/ITableFunction.h>
#include <TableFunctions/TableFunctionFactory.h>
2021-07-13 09:39:36 +00:00
#include <filesystem>
namespace fs = std::filesystem;
namespace DB
{
namespace ErrorCodes
{
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
extern const int BAD_ARGUMENTS;
extern const int SQLITE_ENGINE_ERROR;
2021-07-13 09:39:36 +00:00
extern const int PATH_ACCESS_DENIED;
}
StoragePtr TableFunctionSQLite::executeImpl(const ASTPtr & /*ast_function*/,
ContextPtr context, const String & table_name, ColumnsDescription /*cached_columns*/) const
{
auto columns = getActualTableStructure(context);
auto storage = StorageSQLite::create(StorageID(getDatabaseName(), table_name),
sqlite_db,
remote_table_name,
columns, ConstraintsDescription{}, context);
storage->startup();
return storage;
}
ColumnsDescription TableFunctionSQLite::getActualTableStructure(ContextPtr /* context */) const
{
auto columns = fetchSQLiteTableStructure(sqlite_db.get(), remote_table_name);
if (!columns)
2021-07-13 00:07:53 +00:00
throw Exception(ErrorCodes::SQLITE_ENGINE_ERROR, "Failed to fetch table structure for {}", remote_table_name);
return ColumnsDescription{*columns};
}
void TableFunctionSQLite::parseArguments(const ASTPtr & ast_function, ContextPtr context)
{
const auto & func_args = ast_function->as<ASTFunction &>();
if (!func_args.arguments)
throw Exception("Table function 'sqlite' must have arguments.", ErrorCodes::BAD_ARGUMENTS);
ASTs & args = func_args.arguments->children;
if (args.size() != 2)
throw Exception("SQLite database requires 2 arguments: database path, table name",
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
for (auto & arg : args)
arg = evaluateConstantExpressionOrIdentifierAsLiteral(arg, context);
database_path = args[0]->as<ASTLiteral &>().value.safeGet<String>();
remote_table_name = args[1]->as<ASTLiteral &>().value.safeGet<String>();
2021-07-13 09:39:36 +00:00
std::error_code err;
String canonical_path = fs::canonical(database_path, err);
/// The path existance is also checked here.
if (err)
throw Exception(ErrorCodes::PATH_ACCESS_DENIED, "SQLite database path '{}' is invalid. Error: {}", database_path, err.message());
sqlite3 * tmp_sqlite_db = nullptr;
2021-07-13 09:39:36 +00:00
int status = sqlite3_open(canonical_path.c_str(), &tmp_sqlite_db);
if (status != SQLITE_OK)
throw Exception(ErrorCodes::SQLITE_ENGINE_ERROR,
"Failed to open sqlite database. Status: {}. Message: {}",
status, sqlite3_errstr(status));
sqlite_db = std::shared_ptr<sqlite3>(tmp_sqlite_db, sqlite3_close);
}
void registerTableFunctionSQLite(TableFunctionFactory & factory)
{
factory.registerFunction<TableFunctionSQLite>();
}
}
#endif