mirror of
https://github.com/Snowflake-Labs/dlsync.git
synced 2025-12-18 09:01:27 +00:00
updated log message and changelog
This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
# DLSync Changelog
|
# DLSync Changelog
|
||||||
|
|
||||||
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
## [2.6.0] - 2025-11-24
|
||||||
|
### Added
|
||||||
|
- Added support Masking Policy object type
|
||||||
|
- Fixed log message unsupported object types in create script
|
||||||
## [2.5.0] - 2025-11-06
|
## [2.5.0] - 2025-11-06
|
||||||
### Added
|
### Added
|
||||||
- Added support for Dynamic Table object type
|
- Added support for Dynamic Table object type
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public class SqlTokenizer {
|
|||||||
private static final String IDENTIFIER_REGEX = "((?:\\\"[^\"]+\\\"\\.)|(?:[{}$a-zA-Z0-9_]+\\.))?((?:\\\"[^\"]+\\\"\\.)|(?:[{}$a-zA-Z0-9_]+\\.))?(?i)";
|
private static final String IDENTIFIER_REGEX = "((?:\\\"[^\"]+\\\"\\.)|(?:[{}$a-zA-Z0-9_]+\\.))?((?:\\\"[^\"]+\\\"\\.)|(?:[{}$a-zA-Z0-9_]+\\.))?(?i)";
|
||||||
private static final String MIGRATION_REGEX = VERSION_REGEX + AUTHOR_REGEX + CONTENT_REGEX + ROLL_BACK_REGEX + VERIFY_REGEX;
|
private static final String MIGRATION_REGEX = VERSION_REGEX + AUTHOR_REGEX + CONTENT_REGEX + ROLL_BACK_REGEX + VERIFY_REGEX;
|
||||||
|
|
||||||
private static final String DDL_REGEX = ";\\n+(CREATE\\s+OR\\s+REPLACE\\s+(TRANSIENT\\s|HYBRID\\s|SECURE\\s)?(?<type>DYNAMIC TABLE|FILE FORMAT|VIEW|FUNCTION|PROCEDURE|TABLE|STREAM|SEQUENCE|STAGE|TASK|STREAMLIT|PIPE|ALERT|\\w+)\\s+(?<name>[\\\"\\w.]+)([\\s\\S]+?)(?=(;\\nCREATE\\s+)|(;$)))";
|
private static final String DDL_REGEX = ";\\n+(CREATE\\s+OR\\s+REPLACE\\s+(TRANSIENT\\s|HYBRID\\s|SECURE\\s)?(?<type>DYNAMIC TABLE|FILE FORMAT|MASKING POLICY|VIEW|FUNCTION|PROCEDURE|TABLE|STREAM|SEQUENCE|STAGE|TASK|STREAMLIT|PIPE|ALERT|\\w+)\\s+(?<name>[\\\"\\w.]+)([\\s\\S]+?)(?=(;\\nCREATE\\s+)|(;$)))";
|
||||||
|
|
||||||
private static final String STRING_LITERAL_REGEX = "(?<!as\\s{1,5})'([^'\\\\]*(?:\\\\.[^'\\\\]*)*(?:''[^'\\\\]*)*)'";
|
private static final String STRING_LITERAL_REGEX = "(?<!as\\s{1,5})'([^'\\\\]*(?:\\\\.[^'\\\\]*)*(?:''[^'\\\\]*)*)'";
|
||||||
|
|
||||||
@@ -254,9 +254,12 @@ public class SqlTokenizer {
|
|||||||
log.error("Unable to parse object type from DDL: {}", content);
|
log.error("Unable to parse object type from DDL: {}", content);
|
||||||
throw new RuntimeException("Unable to parse object type from DDL.");
|
throw new RuntimeException("Unable to parse object type from DDL.");
|
||||||
}
|
}
|
||||||
ScriptObjectType objectType = Arrays.stream(ScriptObjectType.values())
|
Optional<ScriptObjectType> optionalObjectType = Arrays.stream(ScriptObjectType.values()).filter( ot -> ot.getSingular().equalsIgnoreCase(type)).findFirst();
|
||||||
.filter(ot -> ot.getSingular().equalsIgnoreCase(type))
|
if(!optionalObjectType.isPresent()) {
|
||||||
.collect(Collectors.toList()).get(0);
|
log.error("Unsupported object type: {} found in DDL!", type);
|
||||||
|
throw new RuntimeException("Unknown object type found in DDL: " + type);
|
||||||
|
}
|
||||||
|
ScriptObjectType objectType = optionalObjectType.get();
|
||||||
|
|
||||||
String fullObjectName = matcher.group("name");
|
String fullObjectName = matcher.group("name");
|
||||||
String scriptObjectName = fullObjectName.split("\\.")[2];
|
String scriptObjectName = fullObjectName.split("\\.")[2];
|
||||||
|
|||||||
@@ -202,6 +202,8 @@ class SqlTokenizerTest {
|
|||||||
"create or replace transient table db1.schema1.table2 (col1 varchar, col2 number);\n" +
|
"create or replace transient table db1.schema1.table2 (col1 varchar, col2 number);\n" +
|
||||||
"create or replace hybrid table db1.schema1.table3 (col1 varchar, col2 number);\n" +
|
"create or replace hybrid table db1.schema1.table3 (col1 varchar, col2 number);\n" +
|
||||||
"create or replace table db1.schema1.\"table4\" (col1 varchar, col2 number);\n" +
|
"create or replace table db1.schema1.\"table4\" (col1 varchar, col2 number);\n" +
|
||||||
|
"create or replace dynamic table db1.schema1.dynamic_table1 (col1 varchar, col2 number)\n as SELECT id, name, COUNT(*) as count FROM db1.schema1.source_table GROUP BY id, name;\n" +
|
||||||
|
"create or replace masking policy db1.schema1.masking_policy1 as (val string) returns string -> case when current_role() in ('ANALYST_ROLE', 'PUBLIC') then val else '****' end;\n" +
|
||||||
"create or replace function db1.schema1.function1(arg1 varchar)\n" +
|
"create or replace function db1.schema1.function1(arg1 varchar)\n" +
|
||||||
"RETURNS VARCHAR(16777216)\n" +
|
"RETURNS VARCHAR(16777216)\n" +
|
||||||
"LANGUAGE JAVASCRIPT\n" +
|
"LANGUAGE JAVASCRIPT\n" +
|
||||||
@@ -215,6 +217,8 @@ class SqlTokenizerTest {
|
|||||||
ScriptFactory.getMigrationScript("db1", "schema1", ScriptObjectType.TABLES, "table2","create or replace transient table db1.schema1.table2 (col1 varchar, col2 number);"),
|
ScriptFactory.getMigrationScript("db1", "schema1", ScriptObjectType.TABLES, "table2","create or replace transient table db1.schema1.table2 (col1 varchar, col2 number);"),
|
||||||
ScriptFactory.getMigrationScript("db1", "schema1", ScriptObjectType.TABLES, "table3","create or replace hybrid table db1.schema1.table3 (col1 varchar, col2 number);"),
|
ScriptFactory.getMigrationScript("db1", "schema1", ScriptObjectType.TABLES, "table3","create or replace hybrid table db1.schema1.table3 (col1 varchar, col2 number);"),
|
||||||
ScriptFactory.getMigrationScript("db1", "schema1", ScriptObjectType.TABLES, "\"table4\"","create or replace table db1.schema1.\"table4\" (col1 varchar, col2 number);"),
|
ScriptFactory.getMigrationScript("db1", "schema1", ScriptObjectType.TABLES, "\"table4\"","create or replace table db1.schema1.\"table4\" (col1 varchar, col2 number);"),
|
||||||
|
ScriptFactory.getMigrationScript("db1", "schema1", ScriptObjectType.DYNAMIC_TABLES, "dynamic_table1","create or replace dynamic table db1.schema1.dynamic_table1 (col1 varchar, col2 number)\n as SELECT id, name, COUNT(*) as count FROM db1.schema1.source_table GROUP BY id, name;"),
|
||||||
|
ScriptFactory.getStateScript("db1", "schema1", ScriptObjectType.MASKING_POLICIES, "masking_policy1","create or replace masking policy db1.schema1.masking_policy1 as (val string) returns string -> case when current_role() in ('ANALYST_ROLE', 'PUBLIC') then val else '****' end;"),
|
||||||
ScriptFactory.getStateScript("db1", "schema1", ScriptObjectType.FUNCTIONS, "function1","create or replace function db1.schema1.function1(arg1 varchar)\n" +
|
ScriptFactory.getStateScript("db1", "schema1", ScriptObjectType.FUNCTIONS, "function1","create or replace function db1.schema1.function1(arg1 varchar)\n" +
|
||||||
"RETURNS VARCHAR(16777216)\n" +
|
"RETURNS VARCHAR(16777216)\n" +
|
||||||
"LANGUAGE JAVASCRIPT\n" +
|
"LANGUAGE JAVASCRIPT\n" +
|
||||||
@@ -621,4 +625,16 @@ class SqlTokenizerTest {
|
|||||||
"Exception message should indicate unknown script type");
|
"Exception message should indicate unknown script type");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void parseDdlScriptUnsupportedObjectType() {
|
||||||
|
String ddl = "create or replace schema schema1;\n\nCREATE OR REPLACE UNKNOWN db1.schema1.OBJECT1;";
|
||||||
|
|
||||||
|
RuntimeException exception = assertThrows(RuntimeException.class, () -> {
|
||||||
|
SqlTokenizer.parseDdlScripts(ddl, "db1", "schema1");
|
||||||
|
}, "Should throw RuntimeException for unsupported object type");
|
||||||
|
|
||||||
|
assertEquals("Unknown object type found in DDL: UNKNOWN", exception.getMessage(),
|
||||||
|
"Exception message should indicate unsupported DDL statement");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user