/* * Licensed to CRATE Technology GmbH ("Crate") under one or more contributor * license agreements. See the NOTICE file distributed with this work for * additional information regarding copyright ownership. Crate licenses * this file to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may * obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * * However, if you have executed another commercial license agreement * with Crate these terms will supersede the license and you may use the * software solely pursuant to the terms of the relevant commercial agreement. */ package io.crate.analyze; import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; import io.crate.analyze.expressions.ExpressionToStringVisitor; import io.crate.data.Row; import io.crate.metadata.settings.CrateSettings; import io.crate.sql.tree.*; import org.apache.logging.log4j.Logger; import org.elasticsearch.common.logging.Loggers; import java.util.*; class SetStatementAnalyzer { private static final Logger logger = Loggers.getLogger(SetStatementAnalyzer.class); public static SetAnalyzedStatement analyze(SetStatement node) { boolean isPersistent = node.settingType().equals(SetStatement.SettingType.PERSISTENT); Map<String, List<Expression>> settings = new HashMap<>(); if (!SetStatement.Scope.GLOBAL.equals(node.scope())) { Assignment assignment = node.assignments().get(0); // parser does not allow using the parameter expressions as setting names in the SET statements, // therefore it is fine to convert the expression to string here. String settingName = ExpressionToStringVisitor.convert(assignment.columnName(), Row.EMPTY); List<String> nameParts = CrateSettings.settingNamesByPrefix(settingName); if (nameParts.size() != 0) { throw new IllegalArgumentException(String.format(Locale.ENGLISH, "GLOBAL Cluster setting '%s' cannot be used with SET SESSION / LOCAL", settingName)); } settings.put(settingName, assignment.expressions()); return new SetAnalyzedStatement(node.scope(), settings, isPersistent); } else { for (Assignment assignment : node.assignments()) { for (String setting : ExpressionToSettingNameListVisitor.convert(assignment)) { CrateSettings.checkIfRuntimeSetting(setting); } String settingName = ExpressionToStringVisitor.convert(assignment.columnName(), Row.EMPTY); settings.put(settingName, ImmutableList.of(assignment.expression())); } return new SetAnalyzedStatement(node.scope(), settings, isPersistent); } } public static ResetAnalyzedStatement analyze(ResetStatement node) { Set<String> settingsToRemove = Sets.newHashSet(); for (Expression expression : node.columns()) { String settingsName = ExpressionToStringVisitor.convert(expression, Row.EMPTY); if (!settingsToRemove.contains(settingsName)) { List<String> settingNames = CrateSettings.settingNamesByPrefix(settingsName); if (settingNames.size() == 0) { throw new IllegalArgumentException(String.format(Locale.ENGLISH, "Setting '%s' not supported", settingsName)); } for (String setting : settingNames) { CrateSettings.checkIfRuntimeSetting(setting); } settingsToRemove.addAll(settingNames); logger.info("resetting [{}]", settingNames); } } return new ResetAnalyzedStatement(settingsToRemove); } private static class ExpressionToSettingNameListVisitor extends AstVisitor<Collection<String>, String> { private static final ExpressionToSettingNameListVisitor INSTANCE = new ExpressionToSettingNameListVisitor(); public static Collection<String> convert(Node node) { return INSTANCE.process(node, null); } @Override public Collection<String> visitAssignment(Assignment node, String context) { String left = ExpressionToStringVisitor.convert(node.columnName(), Row.EMPTY); return node.expression().accept(this, left); } @Override public Collection<String> visitObjectLiteral(ObjectLiteral node, String context) { Collection<String> settingNames = new ArrayList<>(); for (Map.Entry<String, Expression> entry : node.values().entries()) { String s = String.format(Locale.ENGLISH, "%s.%s", context, entry.getKey()); if (entry.getValue() instanceof ObjectLiteral) { settingNames.addAll(entry.getValue().accept(this, s)); } else { settingNames.add(s); } } return settingNames; } @Override protected Collection<String> visitLiteral(Literal node, String context) { return ImmutableList.of(context); } @Override public Collection<String> visitParameterExpression(ParameterExpression node, String context) { return ImmutableList.of(context); } @Override protected Collection<String> visitNode(Node node, String context) { return ImmutableList.of(context); } } }