Source Code Cross Referenced for XML.java in  » Database-DBMS » db-derby-10.2 » org » apache » derby » iapi » types » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database DBMS » db derby 10.2 » org.apache.derby.iapi.types 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:
003:           Derby - Class org.apache.derby.iapi.types.XML
004:
005:           Licensed to the Apache Software Foundation (ASF) under one or more
006:           contributor license agreements.  See the NOTICE file distributed with
007:           this work for additional information regarding copyright ownership.
008:           The ASF licenses this file to you under the Apache License, Version 2.0
009:           (the "License"); you may not use this file except in compliance with
010:           the License.  You may obtain a copy of the License at
011:
012:              http://www.apache.org/licenses/LICENSE-2.0
013:
014:           Unless required by applicable law or agreed to in writing, software
015:           distributed under the License is distributed on an "AS IS" BASIS,
016:           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017:           See the License for the specific language governing permissions and
018:           limitations under the License.
019:
020:         */
021:
022:        package org.apache.derby.iapi.types;
023:
024:        import org.apache.derby.iapi.error.StandardException;
025:
026:        import org.apache.derby.iapi.services.cache.ClassSize;
027:        import org.apache.derby.iapi.services.io.ArrayInputStream;
028:        import org.apache.derby.iapi.services.io.StoredFormatIds;
029:        import org.apache.derby.iapi.services.io.StreamStorable;
030:        import org.apache.derby.iapi.services.io.Storable;
031:        import org.apache.derby.iapi.services.io.TypedFormat;
032:        import org.apache.derby.iapi.services.loader.ClassInspector;
033:        import org.apache.derby.iapi.services.sanity.SanityManager;
034:
035:        import org.apache.derby.iapi.types.DataValueDescriptor;
036:        import org.apache.derby.iapi.types.StringDataValue;
037:        import org.apache.derby.iapi.types.BooleanDataValue;
038:
039:        import org.apache.derby.iapi.reference.SQLState;
040:
041:        import java.sql.ResultSet;
042:        import java.sql.SQLException;
043:        import java.sql.Types;
044:
045:        import java.io.InputStream;
046:        import java.io.IOException;
047:        import java.io.ObjectOutput;
048:        import java.io.ObjectInput;
049:        import java.io.StringReader;
050:
051:        import java.util.ArrayList;
052:
053:        /**
054:         * This type implements the XMLDataValue interface and thus is
055:         * the type on which all XML related operations are executed.
056:         *
057:         * The first and simplest XML store implementation is a UTF-8
058:         * based one--all XML data is stored on disk as a UTF-8 string,
059:         * just like the other Derby string types.  In order to make
060:         * it possible for smarter XML implementations to exist in
061:         * the future, this class always writes an "XML implementation
062:         * id" to disk before writing the rest of its data.  When
063:         * reading the data, the impl id is read first and serves
064:         * as an indicator of how the rest of the data should be
065:         * read.
066:         *
067:         * So long as there's only one implementation (UTF-8)
068:         * the impl id can be ignored; but when smarter implementations
069:         * are written, the impl id will be the key to figuring out
070:         * how an XML value should be read, written, and processed.
071:         */
072:        public class XML extends DataType implements  XMLDataValue,
073:                StreamStorable {
074:            // Id for this implementation.  Should be unique
075:            // across all XML type implementations.
076:            protected static final short UTF8_IMPL_ID = 0;
077:
078:            // Guess at how much memory this type will take.
079:            private static final int BASE_MEMORY_USAGE = ClassSize
080:                    .estimateBaseFromCatalog(XML.class);
081:
082:            // Some syntax-related constants used to determine
083:            // operator behavior.
084:            public static final short XQ_PASS_BY_REF = 1;
085:            public static final short XQ_PASS_BY_VALUE = 2;
086:            public static final short XQ_RETURN_SEQUENCE = 3;
087:            public static final short XQ_RETURN_CONTENT = 4;
088:            public static final short XQ_EMPTY_ON_EMPTY = 5;
089:            public static final short XQ_NULL_ON_EMPTY = 6;
090:
091:            /* Per SQL/XML[2006] 4.2.2, there are several different
092:             * XML "types" defined through use of primary and secondary
093:             * "type modifiers".  For Derby we only support two kinds:
094:             *
095:             * XML(DOCUMENT(ANY)) : A valid and well-formed XML
096:             *  document as defined by W3C, meaning that there is
097:             *  exactly one root element node.  This is the only
098:             *  type of XML that can be stored into a Derby XML
099:             *  column.  This is also the type returned by a call
100:             *  to XMLPARSE since we require the DOCUMENT keyword.
101:             *
102:             * XML(SEQUENCE): A sequence of items (could be nodes or
103:             *  atomic values).  This is the type returned from an
104:             *  XMLQUERY operation.  Any node that is XML(DOCUMENT(ANY))
105:             *  is also XML(SEQUENCE).  Note that an XML(SEQUENCE)
106:             *  value is *only* storable into a Derby XML column
107:             *  if it is also an XML(DOCUMENT(ANY)).  See the
108:             *  normalize method below for the code that enforces
109:             *  this.
110:             */
111:            public static final int XML_DOC_ANY = 0;
112:            public static final int XML_SEQUENCE = 1;
113:
114:            // The fully-qualified type for this XML value.
115:            private int xType;
116:
117:            // The actual XML data in this implementation is just a simple
118:            // string, so this class really just wraps a SQLChar and
119:            // defers most calls to the corresponding calls on that
120:            // SQLChar.  Note that, even though a SQLChar is the
121:            // underlying implementation, an XML value is nonetheless
122:            // NOT considered comparable nor compatible with any of
123:            // Derby string types.
124:            private SQLChar xmlStringValue;
125:
126:            /*
127:             * Status variable used to verify that user's classpath contains
128:             * required classes for accessing/operating on XML data values.
129:             */
130:            private static String xmlReqCheck = null;
131:
132:            /*
133:             * Whether or not this XML value corresponds to a sequence
134:             * that has one or more top-level ("parentless") attribute
135:             * nodes.  If so then we have to throw an error if the user
136:             * attempts to serialize this value, per XML serialization
137:             * rules.
138:             */
139:            private boolean containsTopLevelAttr;
140:
141:            /**
142:             * Default constructor.
143:             */
144:            public XML() {
145:                xmlStringValue = null;
146:                xType = -1;
147:                containsTopLevelAttr = false;
148:            }
149:
150:            /**
151:             * Private constructor used for the getClone() method.
152:             * Returns a new instance of XML whose fields are clones
153:             * of the values received.
154:             *
155:             * @param val A SQLChar instance to clone and use for
156:             *  this XML value.
157:             * @param xmlType Qualified XML type for "val"
158:             * @param seqWithAttr Whether or not "val" corresponds to
159:             *  sequence with one or more top-level attribute nodes.
160:             */
161:            private XML(SQLChar val, int xmlType, boolean seqWithAttr) {
162:                xmlStringValue = (val == null ? null : (SQLChar) val.getClone());
163:                setXType(xmlType);
164:                if (seqWithAttr)
165:                    markAsHavingTopLevelAttr();
166:            }
167:
168:            /* ****
169:             * DataValueDescriptor interface.
170:             * */
171:
172:            /**
173:             * @see DataValueDescriptor#getClone
174:             */
175:            public DataValueDescriptor getClone() {
176:                return new XML(xmlStringValue, getXType(), hasTopLevelAttr());
177:            }
178:
179:            /**
180:             * @see DataValueDescriptor#getNewNull
181:             */
182:            public DataValueDescriptor getNewNull() {
183:                return new XML();
184:            }
185:
186:            /**
187:             * @see DataValueDescriptor#getTypeName
188:             */
189:            public String getTypeName() {
190:                return TypeId.XML_NAME;
191:            }
192:
193:            /**
194:             * @see DataValueDescriptor#typePrecedence
195:             */
196:            public int typePrecedence() {
197:                return TypeId.XML_PRECEDENCE;
198:            }
199:
200:            /**
201:             * @see DataValueDescriptor#getString
202:             */
203:            public String getString() throws StandardException {
204:                return (xmlStringValue == null) ? null : xmlStringValue
205:                        .getString();
206:            }
207:
208:            /**
209:             * @see DataValueDescriptor#getLength
210:             */
211:            public int getLength() throws StandardException {
212:                return ((xmlStringValue == null) ? 0 : xmlStringValue
213:                        .getLength());
214:            }
215:
216:            /** 
217:             * @see DataValueDescriptor#estimateMemoryUsage
218:             */
219:            public int estimateMemoryUsage() {
220:                int sz = BASE_MEMORY_USAGE;
221:                if (xmlStringValue != null)
222:                    sz += xmlStringValue.estimateMemoryUsage();
223:                return sz;
224:            }
225:
226:            /**
227:             * @see DataValueDescriptor#readExternalFromArray
228:             */
229:            public void readExternalFromArray(ArrayInputStream in)
230:                    throws IOException {
231:                if (xmlStringValue == null)
232:                    xmlStringValue = new SQLChar();
233:
234:                // Read the XML implementation id.  Right now there's
235:                // only one implementation (UTF-8 based), so we don't
236:                // use this value.  But if better implementations come
237:                // up in the future, we'll have to use this impl id to
238:                // figure out how to read the data.
239:                in.readShort();
240:
241:                // Now just read the XML data as UTF-8.
242:                xmlStringValue.readExternalFromArray(in);
243:
244:                // If we read it from disk then it must have type
245:                // XML_DOC_ANY because that's all we allow to be
246:                // written into an XML column.
247:                setXType(XML_DOC_ANY);
248:            }
249:
250:            /**
251:             * @see DataType#setFrom
252:             */
253:            protected void setFrom(DataValueDescriptor theValue)
254:                    throws StandardException {
255:                String strVal = theValue.getString();
256:                if (strVal == null) {
257:                    xmlStringValue = null;
258:
259:                    // Null is a valid value for DOCUMENT(ANY)
260:                    setXType(XML_DOC_ANY);
261:                    return;
262:                }
263:
264:                // Here we just store the received value locally.
265:                if (xmlStringValue == null)
266:                    xmlStringValue = new SQLChar();
267:                xmlStringValue.setValue(strVal);
268:
269:                /*
270:                 * Assumption is that if theValue is not an XML
271:                 * value then the caller is aware of whether or
272:                 * not theValue constitutes a valid XML(DOCUMENT(ANY))
273:                 * and will behave accordingly (see in particular the
274:                 * XMLQuery method of this class, which calls the
275:                 * setValue() method of XMLDataValue which in turn
276:                 * brings us to this method).
277:                 */
278:                if (theValue instanceof  XMLDataValue) {
279:                    setXType(((XMLDataValue) theValue).getXType());
280:                    if (((XMLDataValue) theValue).hasTopLevelAttr())
281:                        markAsHavingTopLevelAttr();
282:                }
283:            }
284:
285:            /** 
286:             * @see DataValueDescriptor#setValueFromResultSet 
287:             */
288:            public final void setValueFromResultSet(ResultSet resultSet,
289:                    int colNumber, boolean isNullable) throws SQLException {
290:                if (xmlStringValue == null)
291:                    xmlStringValue = new SQLChar();
292:                xmlStringValue.setValue(resultSet.getString(colNumber));
293:            }
294:
295:            /**
296:             * Compare two XML DataValueDescriptors.  NOTE: This method
297:             * should only be used by the database store for the purpose of
298:             * index positioning--comparisons of XML type are not allowed
299:             * from the language side of things.  That said, all store
300:             * wants to do is order the NULLs, so we don't actually
301:             * have to do a full comparison.  Just return an order
302:             * value based on whether or not this XML value and the
303:             * other XML value are null.  As mentioned in the "compare"
304:             * method of DataValueDescriptor, nulls are considered
305:             * equal to other nulls and less than all other values.
306:             *
307:             * An example of when this method might be used is if the
308:             * user executed a query like:
309:             *
310:             * select i from x_table where x_col is not null
311:             *
312:             * @see DataValueDescriptor#compare
313:             */
314:            public int compare(DataValueDescriptor other)
315:                    throws StandardException {
316:                if (SanityManager.DEBUG) {
317:                    SanityManager.ASSERT(other instanceof  XMLDataValue,
318:                            "Store should NOT have tried to compare an XML value "
319:                                    + "with a non-XML value.");
320:                }
321:
322:                if (isNull()) {
323:                    if (other.isNull())
324:                        // both null, so call them 'equal'.
325:                        return 0;
326:                    // This XML is 'less than' the other.
327:                    return -1;
328:                }
329:
330:                if (other.isNull())
331:                    // This XML is 'greater than' the other.
332:                    return 1;
333:
334:                // Two non-null values: we shouldn't ever get here,
335:                // since that would necessitate a comparsion of XML
336:                // values, which isn't allowed.
337:                if (SanityManager.DEBUG) {
338:                    SanityManager
339:                            .THROWASSERT("Store tried to compare two non-null XML values, "
340:                                    + "which isn't allowed.");
341:                }
342:                return 0;
343:            }
344:
345:            /**
346:             * Normalization method - this method will always be called when
347:             * storing an XML value into an XML column, for example, when
348:             * inserting/updating.  We always force normalization in this
349:             * case because we need to make sure the qualified type of the
350:             * value we're trying to store is XML_DOC_ANY--we don't allow
351:             * anything else.
352:             *
353:             * @param desiredType   The type to normalize the source column to
354:             * @param source        The value to normalize
355:             *
356:             * @exception StandardException Thrown if source is not
357:             *  XML_DOC_ANY.
358:             */
359:            public void normalize(DataTypeDescriptor desiredType,
360:                    DataValueDescriptor source) throws StandardException {
361:                if (SanityManager.DEBUG) {
362:                    SanityManager
363:                            .ASSERT(
364:                                    source instanceof  XMLDataValue,
365:                                    "Tried to store non-XML value into XML column; "
366:                                            + "should have thrown error at compile time.");
367:                }
368:
369:                if (((XMLDataValue) source).getXType() != XML_DOC_ANY) {
370:                    throw StandardException
371:                            .newException(SQLState.LANG_NOT_AN_XML_DOCUMENT);
372:                }
373:
374:                ((DataValueDescriptor) this ).setValue(source);
375:                return;
376:
377:            }
378:
379:            /* ****
380:             * Storable interface, implies Externalizable, TypedFormat
381:             */
382:
383:            /**
384:             * @see TypedFormat#getTypeFormatId
385:             *
386:             * From the engine's perspective, all XML implementations share
387:             * the same format id.
388:             */
389:            public int getTypeFormatId() {
390:                return StoredFormatIds.XML_ID;
391:            }
392:
393:            /**
394:             * @see Storable#isNull
395:             */
396:            public boolean isNull() {
397:                return ((xmlStringValue == null) || xmlStringValue.isNull());
398:            }
399:
400:            /**
401:             * @see Storable#restoreToNull
402:             */
403:            public void restoreToNull() {
404:                if (xmlStringValue != null)
405:                    xmlStringValue.restoreToNull();
406:            }
407:
408:            /**
409:             * Read an XML value from an input stream.
410:             * @param in The stream from which we're reading.
411:             */
412:            public void readExternal(ObjectInput in) throws IOException {
413:                if (xmlStringValue == null)
414:                    xmlStringValue = new SQLChar();
415:
416:                // Read the XML implementation id.  Right now there's
417:                // only one implementation (UTF-8 based), so we don't
418:                // use this value.  But if better implementations come
419:                // up in the future, we'll have to use this impl id to
420:                // figure out how to read the data.
421:                in.readShort();
422:
423:                // Now just read the XML data as UTF-8.
424:                xmlStringValue.readExternal(in);
425:
426:                // If we read it from disk then it must have type
427:                // XML_DOC_ANY because that's all we allow to be
428:                // written into an XML column.
429:                setXType(XML_DOC_ANY);
430:            }
431:
432:            /**
433:             * Write an XML value. 
434:             * @param out The stream to which we're writing.
435:             */
436:            public void writeExternal(ObjectOutput out) throws IOException {
437:                // never called when value is null
438:                if (SanityManager.DEBUG)
439:                    SanityManager.ASSERT(!isNull());
440:
441:                // Write out the XML store impl id.
442:                out.writeShort(UTF8_IMPL_ID);
443:
444:                // Now write out the data.
445:                xmlStringValue.writeExternal(out);
446:            }
447:
448:            /* ****
449:             * StreamStorable interface
450:             * */
451:
452:            /**
453:             * @see StreamStorable#returnStream
454:             */
455:            public InputStream returnStream() {
456:                return (xmlStringValue == null) ? null : xmlStringValue
457:                        .returnStream();
458:            }
459:
460:            /**
461:             * @see StreamStorable#setStream
462:             */
463:            public void setStream(InputStream newStream) {
464:                if (xmlStringValue == null)
465:                    xmlStringValue = new SQLChar();
466:
467:                // The stream that we receive is for an XML data value,
468:                // which means it has an XML implementation id stored
469:                // at the front (we put it there when we wrote it out).
470:                // If we leave that there we'll get a failure when
471:                // our underlying SQLChar tries to read from the
472:                // stream, because the extra impl id will throw
473:                // off the UTF format.  So we need to read in (and
474:                // ignore) the impl id before using the stream.
475:                try {
476:                    // 2 bytes equal a short, which is what an impl id is.
477:                    newStream.read();
478:                    newStream.read();
479:                } catch (Exception e) {
480:                    if (SanityManager.DEBUG)
481:                        SanityManager.THROWASSERT("Failed to read impl id"
482:                                + "bytes in setStream.");
483:                }
484:
485:                // Now go ahead and use the stream.
486:                xmlStringValue.setStream(newStream);
487:
488:                // If we read it from disk then it must have type
489:                // XML_DOC_ANY because that's all we allow to be
490:                // written into an XML column.
491:                setXType(XML_DOC_ANY);
492:            }
493:
494:            /**
495:             * @see StreamStorable#loadStream
496:             */
497:            public void loadStream() throws StandardException {
498:                getString();
499:            }
500:
501:            /* ****
502:             * XMLDataValue interface.
503:             * */
504:
505:            /**
506:             * Method to parse an XML string and, if it's valid,
507:             * store the _serialized_ version locally and then return
508:             * this XMLDataValue.
509:             *
510:             * @param text The string value to check.
511:             * @param preserveWS Whether or not to preserve
512:             *  ignorable whitespace.
513:             * @param sqlxUtil Contains SQL/XML objects and util
514:             *  methods that facilitate execution of XML-related
515:             *  operations
516:             * @return If 'text' constitutes a valid XML document,
517:             *  it has been stored in this XML value and this XML
518:             *  value is returned; otherwise, an exception is thrown. 
519:             * @exception StandardException Thrown on error.
520:             */
521:            public XMLDataValue XMLParse(String text, boolean preserveWS,
522:                    SqlXmlUtil sqlxUtil) throws StandardException {
523:                try {
524:
525:                    if (preserveWS) {
526:                        // Currently the only way a user can view the contents of
527:                        // an XML value is by explicitly calling XMLSERIALIZE.
528:                        // So do a serialization now and just store the result,
529:                        // so that we don't have to re-serialize every time a
530:                        // call is made to XMLSERIALIZE.
531:                        text = sqlxUtil.serializeToString(text);
532:                    } else {
533:                        // We don't support this yet, so we shouldn't
534:                        // get here.
535:                        if (SanityManager.DEBUG)
536:                            SanityManager
537:                                    .THROWASSERT("Tried to STRIP whitespace "
538:                                            + "but we shouldn't have made it this far");
539:                    }
540:
541:                } catch (Throwable t) {
542:                    /* Couldn't parse the XML document.  Throw a StandardException
543:                     * with the parse exception (or other error) nested in it.
544:                     * Note: we catch "Throwable" here to catch as many external
545:                     * errors as possible in order to minimize the chance of an
546:                     * uncaught JAXP/Xalan error (such as a NullPointerException)
547:                     * causing Derby to fail in a more serious way.  In particular,
548:                     * an uncaught Java exception like NPE can result in Derby
549:                     * throwing "ERROR 40XT0: An internal error was identified by
550:                     * RawStore module" for all statements on the connection after
551:                     * the failure--which we clearly don't want.  If we catch the
552:                     * error and wrap it, though, the statement will fail but Derby
553:                     * will continue to run as normal.
554:                     */
555:                    throw StandardException.newException(
556:                            SQLState.LANG_INVALID_XML_DOCUMENT, t, t
557:                                    .getMessage());
558:
559:                }
560:
561:                // If we get here, the text is valid XML so go ahead
562:                // and load/store it.
563:                setXType(XML_DOC_ANY);
564:                if (xmlStringValue == null)
565:                    xmlStringValue = new SQLChar();
566:                xmlStringValue.setValue(text);
567:                return this ;
568:            }
569:
570:            /**
571:             * The SQL/XML XMLSerialize operator.
572:             * Serializes this XML value into a string with a user-specified
573:             * character type, and returns that string via the received
574:             * StringDataValue (if the received StringDataValue is non-null
575:             * and of the correct type; else, a new StringDataValue is
576:             * returned).
577:             *
578:             * @param result The result of a previous call to this method,
579:             *    null if not called yet.
580:             * @param targetType The string type to which we want to serialize.
581:             * @param targetWidth The width of the target type.
582:             * @return A serialized (to string) version of this XML object,
583:             *  in the form of a StringDataValue object.
584:             * @exception StandardException    Thrown on error
585:             */
586:            public StringDataValue XMLSerialize(StringDataValue result,
587:                    int targetType, int targetWidth) throws StandardException {
588:                if (result == null) {
589:                    switch (targetType) {
590:                    case Types.CHAR:
591:                        result = new SQLChar();
592:                        break;
593:                    case Types.VARCHAR:
594:                        result = new SQLVarchar();
595:                        break;
596:                    case Types.LONGVARCHAR:
597:                        result = new SQLLongvarchar();
598:                        break;
599:                    case Types.CLOB:
600:                        result = new SQLClob();
601:                        break;
602:                    default:
603:                        // Shouldn't ever get here, as this check was performed
604:                        // at bind time.
605:
606:                        if (SanityManager.DEBUG) {
607:                            SanityManager
608:                                    .THROWASSERT("Should NOT have made it to XMLSerialize "
609:                                            + "with a non-string target type: "
610:                                            + targetType);
611:                        }
612:                        return null;
613:                    }
614:                }
615:
616:                // Else we're reusing a StringDataValue.  We only reuse
617:                // the result if we're executing the _same_ XMLSERIALIZE
618:                // call on multiple rows.  That means that all rows
619:                // must have the same result type (targetType) and thus
620:                // we know that the StringDataValue already has the
621:                // correct type.  So we're set.
622:
623:                if (this .isNull()) {
624:                    // Attempts to serialize a null XML value lead to a null
625:                    // result (SQL/XML[2003] section 10.13).
626:                    result.setToNull();
627:                    return result;
628:                }
629:
630:                /* XML serialization rules say that sequence "normalization"
631:                 * must occur before serialization, and normalization dictates
632:                 * that a serialization error must be thrown if the XML value
633:                 * is a sequence with a top-level attribute.  We normalized
634:                 * (and serialized) this XML value when it was first created,
635:                 * and at that time we took note of whether or not there is
636:                 * a top-level attribute.  So throw the error here if needed.
637:                 * See SqlXmlUtil.serializeToString() for more on sequence
638:                 * normalization.
639:                 */
640:                if (this .hasTopLevelAttr()) {
641:                    throw StandardException
642:                            .newException(SQLState.LANG_XQUERY_SERIALIZATION_ERROR);
643:                }
644:
645:                // Get the XML value as a string.  For this UTF-8 impl,
646:                // we already have it as a UTF-8 string, so just use
647:                // that.
648:                result.setValue(getString());
649:
650:                // Seems wrong to trunc an XML document, as it then becomes non-
651:                // well-formed and thus useless.  So we throw an error (that's
652:                // what the "true" in the next line says).
653:                result.setWidth(targetWidth, 0, true);
654:                return result;
655:            }
656:
657:            /**
658:             * The SQL/XML XMLExists operator.
659:             * Checks to see if evaluation of the query expression contained
660:             * within the received util object against this XML value returns
661:             * at least one item. NOTE: For now, the query expression must be
662:             * XPath only (XQuery not supported) because that's what Xalan
663:             * supports.
664:             *
665:             * @param sqlxUtil Contains SQL/XML objects and util
666:             *  methods that facilitate execution of XML-related
667:             *  operations
668:             * @return True if evaluation of the query expression stored
669:             *  in sqlxUtil returns at least one node for this XML value;
670:             *  unknown if the xml value is NULL; false otherwise.
671:             * @exception StandardException Thrown on error
672:             */
673:            public BooleanDataValue XMLExists(SqlXmlUtil sqlxUtil)
674:                    throws StandardException {
675:                if (this .isNull()) {
676:                    // if the user specified a context node and that context
677:                    // is null, result of evaluating the query is null
678:                    // (per SQL/XML 6.17:General Rules:1.a), which means that we
679:                    // return "unknown" here (per SQL/XML 8.4:General Rules:2.a).
680:                    return SQLBoolean.unknownTruthValue();
681:                }
682:
683:                // Make sure we have a compiled query (and associated XML
684:                // objects) to evaluate.
685:                if (SanityManager.DEBUG) {
686:                    SanityManager
687:                            .ASSERT(sqlxUtil != null,
688:                                    "Tried to evaluate XML xquery, but no XML objects were loaded.");
689:                }
690:
691:                try {
692:
693:                    return new SQLBoolean(null != sqlxUtil.evalXQExpression(
694:                            this , false, new int[1]));
695:
696:                } catch (StandardException se) {
697:
698:                    // Just re-throw it.
699:                    throw se;
700:
701:                } catch (Throwable xe) {
702:                    /* Failed somewhere during evaluation of the XML query expression;
703:                     * turn error into a StandardException and throw it.  Note: we
704:                     * catch "Throwable" here to catch as many Xalan-produced errors
705:                     * as possible in order to minimize the chance of an uncaught Xalan
706:                     * error (such as a NullPointerException) causing Derby to fail in
707:                     * a more serious way.  In particular, an uncaught Java exception
708:                     * like NPE can result in Derby throwing "ERROR 40XT0: An internal
709:                     * error was identified by RawStore module" for all statements on
710:                     * the connection after the failure--which we clearly don't want.  
711:                     * If we catch the error and wrap it, though, the statement will
712:                     * fail but Derby will continue to run as normal. 
713:                     */
714:                    throw StandardException.newException(
715:                            SQLState.LANG_XML_QUERY_ERROR, xe, "XMLEXISTS", xe
716:                                    .getMessage());
717:                }
718:            }
719:
720:            /**
721:             * Evaluate the XML query expression contained within the received
722:             * util object against this XML value and store the results into
723:             * the received XMLDataValue "result" param (assuming "result" is
724:             * non-null; else create a new XMLDataValue).
725:             *
726:             * @param result The result of a previous call to this method; null
727:             *  if not called yet.
728:             * @param sqlxUtil Contains SQL/XML objects and util methods that
729:             *  facilitate execution of XML-related operations
730:             * @return An XMLDataValue whose content corresponds to the serialized
731:             *  version of the results from evaluation of the query expression.
732:             *  Note: this XMLDataValue may not be storable into Derby XML
733:             *  columns.
734:             * @exception Exception thrown on error (and turned into a
735:             *  StandardException by the caller).
736:             */
737:            public XMLDataValue XMLQuery(XMLDataValue result,
738:                    SqlXmlUtil sqlxUtil) throws StandardException {
739:                if (this .isNull()) {
740:                    // if the context is null, we return null,
741:                    // per SQL/XML[2006] 6.17:GR.1.a.ii.1.
742:                    if (result == null)
743:                        result = (XMLDataValue) getNewNull();
744:                    else
745:                        result.setToNull();
746:                    return result;
747:                }
748:
749:                try {
750:
751:                    // Return an XML data value whose contents are the
752:                    // serialized version of the query results.
753:                    int[] xType = new int[1];
754:                    ArrayList itemRefs = sqlxUtil.evalXQExpression(this , true,
755:                            xType);
756:
757:                    if (result == null)
758:                        result = new XML();
759:                    String strResult = sqlxUtil.serializeToString(itemRefs,
760:                            result);
761:                    result.setValue(new SQLChar(strResult));
762:
763:                    // Now that we've set the result value, make sure
764:                    // to indicate what kind of XML value we have.
765:                    result.setXType(xType[0]);
766:
767:                    // And finally we return the query result as an XML value.
768:                    return result;
769:
770:                } catch (StandardException se) {
771:
772:                    // Just re-throw it.
773:                    throw se;
774:
775:                } catch (Throwable xe) {
776:                    /* Failed somewhere during evaluation of the XML query expression;
777:                     * turn error into a StandardException and throw it.  Note: we
778:                     * catch "Throwable" here to catch as many Xalan-produced errors
779:                     * as possible in order to minimize the chance of an uncaught Xalan
780:                     * error (such as a NullPointerException) causing Derby to fail in
781:                     * a more serious way.  In particular, an uncaught Java exception
782:                     * like NPE can result in Derby throwing "ERROR 40XT0: An internal
783:                     * error was identified by RawStore module" for all statements on
784:                     * the connection after the failure--which we clearly don't want.  
785:                     * If we catch the error and wrap it, though, the statement will
786:                     * fail but Derby will continue to run as normal. 
787:                     */
788:                    throw StandardException.newException(
789:                            SQLState.LANG_XML_QUERY_ERROR, xe, "XMLQUERY", xe
790:                                    .getMessage());
791:                }
792:            }
793:
794:            /* ****
795:             * Helper classes and methods.
796:             * */
797:
798:            /**
799:             * Set this XML value's qualified type.
800:             */
801:            public void setXType(int xtype) {
802:                this .xType = xtype;
803:
804:                /* If the target type is XML_DOC_ANY then this XML value
805:                 * holds a single well-formed Document.  So we know that
806:                 * we do NOT have any top-level attribute nodes.  Note: if
807:                 * xtype is SEQUENCE we don't set "containsTopLevelAttr"
808:                 * here; assumption is that the caller of this method will
809:                 * then set the field as appropriate.  Ex. see "setFrom()"
810:                 * in this class.
811:                 */
812:                if (xtype == XML_DOC_ANY)
813:                    containsTopLevelAttr = false;
814:            }
815:
816:            /**
817:             * Retrieve this XML value's qualified type.
818:             */
819:            public int getXType() {
820:                return xType;
821:            }
822:
823:            /**
824:             * Take note of the fact this XML value represents an XML
825:             * sequence that has one or more top-level attribute nodes.
826:             */
827:            public void markAsHavingTopLevelAttr() {
828:                this .containsTopLevelAttr = true;
829:            }
830:
831:            /**
832:             * Return whether or not this XML value represents a sequence
833:             * that has one or more top-level attribute nodes.
834:             */
835:            public boolean hasTopLevelAttr() {
836:                return containsTopLevelAttr;
837:            }
838:
839:            /**
840:             * See if the required JAXP and Xalan classes are in the
841:             * user's classpath.  Assumption is that we will always
842:             * call this method before instantiating an instance of
843:             * SqlXmlUtil, and thus we will never get a ClassNotFound
844:             * exception caused by missing JAXP/Xalan classes.  Instead,
845:             * if either is missing we should throw an informative
846:             * error indicating what the problem is.
847:             *
848:             * NOTE: This method only does the checks necessary to
849:             * allow successful instantiation of the SqlXmlUtil
850:             * class.  Further checks (esp. the presence of a JAXP
851:             * _implementation_ in addition to the JAXP _interfaces_)
852:             * are performed in the SqlXmlUtil constructor.
853:             *
854:             * @exception StandardException thrown if the required
855:             *  classes cannot be located in the classpath.
856:             */
857:            public static void checkXMLRequirements() throws StandardException {
858:                // Only check once; after that, just re-use the result.
859:                if (xmlReqCheck == null) {
860:                    xmlReqCheck = "";
861:
862:                    /* If the w3c Document class exists, then we
863:                     * assume a JAXP implementation is present in
864:                     * the classpath.  If this assumption is incorrect
865:                     * then we at least know that the JAXP *interface*
866:                     * exists and thus we'll be able to instantiate
867:                     * the SqlXmlUtil class.  We can then do a check
868:                     * for an actual JAXP *implementation* from within
869:                     * the SqlXmlUtil class (see the constructor of
870:                     * that class).
871:                     *
872:                     * Note: The JAXP API and implementation are
873:                     * provided as part the JVM if it is jdk 1.4 or
874:                     * greater.
875:                     */
876:                    if (!ClassInspector.classIsLoadable("org.w3c.dom.Document"))
877:                        xmlReqCheck = "JAXP";
878:
879:                    /* If the XPath class exists, then we assume that our XML
880:                     * query processor (in this case, Xalan), is present in the
881:                     * classpath.  Note: if JAXP API classes aren't present
882:                     * then the following check will return false even if the
883:                     * Xalan classes *are* present; this is because the Xalan
884:                     * XPath class relies on JAXP, as well.  Thus there's no
885:                     * point in checking for Xalan unless we've already confirmed
886:                     * that we have the JAXP interfaces.
887:                     */
888:                    else if (!ClassInspector
889:                            .classIsLoadable("org.apache.xpath.XPath"))
890:                        xmlReqCheck = "Xalan";
891:                }
892:
893:                if (xmlReqCheck.length() != 0) {
894:                    throw StandardException.newException(
895:                            SQLState.LANG_MISSING_XML_CLASSES, xmlReqCheck);
896:                }
897:
898:                return;
899:            }
900:
901:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.