/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.query.processor;
import static org.junit.Assert.*;
import static org.teiid.query.processor.TestProcessor.*;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.sql.Blob;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.TimeZone;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.transform.stax.StAXSource;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.teiid.api.exception.query.ExpressionEvaluationException;
import org.teiid.api.exception.query.QueryParserException;
import org.teiid.api.exception.query.QueryValidatorException;
import org.teiid.client.util.ResultsFuture;
import org.teiid.common.buffer.BufferManagerFactory;
import org.teiid.core.TeiidProcessingException;
import org.teiid.core.types.ArrayImpl;
import org.teiid.core.types.BinaryType;
import org.teiid.core.types.BlobImpl;
import org.teiid.core.types.BlobType;
import org.teiid.core.types.DataTypeManager;
import org.teiid.core.types.InputStreamFactory;
import org.teiid.core.types.XMLType;
import org.teiid.core.types.XMLType.Type;
import org.teiid.core.util.ObjectConverterUtil;
import org.teiid.core.util.PropertiesUtils;
import org.teiid.core.util.TimestampWithTimezone;
import org.teiid.core.util.UnitTestUtil;
import org.teiid.metadata.MetadataStore;
import org.teiid.metadata.Schema;
import org.teiid.metadata.Table;
import org.teiid.query.mapping.relational.QueryNode;
import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.metadata.TransformationMetadata;
import org.teiid.query.optimizer.capabilities.CapabilitiesFinder;
import org.teiid.query.optimizer.capabilities.DefaultCapabilitiesFinder;
import org.teiid.query.parser.QueryParser;
import org.teiid.query.sql.lang.Command;
import org.teiid.query.sql.symbol.Expression;
import org.teiid.query.unittest.RealMetadataFactory;
import org.teiid.query.unittest.TimestampUtil;
import org.teiid.query.util.CommandContext;
import org.teiid.util.StAXSQLXML;
@SuppressWarnings({"nls", "unchecked"})
public class TestSQLXMLProcessing {
@Test public void testXmlElementTextContent() throws Exception {
String sql = "SELECT xmlelement(foo, '<bar>', convert('<bar1/>', xml))"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<foo><bar><bar1/></foo>"),
};
process(sql, expected);
}
/**
* Repeat of the above test, but with a document declaration. Because of the way we do event filtering, we end
* up with a slightly different, but equivalent answer.
*/
@Test public void testXmlElementTextContent1() throws Exception {
String sql = "SELECT xmlelement(foo, '<bar>', convert('<?xml version=\"1.0\" encoding=\"UTF-8\"?><bar1/>', xml))"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<foo><bar><bar1></bar1></foo>"),
};
process(sql, expected);
}
@Test public void testXmlElement() throws Exception {
String sql = "SELECT xmlelement(e1, e2) from pm1.g1 order by e1, e2"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<e1>1</e1>"),
Arrays.asList("<e1>0</e1>"),
Arrays.asList("<e1>0</e1>"),
Arrays.asList("<e1>3</e1>"),
Arrays.asList("<e1>2</e1>"),
Arrays.asList("<e1>1</e1>"),
};
process(sql, expected);
}
@Test public void testXmlElementWithConcat() throws Exception {
String sql = "SELECT xmlelement(e1, e2, xmlconcat(xmlelement(x), xmlelement(y, e3))) from pm1.g1 order by e1, e2"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<e1>1<x></x><y>false</y></e1>"),
Arrays.asList("<e1>0<x></x><y>false</y></e1>"),
Arrays.asList("<e1>0<x></x><y>false</y></e1>"),
Arrays.asList("<e1>3<x></x><y>true</y></e1>"),
Arrays.asList("<e1>2<x></x><y>false</y></e1>"),
Arrays.asList("<e1>1<x></x><y>true</y></e1>"),
};
process(sql, expected);
}
@Test public void testXmlElementWithForest() throws Exception {
String sql = "SELECT xmlelement(x, xmlforest(e1, e2, '1' as val)) from pm1.g1 order by e1, e2 limit 2"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<x><e2>1</e2><val>1</val></x>"), //note e1 is not present, because it's null
Arrays.asList("<x><e1>a</e1><e2>0</e2><val>1</val></x>"),
};
process(sql, expected);
}
@Test(expected=QueryValidatorException.class) public void testXmlForestWithArray() throws Exception {
String sql = "SELECT xmlforest((1,2) as val)"; //$NON-NLS-1$
process(sql, null);
}
@Test public void testXmlForestWithBinary() throws Exception {
String sql = "SELECT xmlforest(X'AB' as val)"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<val>qw==</val>"),
};
process(sql, expected);
}
@Test public void testXmlForestWithBlob() throws Exception {
String sql = "SELECT xmlforest(cast(X'AB' as blob) as val)"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<val>qw==</val>"),
};
process(sql, expected);
}
@Test public void testXmlElementWithForestView() throws Exception {
String sql = "SELECT xmlelement(x, xmlforest(x, y, '1' as val)) from (select e1 as x, e2 as y from pm1.g1) a order by x, y limit 2"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<x><y>1</y><val>1</val></x>"), //note e1 is not present, because it's null
Arrays.asList("<x><x>a</x><y>0</y><val>1</val></x>"),
};
process(sql, expected);
}
@Test public void testXmlElementWithAttributes() throws Exception {
String sql = "SELECT xmlelement(x, xmlattributes(e1, e2, '1' as val)) from pm1.g1 order by e1, e2 limit 2"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<x e2=\"1\" val=\"1\"></x>"), //note e1 is not present, because it's null
Arrays.asList("<x e1=\"a\" e2=\"0\" val=\"1\"></x>"),
};
process(sql, expected);
}
@Test public void testXmlElementWithPi() throws Exception {
String sql = "SELECT xmlelement(x, xmlpi(name e1, ' 1'))"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<x><?e1 1?></x>"),
};
process(sql, expected);
}
@Test public void testXmlElementWithNamespaces() throws Exception {
String sql = "SELECT xmlelement(x, xmlnamespaces(no default, 'http://foo' as x, 'http://foo1' as y), xmlattributes(e1), e2) from pm1.g1 order by e1, e2 limit 2"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<x xmlns=\"\" xmlns:x=\"http://foo\" xmlns:y=\"http://foo1\">1</x>"), //note e1 is not present, because it's null
Arrays.asList("<x xmlns=\"\" xmlns:x=\"http://foo\" xmlns:y=\"http://foo1\" e1=\"a\">0</x>"),
};
process(sql, expected);
}
@Test public void testXmlAgg() throws Exception {
String sql = "SELECT xmlelement(parent, xmlAgg(xmlelement(x, xmlattributes(e1, e2)))) from pm1.g1"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<parent><x e1=\"a\" e2=\"0\"></x><x e2=\"1\"></x><x e1=\"a\" e2=\"3\"></x><x e1=\"c\" e2=\"1\"></x><x e1=\"b\" e2=\"2\"></x><x e1=\"a\" e2=\"0\"></x></parent>"),
};
process(sql, expected);
}
@Test public void testXmlAggOrderBy() throws Exception {
String sql = "SELECT xmlelement(parent, xmlAgg(xmlelement(x, xmlattributes(e1, e2)) order by e2)) from pm1.g1"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<parent><x e1=\"a\" e2=\"0\"></x><x e1=\"a\" e2=\"0\"></x><x e2=\"1\"></x><x e1=\"c\" e2=\"1\"></x><x e1=\"b\" e2=\"2\"></x><x e1=\"a\" e2=\"3\"></x></parent>"),
};
process(sql, expected);
}
@Test public void testXmlSerialize() throws Exception {
String sql = "SELECT xmlserialize(document xmlelement(parent) as string)"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<parent></parent>"),
};
process(sql, expected);
}
@Test public void testXmlSerialize1() throws Exception {
String sql = "SELECT xmlserialize(document xmlelement(parent) as string including xmldeclaration)"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<?xml version=\"1.0\" encoding=\"UTF-8\"?><parent></parent>"),
};
process(sql, expected);
}
@Test public void testXmlSerialize2() throws Exception {
String sql = "SELECT xmlserialize(document xmlelement(parent) as string version '1.2' including xmldeclaration)"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<?xml version=\"1.2\" encoding=\"UTF-8\"?><parent></parent>"),
};
process(sql, expected);
}
@Test public void testXmlSerializeBinary() throws Exception {
String sql = "SELECT xmlserialize(document xmlelement(parent) as varbinary version '1.2' including xmldeclaration)"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList(new BinaryType("<?xml version=\"1.2\" encoding=\"UTF-8\"?><parent></parent>".getBytes(Charset.forName("UTF-8")))),
};
process(sql, expected);
}
@Test public void testXmlSerializeBinary1() throws Exception {
String sql = "SELECT xmlserialize(document xmlelement(parent) as varbinary encoding \"UTF-16\" version '1.2' including xmldeclaration)"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList(new BinaryType("<?xml version=\"1.2\" encoding=\"UTF-16\"?><parent></parent>".getBytes(Charset.forName("UTF-16")))),
};
process(sql, expected);
}
@Test public void testXmlSerializeBinary2() throws Exception {
String sql = "SELECT cast(xmlserialize(document xmlelement(other) as blob encoding \"UTF-16\" version '1.2' including xmldeclaration) as varbinary)"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList(new BinaryType("<?xml version=\"1.2\" encoding=\"UTF-16\"?><other></other>".getBytes(Charset.forName("UTF-16")))),
};
process(sql, expected);
}
/**
* if not specifically excluding, then leave the declaration intact (pre-8.2 behavior)
*/
@Test public void testXmlSerialize3() throws Exception {
String sql = "SELECT xmlserialize(document xmlparse(document '<?xml version=\"1.1\" encoding=\"UTF-8\"?><a></a>') as string)"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<?xml version=\"1.1\" encoding=\"UTF-8\"?><a></a>"),
};
process(sql, expected);
}
@Test public void testXmlTable() throws Exception {
String sql = "select * from xmltable('/a/b' passing convert('<a><b>first</b><b x=\"attr\">second</b></a>', xml) columns x string path '@x', val string path '/.') as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList(null, "first"),
Arrays.asList("attr", "second"),
};
process(sql, expected);
}
@Test(expected=QueryParserException.class) public void testXmlTableWithComplexIdentifier() throws Exception {
String sql = "select * from xmltable('/a/b' passing convert('<a><b>first</b><b x=\"attr\">second</b></a>', xml) columns \"x.y\" string path '@x', val string path '/.') as x"; //$NON-NLS-1$
QueryParser.getQueryParser().parseCommand(sql);
}
@Test public void testXmlTableNull() throws Exception {
String sql = "select * from xmltable('/a/b' passing convert(null, xml) columns x string path '@x', val string path '/.') as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
};
process(sql, expected);
}
@Test(expected=TeiidProcessingException.class) public void testXmlTableSequence() throws Exception {
String sql = "select * from xmltable('/a' passing convert('<a><b>first</b><b x=\"attr\">second</b></a>', xml) columns x string path 'b') as x"; //$NON-NLS-1$
process(sql, null);
}
@Test public void testXmlTableSequenceArray() throws Exception {
String sql = "select * from xmltable('/a' passing convert('<a><b>first</b><b x=\"attr\">second</b></a>', xml) columns x string[] path 'b') as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList(new ArrayImpl("first", "second")),
};
process(sql, expected);
}
@Test public void testXmlTableSequenceArraySingle() throws Exception {
String sql = "select * from xmltable('/a' passing convert('<a><b>first</b></a>', xml) columns x string[] path 'b') as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList(new ArrayImpl("first")),
};
process(sql, expected);
}
/**
* TODO: we should allow explicit null on empty / empty on empty behavior with array values
* @throws Exception
*/
@Test public void testXmlTableSequenceArrayEmpty() throws Exception {
String sql = "select * from xmltable('/a' passing convert('<a></a>', xml) columns x string[] path 'b') as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Collections.singletonList(null)
};
process(sql, expected);
}
@Test public void testXmlTableBinary() throws Exception {
String sql = "select * from xmltable('/a/b' passing convert('<a xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><b xsi:type=\"xs:hexBinary\">0FAB</b><b>1F1C</b></a>', xml) columns val varbinary path '/.') as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList(new BinaryType(new byte[] {0xf, (byte)0xab})),
Arrays.asList(new BinaryType(new byte[] {0x1F, 0x1C})),
};
process(sql, expected);
}
@Test public void testXmlTableBOM() throws Exception {
String sql = "select * from xmltable('/a' passing xmlparse(document X'EFBBBF" + PropertiesUtils.toHex("<a/>".getBytes("UTF-8")) + "' wellformed)) as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<a/>"),
};
process(sql, expected);
}
@Test public void testXsiNil() throws Exception {
String sql = "select * from xmltable('/a/b' passing convert('<a xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><b xsi:nil=\"true\" xsi:type=\"xs:int\"/><b>1</b></a>', xml) columns val integer path '.') as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Collections.singletonList(null),
Arrays.asList(1),
};
process(sql, expected);
}
@Test(expected=TeiidProcessingException.class) public void testXmlTableAsynchError() throws Exception {
String sql = "select * from xmltable('/a/b' passing convert('<a><b>first</b><b x=\"attr\">second</b></a>', xml) columns x blob path '@x', val string path '/.') as x"; //$NON-NLS-1$
process(sql, null);
}
@Test public void testXmlTableNumeric() throws Exception {
String sql = "select * from xmltable('/a' passing convert('<a s=\"1\" d=\"2.0\" l=\"12345678901\"/>', xml) columns x short path '@s', x1 double path '@d', z long path '@l') as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList((short)1, 2.0, 12345678901l)
};
process(sql, expected);
}
@Test public void testXmlTableDateTime() throws Exception {
String sql = "select * from xmltable('/a' passing convert('<a dt=\"0001-11-17T07:38:49\" dtz=\"2011-11-17T07:38:49Z\" t=\"13:23:14\" d=\"2010-04-05\" />', xml) columns x timestamp path '@dt', x1 timestamp path '@dtz', y date path '@d', z time path '@t') as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList(TimestampUtil.createTimestamp(-1899, 10, 19, 7, 38, 49, 0), TimestampUtil.createTimestamp(111, 10, 17, 1, 38, 49, 0), TimestampUtil.createDate(110, 3, 5), TimestampUtil.createTime(13, 23, 14))
};
process(sql, expected);
}
@Test public void testXmlTableDateTimeInDST() throws Exception {
TimestampWithTimezone.resetCalendar(TimeZone.getTimeZone("PST")); //$NON-NLS-1$
try {
String sql = "select * from xmltable('/a' passing convert('<a dt=\"2011-11-01T09:38:49\" dtz=\"2011-11-01T07:38:49Z\"/>', xml) columns x timestamp path '@dt', x1 timestamp path '@dtz') as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList(TimestampUtil.createTimestamp(111, 10, 1, 9, 38, 49, 0), TimestampUtil.createTimestamp(111, 10, 1, 0, 38, 49, 0))
};
process(sql, expected);
} finally {
TimestampWithTimezone.resetCalendar(TimeZone.getTimeZone("GMT-06:00")); //$NON-NLS-1$
}
}
@Test public void testXmlTablePassingSubquery() throws Exception {
String sql = "select * from xmltable('/a/b' passing (SELECT xmlelement(name a, xmlAgg(xmlelement(name b, e1))) from pm1.g1) columns val string path '/.') as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("a"),
Arrays.asList(""),
Arrays.asList("a"),
Arrays.asList("c"),
Arrays.asList("b"),
Arrays.asList("a")
};
process(sql, expected);
}
@Test public void testXmlTableInView() throws Exception {
String sql = "select * from g1"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList(null, "first"),
Arrays.asList("attr", "second"),
};
MetadataStore metadataStore = new MetadataStore();
// Create models
Schema vm1 = RealMetadataFactory.createVirtualModel("vm1", metadataStore); //$NON-NLS-1$
QueryNode vm1g1n1 = new QueryNode("select * from xmltable('/a/b' passing convert('<a><b>first</b><b x=\"attr\">second</b></a>', xml) columns x string path '@x', val string path '/.') as x"); //$NON-NLS-1$ //$NON-NLS-2$
Table vm1g1 = RealMetadataFactory.createVirtualGroup("g1", vm1, vm1g1n1); //$NON-NLS-1$
RealMetadataFactory.createElements(vm1g1,
new String[] { "x", "val" }, //$NON-NLS-1$
new String[] { DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.STRING });
// Create the facade from the store
TransformationMetadata metadata = RealMetadataFactory.createTransformationMetadata(metadataStore, "example");
ProcessorPlan plan = helpGetPlan(helpParse(sql), metadata, new DefaultCapabilitiesFinder(), createCommandContext());
helpProcess(plan, createCommandContext(), dataManager, expected);
plan = helpGetPlan(helpParse(sql), metadata, new DefaultCapabilitiesFinder(), createCommandContext());
doProcess(plan, dataManager, expected, createCommandContext());
}
@Test public void testXmlTableDefaultAndParent() throws Exception {
String sql = "select * from xmltable('/a/b' passing convert('<a y=\"rev\"><b>first</b><b x=\"1\">second</b></a>', xml) columns x integer default -1 path '@x' , val string path '../@y') as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList(-1, "rev"),
Arrays.asList(1, "rev"),
};
process(sql, expected);
}
@Test public void testXmlTableReturnXml() throws Exception {
String sql = "select * from xmltable('/*:a/*:b' passing convert('<a xmlns=\"http:foo\"><b>first</b><b xmlns=\"\" x=\"1\">second</b></a>', xml) columns val xml path '.') as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<b xmlns=\"http:foo\">first</b>"),
Arrays.asList("<b x=\"1\">second</b>"),
};
process(sql, expected);
}
@Test public void testXmlTableNoColumns() throws Exception {
String sql = "select * from xmltable('/a' passing convert('<a><b>first</b><b x=\"1\">second</b></a>', xml)) as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<a><b>first</b><b x=\"1\">second</b></a>"),
};
process(sql, expected);
}
@Test public void testXmlTablePassing() throws Exception {
String sql = "select * from xmltable('<root>{for $x in $a/a/b return <c>{$x}</c>}</root>' passing convert('<a><b>first</b><b x=\"1\">second</b></a>', xml) as a columns x xml path 'c[1]/b') as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<b>first</b>"),
};
process(sql, expected);
}
@Test public void testXmlTableForOrdinalityAndDefaultPath() throws Exception {
String sql = "select * from xmltable('/a/b' passing convert('<a><b><c>1</c></b><b>1</b><b><c>1</c></b><b>1</b></a>', xml) columns x for ordinality, c integer) as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList(1, 1),
Arrays.asList(2, null),
Arrays.asList(3, 1),
Arrays.asList(4, null),
};
ProcessorPlan plan = process(sql, expected);
assertEquals(DataTypeManager.DefaultDataClasses.INTEGER, ((Expression)plan.getOutputElements().get(0)).getType());
}
@Test public void testXmlTableDescendantPath() throws Exception {
String sql = "select * from xmltable('<a>{for $i in (1 to 5) return $i}</a>' columns x string path '//text()') as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("1 2 3 4 5"),
};
process(sql, expected);
}
@Test public void testXmlQuery() throws Exception {
String sql = "select xmlquery('for $i in (1 to 5) return $i')"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("1 2 3 4 5"),
};
process(sql, expected);
}
@Test public void testXmlExists() throws Exception {
String sql = "select xmlexists('for $i in (1 to 1) return $i'), xmlexists('for $i in (1 to 0) return $i')"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList(true, false),
};
process(sql, expected);
}
@Test public void testXmlQueryNull() throws Exception {
String sql = "select xmlquery('/a' passing cast(null as xml))"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Collections.singletonList(null),
};
process(sql, expected);
}
@Test public void testXmlQueryEmptyNull() throws Exception {
String sql = "select xmlquery('/a' passing xmlparse(document '<x/>') null on empty)"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList((String)null)
};
process(sql, expected);
}
@Test public void testXmlQueryEmptyNullString() throws Exception {
String sql = "select xmlquery('/a/b' passing xmlparse(document '<x/>') null on empty)"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList((String)null)
};
process(sql, expected);
}
@Test public void testXmlQueryStreaming() throws Exception {
String sql = "select xmlquery('/a/b' passing xmlparse(document '<a><b x=''1''/><b x=''2''/></a>') null on empty)"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<b x=\"1\"/><b x=\"2\"/>")
};
process(sql, expected);
}
@Test public void testXmlTableStreamingTiming() throws Throwable {
String sql = "select xmlserialize(x.object_value as string), y.x from xmltable('/a/b' passing xmlparse(document '<a><b x=''1''/><b x=''2''/></a>')) as x, (select 1 as x) as y"; //$NON-NLS-1$
final List<?>[] expected = new List<?>[] {
Arrays.asList("<b x=\"1\"/>", 1),
Arrays.asList("<b x=\"2\"/>", 1)
};
executeStreaming(sql, expected, -1);
}
@Test public void testXmlTableStreamingMultibatch() throws Throwable {
String sql = "select t.* from (select xmlelement(a, xmlagg(xmlelement(b, e1))) doc from pm1.g1) as x, xmltable('/a/b' passing doc columns x string path '.') as t"; //$NON-NLS-1$
final List<?>[] expected = new List<?>[] {
Arrays.asList("a"),
Arrays.asList(""),
Arrays.asList("a"),
Arrays.asList("c"),
Arrays.asList("b"),
Arrays.asList("a")
};
dataManager.setBlockOnce();
executeStreaming(sql, expected, 2);
}
@Test(expected=TeiidProcessingException.class) public void testXmlTableStreamingTimingWithError() throws Throwable {
String sql = "select x.x, y.x from xmltable('/a/b' passing xmlparse(document '<a><b x=''1''/><b x=''2''/></a>') columns x integer path '1 div (@x - 1)') as x, (select 1 as x) as y"; //$NON-NLS-1$
final List<?>[] expected = new List<?>[] {
Arrays.asList(1, 1),
Arrays.asList(2, 1)
};
executeStreaming(sql, expected, -1);
}
private void executeStreaming(String sql, final List<?>[] expected, int batchSize)
throws Throwable {
final CommandContext cc = createCommandContext();
if (batchSize != -1) {
cc.setBufferManager(BufferManagerFactory.getTestBufferManager(0, 1));
}
final ResultsFuture<Runnable> r = new ResultsFuture<Runnable>();
Executor ex = new Executor() {
@Override
public void execute(Runnable command) {
r.getResultsReceiver().receiveResults(command);
}
};
cc.setExecutor(ex);
final ProcessorPlan plan = helpGetPlan(helpParse(sql), RealMetadataFactory.example1Cached(), new DefaultCapabilitiesFinder(), cc);
final ResultsFuture<Void> result = new ResultsFuture<Void>();
Thread t = new Thread() {
@Override
public void run() {
try {
doProcess(plan, dataManager, expected, cc);
result.getResultsReceiver().receiveResults(null);
} catch (Throwable e) {
result.getResultsReceiver().exceptionOccurred(e);
}
}
};
t.start();
Runnable runnable = r.get();
runnable.run();
try {
result.get();
} catch (ExecutionException e) {
if (e.getCause() != null) {
throw e.getCause();
}
throw e;
}
}
@Test public void testXmlNameEscaping() throws Exception {
String sql = "select xmlforest(\"xml\") from (select 1 as \"xml\") x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<_u0078_ml>1</_u0078_ml>")
};
process(sql, expected);
}
@Test public void testXmlParseDoc() throws Exception {
String sql = "select xmlparse(document '<a/>')"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<a/>")
};
process(sql, expected);
}
@Test(expected=ExpressionEvaluationException.class) public void testXmlParseDocException() throws Exception {
String sql = "select xmlparse(document 'a<a/>')"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
};
process(sql, expected);
}
@Test public void testXmlParseContent() throws Exception {
String sql = "select xmlparse(content 'a<a/>')"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("a<a/>")
};
process(sql, expected);
}
@Test public void testXmlParseBOM() throws Exception {
String sql = "select xmlparse(content X'EFBBBF" + PropertiesUtils.toHex("<a/>".getBytes("UTF-8")) + "')"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<a/>")
};
process(sql, expected);
}
@Test(expected=ExpressionEvaluationException.class) public void testXmlParseContentException() throws Exception {
String sql = "select xmlparse(content 'a<')"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
};
process(sql, expected);
}
//by pass the validation
@Test public void testXmlParseContentWellformed() throws Exception {
String sql = "select xmlparse(content 'a<' WELLFORMED)"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("a<")
};
process(sql, expected);
}
@Test public void testXmlParseClob() throws Exception {
String sql = "select xmlparse(document cast(? as clob)) x"; //$NON-NLS-1$
List[] expected = new List[] {
Arrays.asList(ObjectConverterUtil.convertToString(new FileInputStream(UnitTestUtil.getTestDataFile("udf.xmi")))),
};
processPreparedStatement(sql, expected, dataManager, new DefaultCapabilitiesFinder(), RealMetadataFactory.example1Cached(), Arrays.asList(TestTextTable.clobFromFile("udf.xmi")));
}
@Test public void testXmlParseBlob() throws Exception {
String sql = "select xmlparse(document cast(? as blob)) x"; //$NON-NLS-1$
List[] expected = new List[] {
Arrays.asList(ObjectConverterUtil.convertToString(new FileInputStream(UnitTestUtil.getTestDataFile("udf.xmi")))),
};
processPreparedStatement(sql, expected, dataManager, new DefaultCapabilitiesFinder(), RealMetadataFactory.example1Cached(), Arrays.asList(blobFromFile("udf.xmi")));
}
@Test public void testXmlParseBlobWithEncoding() throws Exception {
String sql = "select xmlparse(document cast(? as blob)) x"; //$NON-NLS-1$
List[] expected = new List[] {
Arrays.asList(ObjectConverterUtil.convertToString(new InputStreamReader(new FileInputStream(UnitTestUtil.getTestDataFile("encoding.xml")), Charset.forName("ISO-8859-1")))),
};
processPreparedStatement(sql, expected, dataManager, new DefaultCapabilitiesFinder(), RealMetadataFactory.example1Cached(), Arrays.asList(blobFromFile("encoding.xml")));
}
@Test public void testXmlTableTypes() throws Exception {
String sql = "select * from xmltable('/a' passing xmlparse(document '<a>2000-01-01T01:01:00.2-06:00</a>') columns x timestamp path 'xs:dateTime(./text())', y timestamp path '.') as x"; //$NON-NLS-1$
Timestamp ts = TimestampUtil.createTimestamp(100, 0, 1, 1, 1, 0, 200000000);
List<?>[] expected = new List<?>[] {
Arrays.asList(ts, ts),
};
process(sql, expected);
}
@Test public void testXmlTableStreamingParentAttributes() throws Exception {
String sql = "select * from xmltable('/a/b' passing xmlparse(document '<a x=''1''><b>foo</b></a>') columns y string path '.', x integer path '../@x') as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("foo", 1),
};
process(sql, expected);
}
/**
* Highlights that the PathMapFilter needs to be selective in calling startContent
* @throws Exception
*/
@Test public void testXmlStreamingError() throws Exception {
String sql = "select * from xmltable('/a/a' passing xmlparse(document '<a><a>2000-01-01T01:01:00.2-06:00<a></a></a></a>') columns x timestamp path 'xs:dateTime(./text())') as x"; //$NON-NLS-1$
Timestamp ts = TimestampUtil.createTimestamp(100, 0, 1, 1, 1, 0, 200000000);
List<?>[] expected = new List<?>[] {
Arrays.asList(ts),
};
process(sql, expected);
}
@Test public void testXmlTableSubquery() throws Exception {
String sql = "select * from xmltable('/a/b' passing convert('<a><b>first</b><b x=\"attr\">c</b></a>', xml) columns x string path '@x', val string path '/.') as x where val = (select max(e1) from pm1.g1 as x)";
List[] expected = new List[] {
Arrays.asList("attr", "c"),
};
process(sql, expected);
}
private static FakeDataManager dataManager = new FakeDataManager();
@BeforeClass public static void oneTimeSetUp() {
TimestampWithTimezone.resetCalendar(TimeZone.getTimeZone("GMT-06:00")); //$NON-NLS-1$
sampleData1(dataManager);
}
@AfterClass public static void oneTimeTearDown() {
TimestampWithTimezone.resetCalendar(null); //$NON-NLS-1$
}
private ProcessorPlan process(String sql, List<?>[] expected) throws Exception {
CommandContext cc = createCommandContext();
ProcessorPlan plan = helpGetPlan(helpParse(sql), RealMetadataFactory.example1Cached(), new DefaultCapabilitiesFinder(), cc);
helpProcess(plan, cc, dataManager, expected);
return plan;
}
public static BlobType blobFromFile(final String file) {
return new BlobType(new BlobImpl(new InputStreamFactory.FileInputStreamFactory(UnitTestUtil.getTestDataFile(file))));
}
@Test public void testXmlTableWithDefault() throws Exception {
String sql = "select * from xmltable(XMLNAMESPACES(default 'http://x.y.com'), '/a/b' passing convert('<a xmlns=\"http://x.y.com\"><b>first</b><b x=\"attr\">second</b></a>', xml) columns x string path '@x', val string path '/.') as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList(null, "first"),
Arrays.asList("attr", "second"),
};
process(sql, expected);
}
@Test public void testXmlAggNested() throws Exception {
String sql = "SELECT XMLELEMENT(NAME metadata, XMLFOREST(e1), (SELECT XMLAGG(XMLELEMENT(NAME subTypes, XMLFOREST(e1))) FROM pm1.g2 AS b WHERE b.e1 = a.e1)) FROM pm1.g1 AS a where e1 = 'a' GROUP BY e1"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("<metadata><e1>a</e1><subTypes><e1>a</e1></subTypes><subTypes><e1>a</e1></subTypes><subTypes><e1>a</e1></subTypes></metadata>"),
};
process(sql, expected);
}
@Test public void testJsonStreamingXmlTable() throws Exception {
String sql = "select * from xmltable('/Person/phoneNumber' passing jsontoxml('Person', cast(? as blob)) columns x string path 'type', y string path 'number') as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("home", "212 555-1234"),
Arrays.asList("fax", "646 555-4567"),
};
Blob b = BlobType.createBlob(("{ \"firstName\": \"John\", \"lastName\": \"Smith\", \"age\": 25, \"address\": { \"streetAddress\": \"21 2nd Street\", \"city\": \"New York\", \"state\": \"NY\", "+
"\"postalCode\": \"10021\" }, \"phoneNumber\": [ { \"type\": \"home\", \"number\": \"212 555-1234\" }, { \"type\": \"fax\", \"number\": \"646 555-4567\" } ] }").getBytes(Charset.forName("UTF-8")));
processPreparedStatement(sql, expected, dataManager, new DefaultCapabilitiesFinder(), RealMetadataFactory.example1Cached(), Arrays.asList(b));
}
@Test public void testStaxComment() throws Exception {
String sql = "select * from xmltable('/*:Person/phoneNumber' passing cast(? as xml) columns x string path 'type', y string path 'number') as x"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList(null, "8881112222"),
};
XMLInputFactory factory = XMLInputFactory.newFactory();
XMLEventReader reader = factory.createXMLEventReader(new StringReader("<Person><!--hello--><phoneNumber><number>8881112222</number></phoneNumber></Person>"));
XMLType value = new XMLType(new StAXSQLXML(new StAXSource(reader)));
value.setType(Type.DOCUMENT);
Command command = helpParse(sql);
CommandContext context = createCommandContext();
QueryMetadataInterface metadata = RealMetadataFactory.example1Cached();
context.setMetadata(metadata);
CapabilitiesFinder capFinder = new DefaultCapabilitiesFinder();
ProcessorPlan plan = helpGetPlan(command, metadata, capFinder, context);
setParameterValues(Arrays.asList(value), command, context);
doProcess(plan, dataManager, expected, context);
}
@Test(expected=ExpressionEvaluationException.class) public void testExternalEntityResolving() throws Exception {
String sql = "SELECT xmlelement(foo, '<bar>', convert('<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE foo [<!ENTITY xxe SYSTEM \"file:///etc/passwd\">]><bar1>&xxe;</bar1>', xml))"; //$NON-NLS-1$
process(sql, null);
}
@Test public void testXmlText() throws Exception {
String sql = "SELECT xmlserialize(xmltext('foo&bar') as string)"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Arrays.asList("foo&bar"),
};
process(sql, expected);
}
@Test(expected=TeiidProcessingException.class) public void testInvalidXmlComment() throws Exception {
String sql = "SELECT xmlcomment('--')"; //$NON-NLS-1$
process(sql, null);
}
@Test public void testXmlCast() throws Exception {
String sql = "select xmlcast(xmlquery('/a/b' passing convert('<a><b>1</b></a>', xml)) as integer)"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Collections.singletonList(1),
};
assertEquals("SELECT XMLCAST(XMLQUERY('/a/b' PASSING convert('<a><b>1</b></a>', xml)) AS integer)", TestProcessor.helpParse(sql).toString());
process(sql, expected);
}
@Test public void testXmlCast1() throws Exception {
String sql = "select xmlcast(cast('2000-01-01 00:00:00' as timestamp) as xml)"; //$NON-NLS-1$
List<?>[] expected = new List<?>[] {
Collections.singletonList("2000-01-01T06:00:00Z"),
};
process(sql, expected);
}
}