dbms: development [#CONV-2944].

This commit is contained in:
Alexey Milovidov 2011-08-28 05:13:24 +00:00
parent 9b153918e7
commit 420e68e7c7
17 changed files with 435 additions and 33 deletions

View File

@ -30,12 +30,22 @@ public:
Field operator[](size_t n) const { return typename NearestFieldType<T>::Type(data); }
void cut(size_t start, size_t length) { s = length; }
void clear() { s = 0; }
void insert(const Field & x)
{
throw Exception("Cannot insert element into constant column", ErrorCodes::CANNOT_INSERT_ELEMENT_INTO_CONSTANT_COLUMN);
throw Exception("Cannot insert element into constant column " + getName(), ErrorCodes::CANNOT_INSERT_ELEMENT_INTO_CONSTANT_COLUMN);
}
void insertDefault() { ++s; }
void filter(const Filter & filt) {}
void filter(const Filter & filt)
{
size_t new_size = 0;
for (Filter::const_iterator it = filt.begin(); it != filt.end(); ++it)
if (*it)
++new_size;
s = new_size;
}
size_t byteSize() { return sizeof(data) + sizeof(s); }

View File

@ -16,12 +16,14 @@ using Poco::SharedPtr;
* Выражение состоит из идентификаторов столбцов из блока, констант, обычных функций.
* Например: hits * 2 + 3, instr("yandex", url)
* Выражение не меняет количество строк в потоке, и обрабатывает каждую строку независимо от других.
* part_id - идентификатор части выражения, которую надо вычислять.
* Например, может потребоваться вычислить только часть выражения в секции WHERE.
*/
class ExpressionBlockInputStream : public IBlockInputStream
{
public:
ExpressionBlockInputStream(BlockInputStreamPtr input_, SharedPtr<Expression> expression_)
: input(input_), expression(expression_) {}
ExpressionBlockInputStream(BlockInputStreamPtr input_, SharedPtr<Expression> expression_, unsigned part_id_ = 0)
: input(input_), expression(expression_), part_id(part_id_) {}
Block read()
{
@ -29,13 +31,14 @@ public:
if (!res)
return res;
expression->execute(res);
return expression->projectResult(res);
expression->execute(res, part_id);
return res;
}
private:
BlockInputStreamPtr input;
SharedPtr<Expression> expression;
unsigned part_id;
};
}

View File

@ -13,18 +13,18 @@ using Poco::SharedPtr;
/** Реализует операции WHERE, HAVING.
* На вход подаётся поток блоков, в котором в одном из столбцов типа ColumnUInt8 содержатся условия фильтрации.
* Возвращается поток блоков, в котором содержатся только отфильтрованные строки, а также столбец с условиями фильтрации убран.
* Возвращается поток блоков, в котором содержатся только отфильтрованные строки.
*/
class FilterBlockInputStream : public IBlockInputStream
{
public:
/// filter_column_ - номер столбца с условиями фильтрации
FilterBlockInputStream(BlockInputStreamPtr input_, size_t filter_column_);
/// filter_column_ - номер столбца с условиями фильтрации. -1 - последний столбец
FilterBlockInputStream(BlockInputStreamPtr input_, ssize_t filter_column_ = -1);
Block read();
private:
BlockInputStreamPtr input;
size_t filter_column;
ssize_t filter_column;
};
}

View File

@ -0,0 +1,39 @@
#pragma once
#include <Poco/SharedPtr.h>
#include <DB/Interpreters/Expression.h>
#include <DB/DataStreams/IBlockInputStream.h>
namespace DB
{
using Poco::SharedPtr;
/** Выбирает из блока только столбцы, являющиеся результатом вычисления выражения.
* Следует применять после ExpressionBlockInputStream.
*/
class ProjectionBlockInputStream : public IBlockInputStream
{
public:
ProjectionBlockInputStream(BlockInputStreamPtr input_, SharedPtr<Expression> expression_, unsigned part_id_ = 0)
: input(input_), expression(expression_), part_id(part_id_) {}
Block read()
{
Block res = input->read();
if (!res)
return res;
return expression->projectResult(res, part_id);
}
private:
BlockInputStreamPtr input;
SharedPtr<Expression> expression;
unsigned part_id;
};
}

View File

