You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by zh...@apache.org on 2025/12/16 13:14:13 UTC

(shardingsphere) branch master updated: Support for the INSTALL PLUGIN statement (#37402)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new ae9c2ca2d69 Support for the INSTALL PLUGIN statement (#37402)
ae9c2ca2d69 is described below

commit ae9c2ca2d69975e1abea8ece3120607427f0d7a5
Author: cxy <xi...@qq.com>
AuthorDate: Tue Dec 16 21:14:07 2025 +0800

    Support for the INSTALL PLUGIN statement (#37402)
---
 .../src/main/antlr4/imports/doris/DALStatement.g4  | 22 +++++++++-
 .../statement/type/DorisDALStatementVisitor.java   | 49 +++++++++++++++++++++-
 .../dal/plugin/MySQLInstallPluginStatement.java    | 16 +++++++
 .../type/MySQLInstallPluginStatementAssert.java    | 19 ++++++++-
 .../jaxb/segment/impl/plugin/ExpectedPlugin.java   | 19 +++++++++
 .../parser/src/main/resources/case/dal/install.xml | 49 ++++++++++++++++++++++
 .../main/resources/sql/supported/dal/install.xml   |  8 ++++
 7 files changed, 179 insertions(+), 3 deletions(-)

diff --git a/parser/sql/engine/dialect/doris/src/main/antlr4/imports/doris/DALStatement.g4 b/parser/sql/engine/dialect/doris/src/main/antlr4/imports/doris/DALStatement.g4
index 4aa436fbba3..38badae1a10 100644
--- a/parser/sql/engine/dialect/doris/src/main/antlr4/imports/doris/DALStatement.g4
+++ b/parser/sql/engine/dialect/doris/src/main/antlr4/imports/doris/DALStatement.g4
@@ -284,7 +284,27 @@ installComponent
     ;
 
 installPlugin
-    : INSTALL PLUGIN pluginName SONAME shardLibraryName
+    : INSTALL PLUGIN (pluginName SONAME shardLibraryName | FROM pluginSource (PROPERTIES LP_ pluginPropertiesList RP_)?)
+    ;
+
+pluginSource
+    : identifier | string_
+    ;
+
+pluginPropertiesList
+    : pluginProperty (COMMA_ pluginProperty)*
+    ;
+
+pluginProperty
+    : pluginPropertyKey EQ_ pluginPropertyValue
+    ;
+
+pluginPropertyKey
+    : identifier | string_
+    ;
+
+pluginPropertyValue
+    : literals | identifier
     ;
 
 uninstallComponent
diff --git a/parser/sql/engine/dialect/doris/src/main/java/org/apache/shardingsphere/sql/parser/engine/doris/visitor/statement/type/DorisDALStatementVisitor.java b/parser/sql/engine/dialect/doris/src/main/java/org/apache/shardingsphere/sql/parser/engine/doris/visitor/statement/type/DorisDALStatementVisitor.java
index 0e325acfe93..11cb7e4f1ed 100644
--- a/parser/sql/engine/dialect/doris/src/main/java/org/apache/shardingsphere/sql/parser/engine/doris/visitor/statement/type/DorisDALStatementVisitor.java
+++ b/parser/sql/engine/dialect/doris/src/main/java/org/apache/shardingsphere/sql/parser/engine/doris/visitor/statement/type/DorisDALStatementVisitor.java
@@ -125,6 +125,11 @@ import org.apache.shardingsphere.sql.parser.autogen.DorisStatementParser.Propert
 import org.apache.shardingsphere.sql.parser.autogen.DorisStatementParser.ResourceNameContext;
 import org.apache.shardingsphere.sql.parser.autogen.DorisStatementParser.PropertyKeyContext;
 import org.apache.shardingsphere.sql.parser.autogen.DorisStatementParser.PropertyValueContext;
+import org.apache.shardingsphere.sql.parser.autogen.DorisStatementParser.PluginSourceContext;
+import org.apache.shardingsphere.sql.parser.autogen.DorisStatementParser.PluginPropertiesListContext;
+import org.apache.shardingsphere.sql.parser.autogen.DorisStatementParser.PluginPropertyContext;
+import org.apache.shardingsphere.sql.parser.autogen.DorisStatementParser.PluginPropertyKeyContext;
+import org.apache.shardingsphere.sql.parser.autogen.DorisStatementParser.PluginPropertyValueContext;
 import org.apache.shardingsphere.sql.parser.engine.doris.visitor.statement.DorisStatementVisitor;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dal.CacheTableIndexSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dal.CloneActionSegment;
@@ -246,6 +251,8 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Optional;
 import java.util.Properties;
+import java.util.LinkedHashMap;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 /**
@@ -474,7 +481,47 @@ public final class DorisDALStatementVisitor extends DorisStatementVisitor implem
     
     @Override
     public ASTNode visitInstallPlugin(final InstallPluginContext ctx) {
-        return new MySQLInstallPluginStatement(getDatabaseType(), ((IdentifierValue) visit(ctx.pluginName())).getValue());
+        if (null != ctx.pluginName()) {
+            return new MySQLInstallPluginStatement(getDatabaseType(), ((IdentifierValue) visit(ctx.pluginName())).getValue());
+        }
+        String source = getPluginSource(ctx.pluginSource());
+        Map<String, String> properties = null == ctx.pluginPropertiesList() ? null : extractPluginProperties(ctx.pluginPropertiesList());
+        return new MySQLInstallPluginStatement(getDatabaseType(), source, properties);
+    }
+    
+    private String getPluginSource(final PluginSourceContext ctx) {
+        if (null != ctx.identifier()) {
+            return ((IdentifierValue) visit(ctx.identifier())).getValue();
+        }
+        return ((StringLiteralValue) visit(ctx.string_())).getValue();
+    }
+    
+    private Map<String, String> extractPluginProperties(final PluginPropertiesListContext ctx) {
+        Map<String, String> result = new LinkedHashMap<>();
+        for (PluginPropertyContext each : ctx.pluginProperty()) {
+            String key = getPluginPropertyKey(each.pluginPropertyKey());
+            String value = getPluginPropertyValue(each.pluginPropertyValue());
+            result.put(key, value);
+        }
+        return result;
+    }
+    
+    private String getPluginPropertyKey(final PluginPropertyKeyContext ctx) {
+        if (null != ctx.identifier()) {
+            return ((IdentifierValue) visit(ctx.identifier())).getValue();
+        }
+        return ((StringLiteralValue) visit(ctx.string_())).getValue();
+    }
+    
+    private String getPluginPropertyValue(final PluginPropertyValueContext ctx) {
+        if (null != ctx.identifier()) {
+            return ((IdentifierValue) visit(ctx.identifier())).getValue();
+        }
+        ASTNode result = visit(ctx.literals());
+        if (result instanceof LiteralValue) {
+            return getLiteralValueAsString((LiteralValue<?>) result);
+        }
+        return result.toString();
     }
     
     @Override
diff --git a/parser/sql/statement/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/statement/mysql/dal/plugin/MySQLInstallPluginStatement.java b/parser/sql/statement/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/statement/mysql/dal/plugin/MySQLInstallPluginStatement.java
index b6f5c60f886..637d23729ac 100644
--- a/parser/sql/statement/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/statement/mysql/dal/plugin/MySQLInstallPluginStatement.java
+++ b/parser/sql/statement/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/statement/mysql/dal/plugin/MySQLInstallPluginStatement.java
@@ -21,6 +21,9 @@ import lombok.Getter;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dal.DALStatement;
 
+import java.util.Collections;
+import java.util.Map;
+
 /**
  * Install plugin statement for MySQL.
  */
@@ -29,8 +32,21 @@ public final class MySQLInstallPluginStatement extends DALStatement {
     
     private final String pluginName;
     
+    private final String source;
+    
+    private final Map<String, String> properties;
+    
     public MySQLInstallPluginStatement(final DatabaseType databaseType, final String pluginName) {
         super(databaseType);
         this.pluginName = pluginName;
+        this.source = null;
+        this.properties = Collections.emptyMap();
+    }
+    
+    public MySQLInstallPluginStatement(final DatabaseType databaseType, final String source, final Map<String, String> properties) {
+        super(databaseType);
+        this.pluginName = null;
+        this.source = source;
+        this.properties = null == properties ? Collections.emptyMap() : properties;
     }
 }
diff --git a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/statement/dal/dialect/mysql/type/MySQLInstallPluginStatementAssert.java b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/statement/dal/dialect/mysql/type/MySQLInstallPluginStatementAssert.java
index c43f064de86..7fc58bc8cac 100644
--- a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/statement/dal/dialect/mysql/type/MySQLInstallPluginStatementAssert.java
+++ b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/statement/dal/dialect/mysql/type/MySQLInstallPluginStatementAssert.java
@@ -25,6 +25,7 @@ import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.s
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 /**
  * Install plugin statement assert for MySQL.
@@ -40,6 +41,22 @@ public final class MySQLInstallPluginStatementAssert {
      * @param expected expected install plugin statement test case
      */
     public static void assertIs(final SQLCaseAssertContext assertContext, final MySQLInstallPluginStatement actual, final MySQLInstallPluginStatementTestCase expected) {
-        assertThat(assertContext.getText("Actual plugin name does not match: "), actual.getPluginName(), is(expected.getPlugin().getName()));
+        if (null != expected.getPlugin()) {
+            if (null != expected.getPlugin().getName()) {
+                assertThat(assertContext.getText("Actual plugin name does not match: "), actual.getPluginName(), is(expected.getPlugin().getName()));
+            }
+            if (null != expected.getPlugin().getSource()) {
+                assertThat(assertContext.getText("Actual plugin source does not match: "), actual.getSource(), is(expected.getPlugin().getSource()));
+            }
+            if (!expected.getPlugin().getProperties().isEmpty()) {
+                assertNotNull(actual.getProperties(), assertContext.getText("Plugin properties should not be null"));
+                assertThat(assertContext.getText("Plugin properties size does not match: "), actual.getProperties().size(), is(expected.getPlugin().getProperties().size()));
+                expected.getPlugin().getProperties().forEach(property -> {
+                    String actualValue = actual.getProperties().get(property.getKey());
+                    assertNotNull(actualValue, assertContext.getText("Plugin property key '" + property.getKey() + "' should exist"));
+                    assertThat(assertContext.getText("Plugin property value for key '" + property.getKey() + "' does not match: "), actualValue, is(property.getValue()));
+                });
+            }
+        }
     }
 }
diff --git a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/plugin/ExpectedPlugin.java b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/plugin/ExpectedPlugin.java
index ec503b55b29..8e11a443618 100644
--- a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/plugin/ExpectedPlugin.java
+++ b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/plugin/ExpectedPlugin.java
@@ -17,10 +17,29 @@
 
 package org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.plugin;
 
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.AbstractExpectedIdentifierSQLSegment;
+import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.statement.dal.dialect.doris.PropertyTestCase;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import java.util.LinkedList;
+import java.util.List;
 
 /**
  * Expected plugin.
  */
+@XmlAccessorType(XmlAccessType.FIELD)
+@Getter
+@Setter
 public final class ExpectedPlugin extends AbstractExpectedIdentifierSQLSegment {
+    
+    @XmlAttribute
+    private String source;
+    
+    @XmlElement(name = "property")
+    private final List<PropertyTestCase> properties = new LinkedList<>();
 }
diff --git a/test/it/parser/src/main/resources/case/dal/install.xml b/test/it/parser/src/main/resources/case/dal/install.xml
index 7386a992843..11dfdb60bcd 100644
--- a/test/it/parser/src/main/resources/case/dal/install.xml
+++ b/test/it/parser/src/main/resources/case/dal/install.xml
@@ -29,4 +29,53 @@
     <install-plugin sql-case-id="install_plugin">
         <plugin name="binlog" start-index="15" stop-index="20" />
     </install-plugin>
+
+    <install-plugin sql-case-id="install_plugin_from">
+        <plugin source="/home/users/doris/auditdemo.zip" />
+    </install-plugin>
+    
+    <install-plugin sql-case-id="install_plugin_with_properties">
+        <plugin source="/home/users/doris/auditdemo.zip">
+            <property key="md5sum" value="d41d8cd98f00b204e9800998ecf8427e" />
+        </plugin>
+    </install-plugin>
+    
+    <install-plugin sql-case-id="install_plugin_with_identifier">
+        <plugin source="plugin_path">
+            <property key="timeout" value="30" />
+        </plugin>
+    </install-plugin>
+    
+    <install-plugin sql-case-id="install_plugin_with_number">
+        <plugin source="/path/to/plugin.zip">
+            <property key="timeout" value="30" />
+        </plugin>
+    </install-plugin>
+    
+    <install-plugin sql-case-id="install_plugin_with_boolean">
+        <plugin source="/path/to/plugin.zip">
+            <property key="auto_load" value="true" />
+        </plugin>
+    </install-plugin>
+    
+    <install-plugin sql-case-id="install_plugin_with_null">
+        <plugin source="/path/to/plugin.zip">
+            <property key="description" value="NULL" />
+        </plugin>
+    </install-plugin>
+    
+    <install-plugin sql-case-id="install_plugin_multiple_properties">
+        <plugin source="/path/to/plugin.zip">
+            <property key="md5sum" value="abc123" />
+            <property key="timeout" value="30" />
+        </plugin>
+    </install-plugin>
+    
+    <install-plugin sql-case-id="install_plugin_mixed_types">
+        <plugin source="/path/to/plugin.zip">
+            <property key="md5sum" value="abc123" />
+            <property key="timeout" value="30" />
+            <property key="auto_load" value="false" />
+        </plugin>
+    </install-plugin>
 </sql-parser-test-cases>
diff --git a/test/it/parser/src/main/resources/sql/supported/dal/install.xml b/test/it/parser/src/main/resources/sql/supported/dal/install.xml
index f290c1a56c6..b4fac15a00c 100644
--- a/test/it/parser/src/main/resources/sql/supported/dal/install.xml
+++ b/test/it/parser/src/main/resources/sql/supported/dal/install.xml
@@ -20,4 +20,12 @@
     <sql-case id="install_component" value="INSTALL COMPONENT 'file://component1'" db-types="MySQL" />
     <sql-case id="install_components" value="INSTALL COMPONENT 'file://component1', 'file://component2'" db-types="MySQL" />
     <sql-case id="install_plugin" value="INSTALL PLUGIN binlog SONAME 'shared_library_name'" db-types="MySQL" />
+    <sql-case id="install_plugin_from" value="INSTALL PLUGIN FROM &quot;/home/users/doris/auditdemo.zip&quot;" db-types="Doris" />
+    <sql-case id="install_plugin_with_properties" value="INSTALL PLUGIN FROM &quot;/home/users/doris/auditdemo.zip&quot; PROPERTIES (&quot;md5sum&quot; = &quot;d41d8cd98f00b204e9800998ecf8427e&quot;)" db-types="Doris" />
+    <sql-case id="install_plugin_with_identifier" value="INSTALL PLUGIN FROM plugin_path PROPERTIES (`timeout` = `30`)" db-types="Doris" />
+    <sql-case id="install_plugin_with_number" value="INSTALL PLUGIN FROM &quot;/path/to/plugin.zip&quot; PROPERTIES (&quot;timeout&quot; = 30)" db-types="Doris" />
+    <sql-case id="install_plugin_with_boolean" value="INSTALL PLUGIN FROM &quot;/path/to/plugin.zip&quot; PROPERTIES (&quot;auto_load&quot; = true)" db-types="Doris" />
+    <sql-case id="install_plugin_with_null" value="INSTALL PLUGIN FROM &quot;/path/to/plugin.zip&quot; PROPERTIES (&quot;description&quot; = NULL)" db-types="Doris" />
+    <sql-case id="install_plugin_multiple_properties" value="INSTALL PLUGIN FROM &quot;/path/to/plugin.zip&quot; PROPERTIES (&quot;md5sum&quot; = &quot;abc123&quot;, &quot;timeout&quot; = 30)" db-types="Doris" />
+    <sql-case id="install_plugin_mixed_types" value="INSTALL PLUGIN FROM &quot;/path/to/plugin.zip&quot; PROPERTIES (&quot;md5sum&quot; = &quot;abc123&quot;, &quot;timeout&quot; = 30, &quot;auto_load&quot; = false)" db-types="Doris" />
 </sql-cases>