#include "insertPostgreSQLValue.h" #if USE_LIBPQXX #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int BAD_ARGUMENTS; } void insertDefaultPostgreSQLValue(IColumn & column, const IColumn & sample_column) { column.insertFrom(sample_column, 0); } void insertPostgreSQLValue( IColumn & column, std::string_view value, const ExternalResultDescription::ValueType type, const DataTypePtr data_type, std::unordered_map & array_info, size_t idx) { switch (type) { case ExternalResultDescription::ValueType::vtUInt8: { if (value == "t") assert_cast(column).insertValue(1); else if (value == "f") assert_cast(column).insertValue(0); else assert_cast(column).insertValue(pqxx::from_string(value)); break; } case ExternalResultDescription::ValueType::vtUInt16: assert_cast(column).insertValue(pqxx::from_string(value)); break; case ExternalResultDescription::ValueType::vtUInt32: assert_cast(column).insertValue(pqxx::from_string(value)); break; case ExternalResultDescription::ValueType::vtUInt64: assert_cast(column).insertValue(pqxx::from_string(value)); break; case ExternalResultDescription::ValueType::vtInt8: assert_cast(column).insertValue(pqxx::from_string(value)); break; case ExternalResultDescription::ValueType::vtInt16: assert_cast(column).insertValue(pqxx::from_string(value)); break; case ExternalResultDescription::ValueType::vtInt32: assert_cast(column).insertValue(pqxx::from_string(value)); break; case ExternalResultDescription::ValueType::vtInt64: assert_cast(column).insertValue(pqxx::from_string(value)); break; case ExternalResultDescription::ValueType::vtFloat32: assert_cast(column).insertValue(pqxx::from_string(value)); break; case ExternalResultDescription::ValueType::vtFloat64: assert_cast(column).insertValue(pqxx::from_string(value)); break; case ExternalResultDescription::ValueType::vtEnum8:[[fallthrough]]; case ExternalResultDescription::ValueType::vtEnum16:[[fallthrough]]; case ExternalResultDescription::ValueType::vtFixedString:[[fallthrough]]; case ExternalResultDescription::ValueType::vtString: assert_cast(column).insertData(value.data(), value.size()); break; case ExternalResultDescription::ValueType::vtUUID: assert_cast(column).insert(parse(value.data(), value.size())); break; case ExternalResultDescription::ValueType::vtDate: assert_cast(column).insertValue(UInt16{LocalDate{std::string(value)}.getDayNum()}); break; case ExternalResultDescription::ValueType::vtDate32: assert_cast(column).insertValue(Int32{LocalDate{std::string(value)}.getExtenedDayNum()}); break; case ExternalResultDescription::ValueType::vtDateTime: { ReadBufferFromString in(value); time_t time = 0; readDateTimeText(time, in, assert_cast(data_type.get())->getTimeZone()); if (time < 0) time = 0; assert_cast(column).insertValue(time); break; } case ExternalResultDescription::ValueType::vtDateTime64: { ReadBufferFromString in(value); DateTime64 time = 0; readDateTime64Text(time, 6, in, assert_cast(data_type.get())->getTimeZone()); if (time < 0) time = 0; assert_cast(column).insertValue(time); break; } case ExternalResultDescription::ValueType::vtDecimal32: [[fallthrough]]; case ExternalResultDescription::ValueType::vtDecimal64: [[fallthrough]]; case ExternalResultDescription::ValueType::vtDecimal128: [[fallthrough]]; case ExternalResultDescription::ValueType::vtDecimal256: { ReadBufferFromString istr(value); data_type->getDefaultSerialization()->deserializeWholeText(column, istr, FormatSettings{}); break; } case ExternalResultDescription::ValueType::vtArray: { pqxx::array_parser parser{value}; std::pair parsed = parser.get_next(); size_t dimension = 0, max_dimension = 0, expected_dimensions = array_info[idx].num_dimensions; const auto parse_value = array_info[idx].pqxx_parser; std::vector dimensions(expected_dimensions + 1); while (parsed.first != pqxx::array_parser::juncture::done) { if ((parsed.first == pqxx::array_parser::juncture::row_start) && (++dimension > expected_dimensions)) throw Exception("Got more dimensions than expected", ErrorCodes::BAD_ARGUMENTS); else if (parsed.first == pqxx::array_parser::juncture::string_value) dimensions[dimension].emplace_back(parse_value(parsed.second)); else if (parsed.first == pqxx::array_parser::juncture::null_value) dimensions[dimension].emplace_back(array_info[idx].default_value); else if (parsed.first == pqxx::array_parser::juncture::row_end) { max_dimension = std::max(max_dimension, dimension); --dimension; if (dimension == 0) break; dimensions[dimension].emplace_back(Array(dimensions[dimension + 1].begin(), dimensions[dimension + 1].end())); dimensions[dimension + 1].clear(); } parsed = parser.get_next(); } if (max_dimension < expected_dimensions) throw Exception(ErrorCodes::BAD_ARGUMENTS, "Got less dimensions than expected. ({} instead of {})", max_dimension, expected_dimensions); assert_cast(column).insert(Array(dimensions[1].begin(), dimensions[1].end())); break; } } } void preparePostgreSQLArrayInfo( std::unordered_map & array_info, size_t column_idx, const DataTypePtr data_type) { const auto * array_type = typeid_cast(data_type.get()); auto nested = array_type->getNestedType(); size_t count_dimensions = 1; while (isArray(nested)) { ++count_dimensions; nested = typeid_cast(nested.get())->getNestedType(); } Field default_value = nested->getDefault(); if (nested->isNullable()) nested = static_cast(nested.get())->getNestedType(); WhichDataType which(nested); std::function parser; if (which.isUInt8() || which.isUInt16()) parser = [](std::string & field) -> Field { return pqxx::from_string(field); }; else if (which.isInt8() || which.isInt16()) parser = [](std::string & field) -> Field { return pqxx::from_string(field); }; else if (which.isUInt32()) parser = [](std::string & field) -> Field { return pqxx::from_string(field); }; else if (which.isInt32()) parser = [](std::string & field) -> Field { return pqxx::from_string(field); }; else if (which.isUInt64()) parser = [](std::string & field) -> Field { return pqxx::from_string(field); }; else if (which.isInt64()) parser = [](std::string & field) -> Field { return pqxx::from_string(field); }; else if (which.isFloat32()) parser = [](std::string & field) -> Field { return pqxx::from_string(field); }; else if (which.isFloat64()) parser = [](std::string & field) -> Field { return pqxx::from_string(field); }; else if (which.isString() || which.isFixedString()) parser = [](std::string & field) -> Field { return field; }; else if (which.isDate()) parser = [](std::string & field) -> Field { return UInt16{LocalDate{field}.getDayNum()}; }; else if (which.isDateTime()) parser = [nested](std::string & field) -> Field { ReadBufferFromString in(field); time_t time = 0; readDateTimeText(time, in, assert_cast(nested.get())->getTimeZone()); if (time < 0) time = 0; return time; }; else if (which.isDateTime64()) parser = [nested](std::string & field) -> Field { ReadBufferFromString in(field); DateTime64 time = 0; readDateTime64Text(time, 6, in, assert_cast(nested.get())->getTimeZone()); if (time < 0) time = 0; return time; }; else if (which.isDecimal32()) parser = [nested](std::string & field) -> Field { const auto & type = typeid_cast *>(nested.get()); DataTypeDecimal res(getDecimalPrecision(*type), getDecimalScale(*type)); return convertFieldToType(field, res); }; else if (which.isDecimal64()) parser = [nested](std::string & field) -> Field { const auto & type = typeid_cast *>(nested.get()); DataTypeDecimal res(getDecimalPrecision(*type), getDecimalScale(*type)); return convertFieldToType(field, res); }; else if (which.isDecimal128()) parser = [nested](std::string & field) -> Field { const auto & type = typeid_cast *>(nested.get()); DataTypeDecimal res(getDecimalPrecision(*type), getDecimalScale(*type)); return convertFieldToType(field, res); }; else if (which.isDecimal256()) parser = [nested](std::string & field) -> Field { const auto & type = typeid_cast *>(nested.get()); DataTypeDecimal res(getDecimalPrecision(*type), getDecimalScale(*type)); return convertFieldToType(field, res); }; else throw Exception(ErrorCodes::BAD_ARGUMENTS, "Type conversion to {} is not supported", nested->getName()); array_info[column_idx] = {count_dimensions, default_value, parser}; } } #endif