@ -31,12 +31,12 @@ typedef std::map<String, Tables> Databases;
*/
struct Context
{
String path; /// Путь к директории с данными, со слешем на конце.
SharedPtr<Databases> databases; /// Список БД и таблиц в них.
String current_database; /// Текущая БД.
SharedPtr<Functions> functions; /// Обычные функции.
DataTypeFactory data_type_factory; /// Типы данных.
NamesAndTypes columns; /// Столбцы текущей обрабатываемой таблицы.
String path; /// Путь к директории с данными, со слешем на конце.
SharedPtr<Databases> databases; /// Список БД и таблиц в них.
String current_database; /// Текущая БД.
SharedPtr<Functions> functions; /// Обычные функции.
SharedPtr<DataTypeFactory> data_type_factory; /// Типы данных.
NamesAndTypes columns; /// Столбцы текущей обрабатываемой таблицы.
SharedPtr<Poco::FastMutex> mutex; /// Для доступа и модификации разделяемых объектов.

View File

@ -24,6 +24,10 @@ public:
glueTree(ast);
}
/** Получить список столбцов, которых необходимо прочитать из таблицы, чтобы выполнить выражение.
*/
Names getRequiredColumns();
/** Выполнить выражение над блоком. Блок должен содержать все столбцы - идентификаторы.
* Функция добавляет в блок новые столбцы - результаты вычислений.
* part_id - какую часть выражения вычислять.
@ -33,7 +37,7 @@ public:
/** Взять из блока с промежуточными результатами вычислений только столбцы, представляющие собой конечный результат.
* Вернуть новый блок, в котором эти столбцы расположены в правильном порядке.
*/
Block projectResult(Block & block);
Block projectResult(Block & block, unsigned part_id = 0);
/** Получить список типов столбцов результата.
*/
@ -43,6 +47,9 @@ private:
ASTPtr ast;
const Context & context;
typedef std::set<String> NamesSet;
NamesSet required_columns;
/** Для узлов - литералов - прописать их типы данных.
* Для узлов - функций - прописать ссылки на функции и заменить имена на канонические.
@ -71,7 +78,7 @@ private:
void executeImpl(ASTPtr ast, Block & block, unsigned part_id);
void collectFinalColumns(ASTPtr ast, Block & src, Block & dst);
void collectFinalColumns(ASTPtr ast, Block & src, Block & dst, unsigned part_id);
void getReturnTypesImpl(ASTPtr ast, DataTypes & res);
};

View File

@ -0,0 +1,45 @@
#pragma once
#include <DB/Interpreters/Context.h>
#include <DB/DataStreams/IBlockInputStream.h>
namespace DB
{
/** Интерпретирует запрос SELECT. Возвращает поток блоков с результатами выполнения запроса.
*/
class InterpreterSelectQuery
{
public:
InterpreterSelectQuery(ASTPtr query_ptr_, Context & context_, size_t max_block_size_ = DEFAULT_BLOCK_SIZE);
BlockInputStreamPtr execute();
DataTypes getReturnTypes();
private:
StoragePtr getTable();
/** Пометить часть дерева запроса некоторым part_id.
* - для того, чтобы потом можно было вычислить только часть выражения из запроса.
*/
void setPartID(ASTPtr ast, unsigned part_id);
enum PartID
{
PART_OTHER = 0,
PART_SELECT = 1,
PART_WHERE = 2,
PART_HAVING = 3,
};
ASTPtr query_ptr;
Context context;
size_t max_block_size;
};
}

View File

@ -28,7 +28,7 @@ public:
Block read();
private:
size_t block_size;
const Names & column_names;
Names column_names;
StorageLog & storage;
struct Stream

View File

@ -6,7 +6,7 @@
namespace DB
{
FilterBlockInputStream::FilterBlockInputStream(BlockInputStreamPtr input_, size_t filter_column_)
FilterBlockInputStream::FilterBlockInputStream(BlockInputStreamPtr input_, ssize_t filter_column_)
: input(input_), filter_column(filter_column_)
{
}
@ -17,6 +17,9 @@ Block FilterBlockInputStream::read()
if (!res)
return res;
if (filter_column < 0)
filter_column = static_cast<ssize_t>(res.columns()) + filter_column;
size_t columns = res.columns();
ColumnPtr column = res.getByPosition(filter_column).column;
@ -35,10 +38,9 @@ Block FilterBlockInputStream::read()
IColumn::Filter & filter = column_vec->getData();
for (size_t i = 0; i < columns; ++i)
if (i != filter_column)
if (i != static_cast<size_t>(filter_column))
res.getByPosition(i).column->filter(filter);
res.erase(filter_column);
return res;
}

