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-11-10 18:22:26 +00:00
# include <IO/Operators.h>
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 ( ) )
{
2020-11-10 18:22:26 +00:00
throw Exception ( ErrorCodes : : THERE_IS_NO_COLUMN , " Not found column {} {} in dictionary {}. There are only columns {} " ,
column . name , column . type - > getName ( ) , backQuote ( dictionary_name ) ,
StorageDictionary : : generateNamesAndTypesDescription ( dictionary_names_and_types ) ) ;
2020-04-12 20:50:32 +00:00
}
}
}
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 )
{
2020-11-10 18:22:26 +00:00
WriteBufferFromOwnString ss ;
2020-04-12 20:50:32 +00:00
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_ ,
2020-07-03 13:36:08 +00:00
const ColumnsDescription & columns_ ,
2021-04-23 12:18:23 +00:00
const String & comment ,
2020-07-05 14:14:20 +00:00
Location location_ )
2021-04-23 12:18:23 +00:00
: IStorage ( table_id_ ) , dictionary_name ( dictionary_name_ ) , location ( location_ )
2020-04-12 20:50:32 +00:00
{
2020-06-19 15:39:41 +00:00
StorageInMemoryMetadata storage_metadata ;
2020-07-03 13:36:08 +00:00
storage_metadata . setColumns ( columns_ ) ;
2021-04-23 12:18:23 +00:00
storage_metadata . setComment ( comment ) ;
2020-06-19 15:39:41 +00:00
setInMemoryMetadata ( storage_metadata ) ;
2020-04-12 20:50:32 +00:00
}
2020-07-03 13:36:08 +00:00
StorageDictionary : : StorageDictionary (
2020-07-05 14:14:20 +00:00
const StorageID & table_id_ , const String & dictionary_name_ , const DictionaryStructure & dictionary_structure_ , Location location_ )
2021-04-23 12:18:23 +00:00
: StorageDictionary ( table_id_ , dictionary_name_ , ColumnsDescription { getNamesAndTypes ( dictionary_structure_ ) } , String { } , location_ )
2020-07-03 13:36:08 +00:00
{
}
2020-04-12 20:50:32 +00:00
void StorageDictionary : : checkTableCanBeDropped ( ) const
{
2020-07-05 14:14:20 +00:00
if ( location = = Location : : SameDatabaseAndNameAsDictionary )
2020-12-07 14:01:09 +00:00
throw Exception ( " Cannot drop/detach dictionary " + backQuote ( dictionary_name ) + " as table, use DROP DICTIONARY or DETACH DICTIONARY query instead " , ErrorCodes : : CANNOT_DETACH_DICTIONARY_AS_TABLE ) ;
2020-07-05 14:14:20 +00:00
if ( location = = Location : : DictionaryDatabase )
2020-12-07 14:01:09 +00:00
throw Exception ( " Cannot drop/detach table " + getStorageID ( ) . getFullTableName ( ) + " from a database with DICTIONARY engine " , ErrorCodes : : CANNOT_DETACH_DICTIONARY_AS_TABLE ) ;
2020-04-12 20:50:32 +00:00
}
2020-11-11 14:34:58 +00:00
void StorageDictionary : : checkTableCanBeDetached ( ) const
{
checkTableCanBeDropped ( ) ;
}
2020-08-03 13:54:14 +00:00
Pipe StorageDictionary : : read (
2020-04-12 20:50:32 +00:00
const Names & column_names ,
2020-06-15 19:08:58 +00:00
const StorageMetadataPtr & /*metadata_snapshot*/ ,
2020-09-20 17:52:17 +00:00
SelectQueryInfo & /*query_info*/ ,
2021-04-10 23:33:54 +00:00
ContextPtr context ,
2020-04-12 20:50:32 +00:00
QueryProcessingStage : : Enum /*processed_stage*/ ,
const size_t max_block_size ,
const unsigned /*threads*/ )
{
2021-04-10 23:33:54 +00:00
auto dictionary = context - > getExternalDictionariesLoader ( ) . getDictionary ( dictionary_name , context ) ;
2020-04-12 20:50:32 +00:00
auto stream = dictionary - > getBlockInputStream ( column_names , max_block_size ) ;
/// TODO: update dictionary interface for processors.
2020-08-03 13:54:14 +00:00
return Pipe ( std : : make_shared < SourceFromInputStream > ( stream ) ) ;
2020-04-12 20:50:32 +00:00
}
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 ) ;
2021-04-10 23:33:54 +00:00
args . engine_args [ 0 ] = evaluateConstantExpressionOrIdentifierAsLiteral ( args . engine_args [ 0 ] , args . getLocalContext ( ) ) ;
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-07-03 13:36:08 +00:00
if ( ! args . attach )
{
2021-04-10 23:33:54 +00:00
const auto & dictionary = args . getContext ( ) - > getExternalDictionariesLoader ( ) . getDictionary ( dictionary_name , args . getContext ( ) ) ;
2020-07-03 13:36:08 +00:00
const DictionaryStructure & dictionary_structure = dictionary - > getStructure ( ) ;
checkNamesAndTypesCompatibleWithDictionary ( dictionary_name , args . columns , dictionary_structure ) ;
}
2020-04-12 20:50:32 +00:00
2021-04-23 12:18:23 +00:00
return StorageDictionary : : create ( args . table_id , dictionary_name , args . columns , args . comment , StorageDictionary : : Location : : Custom ) ;
2017-12-28 21:36:27 +00:00
} ) ;
}
2017-05-15 13:58:40 +00:00
}