Class PassXML
- All Implemented Interfaces:
SQLData
SQLXML to operate on XML data.
This class also serves as the mapping class for a composite type
javatest.onexml, the better to verify that SQLData
input/output works too. That's why it has to implement SQLData.
Everything mentioning the type XML here needs a conditional implementor tag in case of being loaded into a PostgreSQL instance built without that type.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic classClass that will mock anSQLXMLinstance, returning only binary or character stream data from a byte array or string supplied at construction.static classClass that will proxy methods to anotherSQLXMLclass. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionstatic voidConfigure aDOMResultto acceptCONTENT(a/k/a document fragment), not only the more restrictiveDOCUMENT.static <T extends Adjusting.XML.Parsing<? super T>>
TapplyAdjustments(ResultSet adjust, T axp) Apply adjustments (supplied as a row type with a named column for each desired adjustment and its value) to an instance ofAdjusting.XML.Parsing.static SQLXML"Echo" an XML parameter not by creating a new writableSQLXMLobject at all, but simply returning the passed-in readable one untouched.static SQLXMLJust likebounceXMLParameter(java.sql.SQLXML)but with parameter and return typed astext, and so usable on a PostgreSQL instance lacking the XML type.static SQLXMLcastTextXML(SQLXML sx) Just likebounceXMLParameter(java.sql.SQLXML)but with the parameter typed astextand the return type left as XML, so functions as a cast.static SQLXMLechoXMLParameter(SQLXML sx, int howin, int howout) Echo an XML parameter back, exercising seven different ways (howin => 1-7) of reading an SQLXML object, and seven (howout => 1-7) of returning one.static SQLXMLechoXMLParameter_(SQLXML sx, int howin, int howout) Echo an XML parameter back, but with parameter and return types of PostgreSQLtext.static SQLXMLensureClosed(Result r, SQLXML sx, int how) Ensure the closing of whatever method was used to add content to anSQLXMLobject.static SQLXMLinStringoutXML(String in) static StringinXMLoutString(SQLXML in) static StringLow-level XML echo where the Java parameter and return type are String.static SQLXMLlowLevelXMLEcho(SQLXML sx, int how, ResultSet adjust) Echo the XML parameter back, using lower-level manipulations thanechoXMLParameter.static SQLXMLlowLevelXMLEcho_(SQLXML sx, int how, ResultSet adjust) Text-typed variant of lowLevelXMLEcho (does not require XML type).static SQLXMLmockedXMLEcho(byte[] bytes) Supply a sequence of bytes to be the exact (encoded) content of an XML value, which will be returned; if the encoding is not UTF-8, the value should begin with an XML Decl that names the encoding.static SQLXMLmockedXMLEcho(String chars) Supply a sequence of characters to be the exact (Unicode) content of an XML value, which will be returned; if the value begins with an XML Decl that names an encoding, the content will be assumed to contain only characters representable in that encoding.static voidprepareXMLSchema(String name, SQLXML source, String lang, int how) Precompile a schemasourcein schema languagelangand save it (for the current session) asname.static voidprepareXMLTransform(String name, SQLXML source, int how, boolean enableExtensionFunctions, boolean builtin, ResultSet adjust) Precompile an XSL transformsourceand save it (for the current session) asname.static voidprepareXMLTransformWithJava(String name, SQLXML source, int how, boolean enableExtensionFunctions, boolean builtin, ResultSet adjust) Precompile an XSL transformsourceand save it (for the current session) asname, where the transform may call Java methods.static SQLXMLproxiedXMLEcho(SQLXML sx, int how) Proxy a PL/Java SQLXML source object as if it were of a non-PL/Java implementing class, to confirm that it can still be returned successfully to PostgreSQL.voidstatic SQLXMLtransformXML(String transformName, SQLXML source, int howin, int howout, ResultSet adjust, Boolean indent, Integer indentWidth) Transform some XML according to a named transform prepared withprepareXMLTransform.static voidunclosedSQLXML(int howmany, int how) Create and leave some number of SQLXML objects unclosed, unused, and unreferenced, as a test of reclamation.voidstatic SQLXMLTest the MappedUDT (in one direction anyway).static booleanxmlInStmtAndRS(ResultSet out) Create some XML, pass it to aSELECT ?prepared statement, retrieve it from the result set, and return it via the out-parameter result set of thisRECORD-returning function.static SQLXMLxmlTextNode(byte[] stuff, String encoding, int how, boolean inElement) Test serialization into the PostgreSQL server encoding by returning a text node, optionally wrapped in an element, containing the supplied stuff.
-
Constructor Details
-
Method Details
-
inXMLoutString
@Function(schema="javatest", implementor="postgresql_xml") public static String inXMLoutString(SQLXML in) throws SQLException - Throws:
SQLException
-
inStringoutXML
@Function(schema="javatest", implementor="postgresql_xml") public static SQLXML inStringoutXML(String in) throws SQLException - Throws:
SQLException
-
echoXMLParameter
@Function(schema="javatest", implementor="postgresql_xml", provides="echoXMLParameter") public static SQLXML echoXMLParameter(SQLXML sx, int howin, int howout) throws SQLException Echo an XML parameter back, exercising seven different ways (howin => 1-7) of reading an SQLXML object, and seven (howout => 1-7) of returning one.If howin => 0, the XML parameter is simply saved in a static. It can be read in a subsequent call with sx => null, but only in the same transaction.
The "echoing" is done (in the
echoXMLmethod below) using aTransformer, that is, the "TrAX" Transformation API for XML supplied in Java. It illustrates how an identityTransformercan be used to get the XML content from the source to the result for any of the APIs selectable by howin and howout.It also illustrates something else. When using StAX (6 for howin or howout) and XML of the
CONTENTflavor (multiple top-level elements, characters outside the top element, etc.), it is easy to construct examples that fail. The fault is not really with the StAX API, nor with TrAX proper, but with the small handful of bridge classes that were added to the JRE with StAX's first appearance, to make it interoperate with TrAX. It is not that those classes completely overlook theCONTENTcase: they make some efforts to handle it. Just not the right ones, and given the Java developers' usual reluctance to change such longstanding behavior, that's probably not getting fixed.Moral: StAX is a nice API, have no fear to use it directly in freshly-developed code, but: when using TrAX, make every effort to supply a
TransformerwithSourceandResultobjects of any kind other than StAX.- Throws:
SQLException
-
echoXMLParameter_
@Function(schema="javatest", name="echoXMLParameter", type="text") public static SQLXML echoXMLParameter_(@SQLType("text") SQLXML sx, int howin, int howout) throws SQLException Echo an XML parameter back, but with parameter and return types of PostgreSQLtext.The other version of this method needs a conditional implementor tag because it cannot be declared in a PostgreSQL instance that was built without
libxmlsupport and the PostgreSQLXMLtype. But this version can, simply by mapping theSQLXMLparameter and return types to the SQLtexttype. The Java code is no different.Note that it's possible for both declarations to coexist in PostgreSQL (because as far as it is concerned, their signatures are different), but these two Java methods cannot have the same name (because they differ only in annotations, not in the declared Java types). So, this one needs a slightly tweaked name, and a
nameattribute in the annotation so PostgreSQL sees the right name.- Throws:
SQLException
-
bounceXMLParameter
@Function(schema="javatest", implementor="postgresql_xml") public static SQLXML bounceXMLParameter(SQLXML sx) throws SQLException "Echo" an XML parameter not by creating a new writableSQLXMLobject at all, but simply returning the passed-in readable one untouched.- Throws:
SQLException
-
bounceXMLParameter_
@Function(schema="javatest", type="text", name="bounceXMLParameter") public static SQLXML bounceXMLParameter_(@SQLType("text") SQLXML sx) throws SQLException Just likebounceXMLParameter(java.sql.SQLXML)but with parameter and return typed astext, and so usable on a PostgreSQL instance lacking the XML type.- Throws:
SQLException
-
castTextXML
@Function(schema="javatest", implementor="postgresql_xml") public static SQLXML castTextXML(@SQLType("text") SQLXML sx) throws SQLException Just likebounceXMLParameter(java.sql.SQLXML)but with the parameter typed astextand the return type left as XML, so functions as a cast.Slower than the other cases, because it must verify that the input really is XML before blindly calling it a PostgreSQL XML type. But the speed compares respectably to PostgreSQL's own CAST(text AS xml), at least for larger values; I am seeing Java pull ahead right around 32kB of XML data and beat PG by a factor of 2 or better at sizes of 1 or 2 MB. Unsurprisingly, PG has the clear advantage when values are very short.
- Throws:
SQLException
-
prepareXMLTransform
@Function(schema="javatest", implementor="postgresql_xml", provides="prepareXMLTransform") public static void prepareXMLTransform(String name, SQLXML source, @SQLType(defaultValue="0") int how, @SQLType(defaultValue="false") boolean enableExtensionFunctions, @SQLType(defaultValue="true") boolean builtin, @SQLType(defaultValue={}) ResultSet adjust) throws SQLException Precompile an XSL transformsourceand save it (for the current session) asname.Each value of
how, 1-7, selects a different way of presenting theSQLXMLobject to the XSL processor.Passing
trueforenableExtensionFunctionsallows the transform to use extensions that the Java XSLT implementation supports, such as functions from EXSLT. Those are disabled by default.Passing
falseforbuiltinwill allow aTransformerFactoryother than Java's built-in one to be found using the usual search order and the context class loader (normally the PL/Java class path for the schema where this function is declared). The default oftrueensures that the built-in Java XSLT 1.0 implementation is used. A transformer implementation other than Xalan may not recognize the feature controlled byenableExtensionFunctions, so failure to configure that feature will be logged as a warning ifbuiltinisfalse, instead of thrown as an exception.Out of the box, Java's transformers only support XSLT 1.0. See the S9 example for more capabilities (at the cost of downloading the Saxon jar).
- Throws:
SQLException
-
prepareXMLTransformWithJava
@Function(schema="javatest", implementor="postgresql_xml", provides="prepareXMLTransform") public static void prepareXMLTransformWithJava(String name, SQLXML source, @SQLType(defaultValue="0") int how, @SQLType(defaultValue="false") boolean enableExtensionFunctions, @SQLType(defaultValue="true") boolean builtin, @SQLType(defaultValue={}) ResultSet adjust) throws SQLException Precompile an XSL transformsourceand save it (for the current session) asname, where the transform may call Java methods.Otherwise identical to
prepareXMLTransform, this version sets theTransformerFactory'sextensionClassLoader(to the context class loader, normally the PL/Java class path for the schema where this function is declared), so the transform will be able to use xalan's Java call syntax to call any public Java methods that would be accessible to this class. (That can make a big difference in usefulness for the otherwise rather limited XSLT 1.0.)As with
enableExtensionFunctions, failure by the transformer implementation to recognize or allow theextensionClassLoaderproperty will be logged as a warning ifbuiltinisfalse, rather than thrown as an exception.This example function will be installed with
EXECUTEpermission revoked fromPUBLIC, as it essentially confers the ability to create arbitrary new Java functions, so should only be granted to roles you would be willing to grantUSAGE ON LANGUAGE java.Because this function only prepares the transform, and
transformXMLapplies it, there is some division of labor in determining what limits apply to its behavior. The use of this method instead ofprepareXMLTransformdetermines whether the transform is allowed to see external Java methods at all; it will be the policy permissions granted totransformXMLthat control what those methods can do when the transform is applied. For now, that method is defined in the trusted/sandboxedjavalanguage, so this function could reasonably be granted to any role withUSAGEonjava. If, by contrast,transformXMLwere declared in the 'untrusted'javaU, it would be prudent to allow only superusers access to this function, just as only they canCREATE FUNCTIONin an untrusted language.- Throws:
SQLException
-
transformXML
@Function(schema="javatest", implementor="postgresql_xml", provides="transformXML") public static SQLXML transformXML(String transformName, SQLXML source, @SQLType(defaultValue="0") int howin, @SQLType(defaultValue="0") int howout, @SQLType(defaultValue={}) ResultSet adjust, @SQLType(optional=true) Boolean indent, @SQLType(optional=true) Integer indentWidth) throws SQLException Transform some XML according to a named transform prepared withprepareXMLTransform.Pass null for
transformNameto get a plain identity transform (not such an interesting thing to do, unless you also specify indenting).- Throws:
SQLException
-
prepareXMLSchema
@Function(schema="javatest", implementor="postgresql_xml") public static void prepareXMLSchema(String name, SQLXML source, String lang, int how) throws SQLException Precompile a schemasourcein schema languagelangand save it (for the current session) asname.Each value of
how, 1-7, selects a different way of presenting theSQLXMLobject to the schema parser.The
langparameter is a URI that identifies a known schema language. The only language a Java runtime is required to support is W3C XML Schema 1.0, with URIhttp://www.w3.org/2001/XMLSchema.- Throws:
SQLException
-
lowLevelXMLEcho
@Function(schema="javatest", implementor="postgresql_xml", provides="lowLevelXMLEcho") public static SQLXML lowLevelXMLEcho(SQLXML sx, int how, @SQLType(defaultValue={}) ResultSet adjust) throws SQLException Echo the XML parameter back, using lower-level manipulations thanechoXMLParameter.This illustrates how the simple use of
t.transform(src,rlt)inechoSQLXMLsubstitutes for a lot of fiddly case-by-case code, but when coding for a specific case, all the generality oftransformmay not be needed. It can be interesting to compare memory use when XML values are large.This method has been revised to demonstrate, even for low-level manipulations, how much fiddliness can now be avoided through use of the
Adjusting.XML.SourceResultclass, and how to make adjustments to parsing restrictions by passing the optional row-typed parameter adjust, which defaults to an empty row. For example, passingadjust => (select a from (true as allowdtd, true as expandentityreferences) as a)would allow a document that contains an internal DTD subset and uses entities defined there.The older, pre-
SourceResultcode for doing low-level XML echo has been moved to theoldSchoolLowLevelEchomethod below. It can still be exercised by calling this method, explicitly passingadjust => NULL.- Throws:
SQLException
-
applyAdjustments
public static <T extends Adjusting.XML.Parsing<? super T>> T applyAdjustments(ResultSet adjust, T axp) throws SQLException Apply adjustments (supplied as a row type with a named column for each desired adjustment and its value) to an instance ofAdjusting.XML.Parsing.Column names in the adjust row are case-insensitive versions of the method names in
Adjusting.XML.Parsing, and the value of each column should be of the appropriate type (if the method has a parameter).- Parameters:
adjust- A row type as described above, possibly of no columns if no adjustments are wantedaxp- An instance of Adjusting.XML.Parsing- Returns:
- axp, after applying any adjustments
- Throws:
SQLException
-
proxiedXMLEcho
@Function(schema="javatest", implementor="postgresql_xml", provides="proxiedXMLEcho") public static SQLXML proxiedXMLEcho(SQLXML sx, int how) throws SQLException Proxy a PL/Java SQLXML source object as if it were of a non-PL/Java implementing class, to confirm that it can still be returned successfully to PostgreSQL.- Parameters:
sx- readableSQLXMLobject to proxyhow- 1,2,4,5,6,7 determines what subclass ofSourcewill be returned bygetSource.- Throws:
SQLException
-
mockedXMLEcho
@Function(schema="javatest", implementor="postgresql_xml", provides="mockedXMLEchoB") public static SQLXML mockedXMLEcho(byte[] bytes) throws SQLException Supply a sequence of bytes to be the exact (encoded) content of an XML value, which will be returned; if the encoding is not UTF-8, the value should begin with an XML Decl that names the encoding.Constructs an
SQLXMLinstance that will return the supplied content as aStreamSourcewrapping anInputStream, or viagetBinaryStream, but fail if asked for any other form.- Throws:
SQLException
-
mockedXMLEcho
@Function(schema="javatest", implementor="postgresql_xml", provides="mockedXMLEchoC") public static SQLXML mockedXMLEcho(String chars) throws SQLException Supply a sequence of characters to be the exact (Unicode) content of an XML value, which will be returned; if the value begins with an XML Decl that names an encoding, the content will be assumed to contain only characters representable in that encoding.Constructs an
SQLXMLinstance that will return the supplied content as aStreamSourcewrapping aReader, or viagetCharacterStream, but fail if asked for any other form.- Throws:
SQLException
-
lowLevelXMLEcho_
@Function(schema="javatest", name="lowLevelXMLEcho", type="text") public static SQLXML lowLevelXMLEcho_(@SQLType("text") SQLXML sx, int how, @SQLType(defaultValue={}) ResultSet adjust) throws SQLException Text-typed variant of lowLevelXMLEcho (does not require XML type).- Throws:
SQLException
-
lowLevelXMLEcho
@Function(schema="javatest", implementor="postgresql_xml", type="xml") public static String lowLevelXMLEcho(@SQLType("xml") String x) throws SQLException Low-level XML echo where the Java parameter and return type are String.- Throws:
SQLException
-
xmlInStmtAndRS
@Function(schema="javatest", type="RECORD") public static boolean xmlInStmtAndRS(ResultSet out) throws SQLException Create some XML, pass it to aSELECT ?prepared statement, retrieve it from the result set, and return it via the out-parameter result set of thisRECORD-returning function.- Throws:
SQLException
-
xmlTextNode
@Function(schema="javatest", implementor="postgresql_xml") public static SQLXML xmlTextNode(byte[] stuff, String encoding, int how, boolean inElement) throws Exception Test serialization into the PostgreSQL server encoding by returning a text node, optionally wrapped in an element, containing the supplied stuff.The stuff is supplied as a
byteaand a named encoding, so it is easy to supply stuff that isn't in the server encoding and see what the serializer does with it.As of this writing, if the stuff, decoded according to encoding, contains characters that are not representable in the server encoding, the serializers supplied in the JRE will:
- SAX, DOM: replace the character with a numeric character reference if
the node is wrapped in an element, but not outside of an element; there,
PL/Java ensures an
UnmappableCharacterExceptionis thrown, as the serializer would otherwise silently lose information by replacing the character with a?. - StAX: replace the character with a numeric character reference whether
wrapped in an element or not (outside of an element, this officially
violates the letter of the XML spec, but does not lose information, and
is closer to the spirit of SQL/XML with its
XML(CONTENT)type).
- Parameters:
stuff- Content to be used in the text nodeencoding- Name of an encoding; stuff will be decoded to Unicode according to this encoding, and then serialized into the server encoding, where possible.how- Integer specifying which XML API to test, like every other how in this class; here the only valid choices are 5 (SAX), 6 (StAX), or 7 (DOM).inElement- True if the text node should be wrapped in an element.- Returns:
- The resulting XML content.
- Throws:
Exception
- SAX, DOM: replace the character with a numeric character reference if
the node is wrapped in an element, but not outside of an element; there,
PL/Java ensures an
-
unclosedSQLXML
@Function(schema="javatest") public static void unclosedSQLXML(int howmany, int how) throws SQLException Create and leave some number of SQLXML objects unclosed, unused, and unreferenced, as a test of reclamation.- Parameters:
howmany- Number of SQLXML instances to create.how- If nonzero, the flavor of writing to request on the object before abandoning it; if zero, it is left in its initial, writable state.- Throws:
SQLException
-
ensureClosed
Ensure the closing of whatever method was used to add content to anSQLXMLobject.Before a
SQLXMLobject that has been written to can be used by PostgreSQL (returned as a function result, plugged in as a prepared statement parameter or into aResultSet, etc.), the method used for writing it must be "closed" to ensure the writing is complete.If it is set with
setString, nothing more is needed;setStringobviously sets the whole value at once. AnyOutputStreamorWriterobtained fromsetBinaryStreamorsetCharacterStream, or fromsetResult(StreamResult.class), has to be explicitly closed (aTransformerdoes not close itsResultwhen the transformation is complete!). Those are cases 1, 2, and 4 here.Cases 5 (
SAXResult) and 6 (StAXResult) need no special attention; though theTransformerdoes not close them, the ones returned by thisSQLXMLimplementation are set up to close themselves when theendDocumentevent is written.Case 3 (test of
setStringis handled specially here. As this class allows testing of all techniques for writing theSQLXMLobject, and most of those involve aResult, case 3 is handled by also constructing aResultover aStringWriterand having the content written into that; this method then extracts the content from theStringWriterand passes it tosetString. For cases 1 and 2, likewise, the stream obtained withgetBinaryStreamorgetCharacterStreamhas been wrapped in aResultfor generality in this example.A typical application will not need the generality seen here; it will usually know which technique it is using to write the
SQLXMLobject, and only needs to know how to close that if it needs closing.- Parameters:
r- TheResultonto which writing was done.sx- TheSQLXMLobject being written.how- The integer used in this example class to select which method of writing theSQLXMLobject was to be tested.- Returns:
- The
SQLXMLobjectsx, because why not? - Throws:
SQLException
-
allowFragment
Configure aDOMResultto acceptCONTENT(a/k/a document fragment), not only the more restrictiveDOCUMENT.The other forms of
Resultthat can be requested will happily acceptXML(CONTENT)and not justXML(DOCUMENT). TheDOMResultis pickier, however: if you first callsetNodewith aDocumentFragment, it will accept either form, but if you leave the node unset when passing theDOMResultto a transformer, the transformer will default to putting aDocumentnode there, and then it will not accept a fragment.If you need to handle fragments, this method illustrates how to pre-load the
DOMResultwith an emptyDocumentFragment. Note that if you use some XML processing package that supplies its own classes implementing DOM nodes, you may need to use aDocumentFragmentinstance obtained from that package.- Throws:
SQLException
-
xmlFromComposite
@Function(schema="javatest", implementor="postgresql_xml") public static SQLXML xmlFromComposite() throws SQLExceptionTest the MappedUDT (in one direction anyway).Creates a
PassXMLobject, the Java class that maps thejavatest.onexmlcomposite type, which has one member, of XML type. Stores aSQLXMLvalue in that field of thePassXMLobject, and passes that to an SQL query that expects and returnsjavatest.onexml. Retrieves the XML from the value field of thePassXMLobject created to map the result of the query.- Returns:
- The original XML value, if all goes well.
- Throws:
SQLException
-
getSQLTypeName
- Specified by:
getSQLTypeNamein interfaceSQLData
-
readSQL
- Specified by:
readSQLin interfaceSQLData- Throws:
SQLException
-
writeSQL
- Specified by:
writeSQLin interfaceSQLData- Throws:
SQLException
-