View File

@ -11,6 +11,7 @@
#include <DB/DataStreams/LimitBlockInputStream.h>
#include <DB/DataStreams/ExpressionBlockInputStream.h>
#include <DB/DataStreams/ProjectionBlockInputStream.h>
#include <DB/DataStreams/TabSeparatedRowOutputStream.h>
#include <DB/DataStreams/copyData.h>
@ -59,10 +60,11 @@ int main(int argc, char ** argv)
DB::Names column_names;
column_names.push_back("number");
Poco::SharedPtr<DB::IBlockInputStream> in1(table.read(column_names, 0));
Poco::SharedPtr<DB::ExpressionBlockInputStream> in2 = new DB::ExpressionBlockInputStream(in1, expression);
DB::LimitBlockInputStream in3(in2, 10, std::max(static_cast<Int64>(0), static_cast<Int64>(n) - 10));
Poco::SharedPtr<DB::IBlockInputStream> in;
in = table.read(column_names, 0);
in = new DB::ExpressionBlockInputStream(in, expression);
in = new DB::ProjectionBlockInputStream(in, expression);
in = new DB::LimitBlockInputStream(in, 10, std::max(static_cast<Int64>(0), static_cast<Int64>(n) - 10));
DB::WriteBufferFromOStream out1(std::cout);
DB::TabSeparatedRowOutputStream out2(out1, new DB::DataTypes(expression->getReturnTypes()));
@ -71,7 +73,7 @@ int main(int argc, char ** argv)
Poco::Stopwatch stopwatch;
stopwatch.start();
DB::copyData(in3, out2);
DB::copyData(*in, out2);
stopwatch.stop();
std::cout << std::fixed << std::setprecision(2)

View File

@ -11,6 +11,7 @@
#include <DB/DataStreams/LimitBlockInputStream.h>
#include <DB/DataStreams/ExpressionBlockInputStream.h>
#include <DB/DataStreams/ProjectionBlockInputStream.h>
#include <DB/DataStreams/FilterBlockInputStream.h>
#include <DB/DataStreams/TabSeparatedRowOutputStream.h>
#include <DB/DataStreams/copyData.h>
@ -68,6 +69,7 @@ int main(int argc, char ** argv)
Poco::SharedPtr<DB::IBlockInputStream> in = table.read(column_names, 0);
in = new DB::ExpressionBlockInputStream(in, expression);
in = new DB::ProjectionBlockInputStream(in, expression);
in = new DB::FilterBlockInputStream(in, 1);
in = new DB::LimitBlockInputStream(in, 10, std::max(static_cast<Int64>(0), static_cast<Int64>(n) - 10));

View File

@ -13,6 +13,7 @@
#include <DB/DataStreams/LimitBlockInputStream.h>
#include <DB/DataStreams/ExpressionBlockInputStream.h>
#include <DB/DataStreams/ProjectionBlockInputStream.h>
#include <DB/DataStreams/FilterBlockInputStream.h>
#include <DB/DataStreams/ProfilingBlockInputStream.h>
#include <DB/DataStreams/TabSeparatedRowOutputStream.h>
@ -169,6 +170,7 @@ int main(int argc, char ** argv)
Poco::SharedPtr<DB::IBlockInputStream> in = table.read(column_names, 0);
Poco::SharedPtr<DB::ProfilingBlockInputStream> profiling = new DB::ProfilingBlockInputStream(in);
in = new DB::ExpressionBlockInputStream(profiling, expression);
in = new DB::ProjectionBlockInputStream(in, expression);
in = new DB::FilterBlockInputStream(in, 4);
//in = new DB::LimitBlockInputStream(in, 10, std::max(static_cast<Int64>(0), static_cast<Int64>(n) - 10));

View File

