From b8dfc21c61d2b02e3339fc047b267a0b7e0f531f Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Wed, 8 May 2024 14:48:02 +0700 Subject: [PATCH] feat: split-off the CLI - catch up to JSQLParser 4.10 Snapshot - remove `Parenthesis` in favor of `ParenthesedExpressionList` Signed-off-by: Andreas Reichel --- build.gradle | 22 +- .../jsqlformatter/FragmentContentHandler.java | 109 ---- .../manticore/jsqlformatter/JSQLFormatter.c | 23 - .../jsqlformatter/JSQLFormatter.java | 500 +----------------- .../manticore/jsqlformatter/JavaTools.java | 290 ---------- .../com/manticore/jsqlformatter/RRTools.java | 109 ---- src/site/sphinx/usage.rst | 10 +- .../jsqlformatter/ASTVisualizationTest.java | 161 ------ .../jsqlformatter/simple/aggregate.sql | 6 + 9 files changed, 28 insertions(+), 1202 deletions(-) delete mode 100644 src/main/java/com/manticore/jsqlformatter/FragmentContentHandler.java delete mode 100644 src/main/java/com/manticore/jsqlformatter/JSQLFormatter.c delete mode 100644 src/main/java/com/manticore/jsqlformatter/JavaTools.java delete mode 100644 src/main/java/com/manticore/jsqlformatter/RRTools.java delete mode 100644 src/test/java/com/manticore/jsqlformatter/ASTVisualizationTest.java create mode 100644 src/test/resources/com/manticore/jsqlformatter/simple/aggregate.sql diff --git a/build.gradle b/build.gradle index e2f0f60..049c75a 100644 --- a/build.gradle +++ b/build.gradle @@ -48,33 +48,25 @@ configurations { dependencies { implementation('com.github.jsqlparser:jsqlparser:+'){ changing = true } - // Java Doc in XML Format - xmlDoclet 'com.manticore-projects.tools:xml-doclet:+' - - implementation 'commons-cli:commons-cli:+' implementation 'com.diogonunes:JColor:+' - // https://mvnrepository.com/artifact/org.graalvm.sdk/graal-sdk - implementation 'org.graalvm.sdk:graal-sdk:22.+' - - implementation 'commons-io:commons-io:+' - implementation 'com.github.julianthome:inmemantlr-api:+' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.+' testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.+' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.+' // for the RR Tools - implementation 'org.jsoup:jsoup:+' compileOnly 'net.sf.saxon:Saxon-HE:+' - // for the ASCII Trees - implementation 'hu.webarticum:tree-printer:2.+' - implementation 'com.github.tommyettinger:blazingchain:1.+' + // Java Doc in XML Format + xmlDoclet 'com.manticore-projects.tools:xml-doclet:+' } configurations.configureEach { - resolutionStrategy { - force 'org.apache.commons:commons-text:+' + resolutionStrategy.eachDependency { DependencyResolveDetails details -> + if (details.requested.group == 'com.github.jsqlparser') { + // Check for updates every build + resolutionStrategy.cacheChangingModulesFor 30, 'seconds' + } } } diff --git a/src/main/java/com/manticore/jsqlformatter/FragmentContentHandler.java b/src/main/java/com/manticore/jsqlformatter/FragmentContentHandler.java deleted file mode 100644 index 1eede8b..0000000 --- a/src/main/java/com/manticore/jsqlformatter/FragmentContentHandler.java +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Manticore Projects JSQLFormatter is a SQL Beautifying and Formatting Software. - * Copyright (C) 2023 Andreas Reichel - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.manticore.jsqlformatter; - -import org.xml.sax.Attributes; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; -import org.xml.sax.helpers.DefaultHandler; - -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; -import java.io.StringReader; -import java.util.HashMap; -import java.util.Map; - -public class FragmentContentHandler extends DefaultHandler { - private String xPath = ""; - private final XMLReader xmlReader; - private FragmentContentHandler parent; - private final StringBuilder characters = new StringBuilder(); - private final Map elementNameCount = new HashMap<>(); - - private final StringBuilder builder; - - public FragmentContentHandler(XMLReader xmlReader, StringBuilder builder) { - this.xmlReader = xmlReader; - this.builder = builder; - } - - private FragmentContentHandler(String xPath, XMLReader xmlReader, FragmentContentHandler parent, - StringBuilder builder) { - this(xmlReader, builder); - this.xPath = xPath; - this.parent = parent; - } - - @Override - public void startElement(String uri, String localName, String qName, Attributes atts) - throws SAXException { - Integer count = elementNameCount.get(qName); - if (null == count) { - count = 1; - } else { - count++; - } - elementNameCount.put(qName, count); - String childXPath = xPath + "/" + qName + "[" + count + "]"; - - int attsLength = atts.getLength(); - builder.append(childXPath); - for (int x = 0; x < attsLength; x++) { - if (!atts.getQName(x).equals("object") && !atts.getQName(x).equals("class")) { - builder.append("[@").append(atts.getQName(x)).append("='").append(atts.getValue(x)) - .append("']"); - } - } - builder.append("\n"); - - FragmentContentHandler child = new FragmentContentHandler(childXPath, xmlReader, this, builder); - xmlReader.setContentHandler(child); - } - - @Override - public void endElement(String uri, String localName, String qName) throws SAXException { - String value = characters.toString().trim(); - if (value.length() > 0) { - builder.append(xPath).append("='").append(characters.toString()).append("'").append("\n"); - } - xmlReader.setContentHandler(parent); - } - - @Override - public void characters(char[] ch, int start, int length) throws SAXException { - characters.append(ch, start, length); - } - - public static String getXPath(String xml, Object object) throws Exception { - StringBuilder builder = new StringBuilder(); - - SAXParserFactory spf = SAXParserFactory.newInstance(); - SAXParser sp = spf.newSAXParser(); - XMLReader xr = sp.getXMLReader(); - - FragmentContentHandler handler = new FragmentContentHandler(xr, builder); - xr.setContentHandler(handler); - - InputSource inputSource = new InputSource(new StringReader(xml)); - xr.parse(inputSource); - - return builder.toString(); - } - -} diff --git a/src/main/java/com/manticore/jsqlformatter/JSQLFormatter.c b/src/main/java/com/manticore/jsqlformatter/JSQLFormatter.c deleted file mode 100644 index da3027e..0000000 --- a/src/main/java/com/manticore/jsqlformatter/JSQLFormatter.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include - -#include - -int main(int argc, char **argv) { - graal_isolate_t *isolate = NULL; - graal_isolatethread_t *thread = NULL; - - if (graal_create_isolate(NULL, &isolate, &thread) != 0) { - fprintf(stderr, "graal_create_isolate error\n"); - return 1; - } - - printf("%s", format(thread, "select a,b,c from a inner join b on a.a = b.a where c='2';")); - - if (graal_detach_thread(thread) != 0) { - fprintf(stderr, "graal_detach_thread error\n"); - return 1; - } - - return 0; -} diff --git a/src/main/java/com/manticore/jsqlformatter/JSQLFormatter.java b/src/main/java/com/manticore/jsqlformatter/JSQLFormatter.java index 4846207..907ac72 100644 --- a/src/main/java/com/manticore/jsqlformatter/JSQLFormatter.java +++ b/src/main/java/com/manticore/jsqlformatter/JSQLFormatter.java @@ -20,8 +20,6 @@ import com.diogonunes.jcolor.Ansi; import com.diogonunes.jcolor.AnsiFormat; import com.diogonunes.jcolor.Attribute; -import hu.webarticum.treeprinter.SimpleTreeNode; -import hu.webarticum.treeprinter.printer.listing.ListingTreePrinter; import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.AllValue; import net.sf.jsqlparser.expression.AnalyticExpression; @@ -45,7 +43,6 @@ import net.sf.jsqlparser.expression.NotExpression; import net.sf.jsqlparser.expression.NullValue; import net.sf.jsqlparser.expression.OracleHint; -import net.sf.jsqlparser.expression.Parenthesis; import net.sf.jsqlparser.expression.RowConstructor; import net.sf.jsqlparser.expression.SignedExpression; import net.sf.jsqlparser.expression.StringValue; @@ -71,7 +68,6 @@ import net.sf.jsqlparser.statement.OutputClause; import net.sf.jsqlparser.statement.ReferentialAction; import net.sf.jsqlparser.statement.Statement; -import net.sf.jsqlparser.statement.Statements; import net.sf.jsqlparser.statement.alter.Alter; import net.sf.jsqlparser.statement.alter.AlterExpression; import net.sf.jsqlparser.statement.alter.AlterOperation; @@ -122,48 +118,15 @@ import net.sf.jsqlparser.statement.truncate.Truncate; import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.statement.update.UpdateSet; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.OptionGroup; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.reflect.FieldUtils; -import org.graalvm.nativeimage.IsolateThread; -import org.graalvm.nativeimage.c.function.CEntryPoint; -import org.graalvm.nativeimage.c.type.CCharPointer; -import org.graalvm.nativeimage.c.type.CTypeConversion; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.parser.Parser; -import org.jsoup.select.Elements; - -import javax.swing.tree.TreeNode; + import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutput; -import java.io.ObjectOutputStream; import java.io.StringReader; -import java.lang.reflect.Field; -import java.nio.charset.Charset; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; -import java.util.Base64; import java.util.Collection; -import java.util.Collections; -import java.util.Enumeration; import java.util.List; import java.util.Objects; import java.util.logging.Level; @@ -183,6 +146,7 @@ public class JSQLFormatter { public static final Pattern SQUARED_BRACKET_QUOTATION_PATTERN = Pattern.compile( "(((?!\\[\\d+])\\[.*]\\.\\.?)|(\\.\\[\\w+( +\\w+)*])|((?!\\s\\[\\d+])\\s\\[\\w+( +\\w+)*]))"); + private static final Logger LOGGER = Logger.getLogger(JSQLFormatter.class.getName()); private static final AnsiFormat ANSI_FORMAT_LINE_NUMBER = new AnsiFormat(Attribute.BRIGHT_BLACK_BACK(), Attribute.DESATURATED()); @@ -753,173 +717,6 @@ public static String getAbsoluteFileName(String filename) { return getAbsoluteFile(filename).getAbsolutePath(); } - /** - * @param args The Command Line Parameters. - */ - @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.ExcessiveMethodLength"}) - public static void main(String[] args) throws Exception { - Options options = new Options(); - - options.addOption("i", "inputFile", true, "The input SQL file or folder."); - options.addOption("o", "outputFile", true, "The out SQL file for the formatted statements."); - - OptionGroup formatOptions = new OptionGroup(); - formatOptions.addOption(Option.builder("f").longOpt(FormattingOption.OUTPUT_FORMAT.toString()) - .hasArg().desc("The output-format.\n[PLAIN* ANSI HTML RTF]").build()); - formatOptions.addOption( - Option.builder(null).longOpt("ansi").desc("Output ANSI annotated text.").build()); - formatOptions.addOption( - Option.builder(null).longOpt("html").desc("Output HTML annotated text.").build()); - options.addOptionGroup(formatOptions); - - OptionGroup indentOptions = new OptionGroup(); - indentOptions.addOption(Option.builder("t").longOpt(FormattingOption.INDENT_WIDTH.toString()) - .hasArg().desc("The indent width.\n[2 4* 8]").build()); - indentOptions.addOption(Option.builder("2").desc("Indent with 2 characters.").build()); - indentOptions.addOption(Option.builder("8").desc("Indent with 8 characters.").build()); - options.addOptionGroup(indentOptions); - - options.addOption(Option.builder(null).longOpt(FormattingOption.KEYWORD_SPELLING.toString()) - .hasArg().desc("Keyword spelling.\n[UPPER*, LOWER, CAMEL, KEEP]").build()); - - options.addOption(Option.builder(null).longOpt(FormattingOption.FUNCTION_SPELLING.toString()) - .hasArg().desc("Function name spelling.\n[UPPER, LOWER, CAMEL*, KEEP]").build()); - - options.addOption(Option.builder(null).longOpt(FormattingOption.OBJECT_SPELLING.toString()) - .hasArg().desc("Object name spelling.\n[UPPER, LOWER*, CAMEL, KEEP]").build()); - - options.addOption(Option.builder(null).longOpt(FormattingOption.SEPARATION.toString()).hasArg() - .desc("Position of the field separator.\n[BEFORE*, AFTER]").build()); - - options.addOption(Option.builder(null) - .longOpt(FormattingOption.SQUARE_BRACKET_QUOTATION.toString()).hasArg() - .desc("Interpret Square Brackets as Quotes instead of Arrays.\n[AUTO*, YES, NO]").build()); - - options.addOption(Option.builder(null).longOpt(FormattingOption.SHOW_LINE_NUMBERS.toString()) - .hasArg().desc("Show Line Numbers.\n[YES, NO*]").build()); - - options.addOption(Option.builder(null).longOpt(FormattingOption.BACKSLASH_QUOTING.toString()) - .hasArg().desc("Allow Back Slash '\\' for escaping.\n[YES, NO*]").build()); - - // create the parser - CommandLineParser parser = new DefaultParser(); - try { - // parse the command line arguments - CommandLine line = parser.parse(options, args); - - ArrayList formatterOptions = new ArrayList<>(); - - if (line.hasOption("ansi")) { - FormattingOption.OUTPUT_FORMAT.addFormatterOption(OutputFormat.ANSI.toString(), - formatterOptions); - } - - if (line.hasOption("html")) { - FormattingOption.OUTPUT_FORMAT.addFormatterOption(OutputFormat.HTML.toString(), - formatterOptions); - } - - if (line.hasOption("2")) { - FormattingOption.INDENT_WIDTH.addFormatterOption("2", formatterOptions); - } - - if (line.hasOption("8")) { - FormattingOption.INDENT_WIDTH.addFormatterOption("4", formatterOptions); - } - - FormattingOption.INDENT_WIDTH.addFormatterOption(line, formatterOptions); - FormattingOption.KEYWORD_SPELLING.addFormatterOption(line, formatterOptions); - FormattingOption.FUNCTION_SPELLING.addFormatterOption(line, formatterOptions); - FormattingOption.OBJECT_SPELLING.addFormatterOption(line, formatterOptions); - FormattingOption.SEPARATION.addFormatterOption(line, formatterOptions); - FormattingOption.SQUARE_BRACKET_QUOTATION.addFormatterOption(line, formatterOptions); - FormattingOption.BACKSLASH_QUOTING.addFormatterOption(line, formatterOptions); - FormattingOption.SHOW_LINE_NUMBERS.addFormatterOption(line, formatterOptions); - - if (line.hasOption("help") || line.getOptions().length == 0 && line.getArgs().length == 0) { - HelpFormatter formatter = new HelpFormatter(); - formatter.setOptionComparator(null); - - String startupCommand = - System.getProperty("java.vm.name").equalsIgnoreCase("Substrate VM") ? "./JSQLFormatter" - : "java -jar JSQLFormatter.jar"; - - formatter.printHelp(startupCommand, options, true); - return; - } - - File inputFile = null; - if (line.hasOption("inputFile")) { - inputFile = getAbsoluteFile(line.getOptionValue("inputFile")); - - if (!inputFile.canRead()) { - throw new Exception( - "Can't read the specified INPUT-FILE " + inputFile.getCanonicalPath()); - } - - try (FileInputStream inputStream = new FileInputStream(inputFile)) { - String sqlStr = IOUtils.toString(inputStream, Charset.defaultCharset()); - System.out.println("\n-- FROM " + inputFile.getName() + "\n" - + format(sqlStr, formatterOptions.toArray(new String[formatterOptions.size()]))); - } catch (Exception ex) { - throw new Exception("Error when reading from INPUT FILE " + inputFile.getAbsolutePath(), - ex); - } - } - - List argsList = line.getArgList(); - if (argsList.isEmpty() && !line.hasOption("input-file")) { - throw new Exception("No SQL statements provided for formatting."); - } else { - for (String s : argsList) { - try { - System.out.println("\n-- FROM ARGUMENT LIST\n" - + format(s, formatterOptions.toArray(new String[formatterOptions.size()]))); - } catch (Exception ex) { - LOGGER.log(Level.WARNING, "Failed to format statement\n" + s, ex); - } - } - } - - } catch (ParseException ex) { - LOGGER.log(Level.FINE, "Parsing failed. Reason: " + ex.getMessage(), ex); - - HelpFormatter formatter = new HelpFormatter(); - formatter.setOptionComparator(null); - formatter.printHelp("java -jar H2MigrationTool.jar", options, true); - - throw new Exception("Could not parse the Command Line Arguments.", ex); - } - } - - /** - * Format a list of SQL Statements. - * - *

- * SELECT, INSERT, UPDATE and MERGE statements are supported. - * - * @param thread The - * @param sql The SQL Statements to beautify. - * @param options The Formatting Options (List of "key = value" pairs). - * @return The beautifully formatted SQL Statements, semi-colon separated. - */ - @CEntryPoint(name = "format") - public static CCharPointer format(IsolateThread thread, CCharPointer sql, CCharPointer options) { - String sqlStr = CTypeConversion.toJavaString(sql); - - String[] optionStr = CTypeConversion.toJavaString(options).split(","); - try { - sqlStr = format(sqlStr, optionStr); - } catch (Exception ex) { - System.out.println(ex.getMessage()); - } - - try (CTypeConversion.CCharPointerHolder holder = CTypeConversion.toCString(sqlStr)) { - final CCharPointer result = holder.get(); - return result; - } - } - @SuppressWarnings({"PMD.CyclomaticComplexity"}) public static ArrayList verify(String sqlStr, String... options) { ArrayList exceptions = new ArrayList<>(); @@ -1089,9 +886,11 @@ public static String format(String sqlStr, String... options) throws Exception { } try { - Statement statement = CCJSqlParserUtil.parse(statementSql.replaceAll("\\n\\n+", "\n"), - parser -> parser.withSquareBracketQuotation(useSquareBracketQuotation) - .withBackslashEscapeCharacter(useBackSlashQuoting).withTimeOut(60000)); + Statement statement = + CCJSqlParserUtil.parse(CCJSqlParserUtil.sanitizeSingleSql(statementSql), + parser -> parser.withSquareBracketQuotation(useSquareBracketQuotation) + .withBackslashEscapeCharacter(useBackSlashQuoting).withTimeOut(60000) + .withUnsupportedStatements()); if (statement instanceof Select) { Select select = (Select) statement; @@ -1198,135 +997,6 @@ public static StringBuilder formatToJava(String sqlStr, int indent, String... op return builder; } - public static ArrayList getAstNodes(String sqlStr, String... options) - throws Exception { - ArrayList nodes = new ArrayList<>(); - - Statements statements = CCJSqlParserUtil.parseStatements(sqlStr); - for (Statement statement : statements) { - JavaObjectNode node = new JavaObjectNode(null, "Statements", statement); - nodes.add(node); - } - return nodes; - } - - public static SimpleTreeNode translateNode(TreeNode node) { - SimpleTreeNode simpleTreeNode = new SimpleTreeNode(node.toString()); - Enumeration children = node.children(); - while (children.hasMoreElements()) { - simpleTreeNode.addChild(translateNode(children.nextElement())); - } - - return simpleTreeNode; - } - - public static String encodeObject(Object object) throws IOException { - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - ObjectOutput objectOutput = new ObjectOutputStream(byteArrayOutputStream); - objectOutput.writeObject(object); - objectOutput.flush(); - objectOutput.close(); - byteArrayOutputStream.flush(); - - return Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray()); - } - - public static String formatToTree(String sqlStr, String... options) throws Exception { - applyFormattingOptions(options); - - // The Java TreeNode Structure - JSQLFormatter.JavaObjectNode[] nodes = - JSQLFormatter.getAstNodes(sqlStr).toArray(new JSQLFormatter.JavaObjectNode[0]); - - SimpleTreeNode rootNode = new SimpleTreeNode("SQL Text"); - for (JSQLFormatter.JavaObjectNode node : nodes) { - rootNode.addChild(translateNode(node)); - } - - return new ListingTreePrinter().stringify(rootNode); - } - - private static StringBuilder appendToXML(StringBuilder builder, JavaObjectNode node, int indent) - throws IOException { - - if (node.isLeaf()) { - builder.append(StringUtils.leftPad("", indent * 4)).append("<") - .append(node.object.getClass().getSimpleName()).append(" type='") - .append(node.object.getClass().getSimpleName()).append("'").append(" class='") - .append(node.object.getClass().getName()).append("'").append(" object='") - .append(encodeObject(node.object)).append("'").append(">").append(node.object) - .append("\n"); - // } else if (node.object instanceof net.sf.jsqlparser.schema.Column - // || node.object instanceof net.sf.jsqlparser.schema.Table - // || node.object instanceof net.sf.jsqlparser.schema.Database - // || node.object instanceof net.sf.jsqlparser.schema.Sequence - // || node.object instanceof net.sf.jsqlparser.schema.Server - // || node.object instanceof net.sf.jsqlparser.schema.Synonym) { - // return formatClassName(object); - // } else if (node.object instanceof Collection) { - // return formatCollection((Collection) object); - } else { - builder.append(StringUtils.leftPad("", indent * 4)).append("<").append(node.fieldName) - .append(" type='").append(node.object.getClass().getSimpleName()).append("'") - .append(" class='").append(node.object.getClass().getName()).append("'") - .append(" object='").append(encodeObject(node.object)).append("'").append(">\n"); - - Enumeration children = node.children(); - while (children.hasMoreElements()) { - appendToXML(builder, (JavaObjectNode) children.nextElement(), indent + 1); - } - - builder.append(StringUtils.leftPad("", indent * 4)).append("\n"); - - } - return builder; - } - - public static String formatToXML(String sqlStr, String... options) throws Exception { - applyFormattingOptions(options); - - StringBuilder builder = new StringBuilder(); - JSQLFormatter.JavaObjectNode[] nodes = - JSQLFormatter.getAstNodes(sqlStr).toArray(new JSQLFormatter.JavaObjectNode[0]); - - for (JSQLFormatter.JavaObjectNode node : nodes) { - appendToXML(builder, node, 0); - } - - return builder.toString(); - } - - public static Collection extract(String sql, Class clazz, String xpath) - throws Exception { - ArrayList objects = new ArrayList<>(); - - String xmlStr = formatToXML(sql); - Document doc = Jsoup.parse(xmlStr, "", Parser.xmlParser()); - Elements elements = doc.selectXpath(xpath); - for (Element element : elements) { - String className = element.attr("class"); - String attrStr = element.attr("object"); - - if (clazz.getName().equals(className)) { - byte[] bytes = Base64.getDecoder().decode(attrStr); - ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); - ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); - Object o = objectInputStream.readObject(); - objectInputStream.close(); - - try { - objects.add((T) o); - } catch (Exception ex) { - // @ todo: this should be ignored as we test for equal class names already - LOGGER.log(Level.WARNING, - "Failed to translate a " + o.getClass().getName() + " into a " + clazz.getName()); - } - } - } - return objects; - } - @SuppressWarnings({"PMD.CyclomaticComplexity"}) public static void applyFormattingOptions(String[] options) { // set the formatting options @@ -2514,14 +2184,6 @@ private static void appendExpression(Expression expression, Alias alias, StringB appendOperator(builder, outputFormat, "(+)", "", " "); } - } else if (expression instanceof Parenthesis) { - Parenthesis parenthesis = (Parenthesis) expression; - int subIndent = getSubIndent(builder, false); - builder.append("( "); - appendExpression(parenthesis.getExpression(), null, builder, subIndent, i, n, false, - BreakLine.NEVER); - appendNormalizingTrailingWhiteSpace(builder, " )"); - } else if (expression instanceof CaseExpression) { int subIndent = getSubIndent(builder, false); @@ -3122,6 +2784,7 @@ private static void appendExpressionList(ExpressionList expressionList, Strin int indent, BreakLine breakLine) { if (expressionList instanceof ParenthesedExpressionList) { builder.append("( "); + indent++; } appendExpressionsList(expressionList, builder, indent, breakLine); if (expressionList instanceof ParenthesedExpressionList) { @@ -3142,7 +2805,8 @@ private static void appendExpressionsList(List expressions case AS_NEEDED: BreakLine bl = size == 4 || size >= 5 && i % 3 == 0 ? BreakLine.AFTER_FIRST : BreakLine.NEVER; - appendExpression(expression, null, builder, subIndent, i, expressions.size(), true, bl); + appendExpression(expression, null, builder, subIndent, i, expressions.size(), true, + bl); break; default: @@ -4048,153 +3712,9 @@ public String toString() { return optionName; } - public void addFormatterOption(CommandLine line, ArrayList formatterOptions) { - if (line.hasOption(optionName)) { - formatterOptions.add(optionName + "=" + line.getOptionValue(optionName)); - } - } - public void addFormatterOption(String value, ArrayList formatterOptions) { formatterOptions.add(optionName + "=" + value); } } - public static class JavaObjectNode implements TreeNode { - private final TreeNode parent; - private final ArrayList children = new ArrayList<>(); - public String fieldName; - public Object object; - - public JavaObjectNode(TreeNode parent, String fieldName, Object object) { - this.parent = parent; - this.fieldName = fieldName; - this.object = object; - addChildren(); - } - - @SuppressWarnings({"PMD.CyclomaticComplexity"}) - private void addChildren() { - ArrayList fields = new ArrayList<>(FieldUtils.getAllFieldsList(object.getClass())); - - for (Field field : fields) { - try { - // System.out.println(object.getClass().getName() + " : " + field); - Object child = FieldUtils.readField(field, this.object, true); - if (!(object instanceof Column)) { - if (child.getClass().getName().startsWith("net.sf.jsqlparser") - && !child.getClass().getName().startsWith("net.sf.jsqlparser.parser") - && !child.getClass().isEnum()) { - JavaObjectNode childNode = new JavaObjectNode(this, field.getName(), child); - children.add(childNode); - } else if (child instanceof Collection) { - Collection collection = (Collection) child; - if (!collection.isEmpty() - && collection.toArray()[0].getClass().getName().startsWith("net.sf.jsqlparser")) { - for (Object element : collection) { - if (element.getClass().getName().startsWith("net.sf.jsqlparser")) { - JavaObjectNode subChildNode = - new JavaObjectNode(this, field.getName(), element); - this.children.add(subChildNode); - } - } - } - } - } - } catch (Exception ex) { - LOGGER.log(Level.FINE, "failed to process field " + field.getName(), ex); - } - } - } - - @Override - public TreeNode getChildAt(int childIndex) { - return children.get(childIndex); - } - - @Override - public int getChildCount() { - return children.size(); - } - - @Override - public TreeNode getParent() { - return parent; - } - - @Override - public int getIndex(TreeNode node) { - return children.indexOf(node); - } - - @Override - public boolean getAllowsChildren() { - return true; - } - - @Override - public boolean isLeaf() { - return children.isEmpty(); - } - - @Override - public Enumeration children() { - return Collections.enumeration(children); - } - - - private String formatClassName(Object o) { - if (outputFormat.equals(OutputFormat.HTML)) { - return "" + o.getClass().getSimpleName() + ": " + o - + ""; - } else if (outputFormat.equals(OutputFormat.ANSI)) { - return ANSI_FORMAT_KEYWORD.format(o.getClass().getSimpleName()) + ": " - + ANSI_FORMAT_PARAMETER.format(o.toString()); - } else { - return o.getClass().getSimpleName() + ": " + o; - } - } - - private String formatFieldClassName(Object o) { - if (outputFormat.equals(OutputFormat.HTML)) { - return "" + fieldName + ": " - + o.getClass().getCanonicalName() + ""; - } else if (outputFormat.equals(OutputFormat.ANSI)) { - return ANSI_FORMAT_KEYWORD.format(fieldName) + ": " + ANSI_FORMAT_PARAMETER - .format(o.getClass().getCanonicalName().replace("net.sf.jsqlparser.", "")); - } else { - return fieldName + ": " - + object.getClass().getCanonicalName().replace("net.sf.jsqlparser.", ""); - } - } - - private String formatCollection(Collection collection) { - if (outputFormat.equals(OutputFormat.HTML)) { - return "" + fieldName + " -> Collection<" - + collection.toArray()[0].getClass().getSimpleName() + ">"; - } else if (outputFormat.equals(OutputFormat.ANSI)) { - return ANSI_FORMAT_KEYWORD.format(fieldName) + " -> Collection<" - + ANSI_FORMAT_PARAMETER.format(collection.toArray()[0].getClass().getSimpleName()) - + ">"; - } else { - return object.getClass().getSimpleName() + ": " + object; - } - } - - @Override - public String toString() { - if (object instanceof Column || object instanceof Table - || object instanceof net.sf.jsqlparser.schema.Database - || object instanceof net.sf.jsqlparser.schema.Sequence - || object instanceof net.sf.jsqlparser.schema.Server - || object instanceof net.sf.jsqlparser.schema.Synonym) { - return formatClassName(object); - } else if (object instanceof Collection) { - return formatCollection((Collection) object); - } else if (isLeaf()) { - return formatClassName(object); - } else { - return formatFieldClassName(object); - } - } - } } diff --git a/src/main/java/com/manticore/jsqlformatter/JavaTools.java b/src/main/java/com/manticore/jsqlformatter/JavaTools.java deleted file mode 100644 index ef5d2c8..0000000 --- a/src/main/java/com/manticore/jsqlformatter/JavaTools.java +++ /dev/null @@ -1,290 +0,0 @@ -/** - * Manticore Projects JSQLFormatter is a SQL Beautifying and Formatting Software. - * Copyright (C) 2023 Andreas Reichel - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.manticore.jsqlformatter; - -import org.snt.inmemantlr.GenericParser; -import org.snt.inmemantlr.listener.DefaultTreeListener; -import org.snt.inmemantlr.tree.ParseTree; -import org.snt.inmemantlr.tree.ParseTreeNode; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.StringReader; -import java.util.ArrayList; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * A powerful Java SQL Formatter based on the JSQLParser. - * - * @author Andreas Reichel - * @version 0.1 - */ -public class JavaTools { - private static class LocalVariableDeclaration { - public String label = null; - public String typeString = null; - public StringBuilder sqlBuilder = new StringBuilder(); - public ArrayList parameters = new ArrayList<>(); - } - - public static void main(String[] args) { - - /* - * String columnName = ""; String tableName = ""; String test2 = new StringBuilder("SELECT ") - * .append(columnName) .append(" from ") .append(tableName) .append(";") .toString(); String - * test = "SELECT " + columnName + " from " + tableName + ";"; - */ - - final String[] escaped = {"\"SELECT \" + columnName + \" from \" + noVariableAssigned + \";\";", - "String test = \"SELECT \" + columnName + \" from \" + tableName + \";\";", - "String test2 = new StringBuilder(\"SELECT \").append(columnName).append(\" from \").append(tableName).append(\";\").toString();", - "\"SELECT \" + columnName2 + \" from \" + noVariableAssigned2 + \";\";", - "assertSqlCanBeParsedAndDeparsed(\"WITH split (word, str, hascomma) AS (VALUES ('', 'Auto,A,1234444', 1) UNION ALL SELECT substr(str, 0, CASE WHEN instr(str, ',') THEN instr(str, ',') ELSE length(str) + 1 END), ltrim(substr(str, instr(str, ',')), ','), instr(str, ',') FROM split WHERE hascomma) SELECT trim(word) FROM split WHERE word != ''\");", - "String queryStr = new MessageFormat2(\n" + " \"WITH split ( word\\n\"\n" - + " +\" , str\\n\"\n" - + " +\" , hascomma ) AS (\\n\"\n" - + " +\" VALUES ( '', 'Auto,A,1234444', 1 )\\n\"\n" - + " +\" UNION ALL\\n\"\n" - + " +\" SELECT Substr( str, 0, CASE\\n\"\n" - + " +\" WHEN Instr( str, ',' )\\n\"\n" - + " +\" THEN Instr( str, ',' )\\n\"\n" - + " +\" ELSE Length( str ) + 1\\n\"\n" - + " +\" END )\\n\"\n" - + " +\" , Ltrim( Substr( str, Instr( str, ',' ) ), ',' )\\n\"\n" - + " +\" , Instr( str, ',' )\\n\"\n" - + " +\" FROM split\\n\"\n" - + " +\" WHERE hascomma )\\n\"\n" - + " +\"SELECT Trim( word )\\n\"\n" + " +\"FROM split\\n\"\n" - + " +\"WHERE word != ''\\n\"\n" + " +\";\\n\"\n" - + " ).format(new Object[]{});"}; - for (String s : escaped) { - try { - String sql = formatJava(s); - String javaStr = toJavaMessageFormat(sql); - - System.out.println(javaStr); - } catch (Exception ex) { - Logger.getLogger(JavaTools.class.getName()).log(Level.SEVERE, null, ex); - } - } - } - - public static String formatJava(String javaCode, String... options) throws Exception { - StringBuilder formatted = new StringBuilder(); - - File lexerFile = - new File(ClassLoader.getSystemResource("com/manticore/antlr/JavaLexer.g4").toURI()); - File parserFile = - new File(ClassLoader.getSystemResource("com/manticore/antlr/JavaParser.g4").toURI()); - - final String className = "TMP" + System.currentTimeMillis(); - - final StringBuilder source = new StringBuilder().append("public class ").append(className) - .append("{\n").append("\tpublic static void mock() {").append("\t\t\n"); - source.append("\t\t").append(javaCode).append("\n"); - source.append("\t}\n}\n"); - - DefaultTreeListener t = new DefaultTreeListener(); - GenericParser gp = new GenericParser(lexerFile, parserFile); - gp.setListener(t); - try { - gp.compile(); - // gp.writeAntlrAritfactsTo("/tmp/grammar"); - // gp.store("/tmp/grammar/gp.out", true); - - ParseTree parseTree; - gp.parse(source.toString(), GenericParser.CaseSensitiveType.NONE); - parseTree = t.getParseTree(); - - StringBuilder builder = new StringBuilder(); - int indent = 0; - - ArrayList declarations = new ArrayList<>(); - - ParseTreeNode root = parseTree.getRoot(); - append(builder, root, indent, declarations); - - for (LocalVariableDeclaration declaration : declarations) { - String unformattedSql = declaration.sqlBuilder.toString(); - unformattedSql = unformattedSql.replace("\\n", " "); - unformattedSql = unformattedSql.replace("\\t", " "); - - formatted.append("\n").append(JSQLFormatter.format(unformattedSql, options)); - } - } catch (Exception ex) { - throw new Exception("Could not parse Java Code:\n" + javaCode, ex); - } - return formatted.toString(); - } - - public static String toJavaString(String sql) { - Pattern pattern = Pattern.compile("\\W\\$(\\w+)\\$(\\W|\\Z)"); - StringBuilder builder = new StringBuilder("String queryStr = "); - try { - StringReader stringReader = new StringReader(sql); - BufferedReader bufferedReader = new BufferedReader(stringReader); - String line; - int i = 0; - while ((line = bufferedReader.readLine()) != null) { - Matcher m; - while ((m = pattern.matcher(line)).find()) { - String variableName = m.group(1); - line = line.replaceFirst("\\$" + variableName + "\\$", "\" + " + variableName + " + \""); - } - - if (!line.trim().isEmpty()) { - builder.append("\n\t"); - } - if (i > 0) { - builder.append("+ "); - } else { - builder.append(" "); - } - - if (!line.trim().isEmpty()) { - builder.append("\"").append(line).append("\\n\""); - i++; - } - } - builder.append(";"); - - } catch (IOException ex) { - Logger.getLogger(JavaTools.class.getName()).log(Level.SEVERE, null, ex); - } - return builder.toString().replace(" + \"\"", ""); - } - - public static String toJavaStringBuilder(String sql) { - Pattern pattern = Pattern.compile("\\W\\$(\\w+)\\$(\\W|\\Z)"); - StringBuilder builder = - new StringBuilder("StringBuilder queryStrBuilder = new StringBuilder()"); - try { - StringReader stringReader = new StringReader(sql); - BufferedReader bufferedReader = new BufferedReader(stringReader); - String line; - while ((line = bufferedReader.readLine()) != null) { - Matcher m; - while ((m = pattern.matcher(line)).find()) { - String variableName = m.group(1); - line = line.replaceFirst("\\$" + variableName + "\\$", - "\").append(" + variableName + ").append(\""); - } - - if (!line.trim().isEmpty()) { - builder.append("\n\t"); - } - - if (!line.trim().isEmpty()) { - builder.append(".append(\"").append(line).append("\\n\")"); - } - } - builder.append(";"); - - } catch (IOException ex) { - Logger.getLogger(JavaTools.class.getName()).log(Level.SEVERE, null, ex); - } - return builder.toString().replace(".append(\"\")", ""); - } - - public static String toJavaMessageFormat(String sql) { - Pattern pattern = Pattern.compile("\\W\\$(\\w+)\\$(\\W|\\Z)"); - StringBuilder builder = new StringBuilder("String queryStr = new MessageFormat("); - try { - ArrayList variables = new ArrayList<>(); - - StringReader stringReader = new StringReader(sql); - BufferedReader bufferedReader = new BufferedReader(stringReader); - String line; - int i = 0; - int k = 0; - while ((line = bufferedReader.readLine()) != null) { - Matcher m; - while ((m = pattern.matcher(line)).find()) { - String variableName = m.group(1); - variables.add(variableName); - - line = line.replaceFirst("\\$" + variableName + "\\$", "{" + k + "}"); - k++; - } - if (!line.trim().isEmpty()) { - builder.append("\n\t\t\t"); - } - if (i > 0) { - builder.append("+"); - } - - if (!line.trim().isEmpty()) { - builder.append("\"").append(line).append("\\n\""); - i++; - } - } - builder.append("\n\t\t).format("); - - builder.append("new Object[]{"); - i = 0; - for (String v : variables) { - if (i > 0) { - builder.append(", "); - } - builder.append(v); - i++; - } - builder.append("});\n"); - - } catch (IOException ex) { - Logger.getLogger(JavaTools.class.getName()).log(Level.SEVERE, null, ex); - } - return builder.toString().replace(".append(\"\")", ""); - } - - private static void append(StringBuilder builder, ParseTreeNode p, int indent, - ArrayList declarations) { - for (int i = 0; i < indent; i++) { - builder.append(" "); - } - - builder.append(p.toString()).append("\n"); - if (p.getRule().equalsIgnoreCase("blockStatement")) { - declarations.add(new LocalVariableDeclaration()); - - } else if (p.getRule().equalsIgnoreCase("localVariableDeclaration")) { - declarations.get(declarations.size() - 1).typeString = p.getChild(0).getLabel(); - - } else if (p.getRule().equalsIgnoreCase("variableDeclaratorId")) { - declarations.get(declarations.size() - 1).label = p.getLabel(); - - } else if (p.getRule().equalsIgnoreCase("primary")) { - LocalVariableDeclaration declaration = declarations.get(declarations.size() - 1); - String label = p.getLabel(); - if (p.hasChildren()) { - declaration.sqlBuilder.append(label, 1, label.length() - 1).append(" "); - } else { - declaration.sqlBuilder.append(" $").append(label).append("$"); - declaration.parameters.add(label); - } - } - - for (ParseTreeNode n : p.getChildren()) { - append(builder, n, indent + 1, declarations); - } - } -} diff --git a/src/main/java/com/manticore/jsqlformatter/RRTools.java b/src/main/java/com/manticore/jsqlformatter/RRTools.java deleted file mode 100644 index 56198f9..0000000 --- a/src/main/java/com/manticore/jsqlformatter/RRTools.java +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Manticore Projects JSQLFormatter is a SQL Beautifying and Formatting Software. - * Copyright (C) 2023 Andreas Reichel - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.manticore.jsqlformatter; - -import org.apache.commons.io.FileUtils; -import org.jsoup.Jsoup; -import org.jsoup.helper.W3CDom; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.parser.Parser; -import org.jsoup.select.Elements; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.TreeSet; - -public class RRTools { - public static void main(String[] args) throws IOException { - final String[] _args = - args.length < 1 ? new String[] {"src/site/sphinx/_static/railroad_diagram.xhtml"} : args; - - File file = new File(_args[0]); - if (file.exists() && file.canRead()) { - // insertTOC(file); - extractSVG(file); - } else { - throw new FileNotFoundException("Can't read file " + args[0]); - } - } - - private static String stripTrailing(String s, String suffix) { - if (s.endsWith(suffix)) { - return s.substring(0, s.length() - suffix.length()); - } else { - return s; - } - } - - public static void insertTOC(File file) throws IOException { - System.setProperty(W3CDom.XPathFactoryProperty, "net.sf.saxon.xpath.XPathFactoryImpl"); - - Document doc = Jsoup.parse(file, "UTF-8", "", Parser.xmlParser()); - Elements elements = doc.selectXpath("//*[local-name()='a' and not(@href) and @name]"); - - ArrayList tocEntries = new ArrayList<>(); - TreeSet indexEntries = new TreeSet<>(); - - for (Element link : elements) { - String key = stripTrailing(link.text(), ":"); - tocEntries.add(key); - indexEntries.add(key); - } - - Element tocElement = doc.body().prependElement("H1"); - tocElement.text("Table of Content:"); - tocElement.attr("style", "font-size: 14px; font-weight:bold"); - - Element pElement = tocElement.appendElement("p"); - pElement.attr("style", "font-size: 11px; font-weight:normal"); - for (String s : tocEntries) { - pElement.appendElement("a").attr("href", "#" + s).text(s); - pElement.appendText(" "); - } - - Element indexElement = doc.body().prependElement("H1"); - indexElement.text("Index:"); - indexElement.attr("style", "font-size: 14px; font-weight:bold"); - - pElement = indexElement.appendElement("p"); - pElement.attr("style", "font-size: 11px; font-weight:normal"); - for (String s : indexEntries) { - pElement.appendElement("a").attr("href", "#" + s).text(s); - pElement.appendText(" "); - } - - FileUtils.writeStringToFile(file, doc.outerHtml(), StandardCharsets.UTF_8); - } - - /* - @throws Exception - */ - public static void extractSVG(File file) throws IOException { - System.setProperty(W3CDom.XPathFactoryProperty, "net.sf.saxon.xpath.XPathFactoryImpl"); - - Document doc = Jsoup.parse(file, "UTF-8", "", Parser.xmlParser()); - Elements elements = doc.selectXpath("//svg"); - for (Element svgElement : elements) { - System.out.println(svgElement.text()); - } - } -} diff --git a/src/site/sphinx/usage.rst b/src/site/sphinx/usage.rst index d928c3a..0b58ef4 100644 --- a/src/site/sphinx/usage.rst +++ b/src/site/sphinx/usage.rst @@ -10,19 +10,19 @@ Static Binaries .. code:: Bash - java -jar JSQLFormatter.jar [-i ] [-o ] [-f | --ansi | --html] [-t | -2 | -8] [--keywordSpelling ] [--functionSpelling ] [--objectSpelling ] [--separation ] [--squareBracketQuotation ] --squareBracketQuotation + java -jar JSQLFormatterCLI.jar [-i ] [-o ] [-f | --ansi | --html] [-t | -2 | -8] [--keywordSpelling ] [--functionSpelling ] [--objectSpelling ] [--separation ] [--squareBracketQuotation ] --squareBracketQuotation .. tab:: Linux Shell .. code:: Bash - ./JSQLFormatter [-i ] [-o ] [-f | --ansi | --html] [-t | -2 | -8] [--keywordSpelling ] [--functionSpelling ] [--objectSpelling ] [--separation ] [--squareBracketQuotation ] --squareBracketQuotation + ./JSQLFormatterCLI [-i ] [-o ] [-f | --ansi | --html] [-t | -2 | -8] [--keywordSpelling ] [--functionSpelling ] [--objectSpelling ] [--separation ] [--squareBracketQuotation ] --squareBracketQuotation .. tab:: Windows Power Shell .. code:: Bash - JSQLFormatter.exe [-i ] [-o ] [-f | --ansi | --html] [-t | -2 | -8] [--keywordSpelling ] [--functionSpelling ] [--objectSpelling ] [--separation ] [--squareBracketQuotation ] --squareBracketQuotation + JSQLFormatterCLI.exe [-i ] [-o ] [-f | --ansi | --html] [-t | -2 | -8] [--keywordSpelling ] [--functionSpelling ] [--objectSpelling ] [--separation ] [--squareBracketQuotation ] --squareBracketQuotation .......................... Command Line Options (CLI) @@ -47,7 +47,7 @@ Command Line Options (CLI) .. code:: Bash - java -jar JSQLFormatter.jar "select * from dual;" + java -jar JSQLFormatterCLI.jar "select * from dual;" .. note:: @@ -81,7 +81,7 @@ Dynamic Libraries class Sample { public static void main(String[] args) { - String formattedSql = JSqlFormatter.format("select * fromd dual;"); + String formattedSql = JSqlFormatter.format("select * from dual;"); } } diff --git a/src/test/java/com/manticore/jsqlformatter/ASTVisualizationTest.java b/src/test/java/com/manticore/jsqlformatter/ASTVisualizationTest.java deleted file mode 100644 index 416743e..0000000 --- a/src/test/java/com/manticore/jsqlformatter/ASTVisualizationTest.java +++ /dev/null @@ -1,161 +0,0 @@ -/** - * Manticore Projects JSQLFormatter is a SQL Beautifying and Formatting Software. - * Copyright (C) 2023 Andreas Reichel - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.manticore.jsqlformatter; - - -import blazing.chain.LZSEncoding; -import net.sf.jsqlparser.expression.Function; -import net.sf.jsqlparser.parser.CCJSqlParserUtil; -import net.sf.jsqlparser.parser.SimpleNode; -import net.sf.jsqlparser.schema.Column; -import net.sf.jsqlparser.statement.select.PlainSelect; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutput; -import java.io.ObjectOutputStream; -import java.math.BigDecimal; -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.Collection; - -public class ASTVisualizationTest { - - @Test - public void printAsciiAST() throws Exception { - String sqlString = "select 1 from dual where a=b;"; - - System.out.println(JSQLFormatter.formatToTree(sqlString)); - - System.out.println(JSQLFormatter.formatToTree(sqlString, "outputFormat=ANSI")); - - } - - @Test - public void testCollections() throws Exception { - String sqlString = "select 1,2,3 from dual where a=b and b=c;"; - - System.out.println(JSQLFormatter.formatToTree(sqlString)); - - System.out.println(JSQLFormatter.formatToTree(sqlString, "outputFormat=ANSI")); - - } - - @Test - public void testXML() throws Exception { - String sqlString = "select 1 as b, 2, 3 from dual as tablename where a=b and b=c;"; - - System.out.println(JSQLFormatter.formatToXML(sqlString)); - - - } - - @Test - public void testGetXPath() throws Exception { - String sqlString = "select 1 as b, 2, 3 from dual as tablename where a=b and b=c;"; - String xmlStr = JSQLFormatter.formatToXML(sqlString); - System.out.println(xmlStr); - System.out.println(FragmentContentHandler.getXPath(xmlStr, null)); - - - } - - @Test - public void testXPath() throws Exception { - String sqlString = "select 1 as b, 2, 3 from dual as tablename where a=b and b=c;"; - - // return ANY column of the SELECT statement - Collection columns = JSQLFormatter.extract(sqlString, Column.class, "//Column"); - for (Column column : columns) { - System.out.println("Found ALL column: " + column); - } - - // return only columns part of the WHERE clause on the Left side of the EQUALSTO - columns = JSQLFormatter.extract(sqlString, Column.class, "//where/leftExpression/Column"); - for (Column column : columns) { - System.out.println("Found WHERE column: " + column); - } - - // return only the C column based on the complete XPath - columns = JSQLFormatter.extract(sqlString, Column.class, - "/Statements/selectBody/where/rightExpression/Column[2]"); - for (Column column : columns) { - System.out.println("Found specific column by complete XPath: " + column); - } - } - - @Test - public void testXPathReplace() throws Exception { - String sqlStr = "select func1( func2 ( func3 ( x ) ) ) from tablename where a=b and b=c;"; - PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(sqlStr); - Function func1 = (Function) select.getSelectItem(0).getExpression(); - Function func2 = (Function) func1.getParameters().get(0); - - // Get the parent ExpressionList - SimpleNode node = (SimpleNode) func2.getASTNode().jjtGetParent(); - while (node.jjtGetValue() == null) { - node = (SimpleNode) node.jjtGetParent(); - } - - Function parentFunction = (Function) node.jjtGetValue(); - - Assertions.assertEquals(func1, parentFunction); - } - - @Test - public void testSerialization() throws IOException, ClassNotFoundException { - Object object = new BigDecimal("2345.287272"); - - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - ObjectOutput objectOutput = new ObjectOutputStream(byteArrayOutputStream); - objectOutput.writeObject(object); - objectOutput.flush(); - objectOutput.close(); - byteArrayOutputStream.flush(); - - String serializedObjectStr = - new String(byteArrayOutputStream.toByteArray(), StandardCharsets.ISO_8859_1); - - String lzsEncodedBase64 = LZSEncoding.compressToBase64(serializedObjectStr); - String base64Encoded = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray()); - - System.out.println(serializedObjectStr + "\n" + lzsEncodedBase64 + "\n" + base64Encoded); - - // verify Base64 Encoder - byte[] bytes = serializedObjectStr.getBytes(StandardCharsets.ISO_8859_1); - ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); - ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); - Assertions.assertEquals(object, objectInputStream.readObject()); - objectInputStream.close(); - byteArrayInputStream.close(); - - // verify LZSEncoder - bytes = - LZSEncoding.decompressFromBase64(lzsEncodedBase64).getBytes(StandardCharsets.ISO_8859_1); - byteArrayInputStream = new ByteArrayInputStream(bytes); - objectInputStream = new ObjectInputStream(byteArrayInputStream); - Assertions.assertEquals(object, objectInputStream.readObject()); - objectInputStream.close(); - byteArrayInputStream.close(); - - } -} diff --git a/src/test/resources/com/manticore/jsqlformatter/simple/aggregate.sql b/src/test/resources/com/manticore/jsqlformatter/simple/aggregate.sql new file mode 100644 index 0000000..16b28ec --- /dev/null +++ b/src/test/resources/com/manticore/jsqlformatter/simple/aggregate.sql @@ -0,0 +1,6 @@ +SELECT STRING_AGG( FRUIT,' & ' ORDER BY CASE TYPEOF(FRUIT) + WHEN 'VARCHAR' THEN LENGTH(TRY_CAST(FRUIT AS VARCHAR)) + WHEN 'BLOB' THEN OCTET_LENGTH(TRY_CAST(FRUIT AS BLOB)) + END ) AS STRING_AGG +FROM ( SELECT UNNEST( ['apple','pear','banana','pear'] ) AS FRUIT) AS FRUIT +; \ No newline at end of file