2017-04-25 09:10:27 +00:00
# include <Storages/StorageDictionary.h>
2017-12-28 21:36:27 +00:00
# include <Storages/StorageFactory.h>
2020-04-12 20:50:32 +00:00
# include <DataTypes/DataTypesNumber.h>
# include <Dictionaries/DictionaryStructure.h>
2017-04-25 09:10:27 +00:00
# include <Interpreters/Context.h>
2018-01-12 18:56:13 +00:00
# include <Interpreters/evaluateConstantExpression.h>
2019-09-26 10:41:33 +00:00
# include <Interpreters/ExternalDictionariesLoader.h>
2017-12-28 21:36:27 +00:00
# include <Parsers/ASTLiteral.h>
2020-04-09 23:25:52 +00:00
# include <Common/quoteString.h>
2020-01-31 08:14:20 +00:00
# include <Processors/Sources/SourceFromInputStream.h>
# include <Processors/Pipe.h>
2020-04-12 20:50:32 +00:00
# include <sstream>
2017-04-25 09:10:27 +00:00
2017-12-28 21:36:27 +00:00
2017-06-23 15:55:45 +00:00
namespace DB
{
2017-12-28 21:36:27 +00:00
namespace ErrorCodes
2017-06-22 15:44:19 +00:00
{
2017-12-28 21:36:27 +00:00
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH ;
2018-11-22 21:19:58 +00:00
extern const int THERE_IS_NO_COLUMN ;
2020-04-12 20:50:32 +00:00
extern const int CANNOT_DETACH_DICTIONARY_AS_TABLE ;
2017-06-22 15:44:19 +00:00
}
2020-04-12 20:50:32 +00:00
namespace
2017-04-25 09:10:27 +00:00
{
2020-04-12 20:50:32 +00:00
void checkNamesAndTypesCompatibleWithDictionary ( const String & dictionary_name , const ColumnsDescription & columns , const DictionaryStructure & dictionary_structure )
2019-02-04 19:45:22 +00:00
{
2020-04-12 20:50:32 +00:00
auto dictionary_names_and_types = StorageDictionary : : getNamesAndTypes ( dictionary_structure ) ;
std : : set < NameAndTypePair > names_and_types_set ( dictionary_names_and_types . begin ( ) , dictionary_names_and_types . end ( ) ) ;
2017-04-25 09:10:27 +00:00
2020-04-12 20:50:32 +00:00
for ( const auto & column : columns . getOrdinary ( ) )
{
if ( names_and_types_set . find ( column ) = = names_and_types_set . end ( ) )
{
std : : string message = " Not found column " ;
message + = column . name + " " + column . type - > getName ( ) ;
message + = " in dictionary " + backQuote ( dictionary_name ) + " . " ;
message + = " There are only columns " ;
message + = StorageDictionary : : generateNamesAndTypesDescription ( dictionary_names_and_types ) ;
throw Exception ( message , ErrorCodes : : THERE_IS_NO_COLUMN ) ;
}
}
}
2020-04-09 23:25:52 +00:00
}
2017-04-25 09:10:27 +00:00
2017-12-25 21:57:29 +00:00
NamesAndTypesList StorageDictionary : : getNamesAndTypes ( const DictionaryStructure & dictionary_structure )
2017-04-25 09:10:27 +00:00
{
2017-12-25 21:57:29 +00:00
NamesAndTypesList dictionary_names_and_types ;
2017-04-28 18:33:31 +00:00
2017-12-25 21:10:46 +00:00
if ( dictionary_structure . id )
dictionary_names_and_types . emplace_back ( dictionary_structure . id - > name , std : : make_shared < DataTypeUInt64 > ( ) ) ;
2020-04-13 14:34:01 +00:00
/// In old-style (XML) configuration we don't have this attributes in the
/// main attribute list, so we have to add them to columns list explicitly.
/// In the new configuration (DDL) we have them both in range_* nodes and
/// main attribute list, but for compatibility we add them before main
/// attributes list.
2017-12-25 21:10:46 +00:00
if ( dictionary_structure . range_min )
2018-09-13 13:33:44 +00:00
dictionary_names_and_types . emplace_back ( dictionary_structure . range_min - > name , dictionary_structure . range_min - > type ) ;
2020-04-13 14:34:01 +00:00
2017-12-25 21:10:46 +00:00
if ( dictionary_structure . range_max )
2018-09-13 13:33:44 +00:00
dictionary_names_and_types . emplace_back ( dictionary_structure . range_max - > name , dictionary_structure . range_max - > type ) ;
2020-04-13 14:34:01 +00:00
2017-12-25 21:10:46 +00:00
if ( dictionary_structure . key )
2020-04-13 14:34:01 +00:00
{
2017-12-25 21:10:46 +00:00
for ( const auto & attribute : * dictionary_structure . key )
dictionary_names_and_types . emplace_back ( attribute . name , attribute . type ) ;
2020-04-13 14:34:01 +00:00
}
2017-04-28 18:33:31 +00:00
2017-12-25 21:10:46 +00:00
for ( const auto & attribute : dictionary_structure . attributes )
2020-04-13 14:34:01 +00:00
{
/// Some attributes can be already added (range_min and range_max)
if ( ! dictionary_names_and_types . contains ( attribute . name ) )
dictionary_names_and_types . emplace_back ( attribute . name , attribute . type ) ;
}
2017-04-28 18:33:31 +00:00
2017-12-25 21:10:46 +00:00
return dictionary_names_and_types ;
2017-04-28 18:33:31 +00:00
}
2020-04-12 20:50:32 +00:00
String StorageDictionary : : generateNamesAndTypesDescription ( const NamesAndTypesList & list )
{
std : : stringstream ss ;
bool first = true ;
for ( const auto & name_and_type : list )
2017-06-23 15:55:45 +00:00
{
2020-04-12 20:50:32 +00:00
if ( ! std : : exchange ( first , false ) )
ss < < " , " ;
ss < < name_and_type . name < < ' ' < < name_and_type . type - > getName ( ) ;
2017-04-25 09:10:27 +00:00
}
2020-04-12 20:50:32 +00:00
return ss . str ( ) ;
2017-04-25 09:10:27 +00:00
}
2020-04-12 20:50:32 +00:00
StorageDictionary : : StorageDictionary (
const StorageID & table_id_ ,
const String & dictionary_name_ ,
const DictionaryStructure & dictionary_structure_ )
: IStorage ( table_id_ )
, dictionary_name ( dictionary_name_ )
{
setColumns ( ColumnsDescription { getNamesAndTypes ( dictionary_structure_ ) } ) ;
}
void StorageDictionary : : checkTableCanBeDropped ( ) const
{
throw Exception ( " Cannot detach dictionary " + backQuote ( dictionary_name ) + " as table, use DETACH DICTIONARY query. " , ErrorCodes : : CANNOT_DETACH_DICTIONARY_AS_TABLE ) ;
}
Pipes StorageDictionary : : read (
const Names & column_names ,
const SelectQueryInfo & /*query_info*/ ,
const Context & context ,
QueryProcessingStage : : Enum /*processed_stage*/ ,
const size_t max_block_size ,
const unsigned /*threads*/ )
{
auto dictionary = context . getExternalDictionariesLoader ( ) . getDictionary ( dictionary_name ) ;
auto stream = dictionary - > getBlockInputStream ( column_names , max_block_size ) ;
auto source = std : : make_shared < SourceFromInputStream > ( stream ) ;
/// TODO: update dictionary interface for processors.
Pipes pipes ;
pipes . emplace_back ( std : : move ( source ) ) ;
return pipes ;
}
2017-12-28 21:36:27 +00:00
void registerStorageDictionary ( StorageFactory & factory )
{
2017-12-30 00:36:06 +00:00
factory . registerStorage ( " Dictionary " , [ ] ( const StorageFactory : : Arguments & args )
2017-12-28 21:36:27 +00:00
{
2017-12-30 00:36:06 +00:00
if ( args . engine_args . size ( ) ! = 1 )
2017-12-28 21:36:27 +00:00
throw Exception ( " Storage Dictionary requires single parameter: name of dictionary " ,
ErrorCodes : : NUMBER_OF_ARGUMENTS_DOESNT_MATCH ) ;
2018-01-12 18:56:13 +00:00
args . engine_args [ 0 ] = evaluateConstantExpressionOrIdentifierAsLiteral ( args . engine_args [ 0 ] , args . local_context ) ;
2019-03-15 17:09:14 +00:00
String dictionary_name = args . engine_args [ 0 ] - > as < ASTLiteral & > ( ) . value . safeGet < String > ( ) ;
2017-12-28 21:36:27 +00:00
2020-04-12 20:50:32 +00:00
const auto & dictionary = args . context . getExternalDictionariesLoader ( ) . getDictionary ( dictionary_name ) ;
const DictionaryStructure & dictionary_structure = dictionary - > getStructure ( ) ;
checkNamesAndTypesCompatibleWithDictionary ( dictionary_name , args . columns , dictionary_structure ) ;
return StorageDictionary : : create ( args . table_id , dictionary_name , dictionary_structure ) ;
2017-12-28 21:36:27 +00:00
} ) ;
}
2017-05-15 13:58:40 +00:00
}