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 <[email protected]>
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>

Reply via email to