diff --git a/flink-table/flink-table-planner-blink/src/test/java/org/apache/flink/table/planner/utils/DiffRepository.java b/flink-table/flink-table-planner-blink/src/test/java/org/apache/flink/table/planner/utils/DiffRepository.java index fde10b88387f1..5982b21773f0f 100644 --- a/flink-table/flink-table-planner-blink/src/test/java/org/apache/flink/table/planner/utils/DiffRepository.java +++ b/flink-table/flink-table-planner-blink/src/test/java/org/apache/flink/table/planner/utils/DiffRepository.java @@ -20,6 +20,7 @@ import org.apache.calcite.avatica.util.Spaces; import org.apache.calcite.util.Pair; import org.apache.calcite.util.Util; +import org.apache.calcite.util.XmlOutput; import org.junit.Assert; import org.junit.ComparisonFailure; import org.w3c.dom.CDATASection; diff --git a/flink-table/flink-table-planner-blink/src/test/java/org/apache/flink/table/planner/utils/XmlOutput.java b/flink-table/flink-table-planner-blink/src/test/java/org/apache/flink/table/planner/utils/XmlOutput.java deleted file mode 100644 index b5167d2b8a4e3..0000000000000 --- a/flink-table/flink-table-planner-blink/src/test/java/org/apache/flink/table/planner/utils/XmlOutput.java +++ /dev/null @@ -1,648 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.flink.table.planner.utils; - -import java.io.PrintWriter; -import java.io.Writer; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Deque; -import java.util.List; - -/** - * This class is copied from Calcite's {@link org.apache.calcite.util.XmlOutput}, can be removed - * once we bump to Calcite v1.22.0. The change is in the commit id - * 1745f752561be04ae34d1fa08593c2d3ba4470e8 in Calcite which removes the new line in {@link - * #cdata(String, boolean)}. - * - *
Streaming XML output. - * - *
Use this class to write XML to any streaming source. While the class itself is unstructured
- * and doesn't enforce any DTD specification, use of the class does ensure that the output is
- * syntactically valid XML.
- */
-public class XmlOutput {
-
- // This Writer is the underlying output stream to which all XML is
- // written.
- private final PrintWriter out;
-
- // The tagStack is maintained to check that tags are balanced.
- private final Deque Additionally, the sequence These special treatment rules are required to allow cdata sections to contain XML strings
- * which may themselves contain cdata sections. Traditional CDATA sections do not nest.
- */
- public void cdata(String data) {
- cdata(data, false);
- }
-
- /**
- * Writes a CDATA section (as {@link #cdata(String)}).
- *
- * @param data string to write
- * @param quote if true, quote in a If this function returns true, the string will need to be encoded either using the
- * stringEncodeXML function above or using a CDATA section. Note that MSXML has a nasty bug
- * whereby whitespace characters outside of a CDATA section are lost when parsing. To avoid
- * hitting this bug, this method treats many whitespace characters as "special".
- *
- * @param input the String to scan for XML special characters.
- * @return true if the String contains any such characters.
- */
- private static boolean stringHasXMLSpecials(String input) {
- for (int i = 0; i < input.length(); i++) {
- char c = input.charAt(i);
- switch (c) {
- case '<':
- case '>':
- case '"':
- case '\'':
- case '&':
- case '\t':
- case '\n':
- case '\r':
- return true;
- }
- }
- return false;
- }
-
- /**
- * Utility for replacing special characters with escape sequences in strings.
- *
- * A StringEscaper starts out as an identity transform in the "mutable" state. Call {@link
- * #defineEscape} as many times as necessary to set up mappings, and then call {@link
- * #makeImmutable} before actually applying the defined transform. Or, use one of the global
- * mappings pre-defined here.
- */
- static class StringEscaper implements Cloneable {
- private Listglob
- * is true. The start tag is automatically closed when we start a child node. If there are no
- * child nodes, {@link #endTag} creates an empty tag.
- */
- private boolean inTag;
-
- /** @see #setAlwaysQuoteCData */
- private boolean alwaysQuoteCData;
-
- /** @see #setIgnorePcdata */
- private boolean ignorePcdata;
-
- /**
- * Private helper function to display a degree of indentation.
- *
- * @param out the PrintWriter to which to display output.
- * @param indent the degree of indentation.
- */
- private void displayIndent(PrintWriter out, int indent) {
- if (!compact) {
- for (int i = 0; i < indent; i++) {
- out.print(indentString);
- }
- }
- }
-
- /**
- * Constructs a new XmlOutput based on any {@link Writer}.
- *
- * @param out the writer to which this XmlOutput generates results.
- */
- public XmlOutput(Writer out) {
- this(new PrintWriter(out, true));
- }
-
- /**
- * Constructs a new XmlOutput based on a {@link PrintWriter}.
- *
- * @param out the writer to which this XmlOutput generates results.
- */
- public XmlOutput(PrintWriter out) {
- this.out = out;
- indent = 0;
- tagsWritten = 0;
- }
-
- /**
- * Sets or unsets the compact mode. Compact mode causes the generated XML to be free of
- * extraneous whitespace and other unnecessary characters.
- *
- * @param compact true to turn on compact mode, or false to turn it off.
- */
- public void setCompact(boolean compact) {
- this.compact = compact;
- }
-
- public boolean getCompact() {
- return compact;
- }
-
- /**
- * Sets the string to print for each level of indentation. The default is a tab. The value must
- * not be null. Set this to the empty string to achieve no indentation (note that
- * {@link #setCompact}(true) removes indentation and newlines).
- */
- public void setIndentString(String indentString) {
- this.indentString = indentString;
- }
-
- /** Sets whether to detect that tags are empty. */
- public void setGlob(boolean glob) {
- this.glob = glob;
- }
-
- /**
- * Sets whether to always quote cdata segments (even if they don't contain special characters).
- */
- public void setAlwaysQuoteCData(boolean alwaysQuoteCData) {
- this.alwaysQuoteCData = alwaysQuoteCData;
- }
-
- /** Sets whether to ignore unquoted text, such as whitespace. */
- public void setIgnorePcdata(boolean ignorePcdata) {
- this.ignorePcdata = ignorePcdata;
- }
-
- public boolean getIgnorePcdata() {
- return ignorePcdata;
- }
-
- /**
- * Sends a string directly to the output stream, without escaping any characters. Use with
- * caution!
- */
- public void print(String s) {
- out.print(s);
- }
-
- /**
- * Starts writing a new tag to the stream. The tag's name must be given and its attributes
- * should be specified by a fully constructed AttrVector object.
- *
- * @param tagName the name of the tag to write.
- * @param attributes an XMLAttrVector containing the attributes to include in the tag.
- */
- public void beginTag(String tagName, XMLAttrVector attributes) {
- beginBeginTag(tagName);
- if (attributes != null) {
- attributes.display(out, indent);
- }
- endBeginTag(tagName);
- }
-
- public void beginBeginTag(String tagName) {
- if (inTag) {
- // complete the parent's start tag
- if (compact) {
- out.print(">");
- } else {
- out.println(">");
- }
- inTag = false;
- }
- displayIndent(out, indent);
- out.print("<");
- out.print(tagName);
- }
-
- public void endBeginTag(String tagName) {
- if (glob) {
- inTag = true;
- } else if (compact) {
- out.print(">");
- } else {
- out.println(">");
- }
- out.flush();
- tagStack.push(tagName);
- indent++;
- tagsWritten++;
- }
-
- /** Writes an attribute. */
- public void attribute(String name, String value) {
- printAtt(out, name, value);
- }
-
- /** If we are currently inside the start tag, finishes it off. */
- public void beginNode() {
- if (inTag) {
- // complete the parent's start tag
- if (compact) {
- out.print(">");
- } else {
- out.println(">");
- }
- inTag = false;
- }
- }
-
- /**
- * Completes a tag. This outputs the end tag corresponding to the last exposed beginTag. The tag
- * name must match the name of the corresponding beginTag.
- *
- * @param tagName the name of the end tag to write.
- */
- public void endTag(String tagName) {
- // Check that the end tag matches the corresponding start tag
- String x = tagStack.pop();
- assert x.equals(tagName);
-
- // Lower the indent and display the end tag
- indent--;
- if (inTag) {
- // we're still in the start tag -- this element had no children
- if (compact) {
- out.print("/>");
- } else {
- out.println("/>");
- }
- inTag = false;
- } else {
- displayIndent(out, indent);
- out.print("");
- out.print(tagName);
- if (compact) {
- out.print(">");
- } else {
- out.println(">");
- }
- }
- out.flush();
- }
-
- /**
- * Writes an empty tag to the stream. An empty tag is one with no tags inside it, although it
- * may still have attributes.
- *
- * @param tagName the name of the empty tag.
- * @param attributes an XMLAttrVector containing the attributes to include in the tag.
- */
- public void emptyTag(String tagName, XMLAttrVector attributes) {
- if (inTag) {
- // complete the parent's start tag
- if (compact) {
- out.print(">");
- } else {
- out.println(">");
- }
- inTag = false;
- }
- displayIndent(out, indent);
- out.print("<");
- out.print(tagName);
- if (attributes != null) {
- out.print(" ");
- attributes.display(out, indent);
- }
-
- if (compact) {
- out.print("/>");
- } else {
- out.println("/>");
- }
- out.flush();
- tagsWritten++;
- }
-
- /**
- * Writes a CDATA section. Such sections always appear on their own line. The nature in which
- * the CDATA section is written depends on the actual string content with respect to these
- * special characters/sequences:
- *
- *
- *
- *
- * &
- * "
- * '
- * <
- * >
- * ]]> is special.
- *
- *
- *
- *
- * ]]>
- * will be enclosed in a CDATA section.
- * ]]> sequence
- * will be left as-is but have all of its special characters encoded as entities.
- * <![CDATA[ ... ]]> regardless
- * of the content of data; if false, quote only if the content needs it
- */
- public void cdata(String data, boolean quote) {
- if (inTag) {
- // complete the parent's start tag
- if (compact) {
- out.print(">");
- } else {
- out.println(">");
- }
- inTag = false;
- }
- if (data == null) {
- data = "";
- }
- boolean specials = false;
- boolean cdataEnd = false;
-
- // Scan the string for special characters
- // If special characters are found, scan the string for ']]>'
- if (stringHasXMLSpecials(data)) {
- specials = true;
- if (data.contains("]]>")) {
- cdataEnd = true;
- }
- }
-
- // Display the result
- displayIndent(out, indent);
- if (quote || alwaysQuoteCData) {
- out.print("");
- } else if (!specials) {
- out.println(data);
- } else {
- stringEncodeXML(data, out);
- out.println();
- }
- out.flush();
- tagsWritten++;
- }
-
- /** Writes a String tag; a tag containing nothing but a CDATA section. */
- public void stringTag(String name, String data) {
- beginTag(name, null);
- cdata(data);
- endTag(name);
- }
-
- /** Writes content. */
- public void content(String content) {
- // This method previously used a LineNumberReader, but that class is
- // susceptible to a form of DoS attack. It uses lots of memory and CPU if a
- // malicious client gives it input with very long lines.
- if (content != null) {
- indent++;
- final char[] chars = content.toCharArray();
- int prev = 0;
- for (int i = 0; i < chars.length; i++) {
- if (chars[i] == '\n'
- || chars[i] == '\r' && i + 1 < chars.length && chars[i + 1] == '\n') {
- displayIndent(out, indent);
- out.println(content.substring(prev, i));
- if (chars[i] == '\r') {
- ++i;
- }
- prev = i + 1;
- }
- }
- displayIndent(out, indent);
- out.println(content.substring(prev, chars.length));
- indent--;
- out.flush();
- }
- tagsWritten++;
- }
-
- /** Write header. Use default version 1.0. */
- public void header() {
- out.println("");
- out.flush();
- tagsWritten++;
- }
-
- /** Write header, take version as input. */
- public void header(String version) {
- out.print("");
- out.flush();
- tagsWritten++;
- }
-
- /**
- * Get the total number of tags written.
- *
- * @return the total number of tags written to the XML stream.
- */
- public int numTagsWritten() {
- return tagsWritten;
- }
-
- /** Print an XML attribute name and value for string val. */
- private static void printAtt(PrintWriter pw, String name, String val) {
- if (val != null /* && !val.equals("") */) {
- pw.print(" ");
- pw.print(name);
- pw.print("=\"");
- pw.print(escapeForQuoting(val));
- pw.print("\"");
- }
- }
-
- /**
- * Encode a String for XML output, displaying it to a PrintWriter. The String to be encoded is
- * displayed, except that special characters are converted into entities.
- *
- * @param input a String to convert.
- * @param out a PrintWriter to which to write the results.
- */
- private static void stringEncodeXML(String input, PrintWriter out) {
- for (int i = 0; i < input.length(); i++) {
- char c = input.charAt(i);
- switch (c) {
- case '<':
- case '>':
- case '"':
- case '\'':
- case '&':
- case '\t':
- case '\n':
- case '\r':
- out.print("" + (int) c + ";");
- break;
- default:
- out.print(c);
- }
- }
- }
-
- private static String escapeForQuoting(String val) {
- return StringEscaper.XML_NUMERIC_ESCAPER.escapeString(val);
- }
-
- /**
- * Returns whether a string contains any XML special characters.
- *
- *