From daec78592afb60294e01918c6eb428f1c4746c47 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Wed, 22 Dec 2021 22:30:16 +0100 Subject: [PATCH 01/40] use curly braces for function body --- sqlcl/format.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlcl/format.js b/sqlcl/format.js index 89baff3e..a50cadd9 100644 --- a/sqlcl/format.js +++ b/sqlcl/format.js @@ -41,7 +41,7 @@ var getFiles = function (rootPath, extensions, ignoreMatcher) { } } else { files = javaFiles.walk(javaPaths.get(rootPath.toString())) - .filter(function (f) javaFiles.isRegularFile(f) && isRelevantFile(f, extensions, ignoreMatcher)) + .filter(function (f) {return javaFiles.isRegularFile(f) && isRelevantFile(f, extensions, ignoreMatcher)}) .sorted() .collect(javaCollectors.toList()); } @@ -553,7 +553,7 @@ var unregisterTvdFormat = function () { javaCommandRegistry.removeListener(javaSQLCommand.StmtSubType.G_S_FORALLSTMTS_STMTSUBTYPE); javaCommandRegistry.clearCaches(ctx.getBaseConnection(), ctx); var remainingListeners = javaCommandRegistry.getListeners(ctx.getBaseConnection(), ctx).get(javaSQLCommand.StmtSubType.G_S_FORALLSTMTS_STMTSUBTYPE) - .stream().map(function(l) l.getClass()).collect(javaCollectors.toSet()); + .stream().map(function(l) {return l.getClass()}).collect(javaCollectors.toSet()); // re-register all commands except for class TvdFormat and remaining (not removed) listener classes for (var i in listeners) { if (!listeners.get(i).toString().equals("TvdFormat") && !remainingListeners.contains(listeners.get(i).getClass())) { From 4d81084be5460c12fcbde5c2c3363b570660c63a Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Wed, 22 Dec 2021 22:30:33 +0100 Subject: [PATCH 02/40] remove dead code --- sqlcl/format.js | 1 - 1 file changed, 1 deletion(-) diff --git a/sqlcl/format.js b/sqlcl/format.js index a50cadd9..efb3032e 100644 --- a/sqlcl/format.js +++ b/sqlcl/format.js @@ -165,7 +165,6 @@ var writeFile = function (file, content) { var existsDirectory = function (dir) { var f = new javaFile(dir.toString()); return f.isDirectory(); - return true; } var existsFile = function (file) { From 7055d98a745f368422240963352239bcd8734bd9 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Wed, 22 Dec 2021 22:35:19 +0100 Subject: [PATCH 03/40] compare including data types (avoid type coercion) --- sqlcl/format.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sqlcl/format.js b/sqlcl/format.js index efb3032e..bdee8466 100644 --- a/sqlcl/format.js +++ b/sqlcl/format.js @@ -129,7 +129,7 @@ var configure = function (formatter, xmlPath, arboriPath) { var getConfiguredFormatter = function (xmlPath, arboriPath) { // set relative path for include directive in Arbori program to the directory of the main Arbori program - if (arboriPath != "default") { + if (arboriPath !== "default") { javaSystem.setProperty("dbtools.arbori.home", new javaFile(arboriPath).getParentFile().getAbsolutePath()); } // now instantiate and configure the formatter @@ -208,7 +208,7 @@ var getJsPath = function () { var getCdPath = function (path) { if (path.startsWith("/")) { return path; // Unix, fully qualified - } else if (path.length > 1 && path.substring(1, 2) == ":") { + } else if (path.length > 1 && path.substring(1, 2) === ":") { return path; // Windows, fully qualified, e.g. C:\mydir } var currentDir = ctx.getProperty("script.runner.cd_command"); @@ -268,7 +268,7 @@ var processAndValidateArgs = function (args) { return result(false); } rootPath = getCdPath(args[1]); - if (rootPath != "*" && !existsFile(rootPath) && !existsDirectory(rootPath)) { + if (rootPath !== "*" && !existsFile(rootPath) && !existsDirectory(rootPath)) { ctx.write("file or directory " + rootPath + " does not exist.\n\n"); return result(false); } @@ -482,9 +482,9 @@ var formatMarkdownFile = function (file, formatter) { var getLineSeparator = function (input) { var lineSep; - if (input.indexOf("\r\n") != -1) { + if (input.indexOf("\r\n") !== -1) { lineSep = "\r\n"; - } else if (input.indexOf("\n") != -1) { + } else if (input.indexOf("\n") !== -1) { lineSep = "\n"; } else { lineSep = javaSystem.lineSeparator(); @@ -522,7 +522,7 @@ var run = function (args) { printUsage(args[0].equalsIgnoreCase("tvdformat"), javaSystem.getProperty('tvdformat.standalone') != null); } else { var formatter = getConfiguredFormatter(options.xmlPath, options.arboriPath); - if (options.rootPath == "*") { + if (options.rootPath === "*") { formatBuffer(formatter); } else { var files; From c68979bf89ee6e839e16b75df24e6b780c714870 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Wed, 22 Dec 2021 23:06:46 +0100 Subject: [PATCH 04/40] add comment regarding ECMAScript 5.1 --- sqlcl/format.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sqlcl/format.js b/sqlcl/format.js index bdee8466..c6ffb6ed 100644 --- a/sqlcl/format.js +++ b/sqlcl/format.js @@ -16,6 +16,9 @@ "use strict"; +// SQLcl uses the Nashorn JS engine of the JDK 8/11 by default. +// As a result, this JS file must comply with ECMAScript 5.1. + var javaString = Java.type("java.lang.String"); var javaArrays = Java.type("java.util.Arrays"); var javaPaths = Java.type("java.nio.file.Paths"); From 53e19e8adcd46f4933f8eb051b246a6bf9a745ff Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Thu, 23 Dec 2021 01:06:51 +0100 Subject: [PATCH 05/40] Use JS String features instead of equalsIgnoreCase() --- sqlcl/format.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sqlcl/format.js b/sqlcl/format.js index c6ffb6ed..a58e04db 100644 --- a/sqlcl/format.js +++ b/sqlcl/format.js @@ -522,7 +522,7 @@ var run = function (args) { ctx.write("\n"); var options = processAndValidateArgs(args); if (!options.valid) { - printUsage(args[0].equalsIgnoreCase("tvdformat"), javaSystem.getProperty('tvdformat.standalone') != null); + printUsage(args[0].toLowerCase() === "tvdformat", javaSystem.getProperty('tvdformat.standalone') != null); } else { var formatter = getConfiguredFormatter(options.xmlPath, options.arboriPath); if (options.rootPath === "*") { @@ -567,7 +567,7 @@ var unregisterTvdFormat = function () { var registerTvdFormat = function () { var handleEvent = function (conn, ctx, cmd) { var args = getArgs(cmd.getSql()); - if (args != null && typeof args[0] != "undefined" && args[0].equalsIgnoreCase("tvdformat")) { + if (args != null && typeof args[0] != "undefined" && args[0].toLowerCase() === "tvdformat") { run(args); return true; } @@ -593,7 +593,7 @@ var registerTvdFormat = function () { } // main -if (args.length >= 2 && (args[1].equalsIgnoreCase("-r") || args[1].equalsIgnoreCase("--register"))) { +if (args.length >= 2 && (args[1].toLowerCase() === "-r" || args[1].toLowerCase() === "--register")) { var javaSQLCommand = Java.type("oracle.dbtools.raptor.newscriptrunner.SQLCommand"); var javaCommandRegistry = Java.type("oracle.dbtools.raptor.newscriptrunner.CommandRegistry"); var javaCommandListener = Java.type("oracle.dbtools.raptor.newscriptrunner.CommandListener"); From f132815203d59e60201c4797b1b73c3438ed8ad7 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Thu, 23 Dec 2021 01:08:42 +0100 Subject: [PATCH 06/40] use JS String features instead of equals() --- sqlcl/format.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sqlcl/format.js b/sqlcl/format.js index a58e04db..0dccd19f 100644 --- a/sqlcl/format.js +++ b/sqlcl/format.js @@ -78,14 +78,14 @@ var getRelevantFiles = function (files, extensions, ignoreMatcher) { } var configure = function (formatter, xmlPath, arboriPath) { - if (!"default".equals(xmlPath) && !"embedded".equals(xmlPath) && xmlPath != null) { + if ("default" !== xmlPath && "embedded" !== xmlPath && xmlPath != null) { var url = new javaFile(xmlPath).toURI().toURL(); var options = javaPersist2XML.read(url); var keySet = options.keySet().stream().collect(javaCollectors.toList()); for (var j in keySet) { formatter.options.put(keySet[j], options.get(keySet[j])); } - } else if ("embedded".equals(xmlPath)) { + } else if ("embedded" === xmlPath) { // Code Editor: Format formatter.options.put(formatter.adjustCaseOnly, false); // default: false (set true to skip formatting) // Advanced Format: General @@ -124,7 +124,7 @@ var configure = function (formatter, xmlPath, arboriPath) { formatter.options.put(formatter.formatThreshold, 1); // default: 1 (disables deprecated post-processing logic) } var arboriFileName = arboriPath; - if (!"default".equals(arboriPath)) { + if ("default" !== arboriPath) { arboriFileName = new javaFile(arboriPath).getAbsolutePath(); } formatter.options.put(formatter.formatProgramURL, arboriFileName); // default: "default" (= provided by SQLDev / SQLcl) @@ -401,7 +401,7 @@ var processAndValidateArgs = function (args) { xmlPath = "embedded"; } } else { - if (!"default".equals(xmlPath) && !"embedded".equals(xmlPath)) { + if ("default" !== xmlPath && "embedded" !== xmlPath) { xmlPath = getCdPath(xmlPath); if (!existsFile(xmlPath)) { ctx.write("XML file " + xmlPath + " does not exist.\n\n"); @@ -416,7 +416,7 @@ var processAndValidateArgs = function (args) { arboriPath = "default"; } } else { - if (!"default".equals(arboriPath)) { + if ("default" !== arboriPath) { arboriPath = getCdPath(arboriPath); if (!existsFile(arboriPath)) { ctx.write("Arbori file " + arboriPath + " does not exist.\n\n"); From f1d6a36f862ca3d34c2eddfe027ce6ab85a8dc67 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Thu, 23 Dec 2021 01:11:11 +0100 Subject: [PATCH 07/40] use BufferedWriter to avoid use of getBytes() --- sqlcl/format.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sqlcl/format.js b/sqlcl/format.js index 0dccd19f..3b454f0b 100644 --- a/sqlcl/format.js +++ b/sqlcl/format.js @@ -161,8 +161,9 @@ var readFile = function (file) { } var writeFile = function (file, content) { - var contentString = new javaString(content); - javaFiles.write(file, contentString.getBytes()); + var writer = javaFiles.newBufferedWriter(file); + writer.write(content); + writer.close(); } var existsDirectory = function (dir) { From 0a8528d8702a7a004edf78eaa49ab9326da1ab18 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Thu, 23 Dec 2021 01:13:01 +0100 Subject: [PATCH 08/40] avoid js.nashorn-compat=true and reduce privileges for JS program --- .../main/java/com/trivadis/plsql/formatter/TvdFormat.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java b/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java index ebbe497e..f2bebf91 100644 --- a/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java +++ b/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java @@ -2,6 +2,9 @@ import com.oracle.truffle.js.scriptengine.GraalJSScriptEngine; import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.EnvironmentAccess; +import org.graalvm.polyglot.HostAccess; +import org.graalvm.polyglot.PolyglotAccess; import javax.script.*; import java.io.*; @@ -16,8 +19,8 @@ public class TvdFormat { TvdFormat() { scriptEngine = GraalJSScriptEngine.create(null, Context.newBuilder("js") - .option("js.nashorn-compat", "true") - .allowAllAccess(true)); + .allowHostAccess(HostAccess.ALL) + .allowHostClassLookup((Predicate) s -> true)); ctx = new ScriptRunnerContext(); ctx.setOutputStream(System.out); scriptEngine.getContext().setAttribute("ctx", ctx, ScriptContext.ENGINE_SCOPE); From dc8fef43d9137e67a6cb4e7d4030e17b80b1e882 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Thu, 23 Dec 2021 01:23:12 +0100 Subject: [PATCH 09/40] add comments to main() method of standalone formatter --- .../src/main/java/com/trivadis/plsql/formatter/TvdFormat.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java b/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java index f2bebf91..83eb61b7 100644 --- a/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java +++ b/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java @@ -38,9 +38,13 @@ public void run(String[] arguments) throws IOException, ScriptException { } public static void main(String[] args) throws IOException, ScriptException { + // suppress all logging output LogManager.getLogManager().reset(); + // amend usage help in format.js for standalone tvdformat System.setProperty("tvdformat.standalone", "true"); + // format.js is compiled at runtime with a GraalVM JDK but interpreted with other JDKs System.setProperty("polyglot.engine.WarnInterpreterOnly", "false"); + // run formatter with command line parameters TvdFormat formatter = new TvdFormat(); formatter.run(args); } From 9b2569f31514259c219ef02a879d021aff18acb6 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Thu, 23 Dec 2021 01:40:24 +0100 Subject: [PATCH 10/40] use JS String features instead of equals() --- sqlcl/format.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlcl/format.js b/sqlcl/format.js index 3b454f0b..3ab79e56 100644 --- a/sqlcl/format.js +++ b/sqlcl/format.js @@ -559,7 +559,7 @@ var unregisterTvdFormat = function () { .stream().map(function(l) {return l.getClass()}).collect(javaCollectors.toSet()); // re-register all commands except for class TvdFormat and remaining (not removed) listener classes for (var i in listeners) { - if (!listeners.get(i).toString().equals("TvdFormat") && !remainingListeners.contains(listeners.get(i).getClass())) { + if (listeners.get(i).toString() !== "TvdFormat" && !remainingListeners.contains(listeners.get(i).getClass())) { javaCommandRegistry.addForAllStmtsListener(listeners.get(i).getClass()); } } From d99fcde36b0443d0a1b8502b2e2e5a1c87edfa06 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Thu, 23 Dec 2021 01:42:09 +0100 Subject: [PATCH 11/40] avoid js.nashorn-compat=true and reduce privileges for JS program in SQLcl tests --- .../plsql/formatter/sqlcl/tests/AbstractSqlclTest.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/standalone/src/test/java/com/trivadis/plsql/formatter/sqlcl/tests/AbstractSqlclTest.java b/standalone/src/test/java/com/trivadis/plsql/formatter/sqlcl/tests/AbstractSqlclTest.java index 74be99e3..0a47d9d1 100644 --- a/standalone/src/test/java/com/trivadis/plsql/formatter/sqlcl/tests/AbstractSqlclTest.java +++ b/standalone/src/test/java/com/trivadis/plsql/formatter/sqlcl/tests/AbstractSqlclTest.java @@ -51,14 +51,8 @@ public void setup() { var bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream); var wrapListenBufferOutputStream = new WrapListenBufferOutputStream(bufferedOutputStream); var bindings = new SimpleBindings(); - bindings.put("polyglot.js.nashorn-compat", true); - bindings.put("polyglot.js.allowHostAccess", Boolean.TRUE); - bindings.put("polyglot.js.allowNativeAccess", Boolean.TRUE); - bindings.put("polyglot.js.allowCreateThread", Boolean.TRUE); - bindings.put("polyglot.js.allowIO", Boolean.TRUE); - bindings.put("polyglot.js.allowHostClassLoading", Boolean.TRUE); + bindings.put("polyglot.js.allowHostAccess", true); bindings.put("polyglot.js.allowHostClassLookup", (Predicate) s -> true); - bindings.put("polyglot.js.allowAllAccess", Boolean.TRUE); scriptContext.setBindings(bindings, ScriptContext.ENGINE_SCOPE); sqlcl.setOut(bufferedOutputStream); ctx.setOutputStreamWrapper(wrapListenBufferOutputStream); From 3251c892d02aa4752249bc1ab5432c6c11831418 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Fri, 24 Dec 2021 10:14:00 +0100 Subject: [PATCH 12/40] use JS String features instead of endsWith() --- sqlcl/format.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sqlcl/format.js b/sqlcl/format.js index 3ab79e56..604b694f 100644 --- a/sqlcl/format.js +++ b/sqlcl/format.js @@ -58,7 +58,8 @@ var isRelevantFile = function (file, extensions, ignoreMatcher) { } } for (var i in extensions) { - if (file.toString().toLowerCase().endsWith(extensions[i])) { + var fileName = file.toString().toLowerCase(); + if (fileName.lastIndexOf(extensions[i]) + extensions[i].length === fileName.length) { return true; } } @@ -219,8 +220,8 @@ var getCdPath = function (path) { if (currentDir == null) { return path; } else { - if (path.endsWith(javaFile.separator)) { - return currentdir + path; + if (path.lastIndexOf(javaFile.separator) + javaFile.separator.length === path.length) { + return currentDir + path; } else { return currentDir + javaFile.separator + path; } @@ -278,8 +279,8 @@ var processAndValidateArgs = function (args) { } // If the rootPath ends with '.json', then the file is assumed to be a - // instead. - if (rootPath.endsWith('.json')) { + // instead. + if ((rootPath.lastIndexOf('.json') + 5) === rootPath.length) { var configJson = readFile(javaPaths.get(rootPath)); try { configJson = JSON.parse(configJson); @@ -454,7 +455,8 @@ var formatBuffer = function (formatter) { var isMarkdownFile = function (file, markdownExtensions) { for (var j in markdownExtensions) { - if (file.toString().toLowerCase().endsWith(markdownExtensions[j])) { + var fileName = file.toString().toLowerCase(); + if (fileName.lastIndexOf(markdownExtensions[j]) + markdownExtensions[j].length === fileName.length) { return true; } } From 442b76d2996b8f52c0768333757111c43cca2592 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Fri, 24 Dec 2021 10:14:24 +0100 Subject: [PATCH 13/40] use JS String features instead of startsWith() --- sqlcl/format.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sqlcl/format.js b/sqlcl/format.js index 604b694f..c81df7af 100644 --- a/sqlcl/format.js +++ b/sqlcl/format.js @@ -211,7 +211,7 @@ var getJsPath = function () { } var getCdPath = function (path) { - if (path.startsWith("/")) { + if (path.indexOf("/") === 0) { return path; // Unix, fully qualified } else if (path.length > 1 && path.substring(1, 2) === ":") { return path; // Windows, fully qualified, e.g. C:\mydir @@ -233,7 +233,7 @@ var createIgnoreMatcher = function (ignorePath) { var lines = javaFiles.readAllLines(javaPaths.get(ignorePath)); for (var i=0; i < lines.size(); i++) { var line = lines[i].trim(); - if (line.length > 0 && !line.startsWith('#')) { + if (line.length > 0 && line.indexOf('#') === -1) { if (globPattern.length > 6) { globPattern += ","; } @@ -351,7 +351,7 @@ var processAndValidateArgs = function (args) { } for (var i = 2; i < args.length; i++) { - if (args[i].toLowerCase().startsWith("ext=")) { + if (args[i].toLowerCase().indexOf("ext=") === 0) { extArgFound = true; if (args[i].length > 4) { var values = args[i].substring(4).split(","); @@ -361,7 +361,7 @@ var processAndValidateArgs = function (args) { } continue; } - if (args[i].toLowerCase().startsWith("mext=")) { + if (args[i].toLowerCase().indexOf("mext=") === 0) { mextArgFound = true; if (args[i].length > 5) { var values = args[i].substring(5).split(","); @@ -371,15 +371,15 @@ var processAndValidateArgs = function (args) { } continue; } - if (args[i].toLowerCase().startsWith("xml=")) { + if (args[i].toLowerCase().indexOf("xml=") === 0) { xmlPath = args[i].substring(4); continue; } - if (args[i].toLowerCase().startsWith("arbori=")) { + if (args[i].toLowerCase().indexOf("arbori=") === 0) { arboriPath = args[i].substring(7); continue; } - if (args[i].toLowerCase().startsWith("ignore=")) { + if (args[i].toLowerCase().indexOf("ignore=") === 0) { ignorePath = args[i].substring(7); continue; } From 44bd7bf9efdd17258dcfe43bf675a8d77d08dcee Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Fri, 24 Dec 2021 13:03:53 +0100 Subject: [PATCH 14/40] declare inner enum classes explicitly for native-image compatiblity --- sqlcl/format.js | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/sqlcl/format.js b/sqlcl/format.js index c81df7af..c2bd5966 100644 --- a/sqlcl/format.js +++ b/sqlcl/format.js @@ -19,20 +19,32 @@ // SQLcl uses the Nashorn JS engine of the JDK 8/11 by default. // As a result, this JS file must comply with ECMAScript 5.1. +// java.lang var javaString = Java.type("java.lang.String"); -var javaArrays = Java.type("java.util.Arrays"); -var javaPaths = Java.type("java.nio.file.Paths"); -var javaFile = Java.type("java.io.File"); +var javaSystem = Java.type("java.lang.System"); +// java.nio var javaFiles = Java.type("java.nio.file.Files"); var javaFileSystems = Java.type("java.nio.file.FileSystems"); -var javaCollectors = Java.type("java.util.stream.Collectors"); -var javaPersist2XML = Java.type("oracle.dbtools.app.Persist2XML"); +var javaPaths = Java.type("java.nio.file.Paths"); +// java.io +var javaFile = Java.type("java.io.File"); +// java.util +var javaArrays = Java.type("java.util.Arrays"); var javaPattern = Java.type("java.util.regex.Pattern"); +var javaCollectors = Java.type("java.util.stream.Collectors"); +// oracle.dbtools.app var javaFormat = Java.type("oracle.dbtools.app.Format"); +var javaFormat$Breaks = Java.type("oracle.dbtools.app.Format$Breaks"); +var javaFormat$BreaksX2 = Java.type("oracle.dbtools.app.Format$BreaksX2"); +var javaFormat$Case = Java.type("oracle.dbtools.app.Format$Case"); +var javaFormat$FlowControl = Java.type("oracle.dbtools.app.Format$FlowControl"); +var javaFormat$InlineComments = Java.type("oracle.dbtools.app.Format$InlineComments"); +var javaFormat$Space = Java.type("oracle.dbtools.app.Format$Space"); +var javaPersist2XML = Java.type("oracle.dbtools.app.Persist2XML"); +// oracle.dbtools.parser var javaLexer = Java.type("oracle.dbtools.parser.Lexer"); var javaParsed = Java.type("oracle.dbtools.parser.Parsed"); var javaSqlEarley = Java.type("oracle.dbtools.parser.plsql.SqlEarley"); -var javaSystem = Java.type("java.lang.System"); var getFiles = function (rootPath, extensions, ignoreMatcher) { var files; @@ -90,9 +102,9 @@ var configure = function (formatter, xmlPath, arboriPath) { // Code Editor: Format formatter.options.put(formatter.adjustCaseOnly, false); // default: false (set true to skip formatting) // Advanced Format: General - formatter.options.put(formatter.kwCase, javaFormat.Case.lower); // default: javaFormat.Case.UPPER - formatter.options.put(formatter.idCase, javaFormat.Case.NoCaseChange); // default: javaFormat.Case.lower - formatter.options.put(formatter.singleLineComments, javaFormat.InlineComments.CommentsUnchanged); // default: javaFormat.InlineComments.CommentsUnchanged + formatter.options.put(formatter.kwCase, javaFormat$Case.lower); // default: javaFormat.Case.UPPER + formatter.options.put(formatter.idCase, javaFormat$Case.NoCaseChange); // default: javaFormat.Case.lower + formatter.options.put(formatter.singleLineComments, javaFormat$InlineComments.CommentsUnchanged); // default: javaFormat.InlineComments.CommentsUnchanged // Advanced Format: Alignment formatter.options.put(formatter.alignTabColAliases, false); // default: true formatter.options.put(formatter.alignTypeDecl, true); // default: true @@ -104,22 +116,22 @@ var configure = function (formatter, xmlPath, arboriPath) { formatter.options.put(formatter.identSpaces, 3); // default: 3 formatter.options.put(formatter.useTab, false); // default: false // Advanced Format: Line Breaks - formatter.options.put(formatter.breaksComma, javaFormat.Breaks.After); // default: javaFormat.Breaks.After + formatter.options.put(formatter.breaksComma, javaFormat$Breaks.After); // default: javaFormat.Breaks.After formatter.options.put("commasPerLine", 1); // default: 5 - formatter.options.put(formatter.breaksConcat, javaFormat.Breaks.Before); // default: javaFormat.Breaks.Before - formatter.options.put(formatter.breaksAroundLogicalConjunctions, javaFormat.Breaks.Before); // default: javaFormat.Breaks.Before + formatter.options.put(formatter.breaksConcat, javaFormat$Breaks.Before); // default: javaFormat.Breaks.Before + formatter.options.put(formatter.breaksAroundLogicalConjunctions, javaFormat$Breaks.Before); // default: javaFormat.Breaks.Before formatter.options.put(formatter.breakAnsiiJoin, true); // default: false formatter.options.put(formatter.breakParenCondition, true); // default: false formatter.options.put(formatter.breakOnSubqueries, true); // default: true formatter.options.put(formatter.maxCharLineSize, 120); // default: 128 formatter.options.put(formatter.forceLinebreaksBeforeComment, false); // default: false - formatter.options.put(formatter.extraLinesAfterSignificantStatements, javaFormat.BreaksX2.Keep); // default: javaFormat.BreaksX2.X2 + formatter.options.put(formatter.extraLinesAfterSignificantStatements, javaFormat$BreaksX2.Keep); // default: javaFormat.BreaksX2.X2 formatter.options.put(formatter.breaksAfterSelect, false); // default: true - formatter.options.put(formatter.flowControl, javaFormat.FlowControl.IndentedActions); // default: javaFormat.FlowControl.IndentedActions + formatter.options.put(formatter.flowControl, javaFormat$FlowControl.IndentedActions); // default: javaFormat.FlowControl.IndentedActions // Advanced Format: White Space formatter.options.put(formatter.spaceAroundOperators, true); // default: true formatter.options.put(formatter.spaceAfterCommas, true); // default: true - formatter.options.put(formatter.spaceAroundBrackets, javaFormat.Space.Default); // default: javaFormat.Space.Default + formatter.options.put(formatter.spaceAroundBrackets, javaFormat$Space.Default); // default: javaFormat.Space.Default // Advanced Format: Hidden, not configurable in the GUI preferences dialog of SQLDev 20.4.1 formatter.options.put(formatter.breaksProcArgs, false); // default: false (overridden in Arbori program based on other settings) formatter.options.put(formatter.formatThreshold, 1); // default: 1 (disables deprecated post-processing logic) From 3bfa38f7ab60726f5fa0c2152c5940817eaae6dc Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 12:27:36 +0100 Subject: [PATCH 15/40] use custom replaceAll function instead of JS/Java method to make it work in native image --- settings/sql_developer/trivadis_custom_format.arbori | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/settings/sql_developer/trivadis_custom_format.arbori b/settings/sql_developer/trivadis_custom_format.arbori index dea7a9d9..fb2b79ed 100644 --- a/settings/sql_developer/trivadis_custom_format.arbori +++ b/settings/sql_developer/trivadis_custom_format.arbori @@ -615,9 +615,9 @@ i10_determine_and_normalize_line_separators: } var normalizeLineSeparators = function() { - target.input = target.input.replaceAll("\r", ""); + target.input = replaceAll(target.input, "\r", ""); if (theLineSeparator == "\r\n") { - target.input = target.input.replaceAll("\n", "\r\n"); + target.input = replaceAll(target.input, "\n", "\r\n"); } logger.fine(struct.getClass(), "i10_determine_and_normalize_line_separators: normalized."); } From 62d7f5877b082126a4b2975d9a644b0db734a3eb Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 12:29:44 +0100 Subject: [PATCH 16/40] keySet.iterator() does not work in native image, produce array via stream as workaround --- .../trivadis_custom_format.arbori | 73 ++++++++++--------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/settings/sql_developer/trivadis_custom_format.arbori b/settings/sql_developer/trivadis_custom_format.arbori index fb2b79ed..d6e4d9c0 100644 --- a/settings/sql_developer/trivadis_custom_format.arbori +++ b/settings/sql_developer/trivadis_custom_format.arbori @@ -199,6 +199,7 @@ i5_define_global_variables: var Substitutions = Java.type('oracle.dbtools.parser.Substitutions'); var System = Java.type('java.lang.System'); var Token = Java.type('oracle.dbtools.parser.Token'); + var Collectors = Java.type('java.util.stream.Collectors'); // use reflection to access hidden field newlinePositions var newlinePositionsField = Format.class.getDeclaredField("newlinePositions"); @@ -418,9 +419,9 @@ i5_define_global_functions: // Aligns all nodes per scope. var align = function(map, alignNodeName, indentNodeName, logText) { - var it = map.keySet().iterator(); - while (it.hasNext()) { - var scope = it.next(); + var keys = map.keySet().stream().collect(Collectors.toList()).toArray(); + for (var i in keys) { + var scope = keys[i]; var list = map.get(scope); var maxCol = getMaxColumn(list, alignNodeName); alignAtPos(maxCol, list, alignNodeName, indentNodeName, logText); @@ -506,9 +507,9 @@ i5_define_global_functions: if (spaceAfterCommas) { comma += 1; } - var it = map.keySet().iterator(); - while (it.hasNext()) { - var scope = it.next(); + var keys = map.keySet().stream().collect(Collectors.toList()).toArray(); + for (var i in keys) { + var scope = keys[i]; var list = map.get(scope); for (var i=0; i { - var it = newlinePositions.keySet().iterator(); - while (it.hasNext()) { - var pos = it.next(); + var keys = newlinePositions.keySet().stream().collect(Collectors.toList()).toArray(); + for (var i in keys) { + var pos = keys[i]; if (overrideIndents(pos)) { var indent = getIndent(pos); var nlpos = indent.lastIndexOf("\n"); @@ -899,9 +900,9 @@ a1_replace_tabs_with_spaces: runOnce -> { var indent = getSpaces(indentSpaces); - var it = newlinePositions.keySet().iterator(); - while (it.hasNext()) { - var key = it.next(); + var keys = newlinePositions.keySet().stream().collect(Collectors.toList()).toArray(); + for (var i in keys) { + var key = keys[i]; var value = newlinePositions.get(key); if (value.indexOf("\t") != -1) { struct.putNewline(key, value.replaceAll("\t", indent)); @@ -918,9 +919,9 @@ a2_remove_trailing_spaces: runOnce -> { var indent = getSpaces(indentSpaces); - var it = newlinePositions.keySet().iterator(); - while (it.hasNext()) { - var key = it.next(); + var keys = newlinePositions.keySet().stream().collect(Collectors.toList()).toArray(); + for (var i in keys) { + var key = keys[i]; var value = newlinePositions.get(key); // handle Linux and Windows line separators regardless of the OS var newValue = replaceAll(replaceAll(value, "[ ]+\\n", "\n"), "[ ]+\\r\\n", "\r\n"); @@ -2593,9 +2594,9 @@ r2_init_left_margin: -> { // Left margin is expressed in number of spaces. var leftMargin = new HashMap(); - var it = newlinePositions.keySet().iterator(); - while (it.hasNext()) { - var key = it.next(); + var keys = newlinePositions.keySet().stream().collect(Collectors.toList()).toArray(); + for (var i in keys) { + var key = keys[i]; var value = newlinePositions.get(key); if (value.indexOf("\n") != -1) { // enforce uniform datatype in map; therefore convert values to Integer @@ -3050,9 +3051,9 @@ r2_increment_left_margin_for_assignment: r2_indent_nodes: runOnce -> { - var it = leftMargin.keySet().iterator(); - while (it.hasNext()) { - var key = it.next(); + var keys = leftMargin.keySet().stream().collect(Collectors.toList()).toArray(); + for (var i in keys) { + var key = keys[i]; var margin = leftMargin.get(key); var value = newlinePositions.get(key); var spaces = value.length()-value.lastIndexOf("\n")-1; // 0 = first column @@ -3690,9 +3691,9 @@ r6_ensure_all_assoc_args_are_on_same_line: runOnce -> { var toRemove = new ArrayList(); - var it = assocValues.keySet().iterator(); - while (it.hasNext()) { - var scope = it.next(); + var keys = assocValues.keySet().stream().collect(Collectors.toList()).toArray(); + for (var i in keys) { + var scope = keys[i]; var list = assocValues.get(scope); if (list.size() > 0) { // we start with the second AssocArg @@ -3754,9 +3755,9 @@ a9_find_columns: a9_align_xmltable_columns: runOnce -> { - var it = xmlTableColumns.keySet().iterator(); - while (it.hasNext()) { - var scope = it.next(); + var keys = xmlTableColumns.keySet().stream().collect(Collectors.toList()).toArray(); + for (var i in keys) { + var scope = keys[i]; var pos = getColumn(scope.from+1); var list = xmlTableColumns.get(scope); alignAtPos(pos, list, "aligner", null, "a9_align_xmltable_columns"); @@ -3817,9 +3818,9 @@ a20_find_columns: a20_align_json_table_columns: runOnce -> { - var it = jsonTableColumns.keySet().iterator(); - while (it.hasNext()) { - var scope = it.next(); + var keys = jsonTableColumns.keySet().stream().collect(Collectors.toList()).toArray(); + for (var i in keys) { + var scope = keys[i]; var pos = getColumn(scope.from+2); // first column var list = jsonTableColumns.get(scope); alignAtPos(pos, list, "aligner", null, "a20_align_json_table_columns"); @@ -4143,9 +4144,9 @@ a19_restore_indent_in_conditional_branch: runOnce -> { var indent = getSpaces(indentSpaces); - var it = indentInConditionalBranch.keySet().iterator(); - while (it.hasNext()) { - var key = it.next(); + var keys = indentInConditionalBranch.keySet().stream().collect(Collectors.toList()).toArray(); + for (var i in keys) { + var key = keys[i]; var originalIndent = indentInConditionalBranch.get(key); var indent = getIndent(key); if (indent != originalIndent) { @@ -4166,9 +4167,9 @@ a19_restore_indent_in_conditional_branch: a21_remove_non_ws_indent: runOnce -> { - var it = newlinePositions.keySet().iterator(); - while (it.hasNext()) { - var pos = it.next(); + var keys = newlinePositions.keySet().stream().collect(Collectors.toList()).toArray(); + for (var i in keys) { + var pos = keys[i]; var indent = getIndent(pos); var newIndent = replaceAll(indent, "[^\\s]+", ""); if (indent != newIndent) { From 0b4a4b02e807710cbb1da227a68e1ba1cbac7a3b Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 12:30:14 +0100 Subject: [PATCH 17/40] use JS String features instead of equals() --- settings/sql_developer/trivadis_custom_format.arbori | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings/sql_developer/trivadis_custom_format.arbori b/settings/sql_developer/trivadis_custom_format.arbori index d6e4d9c0..594cfd07 100644 --- a/settings/sql_developer/trivadis_custom_format.arbori +++ b/settings/sql_developer/trivadis_custom_format.arbori @@ -925,7 +925,7 @@ a2_remove_trailing_spaces: var value = newlinePositions.get(key); // handle Linux and Windows line separators regardless of the OS var newValue = replaceAll(replaceAll(value, "[ ]+\\n", "\n"), "[ ]+\\r\\n", "\r\n"); - if (!value.equals(newValue)) { + if (value !== newValue) { struct.putNewline(key, newValue); logger.fine(struct.getClass(), "a2_remove_trailing_spaces: at " + key + "."); } From f8129ed5ab9ff2d02c0062825070cc290567c11d Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 13:23:19 +0100 Subject: [PATCH 18/40] remove unnecessary cast --- .../src/main/java/com/trivadis/plsql/formatter/TvdFormat.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java b/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java index 83eb61b7..d4c16bb9 100644 --- a/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java +++ b/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java @@ -9,7 +9,6 @@ import javax.script.*; import java.io.*; import java.net.URL; -import java.util.function.Predicate; import java.util.logging.LogManager; public class TvdFormat { @@ -20,7 +19,7 @@ public class TvdFormat { scriptEngine = GraalJSScriptEngine.create(null, Context.newBuilder("js") .allowHostAccess(HostAccess.ALL) - .allowHostClassLookup((Predicate) s -> true)); + .allowHostClassLookup(s -> true)); ctx = new ScriptRunnerContext(); ctx.setOutputStream(System.out); scriptEngine.getContext().setAttribute("ctx", ctx, ScriptContext.ENGINE_SCOPE); From 4cb0d709d5219fff466a0b12ec78e003199690af Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 13:24:11 +0100 Subject: [PATCH 19/40] remove unused imports --- .../src/main/java/com/trivadis/plsql/formatter/TvdFormat.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java b/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java index d4c16bb9..a080d159 100644 --- a/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java +++ b/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java @@ -2,9 +2,7 @@ import com.oracle.truffle.js.scriptengine.GraalJSScriptEngine; import org.graalvm.polyglot.Context; -import org.graalvm.polyglot.EnvironmentAccess; import org.graalvm.polyglot.HostAccess; -import org.graalvm.polyglot.PolyglotAccess; import javax.script.*; import java.io.*; From d8316804a177e9c6075a10e76a179aa0077e82d9 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 13:25:25 +0100 Subject: [PATCH 20/40] configure logging file based on TVDFORMAT_LOGGING_CONF_FILE environment variable --- .../java/com/trivadis/plsql/formatter/TvdFormat.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java b/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java index a080d159..5efa1fa7 100644 --- a/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java +++ b/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java @@ -35,8 +35,18 @@ public void run(String[] arguments) throws IOException, ScriptException { } public static void main(String[] args) throws IOException, ScriptException { - // suppress all logging output + // configure logging LogManager.getLogManager().reset(); + String loggingConfFile = System.getenv("TVDFORMAT_LOGGING_CONF_FILE"); + if (loggingConfFile != null) { + // enable logging according java.util.logging configuration file + try { + LogManager.getLogManager().readConfiguration(new FileInputStream(loggingConfFile)); + } catch (FileNotFoundException e) { + System.out.println("\nWarning: The file '" + loggingConfFile + + "' does not exist. Please update the environment variable TVDFORMAT_LOGGING_CONF_FILE.\n"); + } + } // amend usage help in format.js for standalone tvdformat System.setProperty("tvdformat.standalone", "true"); // format.js is compiled at runtime with a GraalVM JDK but interpreted with other JDKs From c5ed0b85e6b0e06753842bf601791ee15383aab2 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 13:26:53 +0100 Subject: [PATCH 21/40] configure Program.debug based on TVDFORMAT_DEBUG environment variable --- .../main/java/com/trivadis/plsql/formatter/TvdFormat.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java b/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java index 5efa1fa7..0414c9e7 100644 --- a/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java +++ b/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java @@ -1,6 +1,7 @@ package com.trivadis.plsql.formatter; import com.oracle.truffle.js.scriptengine.GraalJSScriptEngine; +import oracle.dbtools.arbori.Program; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.HostAccess; @@ -47,6 +48,11 @@ public static void main(String[] args) throws IOException, ScriptException { "' does not exist. Please update the environment variable TVDFORMAT_LOGGING_CONF_FILE.\n"); } } + // enable Arbori program debug + String debug = System.getenv("TVDFORMAT_DEBUG"); + if (debug != null && debug.trim().equalsIgnoreCase("true")) { + Program.debug = true; + } // amend usage help in format.js for standalone tvdformat System.setProperty("tvdformat.standalone", "true"); // format.js is compiled at runtime with a GraalVM JDK but interpreted with other JDKs From 1d8e2eb9752930668fa0b1afdf22ab872d55883d Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 13:27:15 +0100 Subject: [PATCH 22/40] configure Program.timing based on TVDFORMAT_TIMING environment variable --- .../main/java/com/trivadis/plsql/formatter/TvdFormat.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java b/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java index 0414c9e7..c68e93d8 100644 --- a/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java +++ b/standalone/src/main/java/com/trivadis/plsql/formatter/TvdFormat.java @@ -53,6 +53,11 @@ public static void main(String[] args) throws IOException, ScriptException { if (debug != null && debug.trim().equalsIgnoreCase("true")) { Program.debug = true; } + // enable Arbori program timing + String timing = System.getenv("TVDFORMAT_TIMING"); + if (timing != null && timing.trim().equalsIgnoreCase("true")) { + Program.timing = true; + } // amend usage help in format.js for standalone tvdformat System.setProperty("tvdformat.standalone", "true"); // format.js is compiled at runtime with a GraalVM JDK but interpreted with other JDKs From fca0d04921c27167531e38924e1dd0e9ff3d3dcd Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 13:28:19 +0100 Subject: [PATCH 23/40] add native-image JSON configuration files --- .../tvdformat/proxy-config.json | 4 + .../tvdformat/reflect-config.json | 495 ++++++++++++++++++ 2 files changed, 499 insertions(+) create mode 100644 standalone/src/main/resources/META-INF/native-image/com.trivadis.plsql.formatter/tvdformat/proxy-config.json create mode 100644 standalone/src/main/resources/META-INF/native-image/com.trivadis.plsql.formatter/tvdformat/reflect-config.json diff --git a/standalone/src/main/resources/META-INF/native-image/com.trivadis.plsql.formatter/tvdformat/proxy-config.json b/standalone/src/main/resources/META-INF/native-image/com.trivadis.plsql.formatter/tvdformat/proxy-config.json new file mode 100644 index 00000000..08575859 --- /dev/null +++ b/standalone/src/main/resources/META-INF/native-image/com.trivadis.plsql.formatter/tvdformat/proxy-config.json @@ -0,0 +1,4 @@ +[ + [], + ["java.util.function.Predicate"] +] \ No newline at end of file diff --git a/standalone/src/main/resources/META-INF/native-image/com.trivadis.plsql.formatter/tvdformat/reflect-config.json b/standalone/src/main/resources/META-INF/native-image/com.trivadis.plsql.formatter/tvdformat/reflect-config.json new file mode 100644 index 00000000..c0fa69e4 --- /dev/null +++ b/standalone/src/main/resources/META-INF/native-image/com.trivadis.plsql.formatter/tvdformat/reflect-config.json @@ -0,0 +1,495 @@ +[ + { + "name" : "com.trivadis.plsql.formatter.ScriptRunnerContext", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.net.URI", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.util.Collection", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.util.HashMap", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.util.HashMap$KeySet", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.lang.Class", + "methods" : [ + {"name" : "getDeclaredField"} + ] + }, + { + "name" : "java.lang.String", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.lang.reflect.Field", + "methods" : [ + { "name" : "setAccessible"}, + { "name" : "get"} + ] + }, + { + "name" : "java.util.Arrays", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.nio.file.Paths", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.io.BufferedWriter", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.io.File", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.nio.file.Files", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.nio.file.FileSystems", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.util.ArrayList", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.util.HashMap", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.util.HashSet", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.util.Iterator", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.util.regex.Matcher", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.util.stream.Collectors", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.util.stream.ReferencePipeline$Head", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.util.stream.Stream", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.lang.Integer", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.lang.System", + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.io.PrintStream", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "java.util.regex.Pattern", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.app.Format", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.app.Format$Breaks", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.app.Format$BreaksX2", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.app.Format$Case", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.app.Format$FlowControl", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.app.Format$InlineComments", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.app.Format$Space", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.app.Persist2XML", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.arbori.Program", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.arbori.SqlProgram", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.parser.Lexer", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.parser.LexerToken", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.parser.Parsed", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.parser.ParseNode", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.parser.Substitutions", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.parser.Token", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.parser.plsql.SqlEarley", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.parser.plsql.SyntaxError", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.util.Logger", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, + { + "name" : "oracle.dbtools.util.Service", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + } +] \ No newline at end of file From 680e6f4634a64ab76db14f929eb72bc2a0120797 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 13:29:20 +0100 Subject: [PATCH 24/40] add native image Java configuration class called during build --- .../RuntimeReflectionRegistrationFeature.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 standalone/src/main/java/com/trivadis/plsql/formatter/RuntimeReflectionRegistrationFeature.java diff --git a/standalone/src/main/java/com/trivadis/plsql/formatter/RuntimeReflectionRegistrationFeature.java b/standalone/src/main/java/com/trivadis/plsql/formatter/RuntimeReflectionRegistrationFeature.java new file mode 100644 index 00000000..b475d7c8 --- /dev/null +++ b/standalone/src/main/java/com/trivadis/plsql/formatter/RuntimeReflectionRegistrationFeature.java @@ -0,0 +1,42 @@ +package com.trivadis.plsql.formatter; + +import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.nativeimage.hosted.RuntimeReflection; +import org.reflections.Reflections; +import org.reflections.scanners.Scanners; + +import java.util.Set; + +@SuppressWarnings("unused") +public class RuntimeReflectionRegistrationFeature implements Feature { + + private static void register(String classNamePrefix, ClassLoader classLoader) { + Reflections reflections = new Reflections(classNamePrefix); + Set allClassNames = reflections.getAll(Scanners.SubTypes); + // allClassNames contains also inner classes + for (String className : allClassNames) { + registerClass(className, classLoader); + } + } + + private static void registerClass(String className, ClassLoader classLoader) { + try { + Class clazz = Class.forName(className,false, classLoader); + // calling getClass() on a clazz throws an Exception when not found on the classpath + RuntimeReflection.register(clazz.getClass()); + } catch (Throwable t) { + // ignore + } + } + + public void beforeAnalysis(BeforeAnalysisAccess access) { + ClassLoader classLoader = access.getApplicationClassLoader(); + // register all classes in a package + register("oracle.dbtools.app", classLoader); + register("oracle.dbtools.arbori", classLoader); + register("oracle.dbtools.parser", classLoader); + register("oracle.dbtools.raptor.utils", classLoader); + register("oracle.dbtools.util", classLoader); + register("oracle.dbtools.scripting", classLoader); + } +} From 168f2f82198b2d1fade22c8b028d13ae0688b11a Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 13:30:13 +0100 Subject: [PATCH 25/40] add native.image.fallback option and extend build for it --- standalone/pom.xml | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/standalone/pom.xml b/standalone/pom.xml index adab7a59..650daac3 100644 --- a/standalone/pom.xml +++ b/standalone/pom.xml @@ -17,6 +17,8 @@ 21.3.0 21.2.0 true + + force @@ -90,6 +92,17 @@ 5.8.2 test + + + org.reflections + reflections + 0.10.2 + + + org.slf4j + slf4j-jdk14 + 1.7.32 + @@ -179,6 +192,7 @@ META-INF/MANIFEST.MF module-info.class META-INF/versions/** + META-INF/native-image/org.graalvm.*/** @@ -220,17 +234,31 @@ ${skip.native} ${project.artifactId} com.trivadis.plsql.formatter.TvdFormat - - -H:IncludeResources=.* --force-fallback + -H:IncludeResources=.* + -H:DynamicProxyConfigurationFiles=${project.basedir}/src/main/resources/META-INF/native-image/${project.groupId}/${project.artifactId}/proxy-config.json + -H:ReflectionConfigurationFiles=${project.basedir}/src/main/resources/META-INF/native-image/${project.groupId}/${project.artifactId}/reflect-config.json + -H:+ReportExceptionStackTraces + --language:js + --features=com.trivadis.plsql.formatter.RuntimeReflectionRegistrationFeature + --${native.image.fallback}-fallback From 6ebc8c8999c59ff7f9c1200eb77e6cd79a40abf3 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 15:26:55 +0100 Subject: [PATCH 26/40] declare inner enum classes Format.Breaks and Format.Space explicitly for native-image compatibility --- .../trivadis_custom_format.arbori | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/settings/sql_developer/trivadis_custom_format.arbori b/settings/sql_developer/trivadis_custom_format.arbori index 594cfd07..2059971a 100644 --- a/settings/sql_developer/trivadis_custom_format.arbori +++ b/settings/sql_developer/trivadis_custom_format.arbori @@ -187,19 +187,29 @@ identifiers: i5_define_global_variables: runOnce -> { - // Java classes + // java.lang classes + var Integer = Java.type('java.lang.Integer'); + var System = Java.type('java.lang.System'); + + // java.util classes var ArrayList = Java.type('java.util.ArrayList'); - var Format = Java.type('oracle.dbtools.app.Format'); var HashMap = Java.type('java.util.HashMap'); var HashSet = Java.type('java.util.HashSet'); - var Integer = Java.type('java.lang.Integer'); - var LexerToken = Java.type('oracle.dbtools.parser.LexerToken'); - var logger = Java.type('oracle.dbtools.util.Logger'); var Pattern = Java.type("java.util.regex.Pattern"); + var Collectors = Java.type('java.util.stream.Collectors'); + + // oracle.dptools.app classes + var Format = Java.type('oracle.dbtools.app.Format'); + var Format$Breaks = Java.type("oracle.dbtools.app.Format$Breaks"); + var Format$Space = Java.type("oracle.dbtools.app.Format$Space"); + + // oracle.dbtools.parser classes + var LexerToken = Java.type('oracle.dbtools.parser.LexerToken'); var Substitutions = Java.type('oracle.dbtools.parser.Substitutions'); - var System = Java.type('java.lang.System'); var Token = Java.type('oracle.dbtools.parser.Token'); - var Collectors = Java.type('java.util.stream.Collectors'); + + // oracle.dbtools.util classes + var logger = Java.type('oracle.dbtools.util.Logger'); // use reflection to access hidden field newlinePositions var newlinePositionsField = Format.class.getDeclaredField("newlinePositions"); @@ -1100,7 +1110,7 @@ a13_short_nodes: var maxLen = maxCharLineSize / 2; var node = tuple.get("node"); if (getNodeLength(node) <= maxLen) { - if (breaksConcat == Format.Breaks.None || !containsConcat(node)) { + if (breaksConcat == Format$Breaks.None || !containsConcat(node)) { reduceNodeIndents(node); } } @@ -1775,10 +1785,10 @@ o3_whitespace_around_open_paren: [node) '(' -> { var node = tuple.get("node"); - if (spaceAroundBrackets != Format.Space.Default) { + if (spaceAroundBrackets != Format$Space.Default) { if (getIndent(node.from).indexOf("\n") == -1) { var spaceBefore; - if (spaceAroundBrackets == Format.Space.Inside || spaceAroundBrackets == Format.Space.NoSpace) { + if (spaceAroundBrackets == Format$Space.Inside || spaceAroundBrackets == Format$Space.NoSpace) { spaceBefore = ""; } else { spaceBefore = " "; @@ -1789,7 +1799,7 @@ o3_whitespace_around_open_paren: } if (getIndent(node.to).indexOf("\n") == -1) { var spaceAfter; - if (spaceAroundBrackets == Format.Space.Outside || spaceAroundBrackets == Format.Space.NoSpace || spaceAroundBrackets == Format.Space.Default) { + if (spaceAroundBrackets == Format$Space.Outside || spaceAroundBrackets == Format$Space.NoSpace || spaceAroundBrackets == Format$Space.Default) { spaceAfter = ""; } else { spaceAfter = " "; @@ -1805,7 +1815,7 @@ o3_whitespace_around_close_paren: var node = tuple.get("node"); if (getIndent(node.from).indexOf("\n") == -1) { var spaceBefore; - if (spaceAroundBrackets == Format.Space.Outside || spaceAroundBrackets == Format.Space.NoSpace || spaceAroundBrackets == Format.Space.Default) { + if (spaceAroundBrackets == Format$Space.Outside || spaceAroundBrackets == Format$Space.NoSpace || spaceAroundBrackets == Format$Space.Default) { spaceBefore = ""; } else { spaceBefore = " "; @@ -1813,10 +1823,10 @@ o3_whitespace_around_close_paren: struct.putNewline(node.from, spaceBefore); logger.fine(struct.getClass(), "o3_whitespace_around_close_paren: <" + spaceBefore + "> before at " + node.from + "."); } - if (spaceAroundBrackets != Format.Space.Default) { + if (spaceAroundBrackets != Format$Space.Default) { if (getIndent(node.to).indexOf("\n") == -1) { var spaceAfter; - if (spaceAroundBrackets == Format.Space.Inside || spaceAroundBrackets == Format.Space.NoSpace) { + if (spaceAroundBrackets == Format$Space.Inside || spaceAroundBrackets == Format$Space.NoSpace) { spaceAfter = ""; } else { spaceAfter = " "; @@ -1827,7 +1837,7 @@ o3_whitespace_around_close_paren: } } --- based on issue #99, applied only with Format.Space.Default +-- based on issue #99, applied only with Format$Space.Default o3_no_space_before_open_paren: [node) '(' & ( @@ -1836,7 +1846,7 @@ o3_no_space_before_open_paren: | [node^) paren_expr_list & [node^^) function_call ) -> { - if (spaceAroundBrackets == Format.Space.Default) { + if (spaceAroundBrackets == Format$Space.Default) { var node = tuple.get("node"); struct.putNewline(node.from, ""); logger.fine(struct.getClass(), "o3_no_space_before_open_paren: at " + node.from + "."); @@ -2054,7 +2064,7 @@ o9_boolean_option: var node = tuple.get("node") if (struct.breaksBeforeLogicalConjunction()) { if (getIndent(node.from).indexOf("\n") == -1) { - if (breaksAroundLogicalConjunctions != Format.Breaks.BeforeAndAfter) { + if (breaksAroundLogicalConjunctions != Format$Breaks.BeforeAndAfter) { struct.putNewline(node.to, " "); } struct.putNewline(node.from, theLineSeparator); @@ -2063,7 +2073,7 @@ o9_boolean_option: } if (struct.breaksAfterLogicalConjunction()) { if (getIndent(node.to).indexOf("\n") == -1) { - if (breaksAroundLogicalConjunctions != Format.Breaks.BeforeAndAfter) { + if (breaksAroundLogicalConjunctions != Format$Breaks.BeforeAndAfter) { struct.putNewline(node.from, " "); } struct.putNewline(node.to, theLineSeparator); From d9e332362dfd63717b4122da0ab8d5a42bdcaa23 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 15:28:11 +0100 Subject: [PATCH 27/40] use JS String length property instead of Java String length() method for native image compatiblity --- .../trivadis_custom_format.arbori | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/settings/sql_developer/trivadis_custom_format.arbori b/settings/sql_developer/trivadis_custom_format.arbori index 2059971a..8f1b45a3 100644 --- a/settings/sql_developer/trivadis_custom_format.arbori +++ b/settings/sql_developer/trivadis_custom_format.arbori @@ -300,9 +300,9 @@ i5_define_global_functions: // Returns the indentation without leading new lines from a string. var getNumCharsAfterNewLine = function(indent) { if (indent.indexOf("\n") != -1) { - return indent.length() - indent.lastIndexOf("\n") - 1; + return indent.length - indent.lastIndexOf("\n") - 1; } - return indent.length(); + return indent.length; } // Returns the leading new lines from a node position (without trailing spaces). @@ -321,7 +321,7 @@ i5_define_global_functions: var col=getNumCharsAfterNewLine(getIndent(startPos)); var indent = getIndent(startPos); for (var i=startPos-1; i>=0 && indent.indexOf("\n") == -1; i=i-1) { - col += target.src.get(i).content.length(); + col += target.src.get(i).content.length; var indent = getIndent(i); col += getNumCharsAfterNewLine(indent); } @@ -334,7 +334,7 @@ i5_define_global_functions: var col=getNumCharsAfterNewLine(getIndent(startPos)); var indent = getIndent(startPos); for (var i=startPos-1; i>=0 && indent.indexOf("\n") == -1; i=i-1) { - col += target.src.get(i).content.length(); + col += target.src.get(i).content.length; var indent = getIndent(i); if (indent.indexOf("\n") == -1) { col += getNumCharsAfterNewLine(indent); @@ -2494,7 +2494,7 @@ r5_commas: } var getIndentForComma = function(indent) { - var len = indent.length() - 1; + var len = indent.length - 1; if (spaceAfterCommas) { len = len - 1; } @@ -2509,7 +2509,7 @@ r5_commas: var indent = getIndent(nodeFrom); if (indent.indexOf("\n") != -1) { var pos = 0; - for (var i=0; i maxCharLineSize && target.src.get(key).content.length() > 1 && getIndent(key).indexOf("\n") == -1) { + if (pos > maxCharLineSize && target.src.get(key).content.length > 1 && getIndent(key).indexOf("\n") == -1) { struct.putNewline(key, indent); - pos = indent.length() + target.src.get(key).content.length(); + pos = indent.length + target.src.get(key).content.length; logger.fine(struct.getClass(), "a4_add_line_breaks_with_indent: at " + key + "."); } else { var value = getIndent(key); @@ -4197,7 +4197,7 @@ d2_log_time: runOnce -> { var endTime = (new Date()).getTime(); - logger.info(struct.getClass(), "d2_log_time: formatted " + target.input.length() + " chars and " + logger.info(struct.getClass(), "d2_log_time: formatted " + target.input.length + " chars and " + target.root.to + " nodes in " + ((endTime - startTime) / 1000) + " seconds."); } From afa3779f7bc4603a06db157d76adda33f6cda375 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 15:28:48 +0100 Subject: [PATCH 28/40] add StringBuilder class used by default Arbori program --- .../tvdformat/reflect-config.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/standalone/src/main/resources/META-INF/native-image/com.trivadis.plsql.formatter/tvdformat/reflect-config.json b/standalone/src/main/resources/META-INF/native-image/com.trivadis.plsql.formatter/tvdformat/reflect-config.json index c0fa69e4..d909b5e7 100644 --- a/standalone/src/main/resources/META-INF/native-image/com.trivadis.plsql.formatter/tvdformat/reflect-config.json +++ b/standalone/src/main/resources/META-INF/native-image/com.trivadis.plsql.formatter/tvdformat/reflect-config.json @@ -71,6 +71,17 @@ "allPublicFields": true, "allPublicClasses": true }, + { + "name" : "java.lang.StringBuilder", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, { "name" : "java.lang.reflect.Field", "methods" : [ From a03df7e453f18391a660cf3da1df6fd253b87b8c Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 15:29:42 +0100 Subject: [PATCH 29/40] add TreeSet class used by trivadis_custom_format.arbori --- .../tvdformat/reflect-config.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/standalone/src/main/resources/META-INF/native-image/com.trivadis.plsql.formatter/tvdformat/reflect-config.json b/standalone/src/main/resources/META-INF/native-image/com.trivadis.plsql.formatter/tvdformat/reflect-config.json index d909b5e7..6c472544 100644 --- a/standalone/src/main/resources/META-INF/native-image/com.trivadis.plsql.formatter/tvdformat/reflect-config.json +++ b/standalone/src/main/resources/META-INF/native-image/com.trivadis.plsql.formatter/tvdformat/reflect-config.json @@ -54,6 +54,17 @@ "allPublicFields": true, "allPublicClasses": true }, + { + "name" : "java.util.TreeSet", + "allDeclaredConstructors": true, + "allDeclaredMethods": true, + "allDeclaredFields": true, + "allDeclaredClasses": true, + "allPublicConstructors": true, + "allPublicMethods": true, + "allPublicFields": true, + "allPublicClasses": true + }, { "name" : "java.lang.Class", "methods" : [ From fd216350e81c58aee90b03a055ecec7d6bbed374 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 15:30:49 +0100 Subject: [PATCH 30/40] register also all constructors, methods and fields when registering a class --- .../RuntimeReflectionRegistrationFeature.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/standalone/src/main/java/com/trivadis/plsql/formatter/RuntimeReflectionRegistrationFeature.java b/standalone/src/main/java/com/trivadis/plsql/formatter/RuntimeReflectionRegistrationFeature.java index b475d7c8..51d83329 100644 --- a/standalone/src/main/java/com/trivadis/plsql/formatter/RuntimeReflectionRegistrationFeature.java +++ b/standalone/src/main/java/com/trivadis/plsql/formatter/RuntimeReflectionRegistrationFeature.java @@ -5,6 +5,9 @@ import org.reflections.Reflections; import org.reflections.scanners.Scanners; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.Set; @SuppressWarnings("unused") @@ -24,6 +27,15 @@ private static void registerClass(String className, ClassLoader classLoader) { Class clazz = Class.forName(className,false, classLoader); // calling getClass() on a clazz throws an Exception when not found on the classpath RuntimeReflection.register(clazz.getClass()); + for (Constructor constructor : clazz.getDeclaredConstructors()) { + RuntimeReflection.register(constructor); + } + for (Method method : clazz.getDeclaredMethods()) { + RuntimeReflection.register((method)); + } + for (Field field : clazz.getDeclaredFields()) { + RuntimeReflection.register(field); + } } catch (Throwable t) { // ignore } From b74622b9be3eb429ba5ac97654e3b2ef4fa6cbe5 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 15:31:59 +0100 Subject: [PATCH 31/40] registered dependencies outside of classpath, should not be called, therefore ignore for the time being. --- standalone/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/standalone/pom.xml b/standalone/pom.xml index 650daac3..23fe2300 100644 --- a/standalone/pom.xml +++ b/standalone/pom.xml @@ -259,6 +259,7 @@ --language:js --features=com.trivadis.plsql.formatter.RuntimeReflectionRegistrationFeature --${native.image.fallback}-fallback + --allow-incomplete-classpath From e4d0a942f5480ad010219b2d77161ecd78671f47 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 15:32:24 +0100 Subject: [PATCH 32/40] update comments regarding force/no-fallback options --- standalone/pom.xml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/standalone/pom.xml b/standalone/pom.xml index 23fe2300..c40160c0 100644 --- a/standalone/pom.xml +++ b/standalone/pom.xml @@ -236,20 +236,16 @@ com.trivadis.plsql.formatter.TvdFormat -H:IncludeResources=.* From 5c835320134f2cd72eae5c331196d8a3e0d71e9b Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 18:53:52 +0100 Subject: [PATCH 33/40] reduce number of registered classes --- .../RuntimeReflectionRegistrationFeature.java | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/standalone/src/main/java/com/trivadis/plsql/formatter/RuntimeReflectionRegistrationFeature.java b/standalone/src/main/java/com/trivadis/plsql/formatter/RuntimeReflectionRegistrationFeature.java index 51d83329..85a8c409 100644 --- a/standalone/src/main/java/com/trivadis/plsql/formatter/RuntimeReflectionRegistrationFeature.java +++ b/standalone/src/main/java/com/trivadis/plsql/formatter/RuntimeReflectionRegistrationFeature.java @@ -12,19 +12,37 @@ @SuppressWarnings("unused") public class RuntimeReflectionRegistrationFeature implements Feature { + private static final String[] SKIP_CLASS_NAMES = { + "oracle.dbtools.util.Closeables", + }; - private static void register(String classNamePrefix, ClassLoader classLoader) { - Reflections reflections = new Reflections(classNamePrefix); + private static void register(String packageName, boolean includeSubPackages, ClassLoader classLoader) { + Reflections reflections = new Reflections(packageName); Set allClassNames = reflections.getAll(Scanners.SubTypes); // allClassNames contains also inner classes for (String className : allClassNames) { - registerClass(className, classLoader); + if (className.startsWith((packageName))) { + if (includeSubPackages || (!className.substring(packageName.length() + 1).contains("."))) { + if (validClass(className)) { + registerClass(className, classLoader); + } + } + } + } + } + + private static boolean validClass(String className) { + for (String skipClassName : SKIP_CLASS_NAMES) { + if (className.startsWith(skipClassName)) { + return false; + } } + return true; } private static void registerClass(String className, ClassLoader classLoader) { try { - Class clazz = Class.forName(className,false, classLoader); + Class clazz = Class.forName(className, false, classLoader); // calling getClass() on a clazz throws an Exception when not found on the classpath RuntimeReflection.register(clazz.getClass()); for (Constructor constructor : clazz.getDeclaredConstructors()) { @@ -39,16 +57,15 @@ private static void registerClass(String className, ClassLoader classLoader) { } catch (Throwable t) { // ignore } - } + } public void beforeAnalysis(BeforeAnalysisAccess access) { ClassLoader classLoader = access.getApplicationClassLoader(); // register all classes in a package - register("oracle.dbtools.app", classLoader); - register("oracle.dbtools.arbori", classLoader); - register("oracle.dbtools.parser", classLoader); - register("oracle.dbtools.raptor.utils", classLoader); - register("oracle.dbtools.util", classLoader); - register("oracle.dbtools.scripting", classLoader); + register("oracle.dbtools.app", true, classLoader); + register("oracle.dbtools.arbori", true, classLoader); + register("oracle.dbtools.parser", true, classLoader); + register("oracle.dbtools.raptor", false, classLoader); + register("oracle.dbtools.util", true, classLoader); } } From 422dcf5df62b4d0b21da1ad19d81ad64844419b2 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 18:54:26 +0100 Subject: [PATCH 34/40] remove unnecessary --allow-incomplete-classpath argument --- standalone/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/standalone/pom.xml b/standalone/pom.xml index c40160c0..136bd732 100644 --- a/standalone/pom.xml +++ b/standalone/pom.xml @@ -255,7 +255,6 @@ --language:js --features=com.trivadis.plsql.formatter.RuntimeReflectionRegistrationFeature --${native.image.fallback}-fallback - --allow-incomplete-classpath From 6973bf821a90ac283d912bc2b33b3a3cf234045e Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 19:17:28 +0100 Subject: [PATCH 35/40] use JS String features instead of startsWith() --- settings/sql_developer/trivadis_custom_format.arbori | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/settings/sql_developer/trivadis_custom_format.arbori b/settings/sql_developer/trivadis_custom_format.arbori index 8f1b45a3..c10f55ad 100644 --- a/settings/sql_developer/trivadis_custom_format.arbori +++ b/settings/sql_developer/trivadis_custom_format.arbori @@ -799,11 +799,11 @@ i8_save_indent_in_conditional_branch: for (var i in tokens) { var type = tokens[i].type var content = tokens[i].content.toLowerCase() - if (type == Token.MACRO_SKIP && content.startsWith("$if ")) { + if (type == Token.MACRO_SKIP && content.indexOf("$if ") == 0) { withinFirstBranch = true; continue; } - if (withinFirstBranch && type == Token.MACRO_SKIP && content.startsWith("$")) { + if (withinFirstBranch && type == Token.MACRO_SKIP && content.indexOf("$") == 0) { withinFirstBranch = false; continue; } @@ -2552,7 +2552,7 @@ r5_commas: struct.putNewline(commaNode.from, getIndentForComma(indentNextNode)); logger.fine(struct.getClass(), "r5_commas: fix indent before comma at " + commaNode.from + "."); var comment = getLastCommentBetweenPos(commaNode.from-1, commaNode.to); - if (comment != null && comment.startsWith("--")) { + if (comment != null && comment.indexOf("--") == 0) { // we must not remove the newline after a single-line comment (belongs to the single line comment) } else { // remove all whitespace before node @@ -4026,7 +4026,7 @@ a18_indent_comment: var getIndentBefore = function(pos) { var indent = getIndent(pos); var content = target.src.get(pos).content.toLowerCase(); - if (content.startsWith("end")) { + if (content.indexOf("end") == 0) { indent += getSpaces(indentSpaces); if (target.src.get(pos+1).content.toLowerCase() == "case") { indent += getSpaces(indentSpaces); From 8c01f960717b0e94bc188afcb61b5cac9d5168b3 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 19:17:45 +0100 Subject: [PATCH 36/40] use custom replaceAll function instead of JS/Java method to make it work in native image --- settings/sql_developer/trivadis_custom_format.arbori | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/settings/sql_developer/trivadis_custom_format.arbori b/settings/sql_developer/trivadis_custom_format.arbori index c10f55ad..1be07608 100644 --- a/settings/sql_developer/trivadis_custom_format.arbori +++ b/settings/sql_developer/trivadis_custom_format.arbori @@ -915,7 +915,7 @@ a1_replace_tabs_with_spaces: var key = keys[i]; var value = newlinePositions.get(key); if (value.indexOf("\t") != -1) { - struct.putNewline(key, value.replaceAll("\t", indent)); + struct.putNewline(key, replaceAll(value, "\t", indent)); logger.fine(struct.getClass(), "a1_replace_tabs_with_spaces: at " + key + "."); } } @@ -4056,7 +4056,7 @@ a18_indent_comment: substitutions.put(tokens[firstWS].begin, tokens[pos].begin, content); logger.fine(struct.getClass(), "a18_indent_comment: at " + parserPos + "."); if (tokens[pos].type == Token.COMMENT) { - var newComment = tokens[pos].content.replaceAll( + var newComment = replaceAll(tokens[pos].content, oldIndent.substring(oldIndent.lastIndexOf("\n")), newIndent.substring(newIndent.lastIndexOf("\n"))); substitutions.put(tokens[pos].begin, tokens[pos].end, newComment); From 105793b32cd92f5908e4d4a7b8c64b93aaf79b2d Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sat, 25 Dec 2021 21:09:05 +0100 Subject: [PATCH 37/40] fix typo in comment --- settings/sql_developer/trivadis_custom_format.arbori | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings/sql_developer/trivadis_custom_format.arbori b/settings/sql_developer/trivadis_custom_format.arbori index 1be07608..268fb60c 100644 --- a/settings/sql_developer/trivadis_custom_format.arbori +++ b/settings/sql_developer/trivadis_custom_format.arbori @@ -198,7 +198,7 @@ i5_define_global_variables: var Pattern = Java.type("java.util.regex.Pattern"); var Collectors = Java.type('java.util.stream.Collectors'); - // oracle.dptools.app classes + // oracle.dbtools.app classes var Format = Java.type('oracle.dbtools.app.Format'); var Format$Breaks = Java.type("oracle.dbtools.app.Format$Breaks"); var Format$Space = Java.type("oracle.dbtools.app.Format$Space"); From f2178b72f061b570956de686e398aa29b41a1156 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sun, 26 Dec 2021 01:53:17 +0100 Subject: [PATCH 38/40] ignore VSCode project directory --- standalone/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/standalone/.gitignore b/standalone/.gitignore index ba2ce844..2bcf61e3 100644 --- a/standalone/.gitignore +++ b/standalone/.gitignore @@ -31,6 +31,7 @@ hs_err_pid* .project .classpath **/.settings +.vscode # IntelliJ **/.idea From ff3d3cbd3bd0aad5b36035ef799967c819b10a93 Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sun, 26 Dec 2021 01:54:15 +0100 Subject: [PATCH 39/40] disable logging during tests via system variable, configurable in pom.xml --- standalone/pom.xml | 4 ++++ .../formatter/settings/ConfiguredTestFormatter.java | 12 ++++++++---- .../formatter/sqlcl/tests/AbstractSqlclTest.java | 12 ++++++++---- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/standalone/pom.xml b/standalone/pom.xml index 136bd732..ab9345f1 100644 --- a/standalone/pom.xml +++ b/standalone/pom.xml @@ -19,6 +19,7 @@ true force + true @@ -267,6 +268,9 @@ **/*.java + + ${disable.logging} + diff --git a/standalone/src/test/java/com/trivadis/plsql/formatter/settings/ConfiguredTestFormatter.java b/standalone/src/test/java/com/trivadis/plsql/formatter/settings/ConfiguredTestFormatter.java index 5da57497..aa0bc75f 100644 --- a/standalone/src/test/java/com/trivadis/plsql/formatter/settings/ConfiguredTestFormatter.java +++ b/standalone/src/test/java/com/trivadis/plsql/formatter/settings/ConfiguredTestFormatter.java @@ -28,11 +28,15 @@ private void setArboriHome() { } private void loadLoggingConf() { + var disableLogging = System.getProperty("disable.logging"); var manager = LogManager.getLogManager(); - try { - manager.readConfiguration(Thread.currentThread().getContextClassLoader().getResourceAsStream("logging.conf")); - } catch (SecurityException | IOException e) { - e.printStackTrace(); + manager.reset(); + if (disableLogging != null && !disableLogging.trim().equalsIgnoreCase("true")) { + try { + manager.readConfiguration(Thread.currentThread().getContextClassLoader().getResourceAsStream("logging.conf")); + } catch (SecurityException | IOException e) { + e.printStackTrace(); + } } } diff --git a/standalone/src/test/java/com/trivadis/plsql/formatter/sqlcl/tests/AbstractSqlclTest.java b/standalone/src/test/java/com/trivadis/plsql/formatter/sqlcl/tests/AbstractSqlclTest.java index 0a47d9d1..678327c6 100644 --- a/standalone/src/test/java/com/trivadis/plsql/formatter/sqlcl/tests/AbstractSqlclTest.java +++ b/standalone/src/test/java/com/trivadis/plsql/formatter/sqlcl/tests/AbstractSqlclTest.java @@ -31,11 +31,15 @@ public abstract class AbstractSqlclTest { } private void loadLoggingConf() { + var disableLogging = System.getProperty("disable.logging"); var manager = LogManager.getLogManager(); - try { - manager.readConfiguration(Thread.currentThread().getContextClassLoader().getResourceAsStream("logging.conf")); - } catch (SecurityException | IOException e) { - e.printStackTrace(); + manager.reset(); + if (disableLogging != null && !disableLogging.trim().equalsIgnoreCase("true")) { + try { + manager.readConfiguration(Thread.currentThread().getContextClassLoader().getResourceAsStream("logging.conf")); + } catch (SecurityException | IOException e) { + e.printStackTrace(); + } } } From af680c3af5451c772930a627c0bbc8408f2d35ce Mon Sep 17 00:00:00 2001 From: Philipp Salvisberg Date: Sun, 26 Dec 2021 01:54:48 +0100 Subject: [PATCH 40/40] update README --- standalone/README.md | 89 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 10 deletions(-) diff --git a/standalone/README.md b/standalone/README.md index 0d8a2524..2c08a101 100644 --- a/standalone/README.md +++ b/standalone/README.md @@ -2,18 +2,66 @@ ## Introduction -This Maven project produces a standalone command line executable `tvdformat.jar` for the SQLcl script [`format.js`](../sqlcl/format.js). Optionally it produces also a GraalVM native image `tvdformat`. +This Maven project produces a standalone command line executable `tvdformat.jar` for the SQLcl script [`format.js`](../sqlcl/format.js). Optionally it produces also a GraalVM [native image](https://www.graalvm.org/reference-manual/native-image/) `tvdformat`. -The startup time of standalone JAR file and the native image are identical since the image still requires a JDK to execute. However, it is faster than running `format.js` from SQLcl. +The startup time of standalone JAR file and the native image are similar since the image still requires a JDK to execute. However, it is faster than running `format.js` from SQLcl. This project contains JUnit tests for - the SQLDev/SQLcl formatter settings `trivadis_advanced_format.xml` and `trivadis_custom_format.arbori` - the SQLcl script `format.js` - the SQLcl command `tvdformat` -- the standalone executable `tvdformat` +- the standalone exectable `tvdformat` -The project requires a JDK 17, but it produces a Java 8 JAR file. A GraalVM JDK is required only if you want to produce a native image. +The project requires a JDK 17, but it produces a Java 8 executable JAR file. A GraalVM JDK is required only if you want to build a [native image](https://www.graalvm.org/reference-manual/native-image/). + +## Running the Standalone Formatter + +### Configure Logging + +Optionally, you can define the following environment variables: + +Variable | Description +-------- | ----------- +`TVDFORMAT_LOGGING_CONF_FILE` | Path to a [java.util.logging](https://docs.oracle.com/en/java/javase/17/core/java-logging-overview.html#GUID-B83B652C-17EA-48D9-93D2-563AE1FF8EDA) configuration file. Fully qualified or relative paths are supported. [This file](src/test/resources/logging.conf) is used for tests. +`TVDFORMAT_DEBUG` | `true` enables Arbori debug messages. +`TVDFORMAT_TIMING` |`true` enables Arbori query/callback timing messages. + +### Executable JAR + +The `tvdformat.jar` is a shaded, executable JAR. This means it contains all dependend Java classes. However, it still needs a JDK 8 or higher. + +To run it, open a terminal window and type + +``` +java -jar tvdformat.jar +``` + +The parameters are the same as for the [SQLcl command `tvdformat`](../sqlcl/README.md#register-script-formatjs-as-sqlcl-command-tvdformat). Except for formatting the SQLcl buffer, of course. + +### Native Image + +A native image is a platform specific executable. The following images can be produced with a GraalVM JDK 17: + +OS | amd64)? | aarch64? | Requires JDK 8+? | No JDK required? +------- | ------- | -------- | ---------------- | ---------------- +macOS | yes | no | yes | yes +Linux | yes | yes | yes | yes +Windows | yes | no | yes | yes + +Currently there is no way to produce an ARM based (aarch64) native image for macOS and Windows. This reduces the possible combinations from 12 to 8 native images. Native images are not part of a release. You have to build them yourself as described [below](#how-to-build). + +Native images produced with the `--force-fallback` option have a size of around 14 MB. They require a JDK 8+ at runtime and are considered stable. + +Native images produced with the `--no-fallback` option have a size of around 500 MB. They do not require a JDK at runtime. Due to the absence of automatic tests, these images are considered experimental. + +To run a native image open a terminal window and type + +``` +./tvdformat +``` + +The parameters are the same as for the [executable JAR](#executable-jar). ## How to Build @@ -25,12 +73,33 @@ The project requires a JDK 17, but it produces a Java 8 JAR file. A GraalVM JDK 6. Clone the plsql-formatter-settings repository 7. Open a terminal window in the plsql-formatter-settings root folder and type - cd standalone + ``` + cd standalone + ``` + +8. Run Maven build by the following command + + ``` + mvn -Dsqlcl.libdir=/usr/local/bin/sqlcl/lib clean package + ``` + + Amend the parameter `sqlcl.libdir` to match the path of the lib directory of your SQLcl installation. This folder is used to reference libraries such as `dbtools-common.jar` which contains the formatter and its dependencies. These libraries are not available in public Maven repositories. + + You can define the following optional parameters: -6. Run maven build by the following command + | Parameter | Value | Meaning | + | -------------------------- | ------- | ------- | + | `skip.native` | `true` | Do not produce a native image (default) | + | | `false` | Produce a native image | + | `native.image.fallback` | `no` | Produce a native image of about 14 MB which requires a JDK at runtime (default) | + | | `force` | Produce a native image of about 500 MB that runs without JDK | + | `skipTests` | `true` | Run tests (default) | + | | `false` | Do not run tests | + | `disable.logging` | `true` | Disable logging message during test run (default) | + | | `false` | Enable logging message during test run | - mvn -Dsqlcl.libdir=/usr/local/bin/sqlcl/lib -Dskip.native=false clean package + Here's a fully qualified example to produce a native image: - Amend the parameter `sqlcl.libdir` to match the path of the lib directory of you SQLcl installation. This folder is used to reference the `dbtools-common.jar` library (containing the formatter and its dependencies) which is not available in public Maven repositories. - - When you specifiy the parameter `-Dskip.native=false` a native image for your platform is created. When you pass the value `true` (default) then no native image is produced. + ``` + mvn -Dsqlcl.libdir=/usr/local/bin/sqlcl/lib -Dskip.native=false -Dnative.image.fallback=no -DskipTests=true -Ddisable.logging=true clean package + ```