@ -30,6 +30,7 @@ void Expression::addSemantic(ASTPtr ast)
throw Exception("Unknown identifier " + node->name, ErrorCodes::UNKNOWN_IDENTIFIER);
node->type = it->second;
required_columns.insert(node->name);
}
}
else if (ASTLiteral * node = dynamic_cast<ASTLiteral *>(&*ast))
@ -107,6 +108,16 @@ void Expression::glueTreeImpl(ASTPtr ast, Subtrees & subtrees)
}
Names Expression::getRequiredColumns()
{
Names res;
res.reserve(required_columns.size());
for (NamesSet::const_iterator it = required_columns.begin(); it != required_columns.end(); ++it)
res.push_back(*it);
return res;
}
void Expression::setNotCalculated(ASTPtr ast, unsigned part_id)
{
if (ast->part_id == part_id)
@ -189,16 +200,24 @@ void Expression::executeImpl(ASTPtr ast, Block & block, unsigned part_id)
}
Block Expression::projectResult(Block & block)
Block Expression::projectResult(Block & block, unsigned part_id)
{
Block res;
collectFinalColumns(ast, block, res);
collectFinalColumns(ast, block, res, part_id);
return res;
}
void Expression::collectFinalColumns(ASTPtr ast, Block & src, Block & dst)
void Expression::collectFinalColumns(ASTPtr ast, Block & src, Block & dst, unsigned part_id)
{
if (ast->part_id != part_id)
{
if (!dynamic_cast<ASTFunction *>(&*ast))
for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it)
collectFinalColumns(*it, src, dst, part_id);
return;
}
if (ASTIdentifier * ident = dynamic_cast<ASTIdentifier *>(&*ast))
{
if (ident->kind == ASTIdentifier::Column)
@ -211,7 +230,7 @@ void Expression::collectFinalColumns(ASTPtr ast, Block & src, Block & dst)
dst.insert(src.getByPosition(*jt));
else
for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it)
collectFinalColumns(*it, src, dst);
collectFinalColumns(*it, src, dst, part_id);
}

View File

@ -38,7 +38,7 @@ StoragePtr InterpreterCreateQuery::execute(ASTPtr query, Context & context)
{
ASTNameTypePair & name_and_type_pair = dynamic_cast<ASTNameTypePair &>(**it);
StringRange type_range = name_and_type_pair.type->range;
(*columns)[name_and_type_pair.name] = context.data_type_factory.get(String(type_range.first, type_range.second - type_range.first));
(*columns)[name_and_type_pair.name] = context.data_type_factory->get(String(type_range.first, type_range.second - type_range.first));
}
ASTFunction & storage_expr = dynamic_cast<ASTFunction &>(*create.storage);

View File

@ -0,0 +1,102 @@
#include <DB/DataStreams/ExpressionBlockInputStream.h>
#include <DB/DataStreams/ProjectionBlockInputStream.h>
#include <DB/DataStreams/FilterBlockInputStream.h>
#include <DB/DataStreams/LimitBlockInputStream.h>
#include <DB/Parsers/ASTSelectQuery.h>
#include <DB/Parsers/ASTIdentifier.h>
#include <DB/Interpreters/Expression.h>
#include <DB/Interpreters/InterpreterSelectQuery.h>
namespace DB
{
InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, Context & context_, size_t max_block_size_)
: query_ptr(query_ptr_), context(context_), max_block_size(max_block_size_)
{
}
StoragePtr InterpreterSelectQuery::getTable()
{
ASTSelectQuery & query = dynamic_cast<ASTSelectQuery &>(*query_ptr);
/// Из какой таблицы читать данные. JOIN-ы не поддерживаются.
String database_name;
String table_name;
/** Если таблица не указана - используем таблицу system.one.
* Если база данных не указана - используем текущую базу данных.
*/
if (!query.table)
{
database_name = "system";
table_name = "one";
}
else if (!query.database)
database_name = context.current_database;
if (query.database)
database_name = dynamic_cast<ASTIdentifier &>(*query.database).name;
if (query.table)
table_name = dynamic_cast<ASTIdentifier &>(*query.table).name;
if (context.databases->end() == context.databases->find(database_name)
|| (*context.databases)[database_name].end() == (*context.databases)[database_name].find(table_name))
throw Exception("Unknown table " + table_name + " in database " + database_name, ErrorCodes::UNKNOWN_TABLE);
return (*context.databases)[database_name][table_name];
}
DataTypes InterpreterSelectQuery::getReturnTypes()
{
context.columns = getTable()->getColumns();
Expression expression(dynamic_cast<ASTSelectQuery &>(*query_ptr).select_expression_list, context);
return expression.getReturnTypes();
}
BlockInputStreamPtr InterpreterSelectQuery::execute()
{
ASTSelectQuery & query = dynamic_cast<ASTSelectQuery &>(*query_ptr);
StoragePtr table = getTable();
/// Какие столбцы читать из этой таблицы
context.columns = table->getColumns();
Poco::SharedPtr<Expression> expression = new Expression(query_ptr, context);
BlockInputStreamPtr stream = table->read(expression->getRequiredColumns(), query_ptr, max_block_size);
/// Если есть условие WHERE - сначала выполним часть выражения, необходимую для его вычисления
if (query.where_expression)
{
setPartID(query.where_expression, PART_WHERE);
stream = new ExpressionBlockInputStream(stream, expression, PART_WHERE);
stream = new FilterBlockInputStream(stream);
}
/// Выполним оставшуюся часть выражения
stream = new ExpressionBlockInputStream(stream, expression);
setPartID(query.select_expression_list, PART_SELECT);
stream = new ProjectionBlockInputStream(stream, expression, PART_SELECT);
return stream;
}
void InterpreterSelectQuery::setPartID(ASTPtr ast, unsigned part_id)
{
ast->part_id = part_id;
for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it)
setPartID(*it, part_id);
}
}

