void SettingsConstraints::check(const Settings & current_settings, const SettingChange & change) const { const String & name = change.name; size_t setting_index = Settings::findIndex(name); if (setting_index == Settings::npos) return; Field new_value = convertSettingValueToComparableType(change.value, setting_index); Field current_value = current_settings.get(setting_index); /// Setting isn't checked if value wasn't changed. if (current_value == new_value) return; if (!current_settings.allow_ddl && name == "allow_ddl") throw Exception("Cannot modify 'allow_ddl' setting when DDL queries are prohibited for the user", ErrorCodes::QUERY_IS_PROHIBITED); /** The `readonly` value is understood as follows: * 0 - everything allowed. * 1 - only read queries can be made; you can not change the settings. * 2 - You can only do read queries and you can change the settings, except for the `readonly` setting. */ if (current_settings.readonly == 1) throw Exception("Cannot modify '" + name + "' setting in readonly mode", ErrorCodes::READONLY); if (current_settings.readonly > 1 && name == "readonly") throw Exception("Cannot modify 'readonly' setting in readonly mode", ErrorCodes::READONLY); const Constraint * constraint = tryGetConstraint(setting_index); if (constraint) { if (constraint->read_only) throw Exception("Setting " + name + " should not be changed", ErrorCodes::SETTING_CONSTRAINT_VIOLATION); if (!constraint->min_value.isNull() && (new_value < constraint->min_value)) throw Exception( "Setting " + name + " shouldn't be less than " + applyVisitor(FieldVisitorToString(), constraint->min_value), ErrorCodes::SETTING_CONSTRAINT_VIOLATION); if (!constraint->max_value.isNull() && (new_value > constraint->max_value)) throw Exception( "Setting " + name + " shouldn't be greater than " + applyVisitor(FieldVisitorToString(), constraint->max_value), ErrorCodes::SETTING_CONSTRAINT_VIOLATION); } }
std::string Set::describe() const { if (!ordered_set_elements) return "{}"; bool first = true; std::stringstream ss; ss << "{"; for (const Field & f : *ordered_set_elements) { ss << (first ? "" : ", ") << apply_visitor(FieldVisitorToString(), f); first = false; } ss << "}"; return ss.str(); }
void TypeAndConstantInference::dump(WriteBuffer & out) const { /// For need of tests, we need to dump result in some fixed order. std::vector<Info::const_iterator> vec; vec.reserve(info.size()); for (auto it = info.begin(); it != info.end(); ++it) vec.emplace_back(it); std::sort(vec.begin(), vec.end(), [](const auto & a, const auto & b) { return a->first < b->first; }); for (const auto & it : vec) { writeString(it->first, out); writeCString(" -> ", out); writeString(it->second.data_type->getName(), out); if (it->second.is_constant_expression) { writeCString(" = ", out); String value = applyVisitor(FieldVisitorToString(), it->second.value); writeString(value, out); } writeCString(". AST: ", out); if (!it->second.node) writeCString("(none)", out); else { std::stringstream formatted_ast; formatAST(*it->second.node, formatted_ast, false, true); writeString(formatted_ast.str(), out); } writeChar('\n', out); } }
bool ValuesRowInputStream::read(MutableColumns & columns) { size_t num_columns = columns.size(); skipWhitespaceIfAny(istr); if (istr.eof() || *istr.position() == ';') return false; /** Typically, this is the usual format for streaming parsing. * But as an exception, it also supports processing arbitrary expressions instead of values. * This is very inefficient. But if there are no expressions, then there is no overhead. */ ParserExpression parser; assertChar('(', istr); for (size_t i = 0; i < num_columns; ++i) { skipWhitespaceIfAny(istr); char * prev_istr_position = istr.position(); size_t prev_istr_bytes = istr.count() - istr.offset(); bool rollback_on_exception = false; try { header.getByPosition(i).type->deserializeTextQuoted(*columns[i], istr, format_settings); rollback_on_exception = true; skipWhitespaceIfAny(istr); if (i != num_columns - 1) assertChar(',', istr); else assertChar(')', istr); } catch (const Exception & e) { if (!format_settings.values.interpret_expressions) throw; /** The normal streaming parser could not parse the value. * Let's try to parse it with a SQL parser as a constant expression. * This is an exceptional case. */ if (e.code() == ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED || e.code() == ErrorCodes::CANNOT_PARSE_QUOTED_STRING || e.code() == ErrorCodes::CANNOT_PARSE_NUMBER || e.code() == ErrorCodes::CANNOT_PARSE_DATE || e.code() == ErrorCodes::CANNOT_PARSE_DATETIME || e.code() == ErrorCodes::CANNOT_READ_ARRAY_FROM_TEXT) { /// TODO Case when the expression does not fit entirely in the buffer. /// If the beginning of the value is no longer in the buffer. if (istr.count() - istr.offset() != prev_istr_bytes) throw; if (rollback_on_exception) columns[i]->popBack(1); const IDataType & type = *header.getByPosition(i).type; Expected expected; Tokens tokens(prev_istr_position, istr.buffer().end()); TokenIterator token_iterator(tokens); ASTPtr ast; if (!parser.parse(token_iterator, ast, expected)) throw Exception("Cannot parse expression of type " + type.getName() + " here: " + String(prev_istr_position, std::min(SHOW_CHARS_ON_SYNTAX_ERROR, istr.buffer().end() - prev_istr_position)), ErrorCodes::SYNTAX_ERROR); istr.position() = const_cast<char *>(token_iterator->begin); std::pair<Field, DataTypePtr> value_raw = evaluateConstantExpression(ast, *context); Field value = convertFieldToType(value_raw.first, type, value_raw.second.get()); /// Check that we are indeed allowed to insert a NULL. if (value.isNull()) { if (!type.isNullable()) throw Exception{"Expression returns value " + applyVisitor(FieldVisitorToString(), value) + ", that is out of range of type " + type.getName() + ", at: " + String(prev_istr_position, std::min(SHOW_CHARS_ON_SYNTAX_ERROR, istr.buffer().end() - prev_istr_position)), ErrorCodes::VALUE_IS_OUT_OF_RANGE_OF_DATA_TYPE}; } columns[i]->insert(value); skipWhitespaceIfAny(istr); if (i != num_columns - 1) assertChar(',', istr); else assertChar(')', istr); } else throw; } } skipWhitespaceIfAny(istr); if (!istr.eof() && *istr.position() == ',') ++istr.position(); return true; }
bool ValuesRowInputStream::read(Block & block) { size_t size = block.columns(); skipWhitespaceIfAny(istr); if (istr.eof() || *istr.position() == ';') return false; /** Как правило, это обычный формат для потокового парсинга. * Но в качестве исключения, поддерживается также обработка произвольных выражений вместо значений. * Это очень неэффективно. Но если выражений нет, то оверхед отсутствует. */ ParserExpressionWithOptionalAlias parser(false); assertChar('(', istr); for (size_t i = 0; i < size; ++i) { skipWhitespaceIfAny(istr); char * prev_istr_position = istr.position(); size_t prev_istr_bytes = istr.count() - istr.offset(); auto & col = block.getByPosition(i); bool rollback_on_exception = false; try { col.type.get()->deserializeTextQuoted(*col.column.get(), istr); rollback_on_exception = true; skipWhitespaceIfAny(istr); if (i != size - 1) assertChar(',', istr); else assertChar(')', istr); } catch (const Exception & e) { if (!interpret_expressions) throw; /** Обычный потоковый парсер не смог распарсить значение. * Попробуем распарсить его SQL-парсером как константное выражение. * Это исключительный случай. */ if (e.code() == ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED || e.code() == ErrorCodes::CANNOT_PARSE_QUOTED_STRING || e.code() == ErrorCodes::CANNOT_PARSE_DATE || e.code() == ErrorCodes::CANNOT_PARSE_DATETIME || e.code() == ErrorCodes::CANNOT_READ_ARRAY_FROM_TEXT) { /// TODO Работоспособность, если выражение не помещается целиком до конца буфера. /// Если начало значения уже не лежит в буфере. if (istr.count() - istr.offset() != prev_istr_bytes) throw; if (rollback_on_exception) col.column.get()->popBack(1); IDataType & type = *block.safeGetByPosition(i).type; IParser::Pos pos = prev_istr_position; Expected expected = ""; IParser::Pos max_parsed_pos = pos; ASTPtr ast; if (!parser.parse(pos, istr.buffer().end(), ast, max_parsed_pos, expected)) throw Exception("Cannot parse expression of type " + type.getName() + " here: " + String(prev_istr_position, std::min(SHOW_CHARS_ON_SYNTAX_ERROR, istr.buffer().end() - prev_istr_position)), ErrorCodes::SYNTAX_ERROR); istr.position() = const_cast<char *>(max_parsed_pos); std::pair<Field, DataTypePtr> value_raw = evaluateConstantExpression(ast, context); Field value = convertFieldToType(value_raw.first, type, value_raw.second.get()); if (value.isNull()) { /// Check that we are indeed allowed to insert a NULL. bool is_null_allowed = false; if (type.isNullable()) is_null_allowed = true; else { /// NOTE: For now we support only one level of null values, i.e. /// there are not yet such things as Array(Nullable(Array(Nullable(T))). /// Therefore the code below is valid within the current limitations. const auto array_type = typeid_cast<const DataTypeArray *>(&type); if (array_type != nullptr) { const auto & nested_type = array_type->getMostNestedType(); if (nested_type->isNullable()) is_null_allowed = true; } } if (!is_null_allowed) throw Exception{"Expression returns value " + applyVisitor(FieldVisitorToString(), value) + ", that is out of range of type " + type.getName() + ", at: " + String(prev_istr_position, std::min(SHOW_CHARS_ON_SYNTAX_ERROR, istr.buffer().end() - prev_istr_position)), ErrorCodes::VALUE_IS_OUT_OF_RANGE_OF_DATA_TYPE}; } col.column->insert(value); skipWhitespaceIfAny(istr); if (i != size - 1) assertChar(',', istr); else assertChar(')', istr); } else throw; } } skipWhitespaceIfAny(istr); if (!istr.eof() && *istr.position() == ',') ++istr.position(); return true; }