Skip to content

Commit 72a8c3e

Browse files
authored
v.2024-07 (#123)
* v.2024-07 * v.2404-07
1 parent 4f38853 commit 72a8c3e

File tree

9 files changed

+355
-139
lines changed

9 files changed

+355
-139
lines changed

BabelfishCompassUser.Optimistic.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@
113113
[Geospatial features]
114114

115115

116+
[STGEOMFROMTEXT]
117+
118+
116119
[CURSOR variables]
117120

118121

BabelfishCompass_UserGuide.docx

1.03 KB
Binary file not shown.

BabelfishCompass_UserGuide.pdf

777 Bytes
Binary file not shown.

BabelfishFeatures.cfg

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515
# this must always be the first section:
1616
[Babelfish for T-SQL]
1717
# only Babelfish version numbers listed here can be referenced the rules below:
18-
valid_versions=1.0.0, 1.1.0, 1.2.0, 1.3.0, 1.4.0, 1.5.0, 1.6.0, 2.1.0, 2.2.0, 2.3.0, 2.4.0, 2.5.0, 3.1.0, 3.2.0, 3.3.0, 3.4.0, 3.5.0, 4.0.0, 4.1.0
18+
valid_versions=1.0.0, 1.1.0, 1.2.0, 1.3.0, 1.4.0, 1.5.0, 1.6.0, 2.1.0, 2.2.0, 2.3.0, 2.4.0, 2.5.0, 3.1.0, 3.2.0, 3.3.0, 3.4.0, 3.5.0, 4.0.0, 4.1.0, 4.2.0
1919
# x.y.1/2/3 etc are bugfix releases for x.y.0 (no new T-SQL features supported), and are typically based on a newer PG release
2020
file_format=2 # version number for format of this .cfg file. This is not expected to change much
21-
file_timestamp=Apr-2024 # identifies the version of this file, together with the latest Babelfish version supported
21+
file_timestamp=Jul-2024 # identifies the version of this file, together with the latest Babelfish version supported
2222
# format: dd-MON-yyyy or MON-yyyy
2323

2424
# Basic principle:
@@ -218,11 +218,19 @@ complexity_score=HIGH
218218

219219
[Geospatial features]
220220
rule=function_call
221-
supported-3.5.0-3.*=STX,STY,LAT,LONG,STASTEXT,STASBINARY,STDISTANCE,STPOINTFROMTEXT
222-
supported-4.1.0=STX,STY,LAT,LONG,STASTEXT,STASBINARY,STDISTANCE,STPOINTFROMTEXT
221+
supported-3.5.0-3.*=STX,STY,LAT,LONG,STASTEXT,STASBINARY,STDISTANCE,STPOINTFROMTEXT,STGEOMFROMTEXT,POINT
222+
supported-4.1.0=STX,STY,LAT,LONG,STASTEXT,STASBINARY,STDISTANCE,STPOINTFROMTEXT,STGEOMFROMTEXT,POINT
223223
report_group=Geospatial
224224
complexity_score=HIGH
225225

226+
[STGEOMFROMTEXT]
227+
rule=function_call
228+
supported-3.5.0-3.*=POINT
229+
supported-4.1.0=POINT
230+
report_group=Geospatial
231+
complexity_score=HIGH
232+
default_classification-ReviewSemantics=expression
233+
226234
[CURSOR variables]
227235
rule=set_statement
228236
supported-1.0.0=*
@@ -600,6 +608,7 @@ complexity_score=HIGH
600608

601609
[ALTER PROCEDURE]
602610
rule=create_or_alter_procedure
611+
supported-4.2.0=*
603612
report_group=Procedures
604613
complexity_score=HIGH
605614

@@ -770,11 +779,13 @@ report_group=Databases
770779

771780
[ALTER DATABASE]
772781
rule=alter_database,alter_database_scoped_configurations
782+
supported-4.2.0=*
773783
report_group=Databases
774784

775785
[ALTER DATABASE options]
776786
rule=alter_database,alter_database_scoped_configuration
777787
list=SCOPED CONFIGURATION,CURRENT,MODIFY NAME,COLLATE,CATALOG_COLLATION,ALLOW_SNAPSHOT_ISOLATION,ANSI_NULLS,ANSI_NULL_DEFAULT,ANSI_PADDING,ANSI_WARNINGS,ARITHABORT,AUTO_CLOSE,AUTO_SHRINK,AUTO_UPDATE_STATISTICS,AUTO_UPDATE_STATISTICS_ASYNC,DB_CHAINING,COMPATIBILITY_LEVEL,CONCAT_NULL_YIELDS_NULL,CURSOR_CLOSE_ON_COMMIT,CURSOR_DEFAULT,DATE_CORRELATION_OPTIMIZATION,DELAYED_DURABILITY,DISABLE_BROKER,FILESTREAM,HONOR_BROKER_PRIORITY,MULTI_USER,NUMERIC_ROUNDABORT,PAGE_VERIFY,PARAMETERIZATION,QUERY_STORE,QUOTED_IDENTIFIER,READ_COMMITTED_SNAPSHOT,RECOVERY,RECURSIVE_TRIGGERS,TARGET_RECOVERY_TIME,TRUSTWORTHY,ACCELERATED_DATABASE_RECOVERY
788+
supported-4.2.0=MODIFY NAME
778789
report_group=Databases
779790

780791
[Delimited database name]
@@ -1041,6 +1052,7 @@ list=CHECK_CONSTRAINTS,COLUMNS,COLUMN_DOMAIN_USAGE,COLUMN_PRIVILEGES,CONSTRAINT_
10411052
supported-1.2.0=TABLES,COLUMNS,DOMAINS,TABLE_CONSTRAINTS
10421053
supported-2.2.0=COLUMN_DOMAIN_USAGE,CONSTRAINT_COLUMN_USAGE,CHECK_CONSTRAINTS,ROUTINES,VIEWS
10431054
supported-2.4.0=SCHEMATA,SEQUENCES
1055+
supported-3.4.0=KEY_COLUMN_USAGE
10441056
report_group=Catalogs
10451057
10461058
[System Stored Procedures]
@@ -1061,6 +1073,7 @@ supported-3.3.0=sp_testlinkedserver,sp_enum_oledb_providers,sp_addextendedproper
10611073
supported-3.4.0=sp_who,sp_changedbowner
10621074
supported-3.5.0-3.*=sp_procedure_params_100_managed
10631075
supported-4.1.0=sp_procedure_params_100_managed
1076+
supported-4.2.0=sp_renamedb
10641077
default_classification-ReviewManually=sp_db_vardecimal_storage_format,sp_fulltext_database
10651078
report_group-XML=sp_xml_preparedocument,sp_xml_removedocument,sp_xml_schema_rowset,sp_xml_schema_rowset2
10661079
report_group-Distributed Transactions(XA)=sp_sqljdbc_xa_install,sp_sqljdbc_xa_uninstall,sp_sqljdbc_xa_internal_remove,sp_xa_commit,sp_xa_end,sp_xa_forget,sp_xa_forget_ex,sp_xa_init,sp_xa_init_ex,sp_xa_prepare,sp_xa_prepare_ex,sp_xa_recover,sp_xa_rollback,sp_xa_rollback_ex,sp_xa_start,xp_sqljdbc_xa_commit,xp_sqljdbc_xa_end,xp_sqljdbc_xa_forget,xp_sqljdbc_xa_forget_ex,xp_sqljdbc_xa_init,xp_sqljdbc_xa_init_ex,xp_sqljdbc_xa_prepare,xp_sqljdbc_xa_prepare_ex,xp_sqljdbc_xa_recover,xp_sqljdbc_xa_rollback,xp_sqljdbc_xa_rollback_ex,xp_sqljdbc_xa_start
@@ -1091,12 +1104,14 @@ complexity_score=HIGH
10911104
rule=grant_statement
10921105
supported-1.2.0=ALL PRIVILEGES ON OBJECT,SELECT ON OBJECT,INSERT ON OBJECT,UPDATE ON OBJECT,DELETE ON OBJECT,REFERENCES ON OBJECT,EXECUTE ON OBJECT
10931106
supported-2.3.0=CONNECT
1107+
supported-4.2.0=SELECT ON SCHEMA,INSERT ON SCHEMA,UPDATE ON SCHEMA,DELETE ON SCHEMA,REFERENCES ON SCHEMA,EXECUTE ON SCHEMA
10941108
report_group=Permissions
10951109
10961110
[REVOKE]
10971111
rule=revoke_statement
10981112
supported-1.2.0=ALL PRIVILEGES ON OBJECT,SELECT ON OBJECT,INSERT ON OBJECT,UPDATE ON OBJECT,DELETE ON OBJECT,REFERENCES ON OBJECT,EXECUTE ON OBJECT,CASCADE
10991113
supported-2.3.0=CONNECT
1114+
supported-4.2.0=SELECT ON SCHEMA,INSERT ON SCHEMA,UPDATE ON SCHEMA,DELETE ON SCHEMA,REFERENCES ON SCHEMA,EXECUTE ON SCHEMA
11001115
report_group=Permissions
11011116
11021117
[DENY]
@@ -1135,6 +1150,7 @@ complexity_score=HIGH
11351150
rule=pivot_clause
11361151
list=PIVOT,VIEW,CTE,JOIN
11371152
supported-3.4.0=PIVOT
1153+
supported-4.2.0=CTE,JOIN
11381154
report_group=DML
11391155
11401156
[SELECT..UNPIVOT]
@@ -1627,5 +1643,5 @@ list=FORMSOF,ISABOUT,NEAR,INFLECTIONAL,THESAURUS
16271643
complexity_score=HIGH
16281644
16291645
#-----------------------------------------------------------------------------------
1630-
#file checksum=d21da65a
1646+
#file checksum=1dc5386f
16311647
#--- end ---------------------------------------------------------------------------

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11

2+
# 2024-07
3+
- Added support for Babelfish v.4.2.0.
4+
- Added -anon flag to allow sharing Compass reports with customer-specific information removed.
5+
- Include additional geosptial aspects that were already supported in 4.1.0.
6+
- Include INFORMATION_SCHEMA.KEY_COLUMN_USAGE that was already supported in 3.4.0.
7+
- Various small fixes.
8+
29
# 2024-04
310
- Added support for Babelfish v.4.1.0 and v.3.5.0.
411
- Detect and rewrite often-seen FOR XML PATH workaround for STRING_AGG().

src/main/java/compass/Compass.java

Lines changed: 71 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ public class Compass {
109109
protected static boolean pgImport = false;
110110
protected static boolean pgImportAppend = false;
111111
protected static boolean pgImportTable = false;
112-
protected static boolean anonymizedReport = false;
113112
protected static boolean importFormatArg = false;
114113
protected static String mergeReport = "";
115114
protected static String userCfgFile = "";
@@ -133,6 +132,7 @@ public class Compass {
133132
public static String sessionLog;
134133

135134
public static List<String> inputFiles = new ArrayList<>();
135+
public static Map<String, Integer> inputFilesLastLine = new HashMap<>();
136136
public static List<String> inputFilesOrig = new ArrayList<>();
137137
public static Map<String,String> inputFilesMapped = new HashMap<>();
138138
public static List<String> cmdFlags = new ArrayList<>();
@@ -278,6 +278,7 @@ public Compass(String[] args) {
278278
u.appOutput(" -recursive : recursively add files if inputfile is a directory");
279279
u.appOutput(" -include <list> : pattern of input file types to include (e.g.: .txt,.ddl)");
280280
u.appOutput(" -exclude <list> : pattern of input file types to exclude (e.g.: .pptx)");
281+
u.appOutput(" -anon : remove all customer-specific identifiers");
281282
u.appOutput(" -rewrite : rewrites selected unsupported SQL features");
282283
u.appOutput(" -noupdatechk : do not check for " + CompassUtilities.thisProgName + " updates");
283284
u.appOutput(" -importformat <fmt> : process special-format captured query files");
@@ -721,7 +722,10 @@ else if (option.equals("hints")) {
721722
i++;
722723
continue;
723724
}
724-
725+
if (arg.equals("-anon")) {
726+
u.anonymizedData = true;
727+
continue;
728+
}
725729
if (arg.equals("-sqlendpoint")) {
726730
if (i >= args.length) {
727731
System.out.println("Must specify value with -sqlendpoint");
@@ -889,11 +893,7 @@ else if (option.equals("hints")) {
889893
if (arg.equals("-symtab_all")) { // development only: load symtab for all applications -- but we shouldn't need this
890894
u.symTabAll = true;
891895
continue;
892-
}
893-
if (arg.equals("-anon")) { // development only
894-
anonymizedReport = true;
895-
continue;
896-
}
896+
}
897897
}
898898
// arguments must start with [A-Za-z0-9 _-./] : anything else is invalid
899899
if (CompassUtilities.getPatternGroup(arg.substring(0,1), "^([\\w\\-\\.\\/])$", 1).isEmpty()) {
@@ -1038,13 +1038,7 @@ public static void main(String[] args) throws Exception {
10381038
// generate DDL through SMO
10391039
if (autoDDL) {
10401040
getAutoDDL();
1041-
}
1042-
1043-
// generate anon report file
1044-
if (anonymizedReport) {
1045-
runAnonymizedReport();
1046-
return;
1047-
}
1041+
}
10481042

10491043
// only for debugging the config class:
10501044
// if (u.debugCfg) {
@@ -1209,7 +1203,7 @@ public static void main(String[] args) throws Exception {
12091203

12101204
// read custom item ID file, if applicable
12111205
u.openCustomItemIDFile();
1212-
1206+
12131207
if (reportOnly) {
12141208
// only generate reported from already-captured items
12151209
startTime = System.currentTimeMillis();
@@ -1275,7 +1269,7 @@ public static void main(String[] args) throws Exception {
12751269
endRun = System.currentTimeMillis();
12761270
endRunFmt = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss").format(new Date());
12771271
elapsedRun = (endRun - startRun)/ 1000;
1278-
1272+
12791273
comp.reportFinalStats();
12801274
if (generateReport) {
12811275
if (!(parseOnly || importOnly)) {
@@ -1590,13 +1584,17 @@ private static boolean optionsValid() throws Exception {
15901584
}
15911585
}
15921586

1593-
if (anonymizedReport) {
1594-
if (readStdin || listContents || importOnly || reAnalyze || deleteReport || reportOnly) {
1587+
if (u.anonymizedData) {
1588+
if (readStdin || listContents) {
15951589
u.appOutput("-anon cannot be combined with other options");
15961590
return false;
15971591
}
1598-
if ((inputFiles.size() > 0) || autoDDL) {
1599-
u.appOutput("-anon cannot be combined with input files");
1592+
if (reportOption) {
1593+
u.appOutput("-anon cannot be combined with -reportoption");
1594+
return false;
1595+
}
1596+
if ((inputFiles.size() == 0) && !pgImport && !reportOnly && !reAnalyze) {
1597+
u.appOutput("-anon can only be specified when analyzing input files");
16001598
return false;
16011599
}
16021600
return true;
@@ -1947,25 +1945,20 @@ private static boolean optionsValid() throws Exception {
19471945
}
19481946

19491947
private static void runPGImport () throws Exception {
1950-
// import the captured.dat file into a PG table
1951-
1952-
// try {
1953-
u.importPG(pgImportAppend, pgImportFlags);
1954-
// }
1955-
// catch (Exception e) {
1956-
// u.appOutput(u.thisProc()+"error in importPG");
1957-
// throw e;
1958-
// }
1948+
// import the captured.dat file into a PG table
1949+
u.importPG(pgImportAppend, pgImportFlags);
19591950

19601951
//Note: by exiting here, the password entered on command line is not getting written into the log files
19611952
// If this is ever changed, the password should be blanked out in the command-line argument before written to the log file
19621953
u.errorExit();
19631954
}
19641955

1965-
private static void runAnonymizedReport () {
1956+
private static void anonymizeCapturedData () {
19661957
// generated anon report file
1967-
try { u.createAnonymizedReport(); } catch (Exception e) { /*nothing*/ }
1968-
u.errorExit();
1958+
try { u.anonymizeCapturedData(); } catch (Exception e) {
1959+
//System.out.println(e.toString());
1960+
e.printStackTrace();
1961+
}
19691962
}
19701963

19711964
private void reportFinalStats() throws Exception {
@@ -2390,10 +2383,16 @@ private void processInput(String runStartTime) throws Exception {
23902383
// set QUOTED_IDENTIFIER to the default value at the start of the input file
23912384
a.setQuotedIdentifier(quotedIdentifier);
23922385

2393-
// process input file line by line, identifying batches to be parsed
2394-
// this follows the 'sqlcmd' utility which uses 'go' and 'reset' as batch terminators
2395-
// other sqlcmd commands/directives are not handled except 'exit'/'quit'; such sqlcmd
2396-
// commands/directives can only be handled by sqlcmd itself
2386+
// Process input file line by line, identifying batches to be parsed
2387+
// This follows the 'sqlcmd' utility which uses 'go' and 'reset' as batch terminators
2388+
// Other sqlcmd commands/directives are not handled except 'exit'/'quit'
2389+
// Note that we are not trying to parse the entire input file, which would require the
2390+
// sqlcmd commands to be part of the grammar. Not only would this complicate the grammar,
2391+
// slow down parsing and complicate overall processing, but more importantly it would lead
2392+
// to the entire file being rejected if there is a single syntax error or bad character
2393+
// somewhere, instead of just rejecting the offending batch.
2394+
// The price to pay is having to work through each input file to properly process these
2395+
// sqlcmd commands.
23972396

23982397
StringBuilder batchText = new StringBuilder();
23992398
int batchLines = 0;
@@ -2436,19 +2435,35 @@ private void processInput(String runStartTime) throws Exception {
24362435
dynamicSQLContext = "";
24372436
dynamicSQLSubContext = "";
24382437
u.dynamicSQLFlag = false;
2438+
2439+
int lastLineWithoutTerminator = -1;
2440+
if (u.analysisPass == 2) {
2441+
if (inputFilesLastLine.containsKey(inFile)) {
2442+
lastLineWithoutTerminator = inputFilesLastLine.get(inFile);
2443+
if (u.debugging) u.dbgOutput(u.thisProc()+"getting lastLineWithoutTerminator for inFile=["+inFile+"]=["+lastLineWithoutTerminator+"] ", u.debugBatch||u.debugDynamicSQL);
2444+
}
2445+
}
24392446

24402447
while (true) {
24412448
boolean somethingFoundOnLine = false;
24422449
boolean orphanSquareBracket = false;
24432450
if (!lastLineRead) {
2444-
line = inFileReader.readLine();
2451+
if ((u.analysisPass == 2) && (lastLineWithoutTerminator == lineNr)) {
2452+
if (u.debugging) u.dbgOutput("inserting lastLineWithoutTerminator, lineNr=["+lineNr+"]", u.debugBatch||u.debugDynamicSQL);
2453+
line = "go"; // this only applies in case the last batch does not have a terminator AND there is dynamic SQL to process
2454+
}
2455+
else {
2456+
line = inFileReader.readLine();
2457+
}
24452458
}
24462459
else if (u.analysisPass == 2) {
2460+
if (u.debugging) u.dbgOutput(u.thisProc()+"dynSQLCount=["+dynSQLCount+"] u.dynamicSQLBuffer.size()=["+u.dynamicSQLBuffer.size()+"] ", u.debugDynamicSQL);
24472461
if (dynSQLCount < u.dynamicSQLBuffer.size()) {
24482462
if (!analyzingDynamicSQL) {
24492463
u.dynamicSQLBuffer.add(0, "go");
2450-
analyzingDynamicSQL = true;
2464+
analyzingDynamicSQL = true;
24512465
}
2466+
if (u.debugging) u.dbgOutput(u.thisProc()+"u.dynamicSQLBuffer=["+u.dynamicSQLBuffer+"] ", u.debugDynamicSQL);
24522467
line = u.dynamicSQLBuffer.get(dynSQLCount);
24532468
dynSQLCount++;
24542469
if (u.debugging) u.dbgOutput(u.thisProc()+"dynamic SQL: line=["+line+"] ", u.debugDynamicSQL);
@@ -2471,6 +2486,11 @@ else if (dynSQLCount == u.dynamicSQLBuffer.size()) {
24712486
line = null;
24722487
}
24732488
}
2489+
if ((line == null) && (u.analysisPass == 1) && !lastLineRead && !startOfNewBatch) {
2490+
// this only matters in case there is dynamic SQL to process AND the last batch does not have a terminator
2491+
inputFilesLastLine.put(inFile, lineNr);
2492+
if (u.debugging) u.dbgOutput("last line read without GO: lineNr=["+lineNr+"] startOfNewBatch=["+startOfNewBatch+"] lastLineWithoutTerminator=["+inputFilesLastLine.get(lineNr)+"]" , u.debugBatch||u.debugDynamicSQL);
2493+
}
24742494
if ((line == null) && (u.analysisPass == 2) && !lastLineRead) {
24752495
lastLineRead = true;
24762496
if (u.debugging) u.dbgOutput("last line was read! ", u.debugBatch);
@@ -2507,7 +2527,7 @@ else if (dynSQLCount == u.dynamicSQLBuffer.size()) {
25072527
if (!u.importFileAttribute(line,2).isEmpty()) {
25082528
// this is the header line from the import copy, abort
25092529
u.appOutput("This file contains a header line that indicates it was taken from an 'imported' subdirectory\nof a "+u.thisProgName+" report.");
2510-
u.appOutput("Remove the first line; when reprocessing, ensure the file is encoded as UTF-8, or use '-encoding utf8'.");
2530+
u.appOutput("You must remove the first line; when reprocessing, ensure the file is encoded as UTF-8, or use '-encoding utf8'.");
25112531
u.appOutput("Aborting...");
25122532
u.errorExit();
25132533
}
@@ -2882,6 +2902,7 @@ else if (dynSQLCount == u.dynamicSQLBuffer.size()) {
28822902
}
28832903

28842904
if ((u.analysisPass == 1) || ((u.analysisPass == 2) && analyzingDynamicSQL)) {
2905+
if (u.debugging) u.dbgOutput("u.analysisPass=["+u.analysisPass+"] analyzingDynamicSQL=["+analyzingDynamicSQL+"] dumpParseTree=["+dumpParseTree+"] ", u.debugBatch);
28852906
if (hasParseError) {
28862907
// write error batch
28872908
if (u.errBatchFileWriter == null) {
@@ -2922,7 +2943,7 @@ else if (dynSQLCount == u.dynamicSQLBuffer.size()) {
29222943
}
29232944
else if (exportedParseTree != null) {
29242945
// even with -parseonly, we need to run analysis in order to process set quoted_identifier, which affects parsing
2925-
if (u.debugging) u.dbgOutput("Analyzing tree for batch", u.debugBatch);
2946+
if (u.debugging) u.dbgOutput("pass=["+u.analysisPass+"] Analyzing tree for batchNr=["+batchNr+"] batchLines=["+batchLines+"] ", u.debugBatch);
29262947
String phase = "analysisTimeP" + u.analysisPass;
29272948
startTime = System.currentTimeMillis();
29282949

@@ -2999,7 +3020,7 @@ else if (exportedParseTree != null) {
29993020
}
30003021
}
30013022

3002-
if (u.analysisPass == 2) {
3023+
if (u.analysisPass == 2) {
30033024
if (CompassUtilities.devOptions) {
30043025
// temporary, for development
30053026
int secs = ((int) timeElapsedFile / 1000);
@@ -3026,6 +3047,14 @@ else if (exportedParseTree != null) {
30263047
u.closeErrBatchFile();
30273048
}
30283049
} //for inputfiles
3050+
3051+
3052+
// generate anonymized capture files
3053+
if (u.analysisPass == 2) {
3054+
if (u.anonymizedData) {
3055+
anonymizeCapturedData();
3056+
}
3057+
}
30293058
}
30303059

30313060
private static void getAutoDDL () throws Exception {
@@ -3317,7 +3346,7 @@ public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int
33173346
}
33183347

33193348
// export the parse tree
3320-
if (batchNr > 0) {
3349+
if ((batchNr > 0) || (batchNr == 0) && analyzingDynamicSQL) {
33213350
exportedParseTree = tree;
33223351
}
33233352

0 commit comments

Comments
 (0)