qiuyanjun888 commented on code in PR #18398:
URL: 
https://github.com/apache/dolphinscheduler/pull/18398#discussion_r3577398968


##########
dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/test/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTaskTest.java:
##########
@@ -479,6 +484,233 @@ void 
testEnsureSqlContent_whenResourceMissing_throwsTaskException(@TempDir Path
         Assertions.assertInstanceOf(TaskException.class, thrown.getCause());
     }
 
+    @Test
+    void 
testSqlTaskLocalRenderer_rendersIdentifiersValuesListsAndEscapedStrings() 
throws Exception {
+        Map<String, Property> prepareParamsMap = new HashMap<>();
+        prepareParamsMap.put("dd", new Property("dd", Direct.IN, 
DataType.VARCHAR, "20250411"));
+        prepareParamsMap.put("name", new Property("name", Direct.IN, 
DataType.VARCHAR, "O'Reilly"));
+        prepareParamsMap.put("ids", new Property("ids", Direct.IN, 
DataType.LIST,
+                JSONUtils.toJsonString(Lists.newArrayList(1, "x'y"))));
+        prepareParamsMap.put("enabled", new Property("enabled", Direct.IN, 
DataType.BOOLEAN, "true"));
+
+        TaskExecutionContext ctx = new TaskExecutionContext();
+        
ctx.setTaskParams("{\"type\":\"HIVE\",\"datasource\":1,\"sql\":\"select 1\"}");
+        ctx.setScheduleTime(System.currentTimeMillis());
+        ctx.setTaskInstanceId(1);
+        
ctx.setResourceParametersHelper(getResourceParametersHelperWithDatasourceType(DbType.HIVE));
+        ctx.setPrepareParamsMap(prepareParamsMap);
+
+        SqlTask task = new SqlTask(ctx);
+
+        Method method = 
SqlTask.class.getDeclaredMethod("getSqlAndSqlParamsMap", String.class);
+        method.setAccessible(true);
+
+        String inputSql = "create table test_${dd} as select * from user where 
name=${name} "
+                + "and id in (${ids}) and enabled=${enabled}";
+        SqlBinds binds = (SqlBinds) method.invoke(task, inputSql);
+
+        Assertions.assertEquals(
+                "create table test_20250411 as select * from user where 
name='O''Reilly' "
+                        + "and id in (1,'x''y') and enabled=true",
+                binds.getSql());
+        Assertions.assertTrue(binds.getParamsMap().isEmpty());
+    }
+
+    @Test
+    void testSqlTaskLocalRenderer_replacesQuotedPlaceholdersWithSqlLiterals() 
throws Exception {
+        Map<String, Property> prepareParamsMap = new HashMap<>();
+        prepareParamsMap.put("dt", new Property("dt", Direct.IN, 
DataType.DATE, "2026-07-06"));
+        prepareParamsMap.put("name", new Property("name", Direct.IN, 
DataType.VARCHAR, "O'Reilly"));
+
+        TaskExecutionContext ctx = new TaskExecutionContext();
+        
ctx.setTaskParams("{\"type\":\"HIVE\",\"datasource\":1,\"sql\":\"select 1\"}");
+        ctx.setScheduleTime(System.currentTimeMillis());
+        ctx.setTaskInstanceId(1);
+        
ctx.setResourceParametersHelper(getResourceParametersHelperWithDatasourceType(DbType.HIVE));
+        ctx.setPrepareParamsMap(prepareParamsMap);
+
+        SqlTask task = new SqlTask(ctx);
+
+        Method method = 
SqlTask.class.getDeclaredMethod("getSqlAndSqlParamsMap", String.class);
+        method.setAccessible(true);
+
+        SqlBinds binds = (SqlBinds) method.invoke(task,
+                "select * from student where dt='${dt}' and name=\"${name}\"");
+
+        Assertions.assertEquals("select * from student where dt='2026-07-06' 
and name='O''Reilly'",
+                binds.getSql());
+    }
+
+    @Test
+    void 
testSqlTaskLocalRenderer_replacesRawPlaceholderWithDollarAndBackslashCharacters()
 throws Exception {
+        Map<String, Property> prepareParamsMap = new HashMap<>();
+        prepareParamsMap.put("partition", new Property("partition", Direct.IN, 
DataType.VARCHAR,
+                "dt='$[yyyyMMdd]' and path='s3://bucket/a\\b'"));
+
+        TaskExecutionContext ctx = new TaskExecutionContext();
+        
ctx.setTaskParams("{\"type\":\"HIVE\",\"datasource\":1,\"sql\":\"select 1\"}");
+        ctx.setScheduleTime(System.currentTimeMillis());
+        ctx.setTaskInstanceId(1);
+        
ctx.setResourceParametersHelper(getResourceParametersHelperWithDatasourceType(DbType.HIVE));
+        ctx.setPrepareParamsMap(prepareParamsMap);
+
+        SqlTask task = new SqlTask(ctx);
+
+        Method method = 
SqlTask.class.getDeclaredMethod("getSqlAndSqlParamsMap", String.class);
+        method.setAccessible(true);
+
+        SqlBinds binds = (SqlBinds) method.invoke(task,
+                "alter table t add if not exists partition (!{partition})");
+
+        Assertions.assertEquals(
+                "alter table t add if not exists partition (dt='$[yyyyMMdd]' 
and path='s3://bucket/a\\b')",
+                binds.getSql());
+    }
+
+    @Test
+    void testExecuteQueryUsesStatementWithRenderedSql() throws Exception {
+        Connection connection = mock(Connection.class);
+        Statement statement = mock(Statement.class);
+        ResultSet resultSet = mock(ResultSet.class);
+        ResultSetMetaData metaData = mock(ResultSetMetaData.class);
+
+        when(connection.createStatement()).thenReturn(statement);
+        when(statement.executeQuery("select 1 as id")).thenReturn(resultSet);
+        when(resultSet.getMetaData()).thenReturn(metaData);
+        when(metaData.getColumnCount()).thenReturn(1);
+        when(metaData.getColumnLabel(1)).thenReturn("id");
+        when(resultSet.next()).thenReturn(false);
+
+        Method method = SqlTask.class.getDeclaredMethod("executeQuery", 
Connection.class, SqlBinds.class, String.class);
+        method.setAccessible(true);
+
+        String result = (String) method.invoke(sqlTask, connection,
+                new SqlBinds("select 1 as id", new HashMap<>()), "main");
+
+        Assertions.assertEquals("[{\"id\":\"\"}]", result);
+        verify(connection).createStatement();
+        verify(connection, never()).prepareStatement(anyString());
+        verify(statement).executeQuery("select 1 as id");
+    }
+
+    @Test
+    void 
testSqlTaskLocalRenderer_doesNotTreatPlaceholderInsideStringLiteralAsIdentifier()
 throws Exception {
+        Map<String, Property> prepareParamsMap = new HashMap<>();
+        prepareParamsMap.put("name", new Property("name", Direct.IN, 
DataType.VARCHAR, "O'Reilly"));
+
+        TaskExecutionContext ctx = new TaskExecutionContext();
+        
ctx.setTaskParams("{\"type\":\"HIVE\",\"datasource\":1,\"sql\":\"select 1\"}");
+        ctx.setScheduleTime(System.currentTimeMillis());
+        ctx.setTaskInstanceId(1);
+        
ctx.setResourceParametersHelper(getResourceParametersHelperWithDatasourceType(DbType.HIVE));
+        ctx.setPrepareParamsMap(prepareParamsMap);
+
+        SqlTask task = new SqlTask(ctx);
+
+        Method method = 
SqlTask.class.getDeclaredMethod("getSqlAndSqlParamsMap", String.class);
+        method.setAccessible(true);
+
+        SqlBinds binds = (SqlBinds) method.invoke(task,
+                "select * from student where name='prefix_${name}'");
+
+        Assertions.assertEquals("select * from student where 
name='prefix_O''Reilly'", binds.getSql());
+    }
+
+    @Test
+    void 
testSqlTaskLocalRenderer_doesNotRescanRawReplacementForSqlParameters() throws 
Exception {
+        Map<String, Property> prepareParamsMap = new HashMap<>();
+        prepareParamsMap.put("fragment", new Property("fragment", Direct.IN, 
DataType.VARCHAR,
+                "dt='${hiveconf:dt}'"));
+
+        TaskExecutionContext ctx = new TaskExecutionContext();
+        
ctx.setTaskParams("{\"type\":\"HIVE\",\"datasource\":1,\"sql\":\"select 1\"}");
+        ctx.setScheduleTime(System.currentTimeMillis());
+        ctx.setTaskInstanceId(1);
+        
ctx.setResourceParametersHelper(getResourceParametersHelperWithDatasourceType(DbType.HIVE));
+        ctx.setPrepareParamsMap(prepareParamsMap);
+
+        SqlTask task = new SqlTask(ctx);
+
+        Method method = 
SqlTask.class.getDeclaredMethod("getSqlAndSqlParamsMap", String.class);
+        method.setAccessible(true);
+
+        SqlBinds binds = (SqlBinds) method.invoke(task,
+                "alter table t add if not exists partition (!{fragment})");
+
+        Assertions.assertEquals(
+                "alter table t add if not exists partition 
(dt='${hiveconf:dt}')",
+                binds.getSql());
+    }
+
+    @Test
+    void 
testSqlTaskLocalRenderer_doesNotRescanSqlParameterValueForRawPlaceholder() 
throws Exception {
+        Map<String, Property> prepareParamsMap = new HashMap<>();
+        prepareParamsMap.put("name", new Property("name", Direct.IN, 
DataType.VARCHAR, "!{fragment}"));
+        prepareParamsMap.put("fragment", new Property("fragment", Direct.IN, 
DataType.VARCHAR, "unsafe_sql"));
+
+        TaskExecutionContext ctx = new TaskExecutionContext();
+        
ctx.setTaskParams("{\"type\":\"HIVE\",\"datasource\":1,\"sql\":\"select 1\"}");
+        ctx.setScheduleTime(System.currentTimeMillis());
+        ctx.setTaskInstanceId(1);
+        
ctx.setResourceParametersHelper(getResourceParametersHelperWithDatasourceType(DbType.HIVE));
+        ctx.setPrepareParamsMap(prepareParamsMap);
+
+        SqlTask task = new SqlTask(ctx);
+
+        Method method = 
SqlTask.class.getDeclaredMethod("getSqlAndSqlParamsMap", String.class);
+        method.setAccessible(true);
+
+        SqlBinds binds = (SqlBinds) method.invoke(task,
+                "select * from student where name=${name}");
+
+        Assertions.assertEquals("select * from student where 
name='!{fragment}'", binds.getSql());
+    }
+
+    @Test
+    void testSqlTaskLocalRenderer_keepsPlaceholderInsideJsonStringLiteral() 
throws Exception {

Review Comment:
   Fixed in 87add3589c0a9cae9ba43cf794aabeb9b94d2b70: renamed the test to 
`testSqlTaskLocalRenderer_replacesPlaceholderInsideJsonStringLiteral`, matching 
the assertion that `${name}` is rendered inside the JSON string literal.
   
   Validation:
   - Targeted test: 1 run, 0 failures/errors/skips
   - `./mvnw -pl dolphinscheduler-task-plugin/dolphinscheduler-task-sql 
spotless:check`: passed
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to