This is an automated email from the ASF dual-hosted git repository.

jark pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/flink.git


The following commit(s) were added to refs/heads/master by this push:
     new a6a7063cfaf [FLINK-28096][hive] Hive dialect support set variables 
(#20000)
a6a7063cfaf is described below

commit a6a7063cfafd8cd5c1b04169839b92373bf96fde
Author: yuxia Luo <[email protected]>
AuthorDate: Mon Aug 1 14:12:32 2022 +0800

    [FLINK-28096][hive] Hive dialect support set variables (#20000)
---
 .../hive/HiveInternalOptions.java}                 |  27 +-
 .../flink/table/operations/HiveSetOperation.java   |  80 ++++++
 .../delegation/hive/HiveDialectFactory.java        |   2 +-
 .../delegation/hive/HiveOperationExecutor.java     |  90 +++++++
 .../table/planner/delegation/hive/HiveParser.java  |  83 ++++++
 .../delegation/hive/copy/HiveSetProcessor.java     | 284 +++++++++++++++++++++
 .../flink/connectors/hive/HiveDialectITCase.java   |  70 ++++-
 7 files changed, 620 insertions(+), 16 deletions(-)

diff --git 
a/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/planner/delegation/hive/HiveOperationExecutor.java
 
b/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/connectors/hive/HiveInternalOptions.java
similarity index 56%
copy from 
flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/planner/delegation/hive/HiveOperationExecutor.java
copy to 
flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/connectors/hive/HiveInternalOptions.java
index 2eb02ba27a6..655f25b114b 100644
--- 
a/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/planner/delegation/hive/HiveOperationExecutor.java
+++ 
b/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/connectors/hive/HiveInternalOptions.java
@@ -16,21 +16,20 @@
  * limitations under the License.
  */
 
-package org.apache.flink.table.planner.delegation.hive;
+package org.apache.flink.connectors.hive;
 
-import org.apache.flink.table.api.internal.TableResultInternal;
-import org.apache.flink.table.delegation.ExtendedOperationExecutor;
-import org.apache.flink.table.operations.Operation;
+import org.apache.flink.configuration.ConfigOption;
 
-import java.util.Optional;
+import java.util.HashMap;
+import java.util.Map;
 
-/**
- * A Hive's operation executor used to execute operation in custom way instead 
of Flink's
- * implementation.
- */
-public class HiveOperationExecutor implements ExtendedOperationExecutor {
-    @Override
-    public Optional<TableResultInternal> executeOperation(Operation operation) 
{
-        return Optional.empty();
-    }
+import static org.apache.flink.configuration.ConfigOptions.key;
+
+/** This class holds internal configuration constants used by Hive connector 
module. */
+public class HiveInternalOptions {
+    public static final ConfigOption<Map<String, String>> HIVE_VARIABLES =
+            key("__hive.variables__")
+                    .mapType()
+                    .defaultValue(new HashMap<>())
+                    .withDescription("The config used to save the hive 
variables set by Flink.");
 }
diff --git 
a/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/operations/HiveSetOperation.java
 
b/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/operations/HiveSetOperation.java
new file mode 100644
index 00000000000..d675ba8df37
--- /dev/null
+++ 
b/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/operations/HiveSetOperation.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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.
+ */
+
+package org.apache.flink.table.operations;
+
+import javax.annotation.Nullable;
+
+import java.util.Optional;
+
+/** Hive's set operation. */
+public class HiveSetOperation implements Operation {
+    private final @Nullable String key;
+    private final @Nullable String value;
+    // for Hive's command "set -v"
+    private final boolean isVerbose;
+
+    public HiveSetOperation() {
+        this(null, null, false);
+    }
+
+    public HiveSetOperation(boolean isVerbose) {
+        this(null, null, isVerbose);
+    }
+
+    public HiveSetOperation(String key) {
+        this(key, null);
+    }
+
+    public HiveSetOperation(String key, String value) {
+        this(key, value, false);
+    }
+
+    public HiveSetOperation(String key, String value, boolean isVerbose) {
+        this.key = key;
+        this.value = value;
+        this.isVerbose = isVerbose;
+    }
+
+    public boolean isVerbose() {
+        return isVerbose;
+    }
+
+    public Optional<String> getKey() {
+        return Optional.ofNullable(key);
+    }
+
+    public Optional<String> getValue() {
+        return Optional.ofNullable(value);
+    }
+
+    @Override
+    public String asSummaryString() {
+        if (isVerbose) {
+            return "set -v";
+        }
+        StringBuilder sb = new StringBuilder("set");
+        if (key != null) {
+            sb.append(" ").append(key).append("=");
+        }
+        if (value != null) {
+            sb.append(value);
+        }
+        return sb.toString();
+    }
+}
diff --git 
a/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/planner/delegation/hive/HiveDialectFactory.java
 
b/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/planner/delegation/hive/HiveDialectFactory.java
index 10b8dce8f9a..08c2bc15e75 100644
--- 
a/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/planner/delegation/hive/HiveDialectFactory.java
+++ 
b/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/planner/delegation/hive/HiveDialectFactory.java
@@ -56,6 +56,6 @@ public class HiveDialectFactory implements DialectFactory {
 
     @Override
     public ExtendedOperationExecutor createExtendedOperationExecutor(Context 
context) {
-        return new HiveOperationExecutor();
+        return new HiveOperationExecutor(context.getCatalogManager(), 
context.getPlannerContext());
     }
 }
diff --git 
a/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/planner/delegation/hive/HiveOperationExecutor.java
 
b/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/planner/delegation/hive/HiveOperationExecutor.java
index 2eb02ba27a6..459a1bbd7dd 100644
--- 
a/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/planner/delegation/hive/HiveOperationExecutor.java
+++ 
b/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/planner/delegation/hive/HiveOperationExecutor.java
@@ -18,19 +18,109 @@
 
 package org.apache.flink.table.planner.delegation.hive;
 
+import org.apache.flink.connectors.hive.FlinkHiveException;
+import org.apache.flink.connectors.hive.HiveInternalOptions;
+import org.apache.flink.table.api.DataTypes;
+import org.apache.flink.table.api.ResultKind;
+import org.apache.flink.table.api.TableConfig;
+import org.apache.flink.table.api.internal.TableResultImpl;
 import org.apache.flink.table.api.internal.TableResultInternal;
+import org.apache.flink.table.catalog.Catalog;
+import org.apache.flink.table.catalog.CatalogManager;
+import org.apache.flink.table.catalog.Column;
+import org.apache.flink.table.catalog.ResolvedSchema;
+import org.apache.flink.table.catalog.hive.HiveCatalog;
 import org.apache.flink.table.delegation.ExtendedOperationExecutor;
+import org.apache.flink.table.operations.HiveSetOperation;
 import org.apache.flink.table.operations.Operation;
+import org.apache.flink.table.planner.delegation.PlannerContext;
+import org.apache.flink.table.planner.delegation.hive.copy.HiveSetProcessor;
+import org.apache.flink.types.Row;
 
+import org.apache.hadoop.hive.conf.HiveConf;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
 import java.util.Optional;
+import java.util.stream.Collectors;
 
 /**
  * A Hive's operation executor used to execute operation in custom way instead 
of Flink's
  * implementation.
  */
 public class HiveOperationExecutor implements ExtendedOperationExecutor {
+
+    private final CatalogManager catalogManager;
+    private final Map<String, String> hiveVariables;
+    private final TableConfig tableConfig;
+
+    public HiveOperationExecutor(CatalogManager catalogManager, PlannerContext 
plannerContext) {
+        this.catalogManager = catalogManager;
+        tableConfig = plannerContext.getFlinkContext().getTableConfig();
+        this.hiveVariables = 
tableConfig.get(HiveInternalOptions.HIVE_VARIABLES);
+    }
+
     @Override
     public Optional<TableResultInternal> executeOperation(Operation operation) 
{
+        if (operation instanceof HiveSetOperation) {
+            return executeHiveSetOperation((HiveSetOperation) operation);
+        }
         return Optional.empty();
     }
+
+    private Optional<TableResultInternal> executeHiveSetOperation(
+            HiveSetOperation hiveSetOperation) {
+        Catalog currentCatalog =
+                
catalogManager.getCatalog(catalogManager.getCurrentCatalog()).orElse(null);
+        if (!(currentCatalog instanceof HiveCatalog)) {
+            throw new FlinkHiveException(
+                    "Only support SET command when the current catalog is 
HiveCatalog ing Hive dialect.");
+        }
+
+        HiveConf hiveConf = ((HiveCatalog) currentCatalog).getHiveConf();
+
+        if (!hiveSetOperation.getKey().isPresent() && 
!hiveSetOperation.getValue().isPresent()) {
+            List<String> options;
+            if (hiveSetOperation.isVerbose()) {
+                // set -v
+                options =
+                        HiveSetProcessor.dumpOptions(
+                                hiveConf.getAllProperties(), hiveConf, 
hiveVariables, tableConfig);
+            } else {
+                // set
+                options =
+                        HiveSetProcessor.dumpOptions(
+                                hiveConf.getChangedProperties(),
+                                hiveConf,
+                                hiveVariables,
+                                tableConfig);
+            }
+            return Optional.of(buildResultForShowVariable(options));
+        } else {
+            if (!hiveSetOperation.getValue().isPresent()) {
+                // set key
+                String option =
+                        HiveSetProcessor.getVariable(
+                                hiveConf, hiveVariables, 
hiveSetOperation.getKey().get());
+                return 
Optional.of(buildResultForShowVariable(Collections.singletonList(option)));
+            } else {
+                HiveSetProcessor.setVariable(
+                        hiveConf,
+                        hiveVariables,
+                        hiveSetOperation.getKey().get(),
+                        hiveSetOperation.getValue().get());
+                return Optional.of(TableResultImpl.TABLE_RESULT_OK);
+            }
+        }
+    }
+
+    private TableResultInternal buildResultForShowVariable(List<String> 
results) {
+        List<Row> rows = 
results.stream().map(Row::of).collect(Collectors.toList());
+        return TableResultImpl.builder()
+                .resultKind(ResultKind.SUCCESS)
+                .schema(ResolvedSchema.of(Column.physical("variables", 
DataTypes.STRING())))
+                .data(rows)
+                .build();
+    }
 }
diff --git 
a/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/planner/delegation/hive/HiveParser.java
 
b/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/planner/delegation/hive/HiveParser.java
index 6f8cc71b99c..79ffb6bb760 100644
--- 
a/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/planner/delegation/hive/HiveParser.java
+++ 
b/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/planner/delegation/hive/HiveParser.java
@@ -19,7 +19,9 @@
 package org.apache.flink.table.planner.delegation.hive;
 
 import org.apache.flink.connectors.hive.FlinkHiveException;
+import org.apache.flink.connectors.hive.HiveInternalOptions;
 import org.apache.flink.table.api.SqlParserException;
+import org.apache.flink.table.api.TableConfig;
 import org.apache.flink.table.api.ValidationException;
 import org.apache.flink.table.catalog.Catalog;
 import org.apache.flink.table.catalog.CatalogManager;
@@ -29,6 +31,7 @@ import 
org.apache.flink.table.catalog.hive.client.HiveShimLoader;
 import org.apache.flink.table.catalog.hive.util.HiveReflectionUtils;
 import org.apache.flink.table.module.hive.udf.generic.HiveGenericUDFGrouping;
 import org.apache.flink.table.operations.ExplainOperation;
+import org.apache.flink.table.operations.HiveSetOperation;
 import org.apache.flink.table.operations.ModifyOperation;
 import org.apache.flink.table.operations.NopOperation;
 import org.apache.flink.table.operations.Operation;
@@ -57,6 +60,7 @@ import org.apache.hadoop.hive.conf.HiveConf;
 import org.apache.hadoop.hive.ql.lockmgr.LockException;
 import org.apache.hadoop.hive.ql.metadata.Hive;
 import org.apache.hadoop.hive.ql.parse.SemanticException;
+import org.apache.hadoop.hive.ql.processors.HiveCommand;
 import org.apache.hadoop.hive.ql.session.SessionState;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -72,9 +76,13 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.function.Supplier;
 
+import static 
org.apache.flink.table.planner.delegation.hive.copy.HiveSetProcessor.startWithHiveSpecialVariablePrefix;
+
 /** A Parser that uses Hive's planner to parse a statement. */
 public class HiveParser extends ParserImpl {
 
@@ -163,6 +171,8 @@ public class HiveParser extends ParserImpl {
     private final FrameworkConfig frameworkConfig;
     private final SqlFunctionConverter funcConverter;
     private final HiveParserDMLHelper dmlHelper;
+    private final TableConfig tableConfig;
+    private final Map<String, String> hiveVariables;
 
     HiveParser(
             CatalogManager catalogManager,
@@ -183,6 +193,8 @@ public class HiveParser extends ParserImpl {
                         frameworkConfig.getOperatorTable(),
                         catalogReader.nameMatcher());
         this.dmlHelper = new HiveParserDMLHelper(plannerContext, 
funcConverter, catalogManager);
+        this.tableConfig = plannerContext.getFlinkContext().getTableConfig();
+        this.hiveVariables = 
tableConfig.get(HiveInternalOptions.HIVE_VARIABLES);
     }
 
     @Override
@@ -194,6 +206,11 @@ public class HiveParser extends ParserImpl {
             LOG.warn("Current catalog is not HiveCatalog. Falling back to 
Flink's planner.");
             return super.parse(statement);
         }
+
+        Optional<Operation> nonSqlOperation = 
tryProcessHiveNonSqlStatement(statement);
+        if (nonSqlOperation.isPresent()) {
+            return Collections.singletonList(nonSqlOperation.get());
+        }
         HiveConf hiveConf = new HiveConf(((HiveCatalog) 
currentCatalog).getHiveConf());
         hiveConf.setVar(HiveConf.ConfVars.DYNAMICPARTITIONINGMODE, 
"nonstrict");
         hiveConf.set("hive.allow.udf.load.on.demand", "false");
@@ -211,6 +228,72 @@ public class HiveParser extends ParserImpl {
         }
     }
 
+    private Optional<Operation> tryProcessHiveNonSqlStatement(String 
statement) {
+        String[] commandTokens = statement.split("\\s+");
+        HiveCommand hiveCommand = HiveCommand.find(commandTokens);
+        if (hiveCommand != null) {
+            if (hiveCommand == HiveCommand.SET) {
+                return Optional.of(
+                        processSetCmd(
+                                statement, 
statement.substring(commandTokens[0].length()).trim()));
+            } else if (hiveCommand == HiveCommand.RESET) {
+                return Optional.of(super.parse(statement).get(0));
+            } else {
+                throw new UnsupportedOperationException(
+                        String.format("The Hive command %s is not supported.", 
hiveCommand));
+            }
+        }
+        return Optional.empty();
+    }
+
+    private Operation processSetCmd(String originCmd, String setCmdArgs) {
+        String nwcmd = setCmdArgs.trim();
+        // the set command may end with ";" since it won't be removed by Flink 
SQL CLI,
+        // so, we need to remove ";"
+        if (nwcmd.endsWith(";")) {
+            nwcmd = nwcmd.substring(0, nwcmd.length() - 1);
+        }
+
+        if (nwcmd.equals("")) {
+            return new HiveSetOperation();
+        }
+        if (nwcmd.equals("-v")) {
+            return new HiveSetOperation(true);
+        }
+
+        String[] part = new String[2];
+        int eqIndex = nwcmd.indexOf('=');
+        if (nwcmd.contains("=")) {
+            if (eqIndex == nwcmd.length() - 1) { // x=
+                part[0] = nwcmd.substring(0, nwcmd.length() - 1);
+                part[1] = "";
+            } else { // x=y
+                part[0] = nwcmd.substring(0, eqIndex).trim();
+                part[1] = nwcmd.substring(eqIndex + 1).trim();
+                if (!startWithHiveSpecialVariablePrefix(part[0])) {
+                    // TODO:
+                    // currently, for the command set key=value, we will fall 
to
+                    // Flink's implementation, otherwise, user will have no 
way to switch dialect.
+                    // need to figure out whether we should also set the value 
in HiveConf which is
+                    // Hive's implementation
+                    LOG.warn(
+                            "The command 'set {}={}' will only set Flink's 
table config,"
+                                    + " and if you want to set the variable to 
Hive's conf, please use the command like 'set hiveconf:{}={}'.",
+                            part[0],
+                            part[1],
+                            part[0],
+                            part[1]);
+                    return super.parse(originCmd).get(0);
+                }
+            }
+            if (part[0].equals("silent")) {
+                throw new UnsupportedOperationException("Unsupported command 
'set silent'.");
+            }
+            return new HiveSetOperation(part[0], part[1]);
+        }
+        return new HiveSetOperation(nwcmd);
+    }
+
     private List<Operation> processCmd(
             String cmd, HiveConf hiveConf, HiveShim hiveShim, HiveCatalog 
hiveCatalog) {
         try {
diff --git 
a/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/planner/delegation/hive/copy/HiveSetProcessor.java
 
b/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/planner/delegation/hive/copy/HiveSetProcessor.java
new file mode 100644
index 00000000000..51ad1dddd17
--- /dev/null
+++ 
b/flink-connectors/flink-connector-hive/src/main/java/org/apache/flink/table/planner/delegation/hive/copy/HiveSetProcessor.java
@@ -0,0 +1,284 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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.
+ */
+
+package org.apache.flink.table.planner.delegation.hive.copy;
+
+import org.apache.flink.connectors.hive.FlinkHiveException;
+import org.apache.flink.table.api.TableConfig;
+
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.apache.hadoop.hive.conf.VariableSubstitution;
+import org.apache.hadoop.hive.ql.metadata.Hive;
+import org.apache.hadoop.hive.ql.metadata.HiveException;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import static org.apache.hadoop.hive.conf.SystemVariables.ENV_PREFIX;
+import static org.apache.hadoop.hive.conf.SystemVariables.HIVECONF_PREFIX;
+import static org.apache.hadoop.hive.conf.SystemVariables.HIVEVAR_PREFIX;
+import static org.apache.hadoop.hive.conf.SystemVariables.METACONF_PREFIX;
+import static org.apache.hadoop.hive.conf.SystemVariables.SYSTEM_PREFIX;
+
+/** Counterpart of hive's {@link 
org.apache.hadoop.hive.ql.processors.SetProcessor}. */
+public class HiveSetProcessor {
+
+    private static final String[] PASSWORD_STRINGS = new String[] {"password", 
"paswd", "pswd"};
+    private static final String FLINK_PREFIX = "flink:";
+
+    /** Set variable following Hive's implementation. */
+    public static void setVariable(
+            HiveConf hiveConf, Map<String, String> hiveVariables, String 
varname, String varvalue) {
+        if (varname.startsWith(ENV_PREFIX)) {
+            throw new UnsupportedOperationException("env:* variables can not 
be set.");
+        } else if (varname.startsWith(SYSTEM_PREFIX)) {
+            String propName = varname.substring(SYSTEM_PREFIX.length());
+            System.getProperties()
+                    .setProperty(
+                            propName,
+                            new VariableSubstitution(() -> hiveVariables)
+                                    .substitute(hiveConf, varvalue));
+        } else if (varname.startsWith(HIVECONF_PREFIX)) {
+            String propName = varname.substring(HIVECONF_PREFIX.length());
+            setConf(hiveConf, hiveVariables, varname, propName, varvalue);
+        } else if (varname.startsWith(HIVEVAR_PREFIX)) {
+            String propName = varname.substring(HIVEVAR_PREFIX.length());
+            hiveVariables.put(
+                    propName,
+                    new VariableSubstitution(() -> 
hiveVariables).substitute(hiveConf, varvalue));
+        } else if (varname.startsWith(METACONF_PREFIX)) {
+            String propName = varname.substring(METACONF_PREFIX.length());
+            try {
+                Hive hive = Hive.get(hiveConf);
+                hive.setMetaConf(
+                        propName,
+                        new VariableSubstitution(() -> hiveVariables)
+                                .substitute(hiveConf, varvalue));
+            } catch (HiveException e) {
+                throw new FlinkHiveException(
+                        String.format("'SET %s=%s' FAILED.", varname, 
varvalue), e);
+            }
+        } else {
+            setConf(hiveConf, hiveVariables, varname, varname, varvalue);
+        }
+    }
+
+    /**
+     * check whether the variable's name is started with the special variable 
prefix that Hive
+     * reserves.
+     */
+    public static boolean startWithHiveSpecialVariablePrefix(String varname) {
+        String[] hiveSpecialVariablePrefix =
+                new String[] {
+                    ENV_PREFIX, SYSTEM_PREFIX, HIVECONF_PREFIX, 
HIVEVAR_PREFIX, METACONF_PREFIX
+                };
+        for (String prefix : hiveSpecialVariablePrefix) {
+            if (varname.startsWith(prefix)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static void setConf(
+            HiveConf hiveConf,
+            Map<String, String> hiveVariables,
+            String varname,
+            String key,
+            String varvalue) {
+        String value = new VariableSubstitution(() -> 
hiveVariables).substitute(hiveConf, varvalue);
+        if (hiveConf.getBoolVar(HiveConf.ConfVars.HIVECONFVALIDATION)) {
+            HiveConf.ConfVars confVars = HiveConf.getConfVars(key);
+            if (confVars != null) {
+                if (!confVars.isType(value)) {
+                    String message =
+                            String.format(
+                                    "'SET %s=%s' FAILED because %s expects %s 
type value.",
+                                    varname, varvalue, key, 
confVars.typeString());
+                    throw new IllegalArgumentException(message);
+                }
+                String fail = confVars.validate(value);
+                if (fail != null) {
+                    String message =
+                            String.format(
+                                    "'SET %s=%s' FAILED in validation : %s.",
+                                    varname, varvalue, fail);
+                    throw new IllegalArgumentException(message);
+                }
+            }
+        }
+        hiveConf.verifyAndSet(key, value);
+    }
+
+    public static String getVariable(
+            HiveConf hiveConf, Map<String, String> hiveVariables, String 
varname) {
+        if (varname.equals("silent")) {
+            return "silent is not a valid variable";
+        }
+        if (varname.startsWith(SYSTEM_PREFIX)) {
+            String propName = varname.substring(SYSTEM_PREFIX.length());
+            String result = System.getProperty(propName);
+            if (result != null) {
+                if (isHidden(propName)) {
+                    return SYSTEM_PREFIX + propName + " is a hidden config";
+                } else {
+                    return SYSTEM_PREFIX + propName + "=" + result;
+                }
+            } else {
+                return propName + " is undefined as a system property";
+            }
+        } else if (varname.indexOf(ENV_PREFIX) == 0) {
+            String var = varname.substring(ENV_PREFIX.length());
+            if (System.getenv(var) != null) {
+                if (isHidden(var)) {
+                    return ENV_PREFIX + var + " is a hidden config";
+                } else {
+                    return ENV_PREFIX + var + "=" + System.getenv(var);
+                }
+            } else {
+                return varname + " is undefined as an environmental variable";
+            }
+        } else if (varname.indexOf(HIVECONF_PREFIX) == 0) {
+            String var = varname.substring(HIVECONF_PREFIX.length());
+            if (hiveConf.isHiddenConfig(var)) {
+                return HIVECONF_PREFIX + var + " is a hidden config";
+            }
+            if (hiveConf.get(var) != null) {
+                return HIVECONF_PREFIX + var + "=" + hiveConf.get(var);
+            } else {
+                return varname + " is undefined as a hive configuration 
variable";
+            }
+        } else if (varname.indexOf(HIVEVAR_PREFIX) == 0) {
+            String var = varname.substring(HIVEVAR_PREFIX.length());
+            if (hiveVariables.get(var) != null) {
+                return HIVEVAR_PREFIX + var + "=" + hiveVariables.get(var);
+            } else {
+                return varname + " is undefined as a hive variable";
+            }
+        } else if (varname.indexOf(METACONF_PREFIX) == 0) {
+            String var = varname.substring(METACONF_PREFIX.length());
+            String value;
+            try {
+                Hive hive = Hive.get(hiveConf);
+                value = hive.getMetaConf(var);
+            } catch (HiveException e) {
+                throw new FlinkHiveException(
+                        String.format("Failed to get variable for %s.", 
varname), e);
+            }
+
+            if (value != null) {
+                return METACONF_PREFIX + var + "=" + value;
+            } else {
+                return varname + " is undefined as a hive meta variable";
+            }
+        } else {
+            return dumpOption(hiveConf, hiveVariables, varname);
+        }
+    }
+
+    /*
+     * Checks if the value contains any of the PASSWORD_STRINGS and if yes
+     * return true
+     */
+    private static boolean isHidden(String key) {
+        for (String p : PASSWORD_STRINGS) {
+            if (key.toLowerCase().contains(p)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static String dumpOption(
+            HiveConf hiveConf, Map<String, String> hiveVariables, String s) {
+        if (hiveConf.isHiddenConfig(s)) {
+            return s + " is a hidden config";
+        } else if (hiveConf.get(s) != null) {
+            return s + "=" + hiveConf.get(s);
+        } else if (hiveVariables.containsKey(s)) {
+            return s + "=" + hiveVariables.get(s);
+        } else {
+            return s + " is undefined";
+        }
+    }
+
+    public static List<String> dumpOptions(
+            Properties p,
+            HiveConf hiveConf,
+            Map<String, String> hiveVariables,
+            TableConfig tableConfig) {
+        SortedMap<String, String> sortedMap = new TreeMap<>();
+        List<String> optionsList = new ArrayList<>();
+        for (Object one : p.keySet()) {
+            String oneProp = (String) one;
+            String oneValue = p.getProperty(oneProp);
+            if (hiveConf.isHiddenConfig(oneProp)) {
+                continue;
+            }
+            sortedMap.put(oneProp, oneValue);
+        }
+
+        // Inserting hive variables
+        for (String s : hiveVariables.keySet()) {
+            sortedMap.put(HIVEVAR_PREFIX + s, hiveVariables.get(s));
+        }
+
+        for (Map.Entry<String, String> entries : sortedMap.entrySet()) {
+            optionsList.add(entries.getKey() + "=" + entries.getValue());
+        }
+
+        for (Map.Entry<String, String> entry : 
mapToSortedMap(System.getenv()).entrySet()) {
+            if (isHidden(entry.getKey())) {
+                continue;
+            }
+            optionsList.add(ENV_PREFIX + entry.getKey() + "=" + 
entry.getValue());
+        }
+
+        for (Map.Entry<String, String> entry :
+                propertiesToSortedMap(System.getProperties()).entrySet()) {
+            if (isHidden(entry.getKey())) {
+                continue;
+            }
+            optionsList.add(SYSTEM_PREFIX + entry.getKey() + "=" + 
entry.getValue());
+        }
+
+        // Insert Flink table config variable
+        for (Map.Entry<String, String> entry :
+                
mapToSortedMap(tableConfig.getConfiguration().toMap()).entrySet()) {
+            optionsList.add(FLINK_PREFIX + entry.getKey() + "=" + 
entry.getValue());
+        }
+
+        return optionsList;
+    }
+
+    private static SortedMap<String, String> mapToSortedMap(Map<String, 
String> data) {
+        return new TreeMap<>(data);
+    }
+
+    private static SortedMap<String, String> propertiesToSortedMap(Properties 
p) {
+        SortedMap<String, String> sortedPropMap = new TreeMap<>();
+        for (Map.Entry<Object, Object> entry : p.entrySet()) {
+            sortedPropMap.put((String) entry.getKey(), (String) 
entry.getValue());
+        }
+        return sortedPropMap;
+    }
+}
diff --git 
a/flink-connectors/flink-connector-hive/src/test/java/org/apache/flink/connectors/hive/HiveDialectITCase.java
 
b/flink-connectors/flink-connector-hive/src/test/java/org/apache/flink/connectors/hive/HiveDialectITCase.java
index 618f3d69044..baf8c2ab4a5 100644
--- 
a/flink-connectors/flink-connector-hive/src/test/java/org/apache/flink/connectors/hive/HiveDialectITCase.java
+++ 
b/flink-connectors/flink-connector-hive/src/test/java/org/apache/flink/connectors/hive/HiveDialectITCase.java
@@ -40,6 +40,7 @@ import org.apache.flink.table.delegation.Parser;
 import org.apache.flink.table.functions.hive.HiveGenericUDTFTest;
 import 
org.apache.flink.table.functions.hive.util.TestSplitUDTFInitializeWithStructObjectInspector;
 import org.apache.flink.table.operations.DescribeTableOperation;
+import org.apache.flink.table.operations.Operation;
 import org.apache.flink.table.operations.command.ClearOperation;
 import org.apache.flink.table.operations.command.HelpOperation;
 import org.apache.flink.table.operations.command.QuitOperation;
@@ -65,6 +66,7 @@ import org.apache.hadoop.hive.ql.io.RCFileOutputFormat;
 import org.apache.hadoop.hive.ql.io.orc.OrcInputFormat;
 import org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat;
 import org.apache.hadoop.hive.ql.io.orc.OrcSerde;
+import org.apache.hadoop.hive.ql.metadata.Hive;
 import org.apache.hadoop.hive.ql.parse.SemanticException;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDAFCount;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFAbs;
@@ -159,7 +161,6 @@ public class HiveDialectITCase {
         assertThat(parser).isInstanceOf(HiveParser.class);
         
assertThat(parser.parse("HELP").get(0)).isInstanceOf(HelpOperation.class);
         
assertThat(parser.parse("clear").get(0)).isInstanceOf(ClearOperation.class);
-        
assertThat(parser.parse("SET").get(0)).isInstanceOf(SetOperation.class);
         
assertThat(parser.parse("ResET").get(0)).isInstanceOf(ResetOperation.class);
         
assertThat(parser.parse("Exit").get(0)).isInstanceOf(QuitOperation.class);
     }
@@ -1018,6 +1019,73 @@ public class HiveDialectITCase {
                         badMacroName);
     }
 
+    @Test
+    public void testSetCommand() throws Exception {
+        // test set system:
+        tableEnv.executeSql("set system:xxx=5");
+        assertThat(System.getProperty("xxx")).isEqualTo("5");
+
+        // test set hiveconf:
+        tableEnv.executeSql("set hiveconf:yyy=${system:xxx}");
+        assertThat(hiveCatalog.getHiveConf().get("yyy")).isEqualTo("5");
+
+        // test set hivevar:
+        tableEnv.executeSql("set hivevar:a=1");
+        tableEnv.executeSql("set hiveconf:zzz=${hivevar:a}");
+        assertThat(hiveCatalog.getHiveConf().get("zzz")).isEqualTo("1");
+
+        // test the hivevar still exists when we renew the sql parser
+        tableEnv.getConfig().setSqlDialect(SqlDialect.DEFAULT);
+        tableEnv.executeSql("show tables");
+        tableEnv.getConfig().setSqlDialect(SqlDialect.HIVE);
+        tableEnv.executeSql("set hiveconf:zzz1=${hivevar:a}");
+        assertThat(hiveCatalog.getHiveConf().get("zzz1")).isEqualTo("1");
+
+        // test set metaconf:
+        tableEnv.executeSql("set 
metaconf:hive.metastore.try.direct.sql=false");
+        Hive hive = Hive.get(hiveCatalog.getHiveConf());
+        
assertThat(hive.getMetaConf("hive.metastore.try.direct.sql")).isEqualTo("false");
+
+        // test 'set xxx = xxx' should be pared as Flink SetOperation
+        TableEnvironmentInternal tableEnvInternal = (TableEnvironmentInternal) 
tableEnv;
+        Parser parser = tableEnvInternal.getParser();
+        Operation operation = parser.parse("set 
user.name=hive_test_user").get(0);
+        assertThat(operation).isInstanceOf(SetOperation.class);
+        assertThat(operation.asSummaryString()).isEqualTo("SET 
user.name=hive_test_user");
+
+        // test 'set xxx='
+        tableEnv.executeSql("set user.name=");
+        assertThat(hiveCatalog.getHiveConf().get("user.name")).isEmpty();
+
+        // test 'set xxx'
+        List<Row> rows =
+                CollectionUtil.iteratorToList(tableEnv.executeSql("set 
system:xxx").collect());
+        assertThat(rows.toString()).isEqualTo("[+I[system:xxx=5]]");
+
+        // test 'set'
+        rows = 
CollectionUtil.iteratorToList(tableEnv.executeSql("set").collect());
+        assertThat(rows.toString())
+                .contains("system:xxx=5")
+                .contains("env:PATH=" + System.getenv("PATH"))
+                .contains("flink:execution.runtime-mode=BATCH")
+                .contains("hivevar:a=1")
+                .contains("common-key=common-val");
+
+        // test 'set -v'
+        rows = CollectionUtil.iteratorToList(tableEnv.executeSql("set 
-v").collect());
+        assertThat(rows.toString())
+                .contains("system:xxx=5")
+                .contains("env:PATH=" + System.getenv("PATH"))
+                .contains("flink:execution.runtime-mode=BATCH")
+                .contains("hivevar:a=1")
+                .contains("fs.defaultFS=file:///");
+
+        // test set env isn't supported
+        assertThatThrownBy(() -> tableEnv.executeSql("set env:xxx=yyy"))
+                .isInstanceOf(UnsupportedOperationException.class)
+                .hasMessage("env:* variables can not be set.");
+    }
+
     @Test
     public void testUnsupportedOperation() {
         List<String> statements =

Reply via email to