@@ -1145,6 +1145,219 @@ using FunctionDictGetDateOrDefault = FunctionDictGetOrDefault<DataTypeDate, Name
1145
1145
using FunctionDictGetDateTimeOrDefault = FunctionDictGetOrDefault<DataTypeDateTime, NameDictGetDateTimeOrDefault>;
1146
1146
using FunctionDictGetUUIDOrDefault = FunctionDictGetOrDefault<DataTypeUUID, NameDictGetUUIDOrDefault>;
1147
1147
1148
+ #define FOR_DICT_TYPES (M ) \
1149
+ M (UInt8 ) \
1150
+ M (UInt16 ) \
1151
+ M (UInt32 ) \
1152
+ M (UInt64 ) \
1153
+ M (Int8) \
1154
+ M (Int16) \
1155
+ M (Int32) \
1156
+ M (Int64) \
1157
+ M (Float32 ) \
1158
+ M (Float64 ) \
1159
+ M (Date) \
1160
+ M (DateTime) \
1161
+ M (UUID)
1162
+
1163
+ // / This variant of function derives the result type automatically.
1164
+ class FunctionDictGetNoType final : public IFunction
1165
+ {
1166
+ public:
1167
+ static constexpr auto name = " dictGet" ;
1168
+
1169
+ static FunctionPtr create (const Context & context)
1170
+ {
1171
+ return std::make_shared<FunctionDictGetNoType>(context.getExternalDictionaries (), context);
1172
+ }
1173
+
1174
+ FunctionDictGetNoType (const ExternalDictionaries & dictionaries, const Context & context) : dictionaries(dictionaries), context(context) {}
1175
+
1176
+ String getName () const override { return name; }
1177
+
1178
+ private:
1179
+ bool isVariadic () const override { return true ; }
1180
+ size_t getNumberOfArguments () const override { return 0 ; }
1181
+
1182
+ bool useDefaultImplementationForConstants () const final { return true ; }
1183
+ ColumnNumbers getArgumentsThatAreAlwaysConstant () const final { return {0 , 1 }; }
1184
+
1185
+ bool isInjective (const Block & sample_block) override
1186
+ {
1187
+ return isDictGetFunctionInjective (dictionaries, sample_block);
1188
+ }
1189
+
1190
+ DataTypePtr getReturnTypeImpl (const ColumnsWithTypeAndName & arguments) const override
1191
+ {
1192
+ if (arguments.size () != 3 && arguments.size () != 4 )
1193
+ throw Exception{" Function " + getName () + " takes 3 or 4 arguments" , ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH};
1194
+
1195
+ String dict_name;
1196
+ if (auto name_col = checkAndGetColumnConst<ColumnString>(arguments[0 ].column .get ()))
1197
+ {
1198
+ dict_name = name_col->getValue <String>();
1199
+ }
1200
+ else
1201
+ throw Exception{" Illegal type " + arguments[0 ].type ->getName () + " of first argument of function " + getName ()
1202
+ + " , expected a const string." , ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
1203
+
1204
+ String attr_name;
1205
+ if (auto name_col = checkAndGetColumnConst<ColumnString>(arguments[1 ].column .get ()))
1206
+ {
1207
+ attr_name = name_col->getValue <String>();
1208
+ }
1209
+ else
1210
+ throw Exception{" Illegal type " + arguments[1 ].type ->getName () + " of second argument of function " + getName ()
1211
+ + " , expected a const string." , ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
1212
+
1213
+ if (!WhichDataType (arguments[2 ].type ).isUInt64 () &&
1214
+ !isTuple (arguments[2 ].type ))
1215
+ throw Exception{" Illegal type " + arguments[2 ].type ->getName () + " of third argument of function " + getName ()
1216
+ + " , must be UInt64 or tuple(...)." , ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
1217
+
1218
+ if (arguments.size () == 4 )
1219
+ {
1220
+ const auto range_argument = arguments[3 ].type .get ();
1221
+ if (!(range_argument->isValueRepresentedByInteger () &&
1222
+ range_argument->getSizeOfValueInMemory () <= sizeof (Int64)))
1223
+ throw Exception{" Illegal type " + range_argument->getName () + " of fourth argument of function " + getName ()
1224
+ + " , must be convertible to " + TypeName<Int64>::get () + " ." , ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
1225
+ }
1226
+
1227
+ auto dict = dictionaries.getDictionary (dict_name);
1228
+ const DictionaryStructure & structure = dict->getStructure ();
1229
+
1230
+ for (const auto idx : ext::range (0 , structure.attributes .size ()))
1231
+ {
1232
+ const DictionaryAttribute & attribute = structure.attributes [idx];
1233
+ if (attribute.name == attr_name)
1234
+ {
1235
+ WhichDataType dt = attribute.type ;
1236
+ if (dt.idx == TypeIndex::String)
1237
+ impl = FunctionDictGetString::create (context);
1238
+ #define DISPATCH (TYPE ) \
1239
+ else if (dt.idx == TypeIndex::TYPE) \
1240
+ impl = FunctionDictGet<DataType##TYPE, NameDictGet##TYPE>::create (context);
1241
+ FOR_DICT_TYPES (DISPATCH)
1242
+ #undef DISPATCH
1243
+ else
1244
+ throw Exception (" Unknown dictGet type" , ErrorCodes::UNKNOWN_TYPE);
1245
+ return attribute.type ;
1246
+ }
1247
+ }
1248
+ throw Exception{" No such attribute '" + attr_name + " '" , ErrorCodes::BAD_ARGUMENTS};
1249
+ }
1250
+
1251
+ bool isDeterministic () const override { return false ; }
1252
+
1253
+ void executeImpl (Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override
1254
+ {
1255
+ impl->executeImpl (block, arguments, result, input_rows_count);
1256
+ }
1257
+
1258
+ private:
1259
+ const ExternalDictionaries & dictionaries;
1260
+ const Context & context;
1261
+ mutable FunctionPtr impl; // underlying function used by dictGet function without explicit type info
1262
+ };
1263
+
1264
+
1265
+ class FunctionDictGetNoTypeOrDefault final : public IFunction
1266
+ {
1267
+ public:
1268
+ static constexpr auto name = " dictGetOrDefault" ;
1269
+
1270
+ static FunctionPtr create (const Context & context)
1271
+ {
1272
+ return std::make_shared<FunctionDictGetNoTypeOrDefault>(context.getExternalDictionaries (), context);
1273
+ }
1274
+
1275
+ FunctionDictGetNoTypeOrDefault (const ExternalDictionaries & dictionaries, const Context & context) : dictionaries(dictionaries), context(context) {}
1276
+
1277
+ String getName () const override { return name; }
1278
+
1279
+ private:
1280
+ size_t getNumberOfArguments () const override { return 4 ; }
1281
+
1282
+ bool useDefaultImplementationForConstants () const final { return true ; }
1283
+ ColumnNumbers getArgumentsThatAreAlwaysConstant () const final { return {0 , 1 }; }
1284
+
1285
+ bool isInjective (const Block & sample_block) override
1286
+ {
1287
+ return isDictGetFunctionInjective (dictionaries, sample_block);
1288
+ }
1289
+
1290
+ DataTypePtr getReturnTypeImpl (const ColumnsWithTypeAndName & arguments) const override
1291
+ {
1292
+ String dict_name;
1293
+ if (auto name_col = checkAndGetColumnConst<ColumnString>(arguments[0 ].column .get ()))
1294
+ {
1295
+ dict_name = name_col->getValue <String>();
1296
+ }
1297
+ else
1298
+ throw Exception{" Illegal type " + arguments[0 ].type ->getName () + " of first argument of function " + getName ()
1299
+ + " , expected a const string." , ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
1300
+
1301
+ String attr_name;
1302
+ if (auto name_col = checkAndGetColumnConst<ColumnString>(arguments[1 ].column .get ()))
1303
+ {
1304
+ attr_name = name_col->getValue <String>();
1305
+ }
1306
+ else
1307
+ throw Exception{" Illegal type " + arguments[1 ].type ->getName () + " of second argument of function " + getName ()
1308
+ + " , expected a const string." , ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
1309
+
1310
+ if (!WhichDataType (arguments[2 ].type ).isUInt64 () &&
1311
+ !isTuple (arguments[2 ].type ))
1312
+ throw Exception{" Illegal type " + arguments[2 ].type ->getName () + " of third argument of function " + getName ()
1313
+ + " , must be UInt64 or tuple(...)." , ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
1314
+
1315
+ auto dict = dictionaries.getDictionary (dict_name);
1316
+ const DictionaryStructure & structure = dict->getStructure ();
1317
+
1318
+ for (const auto idx : ext::range (0 , structure.attributes .size ()))
1319
+ {
1320
+ const DictionaryAttribute & attribute = structure.attributes [idx];
1321
+ if (attribute.name == attr_name)
1322
+ {
1323
+ WhichDataType dt = attribute.type ;
1324
+ if (dt.idx == TypeIndex::String)
1325
+ {
1326
+ if (!isString (arguments[3 ].type ))
1327
+ throw Exception{" Illegal type " + arguments[3 ].type ->getName () + " of fourth argument of function " + getName () +
1328
+ " , must be String." , ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
1329
+ impl = FunctionDictGetStringOrDefault::create (context);
1330
+ }
1331
+ #define DISPATCH (TYPE ) \
1332
+ else if (dt.idx == TypeIndex::TYPE) \
1333
+ { \
1334
+ if (!checkAndGetDataType<DataType##TYPE>(arguments[3 ].type .get ())) \
1335
+ throw Exception{" Illegal type " + arguments[3 ].type ->getName () + " of fourth argument of function " + getName () \
1336
+ + " , must be " + String (DataType##TYPE{}.getFamilyName ()) + " ." , ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; \
1337
+ impl = FunctionDictGetOrDefault<DataType##TYPE, NameDictGet##TYPE ## OrDefault>::create (context); \
1338
+ }
1339
+ FOR_DICT_TYPES (DISPATCH)
1340
+ #undef DISPATCH
1341
+ else
1342
+ throw Exception (" Unknown dictGetOrDefault type" , ErrorCodes::UNKNOWN_TYPE);
1343
+ return attribute.type ;
1344
+ }
1345
+ }
1346
+ throw Exception{" No such attribute '" + attr_name + " '" , ErrorCodes::BAD_ARGUMENTS};
1347
+ }
1348
+
1349
+ bool isDeterministic () const override { return false ; }
1350
+
1351
+ void executeImpl (Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override
1352
+ {
1353
+ impl->executeImpl (block, arguments, result, input_rows_count);
1354
+ }
1355
+
1356
+ private:
1357
+ const ExternalDictionaries & dictionaries;
1358
+ const Context & context;
1359
+ mutable FunctionPtr impl; // underlying function used by dictGet function without explicit type info
1360
+ };
1148
1361
1149
1362
// / Functions to work with hierarchies.
1150
1363
0 commit comments