View File

@ -0,0 +1,168 @@
#include <iostream>
#include <iomanip>
#include <boost/assign/list_inserter.hpp>
#include <Poco/SharedPtr.h>
#include <Poco/Stopwatch.h>
#include <Poco/NumberParser.h>
#include <DB/IO/WriteBufferFromOStream.h>
#include <DB/Storages/StorageLog.h>
#include <DB/DataStreams/TabSeparatedRowOutputStream.h>
#include <DB/DataStreams/copyData.h>
#include <DB/DataTypes/DataTypesNumberFixed.h>
//#include <DB/Functions/FunctionsArithmetic.h>
#include <DB/Functions/FunctionsComparison.h>
//#include <DB/Functions/FunctionsLogical.h>
#include <DB/Parsers/ParserSelectQuery.h>
#include <DB/Parsers/formatAST.h>
#include <DB/Interpreters/InterpreterSelectQuery.h>
using Poco::SharedPtr;
int main(int argc, char ** argv)
{
try
{
typedef std::pair<std::string, SharedPtr<DB::IDataType> > NameAndTypePair;
typedef std::list<NameAndTypePair> NamesAndTypesList;
NamesAndTypesList names_and_types_list;
boost::assign::push_back(names_and_types_list)
("WatchID", new DB::DataTypeUInt64)
("JavaEnable", new DB::DataTypeUInt8)
("Title", new DB::DataTypeString)
("GoodEvent", new DB::DataTypeUInt32)
("EventTime", new DB::DataTypeDateTime)
("CounterID", new DB::DataTypeUInt32)
("ClientIP", new DB::DataTypeUInt32)
("RegionID", new DB::DataTypeUInt32)
("UniqID", new DB::DataTypeUInt64)
("CounterClass", new DB::DataTypeUInt8)
("OS", new DB::DataTypeUInt8)
("UserAgent", new DB::DataTypeUInt8)
("URL", new DB::DataTypeString)
("Referer", new DB::DataTypeString)
("Refresh", new DB::DataTypeUInt8)
("ResolutionWidth", new DB::DataTypeUInt16)
("ResolutionHeight", new DB::DataTypeUInt16)
("ResolutionDepth", new DB::DataTypeUInt8)
("FlashMajor", new DB::DataTypeUInt8)
("FlashMinor", new DB::DataTypeUInt8)
("FlashMinor2", new DB::DataTypeString)
("NetMajor", new DB::DataTypeUInt8)
("NetMinor", new DB::DataTypeUInt8)
("UserAgentMajor", new DB::DataTypeUInt16)
("UserAgentMinor", new DB::DataTypeFixedString(2))
("CookieEnable", new DB::DataTypeUInt8)
("JavascriptEnable", new DB::DataTypeUInt8)
("IsMobile", new DB::DataTypeUInt8)
("MobilePhone", new DB::DataTypeUInt8)
("MobilePhoneModel", new DB::DataTypeString)
("Params", new DB::DataTypeString)
("IPNetworkID", new DB::DataTypeUInt32)
("TraficSourceID", new DB::DataTypeInt8)
("SearchEngineID", new DB::DataTypeUInt16)
("SearchPhrase", new DB::DataTypeString)
("AdvEngineID", new DB::DataTypeUInt8)
("IsArtifical", new DB::DataTypeUInt8)
("WindowClientWidth", new DB::DataTypeUInt16)
("WindowClientHeight", new DB::DataTypeUInt16)
("ClientTimeZone", new DB::DataTypeInt16)
("ClientEventTime", new DB::DataTypeDateTime)
("SilverlightVersion1", new DB::DataTypeUInt8)
("SilverlightVersion2", new DB::DataTypeUInt8)
("SilverlightVersion3", new DB::DataTypeUInt32)
("SilverlightVersion4", new DB::DataTypeUInt16)
("PageCharset", new DB::DataTypeString)
("CodeVersion", new DB::DataTypeUInt32)
("IsLink", new DB::DataTypeUInt8)
("IsDownload", new DB::DataTypeUInt8)
("IsNotBounce", new DB::DataTypeUInt8)
("FUniqID", new DB::DataTypeUInt64)
("OriginalURL", new DB::DataTypeString)
("HID", new DB::DataTypeUInt32)
("IsOldCounter", new DB::DataTypeUInt8)
("IsEvent", new DB::DataTypeUInt8)
("IsParameter", new DB::DataTypeUInt8)
("DontCountHits", new DB::DataTypeUInt8)
("WithHash", new DB::DataTypeUInt8)
;
SharedPtr<DB::NamesAndTypes> names_and_types_map = new DB::NamesAndTypes;
for (NamesAndTypesList::const_iterator it = names_and_types_list.begin(); it != names_and_types_list.end(); ++it)
{
names_and_types_map->insert(*it);
}
DB::Context context;
/* (*context.functions)["plus"] = new DB::FunctionPlus;
(*context.functions)["minus"] = new DB::FunctionMinus;
(*context.functions)["multiply"] = new DB::FunctionMultiply;
(*context.functions)["divide"] = new DB::FunctionDivideFloating;
(*context.functions)["intDiv"] = new DB::FunctionDivideIntegral;
(*context.functions)["modulo"] = new DB::FunctionModulo;
*/
(*context.functions)["equals"] = new DB::FunctionEquals;
/* (*context.functions)["notEquals"] = new DB::FunctionNotEquals;
(*context.functions)["less"] = new DB::FunctionLess;
(*context.functions)["greater"] = new DB::FunctionGreater;
(*context.functions)["lessOrEquals"] = new DB::FunctionLessOrEquals;
(*context.functions)["greaterOrEquals"] = new DB::FunctionGreaterOrEquals;
(*context.functions)["and"] = new DB::FunctionAnd;
(*context.functions)["or"] = new DB::FunctionOr;
(*context.functions)["xor"] = new DB::FunctionXor;
(*context.functions)["not"] = new DB::FunctionNot;
*/
(*context.databases)["default"]["hits"] = new DB::StorageLog("./", "hits", names_and_types_map, ".bin");
context.current_database = "default";
DB::ParserSelectQuery parser;
DB::ASTPtr ast;
std::string input = "SELECT UniqID, URL, CounterID, IsLink FROM hits WHERE URL = 'http://mail.yandex.ru/neo2/#inbox'";
std::string expected;
const char * begin = input.data();
const char * end = begin + input.size();
const char * pos = begin;
if (!parser.parse(pos, end, ast, expected))
{
std::cout << "Failed at position " << (pos - begin) << ": "
<< mysqlxx::quote << input.substr(pos - begin, 10)
<< ", expected " << expected << "." << std::endl;
}
/* DB::formatAST(*ast, std::cerr);
std::cerr << std::endl;
std::cerr << ast->getTreeID() << std::endl;
*/
DB::InterpreterSelectQuery interpreter(ast, context);
DB::BlockInputStreamPtr in = interpreter.execute();
DB::WriteBufferFromOStream ob(std::cout);
DB::TabSeparatedRowOutputStream out(ob, new DB::DataTypes(interpreter.getReturnTypes()));
DB::copyData(*in, out);
}
catch (const DB::Exception & e)
{
std::cerr << e.what() << ", " << e.message() << std::endl;
return 1;
}
return 0;
}

View File

@ -67,7 +67,8 @@ bool ParserSelectQuery::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & ex
ws.ignore(pos, end);
}
dynamic_cast<ASTIdentifier &>(*select_query->database).kind = ASTIdentifier::Database;
if (select_query->database)
dynamic_cast<ASTIdentifier &>(*select_query->database).kind = ASTIdentifier::Database;
dynamic_cast<ASTIdentifier &>(*select_query->table).kind = ASTIdentifier::Table;
}