Source Code Cross Referenced for DBDictionary.java in  » Database-ORM » openjpa » org » apache » openjpa » jdbc » sql » 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 ORM » openjpa » org.apache.openjpa.jdbc.sql 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one
0003:         * or more contributor license agreements.  See the NOTICE file
0004:         * distributed with this work for additional information
0005:         * regarding copyright ownership.  The ASF licenses this file
0006:         * to you under the Apache License, Version 2.0 (the
0007:         * "License"); you may not use this file except in compliance
0008:         * with the License.  You may obtain a copy of the License at
0009:         *
0010:         * http://www.apache.org/licenses/LICENSE-2.0
0011:         *
0012:         * Unless required by applicable law or agreed to in writing,
0013:         * software distributed under the License is distributed on an
0014:         * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015:         * KIND, either express or implied.  See the License for the
0016:         * specific language governing permissions and limitations
0017:         * under the License.    
0018:         */
0019:        package org.apache.openjpa.jdbc.sql;
0020:
0021:        import java.io.BufferedReader;
0022:        import java.io.ByteArrayInputStream;
0023:        import java.io.CharArrayReader;
0024:        import java.io.IOException;
0025:        import java.io.InputStream;
0026:        import java.io.InputStreamReader;
0027:        import java.io.OutputStream;
0028:        import java.io.Reader;
0029:        import java.io.StringReader;
0030:        import java.io.Writer;
0031:        import java.lang.reflect.InvocationTargetException;
0032:        import java.lang.reflect.Method;
0033:        import java.math.BigDecimal;
0034:        import java.math.BigInteger;
0035:        import java.sql.Array;
0036:        import java.sql.Blob;
0037:        import java.sql.Clob;
0038:        import java.sql.Connection;
0039:        import java.sql.DatabaseMetaData;
0040:        import java.sql.PreparedStatement;
0041:        import java.sql.Ref;
0042:        import java.sql.ResultSet;
0043:        import java.sql.SQLException;
0044:        import java.sql.SQLWarning;
0045:        import java.sql.Statement;
0046:        import java.sql.Time;
0047:        import java.sql.Timestamp;
0048:        import java.sql.Types;
0049:        import java.text.MessageFormat;
0050:        import java.util.ArrayList;
0051:        import java.util.Arrays;
0052:        import java.util.Calendar;
0053:        import java.util.Collection;
0054:        import java.util.Collections;
0055:        import java.util.Date;
0056:        import java.util.HashSet;
0057:        import java.util.Iterator;
0058:        import java.util.LinkedHashSet;
0059:        import java.util.List;
0060:        import java.util.Locale;
0061:        import java.util.Map;
0062:        import java.util.Set;
0063:        import javax.sql.DataSource;
0064:
0065:        import org.apache.commons.lang.StringUtils;
0066:        import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
0067:        import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
0068:        import org.apache.openjpa.jdbc.kernel.JDBCStore;
0069:        import org.apache.openjpa.jdbc.kernel.exps.ExpContext;
0070:        import org.apache.openjpa.jdbc.kernel.exps.ExpState;
0071:        import org.apache.openjpa.jdbc.kernel.exps.FilterValue;
0072:        import org.apache.openjpa.jdbc.kernel.exps.Val;
0073:        import org.apache.openjpa.jdbc.meta.ClassMapping;
0074:        import org.apache.openjpa.jdbc.meta.FieldMapping;
0075:        import org.apache.openjpa.jdbc.meta.JavaSQLTypes;
0076:        import org.apache.openjpa.jdbc.schema.Column;
0077:        import org.apache.openjpa.jdbc.schema.DataSourceFactory;
0078:        import org.apache.openjpa.jdbc.schema.ForeignKey;
0079:        import org.apache.openjpa.jdbc.schema.Index;
0080:        import org.apache.openjpa.jdbc.schema.NameSet;
0081:        import org.apache.openjpa.jdbc.schema.PrimaryKey;
0082:        import org.apache.openjpa.jdbc.schema.Schema;
0083:        import org.apache.openjpa.jdbc.schema.SchemaGroup;
0084:        import org.apache.openjpa.jdbc.schema.Sequence;
0085:        import org.apache.openjpa.jdbc.schema.Table;
0086:        import org.apache.openjpa.jdbc.schema.Unique;
0087:        import org.apache.openjpa.kernel.Filters;
0088:        import org.apache.openjpa.kernel.OpenJPAStateManager;
0089:        import org.apache.openjpa.kernel.exps.Path;
0090:        import org.apache.openjpa.lib.conf.Configurable;
0091:        import org.apache.openjpa.lib.conf.Configuration;
0092:        import org.apache.openjpa.lib.jdbc.ConnectionDecorator;
0093:        import org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator;
0094:        import org.apache.openjpa.lib.log.Log;
0095:        import org.apache.openjpa.lib.util.Localizer;
0096:        import org.apache.openjpa.lib.util.Localizer.Message;
0097:        import org.apache.openjpa.meta.FieldMetaData;
0098:        import org.apache.openjpa.meta.JavaTypes;
0099:        import org.apache.openjpa.meta.ValueStrategies;
0100:        import org.apache.openjpa.util.GeneralException;
0101:        import org.apache.openjpa.util.InternalException;
0102:        import org.apache.openjpa.util.InvalidStateException;
0103:        import org.apache.openjpa.util.OpenJPAException;
0104:        import org.apache.openjpa.util.Serialization;
0105:        import org.apache.openjpa.util.StoreException;
0106:        import org.apache.openjpa.util.UnsupportedException;
0107:        import org.apache.openjpa.util.UserException;
0108:        import serp.util.Numbers;
0109:        import serp.util.Strings;
0110:
0111:        /**
0112:         * Class which allows the creation of SQL dynamically, in a
0113:         * database agnostic fashion. Subclass for the nuances of different data stores.
0114:         */
0115:        public class DBDictionary implements  Configurable, ConnectionDecorator,
0116:                JoinSyntaxes, LoggingConnectionDecorator.SQLWarningHandler {
0117:
0118:            public static final String VENDOR_OTHER = "other";
0119:            public static final String VENDOR_DATADIRECT = "datadirect";
0120:
0121:            public static final String SCHEMA_CASE_UPPER = "upper";
0122:            public static final String SCHEMA_CASE_LOWER = "lower";
0123:            public static final String SCHEMA_CASE_PRESERVE = "preserve";
0124:
0125:            public static final String CONS_NAME_BEFORE = "before";
0126:            public static final String CONS_NAME_MID = "mid";
0127:            public static final String CONS_NAME_AFTER = "after";
0128:
0129:            public int blobBufferSize = 50;
0130:            public int clobBufferSize = 50;
0131:
0132:            protected static final int RANGE_POST_SELECT = 0;
0133:            protected static final int RANGE_PRE_DISTINCT = 1;
0134:            protected static final int RANGE_POST_DISTINCT = 2;
0135:            protected static final int RANGE_POST_LOCK = 3;
0136:
0137:            protected static final int NANO = 1;
0138:            protected static final int MICRO = NANO * 1000;
0139:            protected static final int MILLI = MICRO * 1000;
0140:            protected static final int CENTI = MILLI * 10;
0141:            protected static final int DECI = MILLI * 100;
0142:            protected static final int SEC = MILLI * 1000;
0143:
0144:            protected static final int NAME_ANY = 0;
0145:            protected static final int NAME_TABLE = 1;
0146:            protected static final int NAME_SEQUENCE = 2;
0147:
0148:            protected static final int UNLIMITED = -1;
0149:            protected static final int NO_BATCH = 0;
0150:
0151:            private static final String ZERO_DATE_STR = "'"
0152:                    + new java.sql.Date(0) + "'";
0153:            private static final String ZERO_TIME_STR = "'" + new Time(0) + "'";
0154:            private static final String ZERO_TIMESTAMP_STR = "'"
0155:                    + new Timestamp(0) + "'";
0156:
0157:            public static final List EMPTY_STRING_LIST = Arrays
0158:                    .asList(new String[] {});
0159:            public static final List[] SQL_STATE_CODES = { EMPTY_STRING_LIST, // 0: Default
0160:                    Arrays.asList(new String[] { "41000" }), // 1: LOCK
0161:                    EMPTY_STRING_LIST, // 2: OBJECT_NOT_FOUND
0162:                    EMPTY_STRING_LIST, // 3: OPTIMISTIC
0163:                    Arrays.asList(new String[] { "23000" }), // 4: REFERENTIAL_INTEGRITY
0164:                    EMPTY_STRING_LIST // 5: OBJECT_EXISTS
0165:            };
0166:
0167:            private static final Localizer _loc = Localizer
0168:                    .forPackage(DBDictionary.class);
0169:
0170:            // schema data
0171:            public String platform = "Generic";
0172:            public String driverVendor = null;
0173:            public String catalogSeparator = ".";
0174:            public boolean createPrimaryKeys = true;
0175:            public String constraintNameMode = CONS_NAME_BEFORE;
0176:            public int maxTableNameLength = 128;
0177:            public int maxColumnNameLength = 128;
0178:            public int maxConstraintNameLength = 128;
0179:            public int maxIndexNameLength = 128;
0180:            public int maxIndexesPerTable = Integer.MAX_VALUE;
0181:            public boolean supportsForeignKeys = true;
0182:            public boolean supportsTimestampNanos = true;
0183:            public boolean supportsUniqueConstraints = true;
0184:            public boolean supportsDeferredConstraints = true;
0185:            public boolean supportsRestrictDeleteAction = true;
0186:            public boolean supportsCascadeDeleteAction = true;
0187:            public boolean supportsNullDeleteAction = true;
0188:            public boolean supportsDefaultDeleteAction = true;
0189:            public boolean supportsRestrictUpdateAction = true;
0190:            public boolean supportsCascadeUpdateAction = true;
0191:            public boolean supportsNullUpdateAction = true;
0192:            public boolean supportsDefaultUpdateAction = true;
0193:            public boolean supportsAlterTableWithAddColumn = true;
0194:            public boolean supportsAlterTableWithDropColumn = true;
0195:            public boolean supportsComments = false;
0196:            public String reservedWords = null;
0197:            public String systemSchemas = null;
0198:            public String systemTables = null;
0199:            public String selectWords = null;
0200:            public String fixedSizeTypeNames = null;
0201:            public String schemaCase = SCHEMA_CASE_UPPER;
0202:
0203:            // sql
0204:            public String validationSQL = null;
0205:            public String closePoolSQL = null;
0206:            public String initializationSQL = null;
0207:            public int joinSyntax = SYNTAX_SQL92;
0208:            public String outerJoinClause = "LEFT OUTER JOIN";
0209:            public String innerJoinClause = "INNER JOIN";
0210:            public String crossJoinClause = "CROSS JOIN";
0211:            public boolean requiresConditionForCrossJoin = false;
0212:            public String forUpdateClause = "FOR UPDATE";
0213:            public String tableForUpdateClause = null;
0214:            public String distinctCountColumnSeparator = null;
0215:            public boolean supportsSelectForUpdate = true;
0216:            public boolean supportsLockingWithDistinctClause = true;
0217:            public boolean supportsLockingWithMultipleTables = true;
0218:            public boolean supportsLockingWithOrderClause = true;
0219:            public boolean supportsLockingWithOuterJoin = true;
0220:            public boolean supportsLockingWithInnerJoin = true;
0221:            public boolean supportsLockingWithSelectRange = true;
0222:            public boolean supportsQueryTimeout = true;
0223:            public boolean simulateLocking = false;
0224:            public boolean supportsSubselect = true;
0225:            public boolean supportsCorrelatedSubselect = true;
0226:            public boolean supportsHaving = true;
0227:            public boolean supportsSelectStartIndex = false;
0228:            public boolean supportsSelectEndIndex = false;
0229:            public int rangePosition = RANGE_POST_SELECT;
0230:            public boolean requiresAliasForSubselect = false;
0231:            public boolean allowsAliasInBulkClause = true;
0232:            public boolean supportsMultipleNontransactionalResultSets = true;
0233:            public String searchStringEscape = "\\";
0234:            public boolean requiresCastForMathFunctions = false;
0235:            public boolean requiresCastForComparisons = false;
0236:            public boolean supportsModOperator = false;
0237:            public boolean supportsXMLColumn = false;
0238:
0239:            // functions
0240:            public String castFunction = "CAST({0} AS {1})";
0241:            public String toLowerCaseFunction = "LOWER({0})";
0242:            public String toUpperCaseFunction = "UPPER({0})";
0243:            public String stringLengthFunction = "CHAR_LENGTH({0})";
0244:            public String bitLengthFunction = "(OCTET_LENGTH({0}) * 8)";
0245:            public String trimLeadingFunction = "TRIM(LEADING {1} FROM {0})";
0246:            public String trimTrailingFunction = "TRIM(TRAILING {1} FROM {0})";
0247:            public String trimBothFunction = "TRIM(BOTH {1} FROM {0})";
0248:            public String concatenateFunction = "({0}||{1})";
0249:            public String concatenateDelimiter = "'OPENJPATOKEN'";
0250:            public String substringFunctionName = "SUBSTRING";
0251:            public String currentDateFunction = "CURRENT_DATE";
0252:            public String currentTimeFunction = "CURRENT_TIME";
0253:            public String currentTimestampFunction = "CURRENT_TIMESTAMP";
0254:            public String dropTableSQL = "DROP TABLE {0}";
0255:
0256:            // types
0257:            public boolean storageLimitationsFatal = false;
0258:            public boolean storeLargeNumbersAsStrings = false;
0259:            public boolean storeCharsAsNumbers = true;
0260:            public boolean useGetBytesForBlobs = false;
0261:            public boolean useSetBytesForBlobs = false;
0262:            public boolean useGetObjectForBlobs = false;
0263:            public boolean useGetStringForClobs = false;
0264:            public boolean useSetStringForClobs = false;
0265:            public int maxEmbeddedBlobSize = -1;
0266:            public int maxEmbeddedClobSize = -1;
0267:            public int inClauseLimit = -1;
0268:            public int datePrecision = MILLI;
0269:            public int characterColumnSize = 255;
0270:            public String arrayTypeName = "ARRAY";
0271:            public String bigintTypeName = "BIGINT";
0272:            public String binaryTypeName = "BINARY";
0273:            public String bitTypeName = "BIT";
0274:            public String blobTypeName = "BLOB";
0275:            public String booleanTypeName = "BOOLEAN";
0276:            public String charTypeName = "CHAR";
0277:            public String clobTypeName = "CLOB";
0278:            public String dateTypeName = "DATE";
0279:            public String decimalTypeName = "DECIMAL";
0280:            public String distinctTypeName = "DISTINCT";
0281:            public String doubleTypeName = "DOUBLE";
0282:            public String floatTypeName = "FLOAT";
0283:            public String integerTypeName = "INTEGER";
0284:            public String javaObjectTypeName = "JAVA_OBJECT";
0285:            public String longVarbinaryTypeName = "LONGVARBINARY";
0286:            public String longVarcharTypeName = "LONGVARCHAR";
0287:            public String nullTypeName = "NULL";
0288:            public String numericTypeName = "NUMERIC";
0289:            public String otherTypeName = "OTHER";
0290:            public String realTypeName = "REAL";
0291:            public String refTypeName = "REF";
0292:            public String smallintTypeName = "SMALLINT";
0293:            public String structTypeName = "STRUCT";
0294:            public String timeTypeName = "TIME";
0295:            public String timestampTypeName = "TIMESTAMP";
0296:            public String tinyintTypeName = "TINYINT";
0297:            public String varbinaryTypeName = "VARBINARY";
0298:            public String varcharTypeName = "VARCHAR";
0299:            public String xmlTypeName = "XML";
0300:            public String getStringVal = "";
0301:
0302:            // schema metadata
0303:            public boolean useSchemaName = true;
0304:            public String tableTypes = "TABLE";
0305:            public boolean supportsSchemaForGetTables = true;
0306:            public boolean supportsSchemaForGetColumns = true;
0307:            public boolean supportsNullTableForGetColumns = true;
0308:            public boolean supportsNullTableForGetPrimaryKeys = false;
0309:            public boolean supportsNullTableForGetIndexInfo = false;
0310:            public boolean supportsNullTableForGetImportedKeys = false;
0311:            public boolean useGetBestRowIdentifierForPrimaryKeys = false;
0312:            public boolean requiresAutoCommitForMetaData = false;
0313:
0314:            // auto-increment
0315:            public int maxAutoAssignNameLength = 31;
0316:            public String autoAssignClause = null;
0317:            public String autoAssignTypeName = null;
0318:            public boolean supportsAutoAssign = false;
0319:            public String lastGeneratedKeyQuery = null;
0320:            public String nextSequenceQuery = null;
0321:            public String sequenceSQL = null;
0322:            public String sequenceSchemaSQL = null;
0323:            public String sequenceNameSQL = null;
0324:
0325:            protected JDBCConfiguration conf = null;
0326:            protected Log log = null;
0327:            protected boolean connected = false;
0328:            protected final Set reservedWordSet = new HashSet();
0329:            protected final Set systemSchemaSet = new HashSet();
0330:            protected final Set systemTableSet = new HashSet();
0331:            protected final Set fixedSizeTypeNameSet = new HashSet();
0332:            protected final Set typeModifierSet = new HashSet();
0333:
0334:            /**
0335:             * If a native query begins with any of the values found here then it will
0336:             * be treated as a select statement.  
0337:             */
0338:            protected final Set selectWordSet = new HashSet();
0339:
0340:            // when we store values that lose precion, track the types so that the
0341:            // first time it happens we can warn the user
0342:            private Set _precisionWarnedTypes = null;
0343:
0344:            // cache lob methods
0345:            private Method _setBytes = null;
0346:            private Method _setString = null;
0347:            private Method _setCharStream = null;
0348:
0349:            // batchLimit value:
0350:            // -1 = unlimited
0351:            // 0  = no batch
0352:            // any positive number = batch limit
0353:            public int batchLimit = NO_BATCH;
0354:
0355:            public DBDictionary() {
0356:                fixedSizeTypeNameSet.addAll(Arrays.asList(new String[] {
0357:                        "BIGINT", "BIT", "BLOB", "CLOB", "DATE", "DECIMAL",
0358:                        "DISTINCT", "DOUBLE", "FLOAT", "INTEGER",
0359:                        "JAVA_OBJECT", "NULL", "NUMERIC", "OTHER", "REAL",
0360:                        "REF", "SMALLINT", "STRUCT", "TIME", "TIMESTAMP",
0361:                        "TINYINT", }));
0362:
0363:                selectWordSet.add("SELECT");
0364:            }
0365:
0366:            /**
0367:             * This method is called when the dictionary first sees any connection.
0368:             * It is used to initialize dictionary metadata if needed. If you
0369:             * override this method, be sure to call
0370:             * <code>super.connectedConfiguration</code>.
0371:             */
0372:            public void connectedConfiguration(Connection conn)
0373:                    throws SQLException {
0374:                if (!connected) {
0375:                    try {
0376:                        if (log.isTraceEnabled())
0377:                            log.trace(DBDictionaryFactory.toString(conn
0378:                                    .getMetaData()));
0379:                    } catch (Exception e) {
0380:                        log.trace(e.toString(), e);
0381:                    }
0382:                }
0383:                connected = true;
0384:            }
0385:
0386:            //////////////////////
0387:            // ResultSet wrappers
0388:            //////////////////////
0389:
0390:            /**
0391:             * Convert the specified column of the SQL ResultSet to the proper
0392:             * java type.
0393:             */
0394:            public Array getArray(ResultSet rs, int column) throws SQLException {
0395:                return rs.getArray(column);
0396:            }
0397:
0398:            /**
0399:             * Convert the specified column of the SQL ResultSet to the proper
0400:             * java type.
0401:             */
0402:            public InputStream getAsciiStream(ResultSet rs, int column)
0403:                    throws SQLException {
0404:                return rs.getAsciiStream(column);
0405:            }
0406:
0407:            /**
0408:             * Convert the specified column of the SQL ResultSet to the proper
0409:             * java type.
0410:             */
0411:            public BigDecimal getBigDecimal(ResultSet rs, int column)
0412:                    throws SQLException {
0413:                if (storeLargeNumbersAsStrings) {
0414:                    String str = getString(rs, column);
0415:                    return (str == null) ? null : new BigDecimal(str);
0416:                }
0417:                return rs.getBigDecimal(column);
0418:            }
0419:
0420:            /**
0421:             * Returns the specified column value as an unknown numeric type;
0422:             * we try from the most generic to the least generic.
0423:             */
0424:            public Number getNumber(ResultSet rs, int column)
0425:                    throws SQLException {
0426:                // try from the most generic, and if errors occur, try
0427:                // less generic types; this enables us to handle values
0428:                // like Double.NaN without having to introspect on the
0429:                // ResultSetMetaData (bug #1053). note that we handle
0430:                // generic exceptions, since some drivers may throw
0431:                // NumberFormatExceptions, whereas others may throw SQLExceptions
0432:                try {
0433:                    return getBigDecimal(rs, column);
0434:                } catch (Exception e1) {
0435:                    try {
0436:                        return new Double(getDouble(rs, column));
0437:                    } catch (Exception e2) {
0438:                        try {
0439:                            return new Float(getFloat(rs, column));
0440:                        } catch (Exception e3) {
0441:                            try {
0442:                                return Numbers.valueOf(getLong(rs, column));
0443:                            } catch (Exception e4) {
0444:                                try {
0445:                                    return Numbers.valueOf(getInt(rs, column));
0446:                                } catch (Exception e5) {
0447:                                }
0448:                            }
0449:                        }
0450:                    }
0451:
0452:                    if (e1 instanceof  RuntimeException)
0453:                        throw (RuntimeException) e1;
0454:                    if (e1 instanceof  SQLException)
0455:                        throw (SQLException) e1;
0456:                }
0457:
0458:                return null;
0459:            }
0460:
0461:            /**
0462:             * Convert the specified column of the SQL ResultSet to the proper
0463:             * java type.
0464:             */
0465:            public BigInteger getBigInteger(ResultSet rs, int column)
0466:                    throws SQLException {
0467:                if (storeLargeNumbersAsStrings) {
0468:                    String str = getString(rs, column);
0469:                    return (str == null) ? null : new BigDecimal(str)
0470:                            .toBigInteger();
0471:                }
0472:                BigDecimal bd = getBigDecimal(rs, column);
0473:                return (bd == null) ? null : bd.toBigInteger();
0474:            }
0475:
0476:            /**
0477:             * Convert the specified column of the SQL ResultSet to the proper
0478:             * java type.
0479:             */
0480:            public InputStream getBinaryStream(ResultSet rs, int column)
0481:                    throws SQLException {
0482:                return rs.getBinaryStream(column);
0483:            }
0484:
0485:            /**
0486:             * Convert the specified column of the SQL ResultSet to the proper
0487:             * java type.
0488:             */
0489:            public Blob getBlob(ResultSet rs, int column) throws SQLException {
0490:                return rs.getBlob(column);
0491:            }
0492:
0493:            /**
0494:             * Convert the specified column of the SQL ResultSet to the proper
0495:             * java type.
0496:             */
0497:            public Object getBlobObject(ResultSet rs, int column,
0498:                    JDBCStore store) throws SQLException {
0499:                InputStream in = null;
0500:                if (useGetBytesForBlobs || useGetObjectForBlobs) {
0501:                    byte[] bytes = getBytes(rs, column);
0502:                    if (bytes != null && bytes.length > 0)
0503:                        in = new ByteArrayInputStream(bytes);
0504:                } else {
0505:                    Blob blob = getBlob(rs, column);
0506:                    if (blob != null && blob.length() > 0)
0507:                        in = blob.getBinaryStream();
0508:                }
0509:                if (in == null)
0510:                    return null;
0511:
0512:                try {
0513:                    if (store == null)
0514:                        return Serialization.deserialize(in, null);
0515:                    return Serialization.deserialize(in, store.getContext());
0516:                } finally {
0517:                    try {
0518:                        in.close();
0519:                    } catch (IOException ioe) {
0520:                    }
0521:                }
0522:            }
0523:
0524:            /**
0525:             * Convert the specified column of the SQL ResultSet to the proper
0526:             * java type.
0527:             */
0528:            public boolean getBoolean(ResultSet rs, int column)
0529:                    throws SQLException {
0530:                return rs.getBoolean(column);
0531:            }
0532:
0533:            /**
0534:             * Convert the specified column of the SQL ResultSet to the proper
0535:             * java type.
0536:             */
0537:            public byte getByte(ResultSet rs, int column) throws SQLException {
0538:                return rs.getByte(column);
0539:            }
0540:
0541:            /**
0542:             * Convert the specified column of the SQL ResultSet to the proper
0543:             * java type.
0544:             */
0545:            public byte[] getBytes(ResultSet rs, int column)
0546:                    throws SQLException {
0547:                if (useGetBytesForBlobs)
0548:                    return rs.getBytes(column);
0549:                if (useGetObjectForBlobs)
0550:                    return (byte[]) rs.getObject(column);
0551:
0552:                Blob blob = getBlob(rs, column);
0553:                if (blob == null)
0554:                    return null;
0555:                int length = (int) blob.length();
0556:                if (length == 0)
0557:                    return null;
0558:                return blob.getBytes(1, length);
0559:            }
0560:
0561:            /**
0562:             * Convert the specified column of the SQL ResultSet to the proper
0563:             * java type. Converts the date from a {@link Timestamp} by default.
0564:             */
0565:            public Calendar getCalendar(ResultSet rs, int column)
0566:                    throws SQLException {
0567:                Date d = getDate(rs, column);
0568:                if (d == null)
0569:                    return null;
0570:
0571:                Calendar cal = Calendar.getInstance();
0572:                cal.setTime(d);
0573:                return cal;
0574:            }
0575:
0576:            /**
0577:             * Convert the specified column of the SQL ResultSet to the proper
0578:             * java type.
0579:             */
0580:            public char getChar(ResultSet rs, int column) throws SQLException {
0581:                if (storeCharsAsNumbers)
0582:                    return (char) getInt(rs, column);
0583:
0584:                String str = getString(rs, column);
0585:                return (StringUtils.isEmpty(str)) ? 0 : str.charAt(0);
0586:            }
0587:
0588:            /**
0589:             * Convert the specified column of the SQL ResultSet to the proper
0590:             * java type.
0591:             */
0592:            public Reader getCharacterStream(ResultSet rs, int column)
0593:                    throws SQLException {
0594:                return rs.getCharacterStream(column);
0595:            }
0596:
0597:            /**
0598:             * Convert the specified column of the SQL ResultSet to the proper
0599:             * java type.
0600:             */
0601:            public Clob getClob(ResultSet rs, int column) throws SQLException {
0602:                return rs.getClob(column);
0603:            }
0604:
0605:            /**
0606:             * Convert the specified column of the SQL ResultSet to the proper
0607:             * java type.
0608:             */
0609:            public String getClobString(ResultSet rs, int column)
0610:                    throws SQLException {
0611:                if (useGetStringForClobs)
0612:                    return rs.getString(column);
0613:
0614:                Clob clob = getClob(rs, column);
0615:                if (clob == null)
0616:                    return null;
0617:                if (clob.length() == 0)
0618:                    return "";
0619:
0620:                // unlikely that we'll have strings over Integer.MAX_VALUE chars
0621:                return clob.getSubString(1, (int) clob.length());
0622:            }
0623:
0624:            /**
0625:             * Convert the specified column of the SQL ResultSet to the proper
0626:             * java type. Converts the date from a {@link Timestamp} by default.
0627:             */
0628:            public Date getDate(ResultSet rs, int column) throws SQLException {
0629:                Timestamp tstamp = getTimestamp(rs, column, null);
0630:                if (tstamp == null)
0631:                    return null;
0632:
0633:                // get the fractional seconds component, rounding away anything beyond
0634:                // milliseconds
0635:                int fractional = (int) Math.round(tstamp.getNanos()
0636:                        / (double) MILLI);
0637:
0638:                // get the millis component; some JDBC drivers round this to the
0639:                // nearest second, while others do not
0640:                long millis = (tstamp.getTime() / 1000L) * 1000L;
0641:                return new Date(millis + fractional);
0642:            }
0643:
0644:            /**
0645:             * Convert the specified column of the SQL ResultSet to the proper
0646:             * java type.
0647:             */
0648:            public java.sql.Date getDate(ResultSet rs, int column, Calendar cal)
0649:                    throws SQLException {
0650:                if (cal == null)
0651:                    return rs.getDate(column);
0652:                return rs.getDate(column, cal);
0653:            }
0654:
0655:            /**
0656:             * Convert the specified column of the SQL ResultSet to the proper
0657:             * java type.
0658:             */
0659:            public double getDouble(ResultSet rs, int column)
0660:                    throws SQLException {
0661:                return rs.getDouble(column);
0662:            }
0663:
0664:            /**
0665:             * Convert the specified column of the SQL ResultSet to the proper
0666:             * java type.
0667:             */
0668:            public float getFloat(ResultSet rs, int column) throws SQLException {
0669:                return rs.getFloat(column);
0670:            }
0671:
0672:            /**
0673:             * Convert the specified column of the SQL ResultSet to the proper
0674:             * java type.
0675:             */
0676:            public int getInt(ResultSet rs, int column) throws SQLException {
0677:                return rs.getInt(column);
0678:            }
0679:
0680:            /**
0681:             * Convert the specified column of the SQL ResultSet to the proper
0682:             * java type.
0683:             */
0684:            public Locale getLocale(ResultSet rs, int column)
0685:                    throws SQLException {
0686:                String str = getString(rs, column);
0687:                if (StringUtils.isEmpty(str))
0688:                    return null;
0689:
0690:                String[] params = Strings.split(str, "_", 3);
0691:                if (params.length < 3)
0692:                    return null;
0693:                return new Locale(params[0], params[1], params[2]);
0694:            }
0695:
0696:            /**
0697:             * Convert the specified column of the SQL ResultSet to the proper
0698:             * java type.
0699:             */
0700:            public long getLong(ResultSet rs, int column) throws SQLException {
0701:                return rs.getLong(column);
0702:            }
0703:
0704:            /**
0705:             * Convert the specified column of the SQL ResultSet to the proper
0706:             * java type.
0707:             */
0708:            public Object getObject(ResultSet rs, int column, Map map)
0709:                    throws SQLException {
0710:                if (map == null)
0711:                    return rs.getObject(column);
0712:                return rs.getObject(column, map);
0713:            }
0714:
0715:            /**
0716:             * Convert the specified column of the SQL ResultSet to the proper
0717:             * java type.
0718:             */
0719:            public Ref getRef(ResultSet rs, int column, Map map)
0720:                    throws SQLException {
0721:                return rs.getRef(column);
0722:            }
0723:
0724:            /**
0725:             * Convert the specified column of the SQL ResultSet to the proper
0726:             * java type.
0727:             */
0728:            public short getShort(ResultSet rs, int column) throws SQLException {
0729:                return rs.getShort(column);
0730:            }
0731:
0732:            /**
0733:             * Convert the specified column of the SQL ResultSet to the proper
0734:             * java type.
0735:             */
0736:            public String getString(ResultSet rs, int column)
0737:                    throws SQLException {
0738:                return rs.getString(column);
0739:            }
0740:
0741:            /**
0742:             * Convert the specified column of the SQL ResultSet to the proper
0743:             * java type.
0744:             */
0745:            public Time getTime(ResultSet rs, int column, Calendar cal)
0746:                    throws SQLException {
0747:                if (cal == null)
0748:                    return rs.getTime(column);
0749:                return rs.getTime(column, cal);
0750:            }
0751:
0752:            /**
0753:             * Convert the specified column of the SQL ResultSet to the proper
0754:             * java type.
0755:             */
0756:            public Timestamp getTimestamp(ResultSet rs, int column, Calendar cal)
0757:                    throws SQLException {
0758:                if (cal == null)
0759:                    return rs.getTimestamp(column);
0760:                return rs.getTimestamp(column, cal);
0761:            }
0762:
0763:            //////////////////////////////
0764:            // PreparedStatement wrappers
0765:            //////////////////////////////
0766:
0767:            /**
0768:             * Set the given value as a parameter to the statement.
0769:             */
0770:            public void setArray(PreparedStatement stmnt, int idx, Array val,
0771:                    Column col) throws SQLException {
0772:                stmnt.setArray(idx, val);
0773:            }
0774:
0775:            /**
0776:             * Set the given value as a parameter to the statement.
0777:             */
0778:            public void setAsciiStream(PreparedStatement stmnt, int idx,
0779:                    InputStream val, int length, Column col)
0780:                    throws SQLException {
0781:                stmnt.setAsciiStream(idx, val, length);
0782:            }
0783:
0784:            /**
0785:             * Set the given value as a parameter to the statement.
0786:             */
0787:            public void setBigDecimal(PreparedStatement stmnt, int idx,
0788:                    BigDecimal val, Column col) throws SQLException {
0789:                if ((col != null && col.isCompatible(Types.VARCHAR, null, 0, 0))
0790:                        || (col == null && storeLargeNumbersAsStrings))
0791:                    setString(stmnt, idx, val.toString(), col);
0792:                else
0793:                    stmnt.setBigDecimal(idx, val);
0794:            }
0795:
0796:            /**
0797:             * Set the given value as a parameter to the statement.
0798:             */
0799:            public void setBigInteger(PreparedStatement stmnt, int idx,
0800:                    BigInteger val, Column col) throws SQLException {
0801:                if ((col != null && col.isCompatible(Types.VARCHAR, null, 0, 0))
0802:                        || (col == null && storeLargeNumbersAsStrings))
0803:                    setString(stmnt, idx, val.toString(), col);
0804:                else
0805:                    setBigDecimal(stmnt, idx, new BigDecimal(val), col);
0806:            }
0807:
0808:            /**
0809:             * Set the given value as a parameter to the statement.
0810:             */
0811:            public void setBinaryStream(PreparedStatement stmnt, int idx,
0812:                    InputStream val, int length, Column col)
0813:                    throws SQLException {
0814:                stmnt.setBinaryStream(idx, val, length);
0815:            }
0816:
0817:            /**
0818:             * Set the given value as a parameter to the statement.
0819:             */
0820:            public void setBlob(PreparedStatement stmnt, int idx, Blob val,
0821:                    Column col) throws SQLException {
0822:                stmnt.setBlob(idx, val);
0823:            }
0824:
0825:            /**
0826:             * Set the given value as a parameter to the statement. Uses the
0827:             * {@link #serialize} method to serialize the value.
0828:             */
0829:            public void setBlobObject(PreparedStatement stmnt, int idx,
0830:                    Object val, Column col, JDBCStore store)
0831:                    throws SQLException {
0832:                setBytes(stmnt, idx, serialize(val, store), col);
0833:            }
0834:
0835:            /**
0836:             * Set the given value as a parameter to the statement.
0837:             */
0838:            public void setBoolean(PreparedStatement stmnt, int idx,
0839:                    boolean val, Column col) throws SQLException {
0840:                stmnt.setInt(idx, (val) ? 1 : 0);
0841:            }
0842:
0843:            /**
0844:             * Set the given value as a parameter to the statement.
0845:             */
0846:            public void setByte(PreparedStatement stmnt, int idx, byte val,
0847:                    Column col) throws SQLException {
0848:                stmnt.setByte(idx, val);
0849:            }
0850:
0851:            /**
0852:             * Set the given value as a parameter to the statement.
0853:             */
0854:            public void setBytes(PreparedStatement stmnt, int idx, byte[] val,
0855:                    Column col) throws SQLException {
0856:                if (useSetBytesForBlobs)
0857:                    stmnt.setBytes(idx, val);
0858:                else
0859:                    setBinaryStream(stmnt, idx, new ByteArrayInputStream(val),
0860:                            val.length, col);
0861:            }
0862:
0863:            /**
0864:             * Set the given value as a parameter to the statement.
0865:             */
0866:            public void setChar(PreparedStatement stmnt, int idx, char val,
0867:                    Column col) throws SQLException {
0868:                if ((col != null && col.isCompatible(Types.INTEGER, null, 0, 0))
0869:                        || (col == null && storeCharsAsNumbers))
0870:                    setInt(stmnt, idx, (int) val, col);
0871:                else
0872:                    setString(stmnt, idx, String.valueOf(val), col);
0873:            }
0874:
0875:            /**
0876:             * Set the given value as a parameter to the statement.
0877:             */
0878:            public void setCharacterStream(PreparedStatement stmnt, int idx,
0879:                    Reader val, int length, Column col) throws SQLException {
0880:                stmnt.setCharacterStream(idx, val, length);
0881:            }
0882:
0883:            /**
0884:             * Set the given value as a parameter to the statement.
0885:             */
0886:            public void setClob(PreparedStatement stmnt, int idx, Clob val,
0887:                    Column col) throws SQLException {
0888:                stmnt.setClob(idx, val);
0889:            }
0890:
0891:            /**
0892:             * Set the given value as a parameter to the statement.
0893:             */
0894:            public void setClobString(PreparedStatement stmnt, int idx,
0895:                    String val, Column col) throws SQLException {
0896:                if (useSetStringForClobs)
0897:                    stmnt.setString(idx, val);
0898:                else {
0899:                    // set reader from string
0900:                    StringReader in = new StringReader(val);
0901:                    setCharacterStream(stmnt, idx, in, val.length(), col);
0902:                }
0903:            }
0904:
0905:            /**
0906:             * Set the given value as a parameter to the statement.
0907:             */
0908:            public void setDate(PreparedStatement stmnt, int idx, Date val,
0909:                    Column col) throws SQLException {
0910:                if (col != null && col.getType() == Types.DATE)
0911:                    setDate(stmnt, idx, new java.sql.Date(val.getTime()), null,
0912:                            col);
0913:                else if (col != null && col.getType() == Types.TIME)
0914:                    setTime(stmnt, idx, new Time(val.getTime()), null, col);
0915:                else if (val instanceof  Timestamp)
0916:                    setTimestamp(stmnt, idx, (Timestamp) val, null, col);
0917:                else
0918:                    setTimestamp(stmnt, idx, new Timestamp(val.getTime()),
0919:                            null, col);
0920:            }
0921:
0922:            /**
0923:             * Set the given value as a parameter to the statement.
0924:             */
0925:            public void setDate(PreparedStatement stmnt, int idx,
0926:                    java.sql.Date val, Calendar cal, Column col)
0927:                    throws SQLException {
0928:                if (cal == null)
0929:                    stmnt.setDate(idx, val);
0930:                else
0931:                    stmnt.setDate(idx, val, cal);
0932:            }
0933:
0934:            /**
0935:             * Set the given value as a parameter to the statement.
0936:             */
0937:            public void setCalendar(PreparedStatement stmnt, int idx,
0938:                    Calendar val, Column col) throws SQLException {
0939:                // by default we merely delegate the the Date parameter
0940:                setDate(stmnt, idx, val.getTime(), col);
0941:            }
0942:
0943:            /**
0944:             * Set the given value as a parameter to the statement.
0945:             */
0946:            public void setDouble(PreparedStatement stmnt, int idx, double val,
0947:                    Column col) throws SQLException {
0948:                stmnt.setDouble(idx, val);
0949:            }
0950:
0951:            /**
0952:             * Set the given value as a parameter to the statement.
0953:             */
0954:            public void setFloat(PreparedStatement stmnt, int idx, float val,
0955:                    Column col) throws SQLException {
0956:                stmnt.setFloat(idx, val);
0957:            }
0958:
0959:            /**
0960:             * Set the given value as a parameter to the statement.
0961:             */
0962:            public void setInt(PreparedStatement stmnt, int idx, int val,
0963:                    Column col) throws SQLException {
0964:                stmnt.setInt(idx, val);
0965:            }
0966:
0967:            /**
0968:             * Set the given value as a parameter to the statement.
0969:             */
0970:            public void setLong(PreparedStatement stmnt, int idx, long val,
0971:                    Column col) throws SQLException {
0972:                stmnt.setLong(idx, val);
0973:            }
0974:
0975:            /**
0976:             * Set the given value as a parameter to the statement.
0977:             */
0978:            public void setLocale(PreparedStatement stmnt, int idx, Locale val,
0979:                    Column col) throws SQLException {
0980:                setString(stmnt, idx, val.getLanguage() + "_"
0981:                        + val.getCountry() + "_" + val.getVariant(), col);
0982:            }
0983:
0984:            /**
0985:             * Set the given value as a parameters to the statement. The column
0986:             * type will come from {@link Types}.
0987:             */
0988:            public void setNull(PreparedStatement stmnt, int idx, int colType,
0989:                    Column col) throws SQLException {
0990:                stmnt.setNull(idx, colType);
0991:            }
0992:
0993:            /**
0994:             * Set the given value as a parameter to the statement.
0995:             */
0996:            public void setNumber(PreparedStatement stmnt, int idx, Number num,
0997:                    Column col) throws SQLException {
0998:                // check for known floating point types to give driver a chance to
0999:                // handle special numbers like NaN and infinity; bug #1053
1000:                if (num instanceof  Double)
1001:                    setDouble(stmnt, idx, ((Double) num).doubleValue(), col);
1002:                else if (num instanceof  Float)
1003:                    setFloat(stmnt, idx, ((Float) num).floatValue(), col);
1004:                else
1005:                    setBigDecimal(stmnt, idx, new BigDecimal(num.toString()),
1006:                            col);
1007:            }
1008:
1009:            /**
1010:             * Set the given value as a parameters to the statement. The column
1011:             * type will come from {@link Types}.
1012:             */
1013:            public void setObject(PreparedStatement stmnt, int idx, Object val,
1014:                    int colType, Column col) throws SQLException {
1015:                if (colType == -1 || colType == Types.OTHER)
1016:                    stmnt.setObject(idx, val);
1017:                else
1018:                    stmnt.setObject(idx, val, colType);
1019:            }
1020:
1021:            /**
1022:             * Set the given value as a parameter to the statement.
1023:             */
1024:            public void setRef(PreparedStatement stmnt, int idx, Ref val,
1025:                    Column col) throws SQLException {
1026:                stmnt.setRef(idx, val);
1027:            }
1028:
1029:            /**
1030:             * Set the given value as a parameter to the statement.
1031:             */
1032:            public void setShort(PreparedStatement stmnt, int idx, short val,
1033:                    Column col) throws SQLException {
1034:                stmnt.setShort(idx, val);
1035:            }
1036:
1037:            /**
1038:             * Set the given value as a parameter to the statement.
1039:             */
1040:            public void setString(PreparedStatement stmnt, int idx, String val,
1041:                    Column col) throws SQLException {
1042:                stmnt.setString(idx, val);
1043:            }
1044:
1045:            /**
1046:             * Set the given value as a parameter to the statement.
1047:             */
1048:            public void setTime(PreparedStatement stmnt, int idx, Time val,
1049:                    Calendar cal, Column col) throws SQLException {
1050:                if (cal == null)
1051:                    stmnt.setTime(idx, val);
1052:                else
1053:                    stmnt.setTime(idx, val, cal);
1054:            }
1055:
1056:            /**
1057:             * Set the given value as a parameter to the statement.
1058:             */
1059:            public void setTimestamp(PreparedStatement stmnt, int idx,
1060:                    Timestamp val, Calendar cal, Column col)
1061:                    throws SQLException {
1062:                // ensure that we do not insert dates at a greater precision than
1063:                // that at which they will be returned by a SELECT
1064:                int rounded = (int) Math.round(val.getNanos()
1065:                        / (double) datePrecision);
1066:                int nanos = rounded * datePrecision;
1067:                if (nanos > 999999999) {
1068:                    // rollover to next second
1069:                    val.setTime(val.getTime() + 1000);
1070:                    nanos = 0;
1071:                }
1072:
1073:                if (supportsTimestampNanos)
1074:                    val.setNanos(nanos);
1075:                else
1076:                    val.setNanos(0);
1077:
1078:                if (cal == null)
1079:                    stmnt.setTimestamp(idx, val);
1080:                else
1081:                    stmnt.setTimestamp(idx, val, cal);
1082:            }
1083:
1084:            /**
1085:             * Set a column value into a prepared statement.
1086:             *
1087:             * @param stmnt the prepared statement to parameterize
1088:             * @param idx the index of the parameter in the prepared statement
1089:             * @param val the value of the column
1090:             * @param col the column being set
1091:             * @param type the field mapping type code for the value
1092:             * @param store the store manager for the current context
1093:             */
1094:            public void setTyped(PreparedStatement stmnt, int idx, Object val,
1095:                    Column col, int type, JDBCStore store) throws SQLException {
1096:                if (val == null) {
1097:                    setNull(stmnt, idx, (col == null) ? Types.OTHER : col
1098:                            .getType(), col);
1099:                    return;
1100:                }
1101:
1102:                Sized s;
1103:                Calendard c;
1104:                switch (type) {
1105:                case JavaTypes.BOOLEAN:
1106:                case JavaTypes.BOOLEAN_OBJ:
1107:                    setBoolean(stmnt, idx, ((Boolean) val).booleanValue(), col);
1108:                    break;
1109:                case JavaTypes.BYTE:
1110:                case JavaTypes.BYTE_OBJ:
1111:                    setByte(stmnt, idx, ((Number) val).byteValue(), col);
1112:                    break;
1113:                case JavaTypes.CHAR:
1114:                case JavaTypes.CHAR_OBJ:
1115:                    setChar(stmnt, idx, ((Character) val).charValue(), col);
1116:                    break;
1117:                case JavaTypes.DOUBLE:
1118:                case JavaTypes.DOUBLE_OBJ:
1119:                    setDouble(stmnt, idx, ((Number) val).doubleValue(), col);
1120:                    break;
1121:                case JavaTypes.FLOAT:
1122:                case JavaTypes.FLOAT_OBJ:
1123:                    setFloat(stmnt, idx, ((Number) val).floatValue(), col);
1124:                    break;
1125:                case JavaTypes.INT:
1126:                case JavaTypes.INT_OBJ:
1127:                    setInt(stmnt, idx, ((Number) val).intValue(), col);
1128:                    break;
1129:                case JavaTypes.LONG:
1130:                case JavaTypes.LONG_OBJ:
1131:                    setLong(stmnt, idx, ((Number) val).longValue(), col);
1132:                    break;
1133:                case JavaTypes.SHORT:
1134:                case JavaTypes.SHORT_OBJ:
1135:                    setShort(stmnt, idx, ((Number) val).shortValue(), col);
1136:                    break;
1137:                case JavaTypes.STRING:
1138:                    if (col != null
1139:                            && (col.getType() == Types.CLOB || col.getType() == Types.LONGVARCHAR))
1140:                        setClobString(stmnt, idx, (String) val, col);
1141:                    else
1142:                        setString(stmnt, idx, (String) val, col);
1143:                    break;
1144:                case JavaTypes.OBJECT:
1145:                    setBlobObject(stmnt, idx, val, col, store);
1146:                    break;
1147:                case JavaTypes.DATE:
1148:                    setDate(stmnt, idx, (Date) val, col);
1149:                    break;
1150:                case JavaTypes.CALENDAR:
1151:                    setCalendar(stmnt, idx, (Calendar) val, col);
1152:                    break;
1153:                case JavaTypes.BIGDECIMAL:
1154:                    setBigDecimal(stmnt, idx, (BigDecimal) val, col);
1155:                    break;
1156:                case JavaTypes.BIGINTEGER:
1157:                    setBigInteger(stmnt, idx, (BigInteger) val, col);
1158:                    break;
1159:                case JavaTypes.NUMBER:
1160:                    setNumber(stmnt, idx, (Number) val, col);
1161:                    break;
1162:                case JavaTypes.LOCALE:
1163:                    setLocale(stmnt, idx, (Locale) val, col);
1164:                    break;
1165:                case JavaSQLTypes.SQL_ARRAY:
1166:                    setArray(stmnt, idx, (Array) val, col);
1167:                    break;
1168:                case JavaSQLTypes.ASCII_STREAM:
1169:                    s = (Sized) val;
1170:                    setAsciiStream(stmnt, idx, (InputStream) s.value, s.size,
1171:                            col);
1172:                    break;
1173:                case JavaSQLTypes.BINARY_STREAM:
1174:                    s = (Sized) val;
1175:                    setBinaryStream(stmnt, idx, (InputStream) s.value, s.size,
1176:                            col);
1177:                    break;
1178:                case JavaSQLTypes.BLOB:
1179:                    setBlob(stmnt, idx, (Blob) val, col);
1180:                    break;
1181:                case JavaSQLTypes.BYTES:
1182:                    setBytes(stmnt, idx, (byte[]) val, col);
1183:                    break;
1184:                case JavaSQLTypes.CHAR_STREAM:
1185:                    s = (Sized) val;
1186:                    setCharacterStream(stmnt, idx, (Reader) s.value, s.size,
1187:                            col);
1188:                    break;
1189:                case JavaSQLTypes.CLOB:
1190:                    setClob(stmnt, idx, (Clob) val, col);
1191:                    break;
1192:                case JavaSQLTypes.SQL_DATE:
1193:                    if (val instanceof  Calendard) {
1194:                        c = (Calendard) val;
1195:                        setDate(stmnt, idx, (java.sql.Date) c.value,
1196:                                c.calendar, col);
1197:                    } else
1198:                        setDate(stmnt, idx, (java.sql.Date) val, null, col);
1199:                    break;
1200:                case JavaSQLTypes.REF:
1201:                    setRef(stmnt, idx, (Ref) val, col);
1202:                    break;
1203:                case JavaSQLTypes.TIME:
1204:                    if (val instanceof  Calendard) {
1205:                        c = (Calendard) val;
1206:                        setTime(stmnt, idx, (Time) c.value, c.calendar, col);
1207:                    } else
1208:                        setTime(stmnt, idx, (Time) val, null, col);
1209:                    break;
1210:                case JavaSQLTypes.TIMESTAMP:
1211:                    if (val instanceof  Calendard) {
1212:                        c = (Calendard) val;
1213:                        setTimestamp(stmnt, idx, (Timestamp) c.value,
1214:                                c.calendar, col);
1215:                    } else
1216:                        setTimestamp(stmnt, idx, (Timestamp) val, null, col);
1217:                    break;
1218:                default:
1219:                    if (col != null
1220:                            && (col.getType() == Types.BLOB || col.getType() == Types.VARBINARY))
1221:                        setBlobObject(stmnt, idx, val, col, store);
1222:                    else
1223:                        setObject(stmnt, idx, val, col.getType(), col);
1224:                }
1225:            }
1226:
1227:            /**
1228:             * Set a completely unknown parameter into a prepared statement.
1229:             */
1230:            public void setUnknown(PreparedStatement stmnt, int idx,
1231:                    Object val, Column col) throws SQLException {
1232:                Sized sized = null;
1233:                Calendard cald = null;
1234:                if (val instanceof  Sized) {
1235:                    sized = (Sized) val;
1236:                    val = sized.value;
1237:                } else if (val instanceof  Calendard) {
1238:                    cald = (Calendard) val;
1239:                    val = cald.value;
1240:                }
1241:
1242:                if (val == null)
1243:                    setNull(stmnt, idx, (col == null) ? Types.OTHER : col
1244:                            .getType(), col);
1245:                else if (val instanceof  String)
1246:                    setString(stmnt, idx, val.toString(), col);
1247:                else if (val instanceof  Integer)
1248:                    setInt(stmnt, idx, ((Integer) val).intValue(), col);
1249:                else if (val instanceof  Boolean)
1250:                    setBoolean(stmnt, idx, ((Boolean) val).booleanValue(), col);
1251:                else if (val instanceof  Long)
1252:                    setLong(stmnt, idx, ((Long) val).longValue(), col);
1253:                else if (val instanceof  Float)
1254:                    setFloat(stmnt, idx, ((Float) val).floatValue(), col);
1255:                else if (val instanceof  Double)
1256:                    setDouble(stmnt, idx, ((Double) val).doubleValue(), col);
1257:                else if (val instanceof  Byte)
1258:                    setByte(stmnt, idx, ((Byte) val).byteValue(), col);
1259:                else if (val instanceof  Character)
1260:                    setChar(stmnt, idx, ((Character) val).charValue(), col);
1261:                else if (val instanceof  Short)
1262:                    setShort(stmnt, idx, ((Short) val).shortValue(), col);
1263:                else if (val instanceof  Locale)
1264:                    setLocale(stmnt, idx, (Locale) val, col);
1265:                else if (val instanceof  BigDecimal)
1266:                    setBigDecimal(stmnt, idx, (BigDecimal) val, col);
1267:                else if (val instanceof  BigInteger)
1268:                    setBigInteger(stmnt, idx, (BigInteger) val, col);
1269:                else if (val instanceof  Array)
1270:                    setArray(stmnt, idx, (Array) val, col);
1271:                else if (val instanceof  Blob)
1272:                    setBlob(stmnt, idx, (Blob) val, col);
1273:                else if (val instanceof  byte[])
1274:                    setBytes(stmnt, idx, (byte[]) val, col);
1275:                else if (val instanceof  Clob)
1276:                    setClob(stmnt, idx, (Clob) val, col);
1277:                else if (val instanceof  Ref)
1278:                    setRef(stmnt, idx, (Ref) val, col);
1279:                else if (val instanceof  java.sql.Date)
1280:                    setDate(stmnt, idx, (java.sql.Date) val,
1281:                            (cald == null) ? null : cald.calendar, col);
1282:                else if (val instanceof  Timestamp)
1283:                    setTimestamp(stmnt, idx, (Timestamp) val,
1284:                            (cald == null) ? null : cald.calendar, col);
1285:                else if (val instanceof  Time)
1286:                    setTime(stmnt, idx, (Time) val, (cald == null) ? null
1287:                            : cald.calendar, col);
1288:                else if (val instanceof  Date)
1289:                    setDate(stmnt, idx, (Date) val, col);
1290:                else if (val instanceof  Calendar)
1291:                    setDate(stmnt, idx, ((Calendar) val).getTime(), col);
1292:                else if (val instanceof  Reader)
1293:                    setCharacterStream(stmnt, idx, (Reader) val,
1294:                            (sized == null) ? 0 : sized.size, col);
1295:                else
1296:                    throw new UserException(_loc.get("bad-param", val
1297:                            .getClass()));
1298:            }
1299:
1300:            /**
1301:             * Return the serialized bytes for the given object.
1302:             */
1303:            public byte[] serialize(Object val, JDBCStore store)
1304:                    throws SQLException {
1305:                if (val == null)
1306:                    return null;
1307:                if (val instanceof  SerializedData)
1308:                    return ((SerializedData) val).bytes;
1309:                return Serialization.serialize(val, store.getContext());
1310:            }
1311:
1312:            /**
1313:             * Invoke the JDK 1.4 <code>setBytes</code> method on the given BLOB object.
1314:             */
1315:            public void putBytes(Object blob, byte[] data) throws SQLException {
1316:                if (_setBytes == null) {
1317:                    try {
1318:                        _setBytes = blob.getClass().getMethod("setBytes",
1319:                                new Class[] { long.class, byte[].class });
1320:                    } catch (Exception e) {
1321:                        throw new StoreException(e);
1322:                    }
1323:                }
1324:                invokePutLobMethod(_setBytes, blob, new Object[] {
1325:                        Numbers.valueOf(1L), data });
1326:            }
1327:
1328:            /**
1329:             * Invoke the JDK 1.4 <code>setString</code> method on the given CLOB
1330:             * object.
1331:             */
1332:            public void putString(Object clob, String data) throws SQLException {
1333:                if (_setString == null) {
1334:                    try {
1335:                        _setString = clob.getClass().getMethod("setString",
1336:                                new Class[] { long.class, String.class });
1337:                    } catch (Exception e) {
1338:                        throw new StoreException(e);
1339:                    }
1340:                }
1341:                invokePutLobMethod(_setString, clob, new Object[] {
1342:                        Numbers.valueOf(1L), data });
1343:            }
1344:
1345:            /**
1346:             * Invoke the JDK 1.4 <code>setCharacterStream</code> method on the given
1347:             * CLOB object.
1348:             */
1349:            public void putChars(Object clob, char[] data) throws SQLException {
1350:                if (_setCharStream == null) {
1351:                    try {
1352:                        _setCharStream = clob.getClass().getMethod(
1353:                                "setCharacterStream",
1354:                                new Class[] { long.class });
1355:                    } catch (Exception e) {
1356:                        throw new StoreException(e);
1357:                    }
1358:                }
1359:
1360:                Writer writer = (Writer) invokePutLobMethod(_setCharStream,
1361:                        clob, new Object[] { Numbers.valueOf(1L) });
1362:                try {
1363:                    writer.write(data);
1364:                    writer.flush();
1365:                } catch (IOException ioe) {
1366:                    throw new SQLException(ioe.toString());
1367:                }
1368:            }
1369:
1370:            /**
1371:             * Invoke the given LOB method on the given target with the given data.
1372:             */
1373:            private static Object invokePutLobMethod(Method method,
1374:                    Object target, Object[] args) throws SQLException {
1375:                try {
1376:                    return method.invoke(target, args);
1377:                } catch (InvocationTargetException ite) {
1378:                    Throwable t = ite.getTargetException();
1379:                    if (t instanceof  SQLException)
1380:                        throw (SQLException) t;
1381:                    throw new StoreException(t);
1382:                } catch (Exception e) {
1383:                    throw new StoreException(e);
1384:                }
1385:            }
1386:
1387:            /**
1388:             * Warn that a particular value could not be stored precisely.
1389:             * After the first warning for a particular type, messages
1390:             * will be turned into trace messages.
1391:             */
1392:            protected void storageWarning(Object orig, Object converted) {
1393:                boolean warn;
1394:                synchronized (this ) {
1395:                    if (_precisionWarnedTypes == null)
1396:                        _precisionWarnedTypes = new HashSet();
1397:                    warn = _precisionWarnedTypes.add(orig.getClass());
1398:                }
1399:
1400:                if (storageLimitationsFatal || (warn && log.isWarnEnabled())
1401:                        || (!warn && log.isTraceEnabled())) {
1402:                    Message msg = _loc.get("storage-restriction", new Object[] {
1403:                            platform, orig, orig.getClass().getName(),
1404:                            converted, });
1405:
1406:                    if (storageLimitationsFatal)
1407:                        throw new StoreException(msg);
1408:
1409:                    if (warn)
1410:                        log.warn(msg);
1411:                    else
1412:                        log.trace(msg);
1413:                }
1414:            }
1415:
1416:            /////////
1417:            // Types
1418:            /////////
1419:
1420:            /**
1421:             * Return the preferred {@link Types} constant for the given
1422:             * {@link JavaTypes} or {@link JavaSQLTypes} constant.
1423:             */
1424:            public int getJDBCType(int metaTypeCode, boolean lob) {
1425:                if (lob) {
1426:                    switch (metaTypeCode) {
1427:                    case JavaTypes.STRING:
1428:                    case JavaSQLTypes.ASCII_STREAM:
1429:                    case JavaSQLTypes.CHAR_STREAM:
1430:                        return getPreferredType(Types.CLOB);
1431:                    default:
1432:                        return getPreferredType(Types.BLOB);
1433:                    }
1434:                }
1435:
1436:                switch (metaTypeCode) {
1437:                case JavaTypes.BOOLEAN:
1438:                case JavaTypes.BOOLEAN_OBJ:
1439:                    return getPreferredType(Types.BIT);
1440:                case JavaTypes.BYTE:
1441:                case JavaTypes.BYTE_OBJ:
1442:                    return getPreferredType(Types.TINYINT);
1443:                case JavaTypes.CHAR:
1444:                case JavaTypes.CHAR_OBJ:
1445:                    if (storeCharsAsNumbers)
1446:                        return getPreferredType(Types.INTEGER);
1447:                    return getPreferredType(Types.CHAR);
1448:                case JavaTypes.DOUBLE:
1449:                case JavaTypes.DOUBLE_OBJ:
1450:                    return getPreferredType(Types.DOUBLE);
1451:                case JavaTypes.FLOAT:
1452:                case JavaTypes.FLOAT_OBJ:
1453:                    return getPreferredType(Types.REAL);
1454:                case JavaTypes.INT:
1455:                case JavaTypes.INT_OBJ:
1456:                    return getPreferredType(Types.INTEGER);
1457:                case JavaTypes.LONG:
1458:                case JavaTypes.LONG_OBJ:
1459:                    return getPreferredType(Types.BIGINT);
1460:                case JavaTypes.SHORT:
1461:                case JavaTypes.SHORT_OBJ:
1462:                    return getPreferredType(Types.SMALLINT);
1463:                case JavaTypes.STRING:
1464:                case JavaTypes.LOCALE:
1465:                case JavaSQLTypes.ASCII_STREAM:
1466:                case JavaSQLTypes.CHAR_STREAM:
1467:                    return getPreferredType(Types.VARCHAR);
1468:                case JavaTypes.BIGINTEGER:
1469:                    if (storeLargeNumbersAsStrings)
1470:                        return getPreferredType(Types.VARCHAR);
1471:                    return getPreferredType(Types.BIGINT);
1472:                case JavaTypes.BIGDECIMAL:
1473:                    if (storeLargeNumbersAsStrings)
1474:                        return getPreferredType(Types.VARCHAR);
1475:                    return getPreferredType(Types.DOUBLE);
1476:                case JavaTypes.NUMBER:
1477:                    if (storeLargeNumbersAsStrings)
1478:                        return getPreferredType(Types.VARCHAR);
1479:                    return getPreferredType(Types.NUMERIC);
1480:                case JavaTypes.CALENDAR:
1481:                case JavaTypes.DATE:
1482:                    return getPreferredType(Types.TIMESTAMP);
1483:                case JavaSQLTypes.SQL_ARRAY:
1484:                    return getPreferredType(Types.ARRAY);
1485:                case JavaSQLTypes.BINARY_STREAM:
1486:                case JavaSQLTypes.BLOB:
1487:                case JavaSQLTypes.BYTES:
1488:                    return getPreferredType(Types.BLOB);
1489:                case JavaSQLTypes.CLOB:
1490:                    return getPreferredType(Types.CLOB);
1491:                case JavaSQLTypes.SQL_DATE:
1492:                    return getPreferredType(Types.DATE);
1493:                case JavaSQLTypes.TIME:
1494:                    return getPreferredType(Types.TIME);
1495:                case JavaSQLTypes.TIMESTAMP:
1496:                    return getPreferredType(Types.TIMESTAMP);
1497:                default:
1498:                    return getPreferredType(Types.BLOB);
1499:                }
1500:            }
1501:
1502:            /**
1503:             * Return the preferred {@link Types} type for the given one. Returns
1504:             * the given type by default.
1505:             */
1506:            public int getPreferredType(int type) {
1507:                return type;
1508:            }
1509:
1510:            /**
1511:             * Return the preferred database type name for the given column's type
1512:             * from {@link Types}.
1513:             */
1514:            public String getTypeName(Column col) {
1515:                if (!StringUtils.isEmpty(col.getTypeName()))
1516:                    return appendSize(col, col.getTypeName());
1517:
1518:                if (col.isAutoAssigned() && autoAssignTypeName != null)
1519:                    return appendSize(col, autoAssignTypeName);
1520:
1521:                return appendSize(col, getTypeName(col.getType()));
1522:            }
1523:
1524:            /**
1525:             * Returns the type name for the specific constant as defined
1526:             * by {@link java.sql.Types}.
1527:             *
1528:             * @param type the type
1529:             * @return the name for the type
1530:             */
1531:            public String getTypeName(int type) {
1532:                switch (type) {
1533:                case Types.ARRAY:
1534:                    return arrayTypeName;
1535:                case Types.BIGINT:
1536:                    return bigintTypeName;
1537:                case Types.BINARY:
1538:                    return binaryTypeName;
1539:                case Types.BIT:
1540:                    return bitTypeName;
1541:                case Types.BLOB:
1542:                    return blobTypeName;
1543:                case Types.BOOLEAN:
1544:                    return booleanTypeName;
1545:                case Types.CHAR:
1546:                    return charTypeName;
1547:                case Types.CLOB:
1548:                    return clobTypeName;
1549:                case Types.DATE:
1550:                    return dateTypeName;
1551:                case Types.DECIMAL:
1552:                    return decimalTypeName;
1553:                case Types.DISTINCT:
1554:                    return distinctTypeName;
1555:                case Types.DOUBLE:
1556:                    return doubleTypeName;
1557:                case Types.FLOAT:
1558:                    return floatTypeName;
1559:                case Types.INTEGER:
1560:                    return integerTypeName;
1561:                case Types.JAVA_OBJECT:
1562:                    return javaObjectTypeName;
1563:                case Types.LONGVARBINARY:
1564:                    return longVarbinaryTypeName;
1565:                case Types.LONGVARCHAR:
1566:                    return longVarcharTypeName;
1567:                case Types.NULL:
1568:                    return nullTypeName;
1569:                case Types.NUMERIC:
1570:                    return numericTypeName;
1571:                case Types.OTHER:
1572:                    return otherTypeName;
1573:                case Types.REAL:
1574:                    return realTypeName;
1575:                case Types.REF:
1576:                    return refTypeName;
1577:                case Types.SMALLINT:
1578:                    return smallintTypeName;
1579:                case Types.STRUCT:
1580:                    return structTypeName;
1581:                case Types.TIME:
1582:                    return timeTypeName;
1583:                case Types.TIMESTAMP:
1584:                    return timestampTypeName;
1585:                case Types.TINYINT:
1586:                    return tinyintTypeName;
1587:                case Types.VARBINARY:
1588:                    return varbinaryTypeName;
1589:                case Types.VARCHAR:
1590:                    return varcharTypeName;
1591:                default:
1592:                    return otherTypeName;
1593:                }
1594:            }
1595:
1596:            /**
1597:             * Helper method to add size properties to the specified type.
1598:             * If present, the string "{0}" will be replaced with the size definition;
1599:             * otherwise the size definition will be appended to the type name.
1600:             * If your database has column types that don't allow size definitions,
1601:             * override this method to return the unaltered type name for columns of
1602:             * those types (or add the type names to the
1603:             * <code>fixedSizeTypeNameSet</code>).
1604:             * 
1605:             * <P>Some databases support "type modifiers" for example the unsigned
1606:             * "modifier" in MySQL. In these cases the size should go between the type 
1607:             * and the "modifier", instead of after the modifier. For example 
1608:             * CREATE table FOO ( myint INT (10) UNSIGNED . . .) instead of 
1609:             * CREATE table FOO ( myint INT UNSIGNED (10) . . .).
1610:             * Type modifiers should be added to <code>typeModifierSet</code> in 
1611:             * subclasses. 
1612:             */
1613:            protected String appendSize(Column col, String typeName) {
1614:                if (fixedSizeTypeNameSet.contains(typeName.toUpperCase()))
1615:                    return typeName;
1616:                if (typeName.indexOf('(') != -1)
1617:                    return typeName;
1618:
1619:                String size = null;
1620:                if (col.getSize() > 0) {
1621:                    StringBuffer buf = new StringBuffer(10);
1622:                    buf.append("(").append(col.getSize());
1623:                    if (col.getDecimalDigits() > 0)
1624:                        buf.append(", ").append(col.getDecimalDigits());
1625:                    buf.append(")");
1626:                    size = buf.toString();
1627:                }
1628:
1629:                return insertSize(typeName, size);
1630:            }
1631:
1632:            /**
1633:             * Helper method that inserts a size clause for a given SQL type. 
1634:             * 
1635:             * @see appendSize
1636:             * 
1637:             * @param typeName  The SQL type ie INT
1638:             * @param size      The size clause ie (10)
1639:             * @return          The typeName + size clause. Usually the size clause will 
1640:             *                  be appended to typeName. If the typeName contains a 
1641:             *                  marker : {0} or if typeName contains a modifier the 
1642:             *                  size clause will be inserted appropriately.   
1643:             */
1644:            protected String insertSize(String typeName, String size) {
1645:                if (StringUtils.isEmpty(size)) {
1646:                    int idx = typeName.indexOf("{0}");
1647:                    if (idx != -1) {
1648:                        return typeName.substring(0, idx);
1649:                    }
1650:                    return typeName;
1651:                }
1652:
1653:                int idx = typeName.indexOf("{0}");
1654:                if (idx != -1) {
1655:                    // replace '{0}' with size
1656:                    String ret = typeName.substring(0, idx);
1657:                    if (size != null)
1658:                        ret = ret + size;
1659:                    if (typeName.length() > idx + 3)
1660:                        ret = ret + typeName.substring(idx + 3);
1661:                    return ret;
1662:                }
1663:                if (!typeModifierSet.isEmpty()) {
1664:                    String s;
1665:                    idx = typeName.length();
1666:                    int curIdx = -1;
1667:                    for (Iterator i = typeModifierSet.iterator(); i.hasNext();) {
1668:                        s = (String) i.next();
1669:                        if (typeName.toUpperCase().indexOf(s) != -1) {
1670:                            curIdx = typeName.toUpperCase().indexOf(s);
1671:                            if (curIdx != -1 && curIdx < idx) {
1672:                                idx = curIdx;
1673:                            }
1674:                        }
1675:                    }
1676:                    if (idx != typeName.length()) {
1677:                        String ret = typeName.substring(0, idx);
1678:                        ret = ret + size;
1679:                        ret = ret + ' ' + typeName.substring(idx);
1680:                        return ret;
1681:                    }
1682:                }
1683:                return typeName + size;
1684:            }
1685:
1686:            ///////////
1687:            // Selects
1688:            ///////////
1689:
1690:            /**
1691:             * Set the name of the join syntax to use: sql92, traditional, database
1692:             */
1693:            public void setJoinSyntax(String syntax) {
1694:                if ("sql92".equals(syntax))
1695:                    joinSyntax = SYNTAX_SQL92;
1696:                else if ("traditional".equals(syntax))
1697:                    joinSyntax = SYNTAX_TRADITIONAL;
1698:                else if ("database".equals(syntax))
1699:                    joinSyntax = SYNTAX_DATABASE;
1700:                else if (!StringUtils.isEmpty(syntax))
1701:                    throw new IllegalArgumentException(syntax);
1702:            }
1703:
1704:            /**
1705:             * Return a SQL string to act as a placeholder for the given column.
1706:             */
1707:            public String getPlaceholderValueString(Column col) {
1708:                switch (col.getType()) {
1709:                case Types.BIGINT:
1710:                case Types.BIT:
1711:                case Types.INTEGER:
1712:                case Types.NUMERIC:
1713:                case Types.SMALLINT:
1714:                case Types.TINYINT:
1715:                    return "0";
1716:                case Types.CHAR:
1717:                    return (storeCharsAsNumbers) ? "0" : "' '";
1718:                case Types.CLOB:
1719:                case Types.LONGVARCHAR:
1720:                case Types.VARCHAR:
1721:                    return "''";
1722:                case Types.DATE:
1723:                    return ZERO_DATE_STR;
1724:                case Types.DECIMAL:
1725:                case Types.DOUBLE:
1726:                case Types.FLOAT:
1727:                case Types.REAL:
1728:                    return "0.0";
1729:                case Types.TIME:
1730:                    return ZERO_TIME_STR;
1731:                case Types.TIMESTAMP:
1732:                    return ZERO_TIMESTAMP_STR;
1733:                default:
1734:                    return "NULL";
1735:                }
1736:            }
1737:
1738:            /**
1739:             * Create a SELECT COUNT statement in the proper join syntax for the
1740:             * given instance.
1741:             */
1742:            public SQLBuffer toSelectCount(Select sel) {
1743:                SQLBuffer selectSQL = new SQLBuffer(this );
1744:                SQLBuffer from;
1745:                sel.addJoinClassConditions();
1746:                if (sel.getFromSelect() != null)
1747:                    from = getFromSelect(sel, false);
1748:                else
1749:                    from = getFrom(sel, false);
1750:                SQLBuffer where = getWhere(sel, false);
1751:
1752:                // if no grouping and no range, we might be able to get by without
1753:                // a subselect
1754:                if (sel.getGrouping() == null && sel.getStartIndex() == 0
1755:                        && sel.getEndIndex() == Long.MAX_VALUE) {
1756:                    // if the select has no identifier cols, use COUNT(*)
1757:                    List aliases = (!sel.isDistinct()) ? Collections.EMPTY_LIST
1758:                            : sel.getIdentifierAliases();
1759:                    if (aliases.isEmpty()) {
1760:                        selectSQL.append("COUNT(*)");
1761:                        return toSelect(selectSQL, null, from, where, null,
1762:                                null, null, false, false, 0, Long.MAX_VALUE);
1763:                    }
1764:
1765:                    // if there is a single distinct col, use COUNT(DISTINCT col)
1766:                    if (aliases.size() == 1) {
1767:                        selectSQL.append("COUNT(DISTINCT ").append(
1768:                                aliases.get(0).toString()).append(")");
1769:                        return toSelect(selectSQL, null, from, where, null,
1770:                                null, null, false, false, 0, Long.MAX_VALUE);
1771:                    }
1772:
1773:                    // can we combine distinct cols?
1774:                    if (distinctCountColumnSeparator != null) {
1775:                        selectSQL.append("COUNT(DISTINCT ");
1776:                        for (int i = 0; i < aliases.size(); i++) {
1777:                            if (i > 0) {
1778:                                selectSQL.append(" ");
1779:                                selectSQL.append(distinctCountColumnSeparator);
1780:                                selectSQL.append(" ");
1781:                            }
1782:                            selectSQL.append(aliases.get(i).toString());
1783:                        }
1784:                        selectSQL.append(")");
1785:                        return toSelect(selectSQL, null, from, where, null,
1786:                                null, null, false, false, 0, Long.MAX_VALUE);
1787:                    }
1788:                }
1789:
1790:                // since we can't combine distinct cols, we have to perform an outer
1791:                // COUNT(*) select using the original select as a subselect in the
1792:                // FROM clause
1793:                assertSupport(supportsSubselect, "SupportsSubselect");
1794:
1795:                SQLBuffer subSelect = getSelects(sel, true, false);
1796:                SQLBuffer subFrom = from;
1797:                from = new SQLBuffer(this );
1798:                from.append("(");
1799:                from.append(toSelect(subSelect, null, subFrom, where, sel
1800:                        .getGrouping(), sel.getHaving(), null,
1801:                        sel.isDistinct(), false, sel.getStartIndex(), sel
1802:                                .getEndIndex(), true));
1803:                from.append(")");
1804:                if (requiresAliasForSubselect)
1805:                    from.append(" ").append(Select.FROM_SELECT_ALIAS);
1806:
1807:                selectSQL.append("COUNT(*)");
1808:                return toSelect(selectSQL, null, from, null, null, null, null,
1809:                        false, false, 0, Long.MAX_VALUE);
1810:            }
1811:
1812:            /**
1813:             * Create a DELETE statement for the specified Select. If the
1814:             * database does not support the bulk delete statement (such as
1815:             * cases where a subselect is required and the database doesn't support
1816:             * subselects), this method should return null.
1817:             */
1818:            public SQLBuffer toDelete(ClassMapping mapping, Select sel,
1819:                    Object[] params) {
1820:                return toBulkOperation(mapping, sel, null, params, null);
1821:            }
1822:
1823:            public SQLBuffer toUpdate(ClassMapping mapping, Select sel,
1824:                    JDBCStore store, Object[] params, Map updates) {
1825:                return toBulkOperation(mapping, sel, store, params, updates);
1826:            }
1827:
1828:            /**
1829:             * Returns the SQL for a bulk operation, either a DELETE or an UPDATE.
1830:             *
1831:             * @param mapping the mappng against which we are operating
1832:             * @param sel the Select that will constitute the WHERE clause
1833:             * @param store the current store
1834:             * @param updateParams the Map that holds the update parameters; a null
1835:             * value indicates that this is a delete operation
1836:             * @return the SQLBuffer for the update, or <em>null</em> if it is not
1837:             * possible to perform the bulk update
1838:             */
1839:            protected SQLBuffer toBulkOperation(ClassMapping mapping,
1840:                    Select sel, JDBCStore store, Object[] params,
1841:                    Map updateParams) {
1842:                SQLBuffer sql = new SQLBuffer(this );
1843:                if (updateParams == null)
1844:                    sql.append("DELETE FROM ");
1845:                else
1846:                    sql.append("UPDATE ");
1847:                sel.addJoinClassConditions();
1848:
1849:                // if there is only a single table in the select, then we can
1850:                // just issue a single DELETE FROM TABLE WHERE <conditions>
1851:                // statement; otherwise, since SQL doesn't allow deleting
1852:                // from one of a multi-table select, we need to issue a subselect
1853:                // like DELETE FROM TABLE WHERE EXISTS
1854:                // (SELECT 1 FROM TABLE t0 WHERE t0.ID = TABLE.ID); also, some
1855:                // databases do not allow aliases in delete statements, which
1856:                // also causes us to use a subselect
1857:                if (sel.getTableAliases().size() == 1 && supportsSubselect
1858:                        && allowsAliasInBulkClause) {
1859:                    SQLBuffer from;
1860:                    if (sel.getFromSelect() != null)
1861:                        from = getFromSelect(sel, false);
1862:                    else
1863:                        from = getFrom(sel, false);
1864:
1865:                    sql.append(from);
1866:                    appendUpdates(sel, store, sql, params, updateParams,
1867:                            allowsAliasInBulkClause);
1868:
1869:                    SQLBuffer where = sel.getWhere();
1870:                    if (where != null && !where.isEmpty()) {
1871:                        sql.append(" WHERE ");
1872:                        sql.append(where);
1873:                    }
1874:                    return sql;
1875:                }
1876:
1877:                Table table = mapping.getTable();
1878:                String tableName = getFullName(table, false);
1879:
1880:                // only use a  subselect if the where is not empty; otherwise
1881:                // an unqualified delete or update will work
1882:                if (sel.getWhere() == null || sel.getWhere().isEmpty()) {
1883:                    sql.append(tableName);
1884:                    appendUpdates(sel, store, sql, params, updateParams, false);
1885:                    return sql;
1886:                }
1887:
1888:                // we need to use a subselect if we are to bulk delete where
1889:                // the select includes multiple tables; if the database
1890:                // doesn't support it, then we need to sigal this by returning null
1891:                if (!supportsSubselect || !supportsCorrelatedSubselect)
1892:                    return null;
1893:
1894:                Column[] pks = mapping.getPrimaryKeyColumns();
1895:                sel.clearSelects();
1896:                sel.setDistinct(true);
1897:
1898:                // if we have only a single PK, we can use a non-correlated
1899:                // subquery (using an IN statement), which is much faster than
1900:                // a correlated subquery (since a correlated subquery needs
1901:                // to be executed once for each row in the table)
1902:                if (pks.length == 1) {
1903:                    sel.select(pks[0]);
1904:                    sql.append(tableName);
1905:                    appendUpdates(sel, store, sql, params, updateParams, false);
1906:                    sql.append(" WHERE ").append(pks[0]).append(" IN (")
1907:                            .append(sel.toSelect(false, null)).append(")");
1908:                } else {
1909:                    sel.clearSelects();
1910:                    sel.setDistinct(false);
1911:
1912:                    // since the select is using a correlated subquery, we
1913:                    // only need to select a bogus virtual column
1914:                    sel.select("1", null);
1915:
1916:                    // add in the joins to the table
1917:                    Column[] cols = table.getPrimaryKey().getColumns();
1918:                    SQLBuffer buf = new SQLBuffer(this );
1919:                    buf.append("(");
1920:                    for (int i = 0; i < cols.length; i++) {
1921:                        if (i > 0)
1922:                            buf.append(" AND ");
1923:
1924:                        // add in "t0.PK = MYTABLE.PK"
1925:                        buf.append(sel.getColumnAlias(cols[i], null)).append(
1926:                                " = ").append(table).append(catalogSeparator)
1927:                                .append(cols[i]);
1928:                    }
1929:                    buf.append(")");
1930:                    sel.where(buf, null);
1931:
1932:                    sql.append(tableName);
1933:                    appendUpdates(sel, store, sql, params, updateParams, false);
1934:                    sql.append(" WHERE EXISTS (").append(
1935:                            sel.toSelect(false, null)).append(")");
1936:                }
1937:                return sql;
1938:            }
1939:
1940:            protected void appendUpdates(Select sel, JDBCStore store,
1941:                    SQLBuffer sql, Object[] params, Map updateParams,
1942:                    boolean allowAlias) {
1943:                if (updateParams == null || updateParams.size() == 0)
1944:                    return;
1945:
1946:                // manually build up the SET clause for the UPDATE statement
1947:                sql.append(" SET ");
1948:                ExpContext ctx = new ExpContext(store, params, store
1949:                        .getFetchConfiguration());
1950:
1951:                // If the updates map contains any version fields, assume that the
1952:                // optimistic lock version data is being handled properly by the
1953:                // caller. Otherwise, give the version indicator an opportunity to
1954:                // add more update clauses as needed.
1955:                boolean augmentUpdates = true;
1956:
1957:                for (Iterator i = updateParams.entrySet().iterator(); i
1958:                        .hasNext();) {
1959:                    Map.Entry next = (Map.Entry) i.next();
1960:                    Path path = (Path) next.getKey();
1961:                    FieldMapping fmd = (FieldMapping) path.last();
1962:
1963:                    if (fmd.isVersion())
1964:                        augmentUpdates = false;
1965:
1966:                    Val val = (Val) next.getValue();
1967:
1968:                    Column col = fmd.getColumns()[0];
1969:                    sql.append(col.getName());
1970:                    sql.append(" = ");
1971:
1972:                    ExpState state = val.initialize(sel, ctx, 0);
1973:                    // JDBC Paths are always PCPaths; PCPath implements Val
1974:                    ExpState pathState = ((Val) path).initialize(sel, ctx, 0);
1975:                    calculateValue(val, sel, ctx, state, path, pathState);
1976:
1977:                    // append the value with a null for the Select; i
1978:                    // indicates that the
1979:                    int length = val.length(sel, ctx, state);
1980:                    for (int j = 0; j < length; j++)
1981:                        val.appendTo((allowAlias) ? sel : null, ctx, state,
1982:                                sql, j);
1983:
1984:                    if (i.hasNext())
1985:                        sql.append(", ");
1986:                }
1987:
1988:                if (augmentUpdates) {
1989:                    Path path = (Path) updateParams.keySet().iterator().next();
1990:                    FieldMapping fm = (FieldMapping) path.last();
1991:                    ClassMapping meta = fm.getDeclaringMapping();
1992:                    Map updates = meta.getVersion().getBulkUpdateValues();
1993:                    for (Iterator iter = updates.entrySet().iterator(); iter
1994:                            .hasNext();) {
1995:                        Map.Entry e = (Map.Entry) iter.next();
1996:                        Column col = (Column) e.getKey();
1997:                        String val = (String) e.getValue();
1998:                        sql.append(", ").append(col.getName()).append(" = ")
1999:                                .append(val);
2000:                    }
2001:                }
2002:            }
2003:
2004:            /**
2005:             * Create SQL to delete the contents of the specified tables. 
2006:             * The default implementation drops all non-deferred RESTRICT foreign key 
2007:             * constraints involving the specified tables, issues DELETE statements 
2008:             * against the tables, and then adds the dropped constraints back in. 
2009:             * Databases with more optimal ways of deleting the contents of several 
2010:             * tables should override this method.
2011:             */
2012:            public String[] getDeleteTableContentsSQL(Table[] tables) {
2013:                Collection sql = new ArrayList();
2014:
2015:                // collect and drop non-deferred physical restrict constraints, and
2016:                // collect the DELETE FROM statements
2017:                Collection deleteSQL = new ArrayList(tables.length);
2018:                Collection restrictConstraints = new LinkedHashSet();
2019:                for (int i = 0; i < tables.length; i++) {
2020:                    ForeignKey[] fks = tables[i].getForeignKeys();
2021:                    for (int j = 0; j < fks.length; j++) {
2022:                        if (!fks[j].isLogical()
2023:                                && !fks[j].isDeferred()
2024:                                && fks[j].getDeleteAction() == ForeignKey.ACTION_RESTRICT)
2025:                            restrictConstraints.add(fks[j]);
2026:                        String[] constraintSQL = getDropForeignKeySQL(fks[j]);
2027:                        sql.addAll(Arrays.asList(constraintSQL));
2028:                    }
2029:
2030:                    deleteSQL.add("DELETE FROM " + tables[i].getFullName());
2031:                }
2032:
2033:                // add the delete statements after all the constraint mutations
2034:                sql.addAll(deleteSQL);
2035:
2036:                // add the deleted constraints back to the schema
2037:                for (Iterator iter = restrictConstraints.iterator(); iter
2038:                        .hasNext();) {
2039:                    String[] constraintSQL = getAddForeignKeySQL((ForeignKey) iter
2040:                            .next());
2041:                    sql.addAll(Arrays.asList(constraintSQL));
2042:                }
2043:
2044:                return (String[]) sql.toArray(new String[sql.size()]);
2045:            }
2046:
2047:            /**
2048:             * Create a SELECT statement in the proper join syntax for the given
2049:             * instance.
2050:             */
2051:            public SQLBuffer toSelect(Select sel, boolean forUpdate,
2052:                    JDBCFetchConfiguration fetch) {
2053:                sel.addJoinClassConditions();
2054:                boolean update = forUpdate && sel.getFromSelect() == null;
2055:                SQLBuffer select = getSelects(sel, false, update);
2056:                SQLBuffer ordering = null;
2057:                if (!sel.isAggregate() || sel.getGrouping() != null)
2058:                    ordering = sel.getOrdering();
2059:                SQLBuffer from;
2060:                if (sel.getFromSelect() != null)
2061:                    from = getFromSelect(sel, forUpdate);
2062:                else
2063:                    from = getFrom(sel, update);
2064:                SQLBuffer where = getWhere(sel, update);
2065:                return toSelect(select, fetch, from, where, sel.getGrouping(),
2066:                        sel.getHaving(), ordering, sel.isDistinct(), forUpdate,
2067:                        sel.getStartIndex(), sel.getEndIndex(), sel);
2068:            }
2069:
2070:            /**
2071:             * Return the portion of the select statement between the FROM keyword
2072:             * and the WHERE keyword.
2073:             */
2074:            protected SQLBuffer getFrom(Select sel, boolean forUpdate) {
2075:                SQLBuffer fromSQL = new SQLBuffer(this );
2076:                Collection aliases = sel.getTableAliases();
2077:                if (aliases.size() < 2 || sel.getJoinSyntax() != SYNTAX_SQL92) {
2078:                    for (Iterator itr = aliases.iterator(); itr.hasNext();) {
2079:                        fromSQL.append(itr.next().toString());
2080:                        if (forUpdate && tableForUpdateClause != null)
2081:                            fromSQL.append(" ").append(tableForUpdateClause);
2082:                        if (itr.hasNext())
2083:                            fromSQL.append(", ");
2084:                    }
2085:                } else {
2086:                    Iterator itr = sel.getJoinIterator();
2087:                    boolean first = true;
2088:                    while (itr.hasNext()) {
2089:                        fromSQL.append(toSQL92Join((Join) itr.next(),
2090:                                forUpdate, first));
2091:                        first = false;
2092:                    }
2093:                }
2094:                return fromSQL;
2095:            }
2096:
2097:            /**
2098:             * Return the FROM clause for a select that selects from a tmp table
2099:             * created by an inner select.
2100:             */
2101:            protected SQLBuffer getFromSelect(Select sel, boolean forUpdate) {
2102:                SQLBuffer fromSQL = new SQLBuffer(this );
2103:                fromSQL.append("(");
2104:                fromSQL.append(toSelect(sel.getFromSelect(), forUpdate, null));
2105:                fromSQL.append(")");
2106:                if (requiresAliasForSubselect)
2107:                    fromSQL.append(" ").append(Select.FROM_SELECT_ALIAS);
2108:                return fromSQL;
2109:            }
2110:
2111:            /**
2112:             * Return the WHERE portion of the select statement, or null if no where
2113:             * conditions.
2114:             */
2115:            protected SQLBuffer getWhere(Select sel, boolean forUpdate) {
2116:                Joins joins = sel.getJoins();
2117:                if (sel.getJoinSyntax() == SYNTAX_SQL92 || joins == null
2118:                        || joins.isEmpty())
2119:                    return sel.getWhere();
2120:
2121:                SQLBuffer where = new SQLBuffer(this );
2122:                if (sel.getWhere() != null)
2123:                    where.append(sel.getWhere());
2124:                if (joins != null)
2125:                    sel.append(where, joins);
2126:                return where;
2127:            }
2128:
2129:            /**
2130:             * Use the given join instance to create SQL joining its tables in
2131:             * the traditional style.
2132:             */
2133:            public SQLBuffer toTraditionalJoin(Join join) {
2134:                ForeignKey fk = join.getForeignKey();
2135:                if (fk == null)
2136:                    return null;
2137:
2138:                boolean inverse = join.isForeignKeyInversed();
2139:                Column[] from = (inverse) ? fk.getPrimaryKeyColumns() : fk
2140:                        .getColumns();
2141:                Column[] to = (inverse) ? fk.getColumns() : fk
2142:                        .getPrimaryKeyColumns();
2143:
2144:                // do column joins
2145:                SQLBuffer buf = new SQLBuffer(this );
2146:                int count = 0;
2147:                for (int i = 0; i < from.length; i++, count++) {
2148:                    if (count > 0)
2149:                        buf.append(" AND ");
2150:                    buf.append(join.getAlias1()).append(".").append(from[i]);
2151:                    buf.append(" = ");
2152:                    buf.append(join.getAlias2()).append(".").append(to[i]);
2153:                }
2154:
2155:                // do constant joins
2156:                Column[] constCols = fk.getConstantColumns();
2157:                for (int i = 0; i < constCols.length; i++, count++) {
2158:                    if (count > 0)
2159:                        buf.append(" AND ");
2160:                    if (inverse)
2161:                        buf.appendValue(fk.getConstant(constCols[i]),
2162:                                constCols[i]);
2163:                    else
2164:                        buf.append(join.getAlias1()).append(".").append(
2165:                                constCols[i]);
2166:                    buf.append(" = ");
2167:
2168:                    if (inverse)
2169:                        buf.append(join.getAlias2()).append(".").append(
2170:                                constCols[i]);
2171:                    else
2172:                        buf.appendValue(fk.getConstant(constCols[i]),
2173:                                constCols[i]);
2174:                }
2175:
2176:                Column[] constColsPK = fk.getConstantPrimaryKeyColumns();
2177:                for (int i = 0; i < constColsPK.length; i++, count++) {
2178:                    if (count > 0)
2179:                        buf.append(" AND ");
2180:                    if (inverse)
2181:                        buf.append(join.getAlias1()).append(".").append(
2182:                                constColsPK[i]);
2183:                    else
2184:                        buf.appendValue(fk
2185:                                .getPrimaryKeyConstant(constColsPK[i]),
2186:                                constColsPK[i]);
2187:                    buf.append(" = ");
2188:
2189:                    if (inverse)
2190:                        buf.appendValue(fk
2191:                                .getPrimaryKeyConstant(constColsPK[i]),
2192:                                constColsPK[i]);
2193:                    else
2194:                        buf.append(join.getAlias2()).append(".").append(
2195:                                constColsPK[i]);
2196:                }
2197:                return buf;
2198:            }
2199:
2200:            /**
2201:             * Use the given join instance to create SQL joining its tables in
2202:             * the SQL92 style.
2203:             */
2204:            public SQLBuffer toSQL92Join(Join join, boolean forUpdate,
2205:                    boolean first) {
2206:                SQLBuffer buf = new SQLBuffer(this );
2207:                if (first) {
2208:                    buf.append(join.getTable1()).append(" ").append(
2209:                            join.getAlias1());
2210:                    if (forUpdate && tableForUpdateClause != null)
2211:                        buf.append(" ").append(tableForUpdateClause);
2212:                }
2213:
2214:                buf.append(" ");
2215:                if (join.getType() == Join.TYPE_OUTER)
2216:                    buf.append(outerJoinClause);
2217:                else if (join.getType() == Join.TYPE_INNER)
2218:                    buf.append(innerJoinClause);
2219:                else
2220:                    // cross
2221:                    buf.append(crossJoinClause);
2222:                buf.append(" ");
2223:
2224:                buf.append(join.getTable2()).append(" ").append(
2225:                        join.getAlias2());
2226:                if (forUpdate && tableForUpdateClause != null)
2227:                    buf.append(" ").append(tableForUpdateClause);
2228:
2229:                if (join.getForeignKey() != null)
2230:                    buf.append(" ON ").append(toTraditionalJoin(join));
2231:                else if (requiresConditionForCrossJoin
2232:                        && join.getType() == Join.TYPE_CROSS)
2233:                    buf.append(" ON (1 = 1)");
2234:
2235:                return buf;
2236:            }
2237:
2238:            /**
2239:             * Use the given join instance to create SQL joining its tables in
2240:             * the database's native syntax. Throws an exception by default.
2241:             */
2242:            public SQLBuffer toNativeJoin(Join join) {
2243:                throw new UnsupportedException();
2244:            }
2245:
2246:            /**
2247:             * Returns if the given foreign key can be eagerly loaded using other joins.
2248:             */
2249:            public boolean canOuterJoin(int syntax, ForeignKey fk) {
2250:                return syntax != SYNTAX_TRADITIONAL;
2251:            }
2252:
2253:            /**
2254:             * Combine the given components into a SELECT statement.
2255:             */
2256:            public SQLBuffer toSelect(SQLBuffer selects,
2257:                    JDBCFetchConfiguration fetch, SQLBuffer from,
2258:                    SQLBuffer where, SQLBuffer group, SQLBuffer having,
2259:                    SQLBuffer order, boolean distinct, boolean forUpdate,
2260:                    long start, long end) {
2261:                return toOperation(getSelectOperation(fetch), selects, from,
2262:                        where, group, having, order, distinct, start, end,
2263:                        getForUpdateClause(fetch, forUpdate, null));
2264:            }
2265:
2266:            /**
2267:             * Combine the given components into a SELECT statement.
2268:             */
2269:            public SQLBuffer toSelect(SQLBuffer selects,
2270:                    JDBCFetchConfiguration fetch, SQLBuffer from,
2271:                    SQLBuffer where, SQLBuffer group, SQLBuffer having,
2272:                    SQLBuffer order, boolean distinct, boolean forUpdate,
2273:                    long start, long end, boolean subselect) {
2274:                return toOperation(getSelectOperation(fetch), selects, from,
2275:                        where, group, having, order, distinct, start, end,
2276:                        getForUpdateClause(fetch, forUpdate, null), subselect);
2277:            }
2278:
2279:            public SQLBuffer toSelect(SQLBuffer selects,
2280:                    JDBCFetchConfiguration fetch, SQLBuffer from,
2281:                    SQLBuffer where, SQLBuffer group, SQLBuffer having,
2282:                    SQLBuffer order, boolean distinct, boolean forUpdate,
2283:                    long start, long end, boolean subselect,
2284:                    boolean checkTableForUpdate) {
2285:                return toOperation(getSelectOperation(fetch), selects, from,
2286:                        where, group, having, order, distinct, start, end,
2287:                        getForUpdateClause(fetch, forUpdate, null), subselect,
2288:                        checkTableForUpdate);
2289:            }
2290:
2291:            /**
2292:             * Combine the given components into a SELECT statement.
2293:             */
2294:            public SQLBuffer toSelect(SQLBuffer selects,
2295:                    JDBCFetchConfiguration fetch, SQLBuffer from,
2296:                    SQLBuffer where, SQLBuffer group, SQLBuffer having,
2297:                    SQLBuffer order, boolean distinct, boolean forUpdate,
2298:                    long start, long end, Select sel) {
2299:                return toOperation(getSelectOperation(fetch), selects, from,
2300:                        where, group, having, order, distinct, start, end,
2301:                        getForUpdateClause(fetch, forUpdate, sel));
2302:            }
2303:
2304:            /**
2305:             * Get the update clause for the query based on the
2306:             * updateClause and isolationLevel hints
2307:             */
2308:            protected String getForUpdateClause(JDBCFetchConfiguration fetch,
2309:                    boolean isForUpdate, Select sel) {
2310:                if (fetch != null && fetch.getIsolation() != -1) {
2311:                    throw new InvalidStateException(_loc.get(
2312:                            "isolation-level-config-not-supported", getClass()
2313:                                    .getName()));
2314:                } else if (isForUpdate && !simulateLocking) {
2315:                    assertSupport(supportsSelectForUpdate,
2316:                            "SupportsSelectForUpdate");
2317:                    return forUpdateClause;
2318:                } else {
2319:                    return null;
2320:                }
2321:            }
2322:
2323:            /**
2324:             * Return the "SELECT" operation clause, adding any available hints, etc.
2325:             */
2326:            public String getSelectOperation(JDBCFetchConfiguration fetch) {
2327:                return "SELECT";
2328:            }
2329:
2330:            /**
2331:             * Return the SQL for the given selecting operation.
2332:             */
2333:            public SQLBuffer toOperation(String op, SQLBuffer selects,
2334:                    SQLBuffer from, SQLBuffer where, SQLBuffer group,
2335:                    SQLBuffer having, SQLBuffer order, boolean distinct,
2336:                    long start, long end, String forUpdateClause) {
2337:                return toOperation(op, selects, from, where, group, having,
2338:                        order, distinct, start, end, forUpdateClause, false);
2339:            }
2340:
2341:            /**
2342:             * Return the SQL for the given selecting operation.
2343:             */
2344:            public SQLBuffer toOperation(String op, SQLBuffer selects,
2345:                    SQLBuffer from, SQLBuffer where, SQLBuffer group,
2346:                    SQLBuffer having, SQLBuffer order, boolean distinct,
2347:                    long start, long end, String forUpdateClause,
2348:                    boolean subselect) {
2349:                return toOperation(op, selects, from, where, group, having,
2350:                        order, distinct, start, end, forUpdateClause,
2351:                        subselect, false);
2352:            }
2353:
2354:            /**
2355:             * Return the SQL for the given selecting operation.
2356:             */
2357:            private SQLBuffer toOperation(String op, SQLBuffer selects,
2358:                    SQLBuffer from, SQLBuffer where, SQLBuffer group,
2359:                    SQLBuffer having, SQLBuffer order, boolean distinct,
2360:                    long start, long end, String forUpdateClause,
2361:                    boolean subselect, boolean checkTableForUpdate) {
2362:                SQLBuffer buf = new SQLBuffer(this );
2363:                buf.append(op);
2364:
2365:                boolean range = start != 0 || end != Long.MAX_VALUE;
2366:                if (range && rangePosition == RANGE_PRE_DISTINCT)
2367:                    appendSelectRange(buf, start, end, subselect);
2368:                if (distinct)
2369:                    buf.append(" DISTINCT");
2370:                if (range && rangePosition == RANGE_POST_DISTINCT)
2371:                    appendSelectRange(buf, start, end, subselect);
2372:
2373:                buf.append(" ").append(selects).append(" FROM ").append(from);
2374:
2375:                if (checkTableForUpdate
2376:                        && (StringUtils.isEmpty(forUpdateClause) && !StringUtils
2377:                                .isEmpty(tableForUpdateClause))) {
2378:                    buf.append(" ").append(tableForUpdateClause);
2379:                }
2380:
2381:                if (where != null && !where.isEmpty())
2382:                    buf.append(" WHERE ").append(where);
2383:                if (group != null && !group.isEmpty())
2384:                    buf.append(" GROUP BY ").append(group);
2385:                if (having != null && !having.isEmpty()) {
2386:                    assertSupport(supportsHaving, "SupportsHaving");
2387:                    buf.append(" HAVING ").append(having);
2388:                }
2389:                if (order != null && !order.isEmpty())
2390:                    buf.append(" ORDER BY ").append(order);
2391:                if (range && rangePosition == RANGE_POST_SELECT)
2392:                    appendSelectRange(buf, start, end, subselect);
2393:                if (forUpdateClause != null)
2394:                    buf.append(" ").append(forUpdateClause);
2395:                if (range && rangePosition == RANGE_POST_LOCK)
2396:                    appendSelectRange(buf, start, end, subselect);
2397:                return buf;
2398:            }
2399:
2400:            /**
2401:             * If this dictionary can select ranges,
2402:             * use this method to append the range SQL.
2403:             */
2404:            protected void appendSelectRange(SQLBuffer buf, long start,
2405:                    long end, boolean subselect) {
2406:            }
2407:
2408:            /**
2409:             * Return the portion of the select statement between the SELECT keyword
2410:             * and the FROM keyword.
2411:             */
2412:            protected SQLBuffer getSelects(Select sel,
2413:                    boolean distinctIdentifiers, boolean forUpdate) {
2414:                // append the aliases for all the columns
2415:                SQLBuffer selectSQL = new SQLBuffer(this );
2416:                List aliases;
2417:                if (distinctIdentifiers)
2418:                    aliases = sel.getIdentifierAliases();
2419:                else
2420:                    aliases = sel.getSelectAliases();
2421:
2422:                Object alias;
2423:                for (int i = 0; i < aliases.size(); i++) {
2424:                    alias = aliases.get(i);
2425:                    appendSelect(selectSQL, alias, sel, i);
2426:                    if (i < aliases.size() - 1)
2427:                        selectSQL.append(", ");
2428:                }
2429:                return selectSQL;
2430:            }
2431:
2432:            /**
2433:             * Append <code>elem</code> to <code>selectSQL</code>.
2434:             * @param selectSQL The SQLBuffer to append to.
2435:             * @param alias A {@link SQLBuffer} or a {@link String} to append.
2436:             *
2437:             * @since 1.1.0
2438:             */
2439:            protected void appendSelect(SQLBuffer selectSQL, Object elem,
2440:                    Select sel, int idx) {
2441:                if (elem instanceof  SQLBuffer)
2442:                    selectSQL.append((SQLBuffer) elem);
2443:                else
2444:                    selectSQL.append(elem.toString());
2445:            }
2446:
2447:            /**
2448:             * Returns true if a "FOR UPDATE" clause can be used for the specified
2449:             * Select object.
2450:             */
2451:            public boolean supportsLocking(Select sel) {
2452:                if (sel.isAggregate())
2453:                    return false;
2454:                if (!supportsSelectForUpdate)
2455:                    return false;
2456:                if (!supportsLockingWithSelectRange
2457:                        && (sel.getStartIndex() != 0 || sel.getEndIndex() != Long.MAX_VALUE))
2458:                    return false;
2459:
2460:                // only inner select is locked
2461:                if (sel.getFromSelect() != null)
2462:                    sel = sel.getFromSelect();
2463:
2464:                if (!supportsLockingWithDistinctClause && sel.isDistinct())
2465:                    return false;
2466:                if (!supportsLockingWithMultipleTables
2467:                        && sel.getTableAliases().size() > 1)
2468:                    return false;
2469:                if (!supportsLockingWithOrderClause
2470:                        && sel.getOrdering() != null)
2471:                    return false;
2472:                if (!supportsLockingWithOuterJoin
2473:                        || !supportsLockingWithInnerJoin) {
2474:                    for (Iterator itr = sel.getJoinIterator(); itr.hasNext();) {
2475:                        Join join = (Join) itr.next();
2476:                        if (!supportsLockingWithOuterJoin
2477:                                && join.getType() == Join.TYPE_OUTER)
2478:                            return false;
2479:                        if (!supportsLockingWithInnerJoin
2480:                                && join.getType() == Join.TYPE_INNER)
2481:                            return false;
2482:                    }
2483:                }
2484:                return true;
2485:            }
2486:
2487:            /**
2488:             * Return false if the given select requires a forward-only result set.
2489:             */
2490:            public boolean supportsRandomAccessResultSet(Select sel,
2491:                    boolean forUpdate) {
2492:                return !sel.isAggregate();
2493:            }
2494:
2495:            /**
2496:             * Assert that the given dictionary flag is true. If it is not true,
2497:             * throw an error saying that the given setting needs to return true for
2498:             * the current operation to work.
2499:             */
2500:            public void assertSupport(boolean feature, String property) {
2501:                if (!feature)
2502:                    throw new UnsupportedException(_loc.get(
2503:                            "feature-not-supported", getClass(), property));
2504:            }
2505:
2506:            ////////////////////
2507:            // Query functions
2508:            ////////////////////
2509:
2510:            /**
2511:             * Invoke this database's substring function.
2512:             *
2513:             * @param buf the SQL buffer to write the substring invocation to
2514:             * @param str a query value representing the target string
2515:             * @param start a query value representing the start index
2516:             * @param end a query value representing the end index, or null for none
2517:             */
2518:            public void substring(SQLBuffer buf, FilterValue str,
2519:                    FilterValue start, FilterValue end) {
2520:                buf.append(substringFunctionName).append("(");
2521:                str.appendTo(buf);
2522:                buf.append(", ");
2523:                if (start.getValue() instanceof  Number) {
2524:                    long startLong = toLong(start);
2525:                    buf.append(Long.toString(startLong + 1));
2526:                } else {
2527:                    buf.append("(");
2528:                    start.appendTo(buf);
2529:                    buf.append(" + 1)");
2530:                }
2531:                if (end != null) {
2532:                    buf.append(", ");
2533:                    if (start.getValue() instanceof  Number
2534:                            && end.getValue() instanceof  Number) {
2535:                        long startLong = toLong(start);
2536:                        long endLong = toLong(end);
2537:                        buf.append(Long.toString(endLong - startLong));
2538:                    } else {
2539:                        end.appendTo(buf);
2540:                        buf.append(" - (");
2541:                        start.appendTo(buf);
2542:                        buf.append(")");
2543:                    }
2544:                }
2545:                buf.append(")");
2546:            }
2547:
2548:            long toLong(FilterValue litValue) {
2549:                return ((Number) litValue.getValue()).longValue();
2550:            }
2551:
2552:            /**
2553:             * Invoke this database's indexOf function.
2554:             *
2555:             * @param buf the SQL buffer to write the indexOf invocation to
2556:             * @param str a query value representing the target string
2557:             * @param find a query value representing the search string
2558:             * @param start a query value representing the start index, or null
2559:             * to start at the beginning
2560:             */
2561:            public void indexOf(SQLBuffer buf, FilterValue str,
2562:                    FilterValue find, FilterValue start) {
2563:                buf.append("(INSTR((");
2564:                if (start != null)
2565:                    substring(buf, str, start, null);
2566:                else
2567:                    str.appendTo(buf);
2568:                buf.append("), (");
2569:                find.appendTo(buf);
2570:                buf.append(")) - 1");
2571:                if (start != null) {
2572:                    buf.append(" + ");
2573:                    start.appendTo(buf);
2574:                }
2575:                buf.append(")");
2576:            }
2577:
2578:            /**
2579:             * Append the numeric parts of a mathematical function.
2580:             *
2581:             * @param buf the SQL buffer to write the math function
2582:             * @param op the mathematical operation to perform
2583:             * @param lhs the left hand side of the math function
2584:             * @param rhs the right hand side of the math function
2585:             */
2586:            public void mathFunction(SQLBuffer buf, String op, FilterValue lhs,
2587:                    FilterValue rhs) {
2588:                boolean castlhs = false;
2589:                boolean castrhs = false;
2590:                Class lc = Filters.wrap(lhs.getType());
2591:                Class rc = Filters.wrap(rhs.getType());
2592:                int type = 0;
2593:                if (requiresCastForMathFunctions
2594:                        && (lc != rc || (lhs.isConstant() && rhs.isConstant()))) {
2595:                    Class c = Filters.promote(lc, rc);
2596:                    type = getJDBCType(JavaTypes.getTypeCode(c), false);
2597:                    if (type != Types.VARBINARY && type != Types.BLOB) {
2598:                        castlhs = (lhs.isConstant() && rhs.isConstant())
2599:                                || lc != c;
2600:                        castrhs = (lhs.isConstant() && rhs.isConstant())
2601:                                || rc != c;
2602:                    }
2603:                }
2604:
2605:                boolean mod = "MOD".equals(op);
2606:                if (mod) {
2607:                    if (supportsModOperator)
2608:                        op = "%";
2609:                    else
2610:                        buf.append(op);
2611:                }
2612:                buf.append("(");
2613:
2614:                if (castlhs)
2615:                    appendCast(buf, lhs, type);
2616:                else
2617:                    lhs.appendTo(buf);
2618:
2619:                if (mod && !supportsModOperator)
2620:                    buf.append(", ");
2621:                else
2622:                    buf.append(" ").append(op).append(" ");
2623:
2624:                if (castrhs)
2625:                    appendCast(buf, rhs, type);
2626:                else
2627:                    rhs.appendTo(buf);
2628:
2629:                buf.append(")");
2630:            }
2631:
2632:            /**
2633:             * Append a comparison.
2634:             *
2635:             * @param buf the SQL buffer to write the comparison
2636:             * @param op the comparison operation to perform
2637:             * @param lhs the left hand side of the comparison
2638:             * @param rhs the right hand side of the comparison
2639:             */
2640:            public void comparison(SQLBuffer buf, String op, FilterValue lhs,
2641:                    FilterValue rhs) {
2642:                boolean lhsxml = lhs.getXPath() != null;
2643:                boolean rhsxml = rhs.getXPath() != null;
2644:                if (lhsxml || rhsxml) {
2645:                    appendXmlComparison(buf, op, lhs, rhs, lhsxml, rhsxml);
2646:                    return;
2647:                }
2648:                boolean castlhs = false;
2649:                boolean castrhs = false;
2650:                Class lc = Filters.wrap(lhs.getType());
2651:                Class rc = Filters.wrap(rhs.getType());
2652:                int type = 0;
2653:                if (requiresCastForComparisons
2654:                        && (lc != rc || (lhs.isConstant() && rhs.isConstant()))) {
2655:                    Class c = Filters.promote(lc, rc);
2656:                    type = getJDBCType(JavaTypes.getTypeCode(c), false);
2657:                    if (type != Types.VARBINARY && type != Types.BLOB) {
2658:                        castlhs = (lhs.isConstant() && rhs.isConstant())
2659:                                || lc != c;
2660:                        castrhs = (lhs.isConstant() && rhs.isConstant())
2661:                                || rc != c;
2662:                    }
2663:                }
2664:
2665:                if (castlhs)
2666:                    appendCast(buf, lhs, type);
2667:                else
2668:                    lhs.appendTo(buf);
2669:
2670:                buf.append(" ").append(op).append(" ");
2671:
2672:                if (castrhs)
2673:                    appendCast(buf, rhs, type);
2674:                else
2675:                    rhs.appendTo(buf);
2676:            }
2677:
2678:            /**
2679:             * If this dictionary supports XML type,
2680:             * use this method to append xml predicate.
2681:             */
2682:            public void appendXmlComparison(SQLBuffer buf, String op,
2683:                    FilterValue lhs, FilterValue rhs, boolean lhsxml,
2684:                    boolean rhsxml) {
2685:                assertSupport(supportsXMLColumn, "SupportsXMLColumn");
2686:            }
2687:
2688:            /**
2689:             * Append SQL for the given numeric value to the buffer, casting as needed.
2690:             */
2691:            protected void appendNumericCast(SQLBuffer buf, FilterValue val) {
2692:                if (val.isConstant())
2693:                    appendCast(buf, val, Types.NUMERIC);
2694:                else
2695:                    val.appendTo(buf);
2696:            }
2697:
2698:            /**
2699:             * Cast the specified value to the specified type.
2700:             *
2701:             * @param buf the buffer to append the cast to
2702:             * @param val the value to cast
2703:             * @param type the type of the case, e.g. {@link Types#NUMERIC}
2704:             */
2705:            public void appendCast(SQLBuffer buf, Object val, int type) {
2706:                // Convert the cast function: "CAST({0} AS {1})"
2707:                int firstParam = castFunction.indexOf("{0}");
2708:                String pre = castFunction.substring(0, firstParam); // "CAST("
2709:                String mid = castFunction.substring(firstParam + 3);
2710:                int secondParam = mid.indexOf("{1}");
2711:                String post;
2712:                if (secondParam > -1) {
2713:                    post = mid.substring(secondParam + 3); // ")"
2714:                    mid = mid.substring(0, secondParam); // " AS "
2715:                } else
2716:                    post = "";
2717:
2718:                buf.append(pre);
2719:                if (val instanceof  FilterValue)
2720:                    ((FilterValue) val).appendTo(buf);
2721:                else if (val instanceof  SQLBuffer)
2722:                    buf.append(((SQLBuffer) val));
2723:                else
2724:                    buf.append(val.toString());
2725:                buf.append(mid);
2726:                buf.append(getTypeName(type));
2727:                appendLength(buf, type);
2728:                buf.append(post);
2729:            }
2730:
2731:            protected void appendLength(SQLBuffer buf, int type) {
2732:            }
2733:
2734:            /**
2735:             * add CAST for a function operator where operand is a param
2736:             * @param func  function name
2737:             * @param val 
2738:             * @return updated func
2739:             */
2740:            public String addCastAsType(String func, Val val) {
2741:                return null;
2742:            }
2743:
2744:            ///////////
2745:            // DDL SQL
2746:            ///////////
2747:
2748:            /**
2749:             * Increment the reference count of any table components that this
2750:             * dictionary adds that are not used by mappings. Does nothing by default.
2751:             */
2752:            public void refSchemaComponents(Table table) {
2753:            }
2754:
2755:            /**
2756:             * Returns the full name of the table, including the schema (delimited
2757:             * by {@link #catalogSeparator}).
2758:             */
2759:            public String getFullName(Table table, boolean logical) {
2760:                if (!useSchemaName || table.getSchemaName() == null)
2761:                    return table.getName();
2762:                if (logical || ".".equals(catalogSeparator))
2763:                    return table.getFullName();
2764:                return table.getSchemaName() + catalogSeparator
2765:                        + table.getName();
2766:            }
2767:
2768:            /**
2769:             * Returns the full name of the index, including the schema (delimited
2770:             * by the result of {@link #catalogSeparator}).
2771:             */
2772:            public String getFullName(Index index) {
2773:                if (!useSchemaName || index.getSchemaName() == null)
2774:                    return index.getName();
2775:                if (".".equals(catalogSeparator))
2776:                    return index.getFullName();
2777:                return index.getSchemaName() + catalogSeparator
2778:                        + index.getName();
2779:            }
2780:
2781:            /**
2782:             * Returns the full name of the sequence, including the schema (delimited
2783:             * by the result of {@link #catalogSeparator}).
2784:             */
2785:            public String getFullName(Sequence seq) {
2786:                if (!useSchemaName || seq.getSchemaName() == null)
2787:                    return seq.getName();
2788:                if (".".equals(catalogSeparator))
2789:                    return seq.getFullName();
2790:                return seq.getSchemaName() + catalogSeparator + seq.getName();
2791:            }
2792:
2793:            /**
2794:             * Make any necessary changes to the given table name to make it valid
2795:             * for the current DB.
2796:             */
2797:            public String getValidTableName(String name, Schema schema) {
2798:                while (name.startsWith("_"))
2799:                    name = name.substring(1);
2800:                return makeNameValid(name, schema.getSchemaGroup(),
2801:                        maxTableNameLength, NAME_TABLE);
2802:            }
2803:
2804:            /**
2805:             * Make any necessary changes to the given sequence name to make it valid
2806:             * for the current DB.
2807:             */
2808:            public String getValidSequenceName(String name, Schema schema) {
2809:                while (name.startsWith("_"))
2810:                    name = name.substring(1);
2811:                return makeNameValid("S_" + name, schema.getSchemaGroup(),
2812:                        maxTableNameLength, NAME_SEQUENCE);
2813:            }
2814:
2815:            /**
2816:             * Make any necessary changes to the given column name to make it valid
2817:             * for the current DB.
2818:             */
2819:            public String getValidColumnName(String name, Table table) {
2820:                while (name.startsWith("_"))
2821:                    name = name.substring(1);
2822:                return makeNameValid(name, table, maxColumnNameLength, NAME_ANY);
2823:            }
2824:
2825:            /**
2826:             * Make any necessary changes to the given primary key name to make it
2827:             * valid for the current DB.
2828:             */
2829:            public String getValidPrimaryKeyName(String name, Table table) {
2830:                while (name.startsWith("_"))
2831:                    name = name.substring(1);
2832:                return makeNameValid("P_" + name, table.getSchema()
2833:                        .getSchemaGroup(), maxConstraintNameLength, NAME_ANY);
2834:            }
2835:
2836:            /**
2837:             * Make any necessary changes to the given foreign key name to make it
2838:             * valid for the current DB.
2839:             */
2840:            public String getValidForeignKeyName(String name, Table table,
2841:                    Table toTable) {
2842:                while (name.startsWith("_"))
2843:                    name = name.substring(1);
2844:                String tableName = table.getName();
2845:                int len = Math.min(tableName.length(), 7);
2846:                name = "F_" + shorten(tableName, len) + "_" + name;
2847:                return makeNameValid(name, table.getSchema().getSchemaGroup(),
2848:                        maxConstraintNameLength, NAME_ANY);
2849:            }
2850:
2851:            /**
2852:             * Make any necessary changes to the given index name to make it valid
2853:             * for the current DB.
2854:             */
2855:            public String getValidIndexName(String name, Table table) {
2856:                while (name.startsWith("_"))
2857:                    name = name.substring(1);
2858:                String tableName = table.getName();
2859:                int len = Math.min(tableName.length(), 7);
2860:                name = "I_" + shorten(tableName, len) + "_" + name;
2861:                return makeNameValid(name, table.getSchema().getSchemaGroup(),
2862:                        maxIndexNameLength, NAME_ANY);
2863:            }
2864:
2865:            /**
2866:             * Make any necessary changes to the given unique constraint name to make
2867:             * it valid for the current DB.
2868:             */
2869:            public String getValidUniqueName(String name, Table table) {
2870:                while (name.startsWith("_"))
2871:                    name = name.substring(1);
2872:                String tableName = table.getName();
2873:                int len = Math.min(tableName.length(), 7);
2874:                name = "U_" + shorten(tableName, len) + "_" + name;
2875:                return makeNameValid(name, table.getSchema().getSchemaGroup(),
2876:                        maxConstraintNameLength, NAME_ANY);
2877:            }
2878:
2879:            /**
2880:             * Shorten the specified name to the specified target name. This will
2881:             * be done by first stripping out the vowels, and then removing
2882:             * characters from the middle of the word until it reaches the target
2883:             * length.
2884:             */
2885:            protected static String shorten(String name, int targetLength) {
2886:                if (name == null || name.length() <= targetLength)
2887:                    return name;
2888:
2889:                StringBuffer nm = new StringBuffer(name);
2890:                while (nm.length() > targetLength) {
2891:                    if (!stripVowel(nm)) {
2892:                        // cut out the middle char
2893:                        nm.replace(nm.length() / 2, (nm.length() / 2) + 1, "");
2894:                    }
2895:                }
2896:                return nm.toString();
2897:            }
2898:
2899:            /**
2900:             * Remove vowels from the specified StringBuffer.
2901:             *
2902:             * @return true if any vowels have been removed
2903:             */
2904:            private static boolean stripVowel(StringBuffer name) {
2905:                if (name == null || name.length() == 0)
2906:                    return false;
2907:
2908:                char[] vowels = { 'A', 'E', 'I', 'O', 'U', };
2909:                for (int i = 0; i < vowels.length; i++) {
2910:                    int index = name.toString().toUpperCase()
2911:                            .indexOf(vowels[i]);
2912:                    if (index != -1) {
2913:                        name.replace(index, index + 1, "");
2914:                        return true;
2915:                    }
2916:                }
2917:                return false;
2918:            }
2919:
2920:            /**
2921:             * Shortens the given name to the given maximum length, then checks that
2922:             * it is not a reserved word. If it is reserved, appends a "0". If
2923:             * the name conflicts with an existing schema component, the last
2924:             * character is replace with '0', then '1', etc.
2925:             * Note that the given max len may be 0 if the database metadata is
2926:             * incomplete.
2927:             */
2928:            protected String makeNameValid(String name, NameSet set,
2929:                    int maxLen, int nameType) {
2930:                if (maxLen < 1)
2931:                    maxLen = 255;
2932:                if (name.length() > maxLen)
2933:                    name = name.substring(0, maxLen);
2934:                if (reservedWordSet.contains(name.toUpperCase())) {
2935:                    if (name.length() == maxLen)
2936:                        name = name.substring(0, name.length() - 1);
2937:                    name += "0";
2938:                }
2939:
2940:                // now make sure the name is unique
2941:                if (set != null) {
2942:                    outer: for (int version = 1, chars = 1; true; version++) {
2943:                        // for table names, we check for the table itself in case the
2944:                        // name set is lazy about schema reflection
2945:                        switch (nameType) {
2946:                        case NAME_TABLE:
2947:                            if (!((SchemaGroup) set).isKnownTable(name))
2948:                                break outer;
2949:                            break;
2950:                        case NAME_SEQUENCE:
2951:                            if (!((SchemaGroup) set).isKnownSequence(name))
2952:                                break outer;
2953:                            break;
2954:                        default:
2955:                            if (!set.isNameTaken(name))
2956:                                break outer;
2957:                        }
2958:
2959:                        // a single char for the version is probably enough, but might
2960:                        // as well be general about it...
2961:                        if (version > 1)
2962:                            name = name.substring(0, name.length() - chars);
2963:                        if (version >= Math.pow(10, chars))
2964:                            chars++;
2965:                        if (name.length() + chars > maxLen)
2966:                            name = name.substring(0, maxLen - chars);
2967:                        name = name + version;
2968:                    }
2969:                }
2970:                return name.toUpperCase();
2971:            }
2972:
2973:            /**
2974:             * Return a series of SQL statements to create the given table, complete
2975:             * with columns. Indexes and constraints will be created separately.
2976:             */
2977:            public String[] getCreateTableSQL(Table table) {
2978:                StringBuffer buf = new StringBuffer();
2979:                buf.append("CREATE TABLE ").append(getFullName(table, false));
2980:                if (supportsComments && table.hasComment()) {
2981:                    buf.append(" ");
2982:                    comment(buf, table.getComment());
2983:                    buf.append("\n    (");
2984:                } else {
2985:                    buf.append(" (");
2986:                }
2987:
2988:                // do this before getting the columns so we know how to handle
2989:                // the last comma
2990:                StringBuffer endBuf = new StringBuffer();
2991:                PrimaryKey pk = table.getPrimaryKey();
2992:                String pkStr;
2993:                if (pk != null) {
2994:                    pkStr = getPrimaryKeyConstraintSQL(pk);
2995:                    if (pkStr != null)
2996:                        endBuf.append(pkStr);
2997:                }
2998:
2999:                Unique[] unqs = table.getUniques();
3000:                String unqStr;
3001:                for (int i = 0; i < unqs.length; i++) {
3002:                    unqStr = getUniqueConstraintSQL(unqs[i]);
3003:                    if (unqStr != null) {
3004:                        if (endBuf.length() > 0)
3005:                            endBuf.append(", ");
3006:                        endBuf.append(unqStr);
3007:                    }
3008:                }
3009:
3010:                Column[] cols = table.getColumns();
3011:                for (int i = 0; i < cols.length; i++) {
3012:                    buf.append(getDeclareColumnSQL(cols[i], false));
3013:                    if (i < cols.length - 1 || endBuf.length() > 0)
3014:                        buf.append(", ");
3015:                    if (supportsComments && cols[i].hasComment()) {
3016:                        comment(buf, cols[i].getComment());
3017:                        buf.append("\n    ");
3018:                    }
3019:                }
3020:
3021:                buf.append(endBuf.toString());
3022:                buf.append(")");
3023:                return new String[] { buf.toString() };
3024:            }
3025:
3026:            protected StringBuffer comment(StringBuffer buf, String comment) {
3027:                return buf.append("-- ").append(comment);
3028:            }
3029:
3030:            /**
3031:             * Return a series of SQL statements to drop the given table. Indexes
3032:             * will be dropped separately. Returns
3033:             * <code>DROP TABLE &lt;table name&gt;</code> by default.
3034:             */
3035:            public String[] getDropTableSQL(Table table) {
3036:                String drop = MessageFormat.format(dropTableSQL,
3037:                        new Object[] { getFullName(table, false) });
3038:                return new String[] { drop };
3039:            }
3040:
3041:            /**
3042:             * Return a series of SQL statements to create the given sequence. Returns
3043:             * <code>CREATE SEQUENCE &lt;sequence name&gt;[ START WITH &lt;start&gt;]
3044:             * [ INCREMENT BY &lt;increment&gt;]</code> by default.
3045:             */
3046:            public String[] getCreateSequenceSQL(Sequence seq) {
3047:                if (nextSequenceQuery == null)
3048:                    return null;
3049:
3050:                StringBuffer buf = new StringBuffer();
3051:                buf.append("CREATE SEQUENCE ");
3052:                buf.append(getFullName(seq));
3053:                if (seq.getInitialValue() != 0)
3054:                    buf.append(" START WITH ").append(seq.getInitialValue());
3055:                if (seq.getIncrement() > 1)
3056:                    buf.append(" INCREMENT BY ").append(seq.getIncrement());
3057:                return new String[] { buf.toString() };
3058:            }
3059:
3060:            /**
3061:             * Return a series of SQL statements to drop the given sequence. Returns
3062:             * <code>DROP SEQUENCE &lt;sequence name&gt;</code> by default.
3063:             */
3064:            public String[] getDropSequenceSQL(Sequence seq) {
3065:                return new String[] { "DROP SEQUENCE " + getFullName(seq) };
3066:            }
3067:
3068:            /**
3069:             * Return a series of SQL statements to create the given index. Returns
3070:             * <code>CREATE [UNIQUE] INDEX &lt;index name&gt; ON &lt;table name&gt;
3071:             * (&lt;col list&gt;)</code> by default.
3072:             */
3073:            public String[] getCreateIndexSQL(Index index) {
3074:                StringBuffer buf = new StringBuffer();
3075:                buf.append("CREATE ");
3076:                if (index.isUnique())
3077:                    buf.append("UNIQUE ");
3078:                buf.append("INDEX ").append(index.getName());
3079:
3080:                buf.append(" ON ").append(getFullName(index.getTable(), false));
3081:                buf.append(" (").append(Strings.join(index.getColumns(), ", "))
3082:                        .append(")");
3083:
3084:                return new String[] { buf.toString() };
3085:            }
3086:
3087:            /**
3088:             * Return a series of SQL statements to drop the given index. Returns
3089:             * <code>DROP INDEX &lt;index name&gt;</code> by default.
3090:             */
3091:            public String[] getDropIndexSQL(Index index) {
3092:                return new String[] { "DROP INDEX " + getFullName(index) };
3093:            }
3094:
3095:            /**
3096:             * Return a series of SQL statements to add the given column to
3097:             * its table. Return an empty array if operation not supported. Returns
3098:             * <code>ALTER TABLE &lt;table name&gt; ADD (&lt;col dec&gt;)</code>
3099:             * by default.
3100:             */
3101:            public String[] getAddColumnSQL(Column column) {
3102:                if (!supportsAlterTableWithAddColumn)
3103:                    return new String[0];
3104:
3105:                String dec = getDeclareColumnSQL(column, true);
3106:                if (dec == null)
3107:                    return new String[0];
3108:                return new String[] { "ALTER TABLE "
3109:                        + getFullName(column.getTable(), false) + " ADD " + dec };
3110:            }
3111:
3112:            /**
3113:             * Return a series of SQL statements to drop the given column from
3114:             * its table. Return an empty array if operation not supported. Returns
3115:             * <code>ALTER TABLE &lt;table name&gt; DROP COLUMN &lt;col name&gt;</code>
3116:             * by default.
3117:             */
3118:            public String[] getDropColumnSQL(Column column) {
3119:                if (!supportsAlterTableWithDropColumn)
3120:                    return new String[0];
3121:                return new String[] { "ALTER TABLE "
3122:                        + getFullName(column.getTable(), false)
3123:                        + " DROP COLUMN " + column };
3124:            }
3125:
3126:            /**
3127:             * Return a series of SQL statements to add the given primary key to
3128:             * its table. Return an empty array if operation not supported.
3129:             * Returns <code>ALTER TABLE &lt;table name&gt; ADD
3130:             * &lt;pk cons sql &gt;</code> by default.
3131:             */
3132:            public String[] getAddPrimaryKeySQL(PrimaryKey pk) {
3133:                String pksql = getPrimaryKeyConstraintSQL(pk);
3134:                if (pksql == null)
3135:                    return new String[0];
3136:                return new String[] { "ALTER TABLE "
3137:                        + getFullName(pk.getTable(), false) + " ADD " + pksql };
3138:            }
3139:
3140:            /**
3141:             * Return a series of SQL statements to drop the given primary key from
3142:             * its table. Return an empty array if operation not supported.
3143:             * Returns <code>ALTER TABLE &lt;table name&gt; DROP CONSTRAINT
3144:             * &lt;pk name&gt;</code> by default.
3145:             */
3146:            public String[] getDropPrimaryKeySQL(PrimaryKey pk) {
3147:                if (pk.getName() == null)
3148:                    return new String[0];
3149:                return new String[] { "ALTER TABLE "
3150:                        + getFullName(pk.getTable(), false)
3151:                        + " DROP CONSTRAINT " + pk.getName() };
3152:            }
3153:
3154:            /**
3155:             * Return a series of SQL statements to add the given foreign key to
3156:             * its table. Return an empty array if operation not supported.
3157:             * Returns <code>ALTER TABLE &lt;table name&gt; ADD
3158:             * &lt;fk cons sql &gt;</code> by default.
3159:             */
3160:            public String[] getAddForeignKeySQL(ForeignKey fk) {
3161:                String fkSQL = getForeignKeyConstraintSQL(fk);
3162:                if (fkSQL == null)
3163:                    return new String[0];
3164:                return new String[] { "ALTER TABLE "
3165:                        + getFullName(fk.getTable(), false) + " ADD " + fkSQL };
3166:            }
3167:
3168:            /**
3169:             * Return a series of SQL statements to drop the given foreign key from
3170:             * its table. Return an empty array if operation not supported.
3171:             * Returns <code>ALTER TABLE &lt;table name&gt; DROP CONSTRAINT
3172:             * &lt;fk name&gt;</code> by default.
3173:             */
3174:            public String[] getDropForeignKeySQL(ForeignKey fk) {
3175:                if (fk.getName() == null)
3176:                    return new String[0];
3177:                return new String[] { "ALTER TABLE "
3178:                        + getFullName(fk.getTable(), false)
3179:                        + " DROP CONSTRAINT " + fk.getName() };
3180:            }
3181:
3182:            /**
3183:             * Return the declaration SQL for the given column. This method is used
3184:             * for each column from within {@link #getCreateTableSQL} and
3185:             * {@link #getAddColumnSQL}.
3186:             */
3187:            protected String getDeclareColumnSQL(Column col, boolean alter) {
3188:                StringBuffer buf = new StringBuffer();
3189:                buf.append(col).append(" ");
3190:                buf.append(getTypeName(col));
3191:
3192:                // can't add constraints to a column we're adding after table
3193:                // creation, cause some data might already be inserted
3194:                if (!alter) {
3195:                    if (col.getDefaultString() != null && !col.isAutoAssigned())
3196:                        buf.append(" DEFAULT ").append(col.getDefaultString());
3197:                    if (col.isNotNull())
3198:                        buf.append(" NOT NULL");
3199:                }
3200:                if (col.isAutoAssigned()) {
3201:                    if (!supportsAutoAssign)
3202:                        log.warn(_loc.get("invalid-autoassign", platform, col));
3203:                    else if (autoAssignClause != null)
3204:                        buf.append(" ").append(autoAssignClause);
3205:                }
3206:                return buf.toString();
3207:            }
3208:
3209:            /**
3210:             * Return the declaration SQL for the given primary key. This method is
3211:             * used from within {@link #getCreateTableSQL} and
3212:             * {@link #getAddPrimaryKeySQL}. Returns
3213:             * <code>CONSTRAINT &lt;pk name&gt; PRIMARY KEY (&lt;col list&gt;)</code>
3214:             * by default.
3215:             */
3216:            protected String getPrimaryKeyConstraintSQL(PrimaryKey pk) {
3217:                // if we have disabled the creation of primary keys, abort here
3218:                if (!createPrimaryKeys)
3219:                    return null;
3220:
3221:                String name = pk.getName();
3222:                if (name != null
3223:                        && reservedWordSet.contains(name.toUpperCase()))
3224:                    name = null;
3225:
3226:                StringBuffer buf = new StringBuffer();
3227:                if (name != null && CONS_NAME_BEFORE.equals(constraintNameMode))
3228:                    buf.append("CONSTRAINT ").append(name).append(" ");
3229:                buf.append("PRIMARY KEY ");
3230:                if (name != null && CONS_NAME_MID.equals(constraintNameMode))
3231:                    buf.append(name).append(" ");
3232:                buf.append("(").append(Strings.join(pk.getColumns(), ", "))
3233:                        .append(")");
3234:                if (name != null && CONS_NAME_AFTER.equals(constraintNameMode))
3235:                    buf.append(" CONSTRAINT ").append(name);
3236:                return buf.toString();
3237:            }
3238:
3239:            /**
3240:             * Return the declaration SQL for the given foreign key, or null if it is
3241:             * not supported. This method is used from within
3242:             * {@link #getCreateTableSQL} and {@link #getAddForeignKeySQL}. Returns
3243:             * <code>CONSTRAINT &lt;cons name&gt; FOREIGN KEY (&lt;col list&gt;)
3244:             * REFERENCES &lt;foreign table&gt; (&lt;col list&gt;)
3245:             * [ON DELETE &lt;action&gt;] [ON UPDATE &lt;action&gt;]</code> by default.
3246:             */
3247:            protected String getForeignKeyConstraintSQL(ForeignKey fk) {
3248:                if (!supportsForeignKeys)
3249:                    return null;
3250:                if (fk.getDeleteAction() == ForeignKey.ACTION_NONE)
3251:                    return null;
3252:                if (fk.isDeferred() && !supportsDeferredForeignKeyConstraints())
3253:                    return null;
3254:                if (!supportsDeleteAction(fk.getDeleteAction())
3255:                        || !supportsUpdateAction(fk.getUpdateAction()))
3256:                    return null;
3257:
3258:                Column[] locals = fk.getColumns();
3259:                Column[] foreigns = fk.getPrimaryKeyColumns();
3260:
3261:                int delActionId = fk.getDeleteAction();
3262:                if (delActionId == ForeignKey.ACTION_NULL) {
3263:                    for (int i = 0; i < locals.length; i++) {
3264:                        if (locals[i].isNotNull())
3265:                            delActionId = ForeignKey.ACTION_NONE;
3266:                    }
3267:                }
3268:
3269:                String delAction = getActionName(delActionId);
3270:                String upAction = getActionName(fk.getUpdateAction());
3271:
3272:                StringBuffer buf = new StringBuffer();
3273:                if (fk.getName() != null
3274:                        && CONS_NAME_BEFORE.equals(constraintNameMode))
3275:                    buf.append("CONSTRAINT ").append(fk.getName()).append(" ");
3276:                buf.append("FOREIGN KEY ");
3277:                if (fk.getName() != null
3278:                        && CONS_NAME_MID.equals(constraintNameMode))
3279:                    buf.append(fk.getName()).append(" ");
3280:                buf.append("(").append(Strings.join(locals, ", ")).append(")");
3281:                buf.append(" REFERENCES ");
3282:                buf.append(getFullName(foreigns[0].getTable(), false));
3283:                buf.append(" (").append(Strings.join(foreigns, ", ")).append(
3284:                        ")");
3285:                if (delAction != null)
3286:                    buf.append(" ON DELETE ").append(delAction);
3287:                if (upAction != null)
3288:                    buf.append(" ON UPDATE ").append(upAction);
3289:                if (fk.isDeferred())
3290:                    buf.append(" INITIALLY DEFERRED");
3291:                if (supportsDeferredForeignKeyConstraints())
3292:                    buf.append(" DEFERRABLE");
3293:                if (fk.getName() != null
3294:                        && CONS_NAME_AFTER.equals(constraintNameMode))
3295:                    buf.append(" CONSTRAINT ").append(fk.getName());
3296:                return buf.toString();
3297:            }
3298:
3299:            /**
3300:             * Whether or not this dictionary supports deferred foreign key constraints.
3301:             * This implementation returns {@link #supportsUniqueConstraints}.
3302:             *
3303:             * @since 1.1.0
3304:             */
3305:            protected boolean supportsDeferredForeignKeyConstraints() {
3306:                return supportsDeferredConstraints;
3307:            }
3308:
3309:            /**
3310:             * Return the name of the given foreign key action.
3311:             */
3312:            private String getActionName(int action) {
3313:                switch (action) {
3314:                case ForeignKey.ACTION_CASCADE:
3315:                    return "CASCADE";
3316:                case ForeignKey.ACTION_NULL:
3317:                    return "SET NULL";
3318:                case ForeignKey.ACTION_DEFAULT:
3319:                    return "SET DEFAULT";
3320:                default:
3321:                    return null;
3322:                }
3323:            }
3324:
3325:            /**
3326:             * Whether this database supports the given foreign key delete action.
3327:             */
3328:            public boolean supportsDeleteAction(int action) {
3329:                if (action == ForeignKey.ACTION_NONE)
3330:                    return true;
3331:                if (!supportsForeignKeys)
3332:                    return false;
3333:                switch (action) {
3334:                case ForeignKey.ACTION_RESTRICT:
3335:                    return supportsRestrictDeleteAction;
3336:                case ForeignKey.ACTION_CASCADE:
3337:                    return supportsCascadeDeleteAction;
3338:                case ForeignKey.ACTION_NULL:
3339:                    return supportsNullDeleteAction;
3340:                case ForeignKey.ACTION_DEFAULT:
3341:                    return supportsDefaultDeleteAction;
3342:                default:
3343:                    return false;
3344:                }
3345:            }
3346:
3347:            /**
3348:             * Whether this database supports the given foreign key update action.
3349:             */
3350:            public boolean supportsUpdateAction(int action) {
3351:                if (action == ForeignKey.ACTION_NONE)
3352:                    return true;
3353:                if (!supportsForeignKeys)
3354:                    return false;
3355:                switch (action) {
3356:                case ForeignKey.ACTION_RESTRICT:
3357:                    return supportsRestrictUpdateAction;
3358:                case ForeignKey.ACTION_CASCADE:
3359:                    return supportsCascadeUpdateAction;
3360:                case ForeignKey.ACTION_NULL:
3361:                    return supportsNullUpdateAction;
3362:                case ForeignKey.ACTION_DEFAULT:
3363:                    return supportsDefaultUpdateAction;
3364:                default:
3365:                    return false;
3366:                }
3367:            }
3368:
3369:            /**
3370:             * Return the declaration SQL for the given unique constraint. This
3371:             * method is used from within {@link #getCreateTableSQL}.
3372:             * Returns	<code>CONSTRAINT &lt;name&gt; UNIQUE (&lt;col list&gt;)</code>
3373:             * by default.
3374:             */
3375:            protected String getUniqueConstraintSQL(Unique unq) {
3376:                if (!supportsUniqueConstraints
3377:                        || (unq.isDeferred() && !supportsDeferredUniqueConstraints()))
3378:                    return null;
3379:
3380:                StringBuffer buf = new StringBuffer();
3381:                if (unq.getName() != null
3382:                        && CONS_NAME_BEFORE.equals(constraintNameMode))
3383:                    buf.append("CONSTRAINT ").append(unq.getName()).append(" ");
3384:                buf.append("UNIQUE ");
3385:                if (unq.getName() != null
3386:                        && CONS_NAME_MID.equals(constraintNameMode))
3387:                    buf.append(unq.getName()).append(" ");
3388:                buf.append("(").append(Strings.join(unq.getColumns(), ", "))
3389:                        .append(")");
3390:                if (unq.isDeferred())
3391:                    buf.append(" INITIALLY DEFERRED");
3392:                if (supportsDeferredUniqueConstraints())
3393:                    buf.append(" DEFERRABLE");
3394:                if (unq.getName() != null
3395:                        && CONS_NAME_AFTER.equals(constraintNameMode))
3396:                    buf.append(" CONSTRAINT ").append(unq.getName());
3397:                return buf.toString();
3398:            }
3399:
3400:            /**
3401:             * Whether or not this dictionary supports deferred unique constraints.
3402:             * This implementation returns {@link #supportsUniqueConstraints}.
3403:             *
3404:             * @since 1.1.0
3405:             */
3406:            protected boolean supportsDeferredUniqueConstraints() {
3407:                return supportsDeferredConstraints;
3408:            }
3409:
3410:            /////////////////////
3411:            // Database metadata
3412:            /////////////////////
3413:
3414:            /**
3415:             * This method is used to filter system tables from database metadata.
3416:             * Return true if the given table name represents a system table that
3417:             * should not appear in the schema definition. By default, returns
3418:             * true only if the given table is in the internal list of system tables,
3419:             * or if the given schema is in the list of system schemas and is not
3420:             * the target schema.
3421:             *
3422:             * @param name the table name
3423:             * @param schema the table schema; may be null
3424:             * @param targetSchema if true, then the given schema was listed by
3425:             * the user as one of his schemas
3426:             */
3427:            public boolean isSystemTable(String name, String schema,
3428:                    boolean targetSchema) {
3429:                if (systemTableSet.contains(name.toUpperCase()))
3430:                    return true;
3431:                return !targetSchema && schema != null
3432:                        && systemSchemaSet.contains(schema.toUpperCase());
3433:            }
3434:
3435:            /**
3436:             * This method is used to filter system indexes from database metadata.
3437:             * Return true if the given index name represents a system index that
3438:             * should not appear in the schema definition. Returns false by default.
3439:             *
3440:             * @param name the index name
3441:             * @param table the index table
3442:             */
3443:            public boolean isSystemIndex(String name, Table table) {
3444:                return false;
3445:            }
3446:
3447:            /**
3448:             * This method is used to filter system sequences from database metadata.
3449:             * Return true if the given sequence represents a system sequence that
3450:             * should not appear in the schema definition. Returns true if system
3451:             * schema by default.
3452:             *
3453:             * @param name the table name
3454:             * @param schema the table schema; may be null
3455:             * @param targetSchema if true, then the given schema was listed by
3456:             * the user as one of his schemas
3457:             */
3458:            public boolean isSystemSequence(String name, String schema,
3459:                    boolean targetSchema) {
3460:                return !targetSchema && schema != null
3461:                        && systemSchemaSet.contains(schema.toUpperCase());
3462:            }
3463:
3464:            /**
3465:             * Reflect on the schema to find tables matching the given name pattern.
3466:             */
3467:            public Table[] getTables(DatabaseMetaData meta, String catalog,
3468:                    String schemaName, String tableName, Connection conn)
3469:                    throws SQLException {
3470:                if (!supportsSchemaForGetTables)
3471:                    schemaName = null;
3472:                else
3473:                    schemaName = getSchemaNameForMetadata(schemaName);
3474:
3475:                String[] types = Strings.split(tableTypes, ",", 0);
3476:                for (int i = 0; i < types.length; i++)
3477:                    types[i] = types[i].trim();
3478:
3479:                beforeMetadataOperation(conn);
3480:                ResultSet tables = null;
3481:                try {
3482:                    tables = meta.getTables(getCatalogNameForMetadata(catalog),
3483:                            schemaName, getTableNameForMetadata(tableName),
3484:                            types);
3485:                    List tableList = new ArrayList();
3486:                    while (tables != null && tables.next())
3487:                        tableList.add(newTable(tables));
3488:                    return (Table[]) tableList.toArray(new Table[tableList
3489:                            .size()]);
3490:                } finally {
3491:                    if (tables != null)
3492:                        try {
3493:                            tables.close();
3494:                        } catch (Exception e) {
3495:                        }
3496:                }
3497:            }
3498:
3499:            /**
3500:             * Create a new table from the information in the schema metadata.
3501:             */
3502:            protected Table newTable(ResultSet tableMeta) throws SQLException {
3503:                Table t = new Table();
3504:                t.setName(tableMeta.getString("TABLE_NAME"));
3505:                return t;
3506:            }
3507:
3508:            /**
3509:             * Reflect on the schema to find sequences matching the given name pattern.
3510:             * Returns an empty array by default, as there is no standard way to
3511:             * retrieve a list of sequences.
3512:             */
3513:            public Sequence[] getSequences(DatabaseMetaData meta,
3514:                    String catalog, String schemaName, String sequenceName,
3515:                    Connection conn) throws SQLException {
3516:                String str = getSequencesSQL(schemaName, sequenceName);
3517:                if (str == null)
3518:                    return new Sequence[0];
3519:
3520:                PreparedStatement stmnt = prepareStatement(conn, str);
3521:                ResultSet rs = null;
3522:                try {
3523:                    int idx = 1;
3524:                    if (schemaName != null)
3525:                        stmnt.setString(idx++, schemaName.toUpperCase());
3526:                    if (sequenceName != null)
3527:                        stmnt.setString(idx++, sequenceName);
3528:
3529:                    rs = executeQuery(conn, stmnt, str);
3530:                    return getSequence(rs);
3531:                } finally {
3532:                    if (rs != null)
3533:                        try {
3534:                            rs.close();
3535:                        } catch (SQLException se) {
3536:                        }
3537:                    if (stmnt != null)
3538:                        try {
3539:                            stmnt.close();
3540:                        } catch (SQLException se) {
3541:                        }
3542:                }
3543:            }
3544:
3545:            /**
3546:             * Create a new sequence from the information in the schema metadata.
3547:             */
3548:            protected Sequence newSequence(ResultSet sequenceMeta)
3549:                    throws SQLException {
3550:                Sequence seq = new Sequence();
3551:                seq.setSchemaName(sequenceMeta.getString("SEQUENCE_SCHEMA"));
3552:                seq.setName(sequenceMeta.getString("SEQUENCE_NAME"));
3553:                return seq;
3554:            }
3555:
3556:            /**
3557:             * Return the SQL needed to select the list of sequences.
3558:             */
3559:            protected String getSequencesSQL(String schemaName,
3560:                    String sequenceName) {
3561:                return null;
3562:            }
3563:
3564:            /**
3565:             * Reflect on the schema to find columns matching the given table and
3566:             * column patterns.
3567:             */
3568:            public Column[] getColumns(DatabaseMetaData meta, String catalog,
3569:                    String schemaName, String tableName, String columnName,
3570:                    Connection conn) throws SQLException {
3571:                if (tableName == null && !supportsNullTableForGetColumns)
3572:                    return null;
3573:
3574:                if (!supportsSchemaForGetColumns)
3575:                    schemaName = null;
3576:                else
3577:                    schemaName = getSchemaNameForMetadata(schemaName);
3578:
3579:                beforeMetadataOperation(conn);
3580:                ResultSet cols = null;
3581:                try {
3582:                    cols = meta.getColumns(getCatalogNameForMetadata(catalog),
3583:                            schemaName, getTableNameForMetadata(tableName),
3584:                            getColumnNameForMetadata(columnName));
3585:
3586:                    List columnList = new ArrayList();
3587:                    while (cols != null && cols.next())
3588:                        columnList.add(newColumn(cols));
3589:                    return (Column[]) columnList.toArray(new Column[columnList
3590:                            .size()]);
3591:                } finally {
3592:                    if (cols != null)
3593:                        try {
3594:                            cols.close();
3595:                        } catch (Exception e) {
3596:                        }
3597:                }
3598:            }
3599:
3600:            /**
3601:             * Create a new column from the information in the schema metadata.
3602:             */
3603:            protected Column newColumn(ResultSet colMeta) throws SQLException {
3604:                Column c = new Column();
3605:                c.setSchemaName(colMeta.getString("TABLE_SCHEM"));
3606:                c.setTableName(colMeta.getString("TABLE_NAME"));
3607:                c.setName(colMeta.getString("COLUMN_NAME"));
3608:                c.setType(colMeta.getInt("DATA_TYPE"));
3609:                c.setTypeName(colMeta.getString("TYPE_NAME"));
3610:                c.setSize(colMeta.getInt("COLUMN_SIZE"));
3611:                c.setDecimalDigits(colMeta.getInt("DECIMAL_DIGITS"));
3612:                c
3613:                        .setNotNull(colMeta.getInt("NULLABLE") == DatabaseMetaData.columnNoNulls);
3614:
3615:                String def = colMeta.getString("COLUMN_DEF");
3616:                if (!StringUtils.isEmpty(def) && !"null".equalsIgnoreCase(def))
3617:                    c.setDefaultString(def);
3618:                return c;
3619:            }
3620:
3621:            /**
3622:             * Reflect on the schema to find primary keys for the given table pattern.
3623:             */
3624:            public PrimaryKey[] getPrimaryKeys(DatabaseMetaData meta,
3625:                    String catalog, String schemaName, String tableName,
3626:                    Connection conn) throws SQLException {
3627:                if (useGetBestRowIdentifierForPrimaryKeys)
3628:                    return getPrimaryKeysFromBestRowIdentifier(meta, catalog,
3629:                            schemaName, tableName, conn);
3630:                return getPrimaryKeysFromGetPrimaryKeys(meta, catalog,
3631:                        schemaName, tableName, conn);
3632:            }
3633:
3634:            /**
3635:             * Reflect on the schema to find primary keys for the given table pattern.
3636:             */
3637:            protected PrimaryKey[] getPrimaryKeysFromGetPrimaryKeys(
3638:                    DatabaseMetaData meta, String catalog, String schemaName,
3639:                    String tableName, Connection conn) throws SQLException {
3640:                if (tableName == null && !supportsNullTableForGetPrimaryKeys)
3641:                    return null;
3642:
3643:                beforeMetadataOperation(conn);
3644:                ResultSet pks = null;
3645:                try {
3646:                    pks = meta.getPrimaryKeys(
3647:                            getCatalogNameForMetadata(catalog),
3648:                            getSchemaNameForMetadata(schemaName),
3649:                            getTableNameForMetadata(tableName));
3650:
3651:                    List pkList = new ArrayList();
3652:                    while (pks != null && pks.next())
3653:                        pkList.add(newPrimaryKey(pks));
3654:                    return (PrimaryKey[]) pkList.toArray(new PrimaryKey[pkList
3655:                            .size()]);
3656:                } finally {
3657:                    if (pks != null)
3658:                        try {
3659:                            pks.close();
3660:                        } catch (Exception e) {
3661:                        }
3662:                }
3663:            }
3664:
3665:            /**
3666:             * Create a new primary key from the information in the schema metadata.
3667:             */
3668:            protected PrimaryKey newPrimaryKey(ResultSet pkMeta)
3669:                    throws SQLException {
3670:                PrimaryKey pk = new PrimaryKey();
3671:                pk.setSchemaName(pkMeta.getString("TABLE_SCHEM"));
3672:                pk.setTableName(pkMeta.getString("TABLE_NAME"));
3673:                pk.setColumnName(pkMeta.getString("COLUMN_NAME"));
3674:                pk.setName(pkMeta.getString("PK_NAME"));
3675:                return pk;
3676:            }
3677:
3678:            /**
3679:             * Reflect on the schema to find primary keys for the given table pattern.
3680:             */
3681:            protected PrimaryKey[] getPrimaryKeysFromBestRowIdentifier(
3682:                    DatabaseMetaData meta, String catalog, String schemaName,
3683:                    String tableName, Connection conn) throws SQLException {
3684:                if (tableName == null)
3685:                    return null;
3686:
3687:                beforeMetadataOperation(conn);
3688:                ResultSet pks = null;
3689:                try {
3690:                    pks = meta.getBestRowIdentifier(catalog, schemaName,
3691:                            tableName, 0, false);
3692:
3693:                    List pkList = new ArrayList();
3694:                    while (pks != null && pks.next()) {
3695:                        PrimaryKey pk = new PrimaryKey();
3696:                        pk.setSchemaName(schemaName);
3697:                        pk.setTableName(tableName);
3698:                        pk.setColumnName(pks.getString("COLUMN_NAME"));
3699:                        pkList.add(pk);
3700:                    }
3701:                    return (PrimaryKey[]) pkList.toArray(new PrimaryKey[pkList
3702:                            .size()]);
3703:                } finally {
3704:                    if (pks != null)
3705:                        try {
3706:                            pks.close();
3707:                        } catch (Exception e) {
3708:                        }
3709:                }
3710:            }
3711:
3712:            /**
3713:             * Reflect on the schema to find indexes matching the given table pattern.
3714:             */
3715:            public Index[] getIndexInfo(DatabaseMetaData meta, String catalog,
3716:                    String schemaName, String tableName, boolean unique,
3717:                    boolean approx, Connection conn) throws SQLException {
3718:                if (tableName == null && !supportsNullTableForGetIndexInfo)
3719:                    return null;
3720:
3721:                beforeMetadataOperation(conn);
3722:                ResultSet indexes = null;
3723:                try {
3724:                    indexes = meta.getIndexInfo(
3725:                            getCatalogNameForMetadata(catalog),
3726:                            getSchemaNameForMetadata(schemaName),
3727:                            getTableNameForMetadata(tableName), unique, approx);
3728:
3729:                    List indexList = new ArrayList();
3730:                    while (indexes != null && indexes.next())
3731:                        indexList.add(newIndex(indexes));
3732:                    return (Index[]) indexList.toArray(new Index[indexList
3733:                            .size()]);
3734:                } finally {
3735:                    if (indexes != null)
3736:                        try {
3737:                            indexes.close();
3738:                        } catch (Exception e) {
3739:                        }
3740:                }
3741:            }
3742:
3743:            /**
3744:             * Create a new index from the information in the schema metadata.
3745:             */
3746:            protected Index newIndex(ResultSet idxMeta) throws SQLException {
3747:                Index idx = new Index();
3748:                idx.setSchemaName(idxMeta.getString("TABLE_SCHEM"));
3749:                idx.setTableName(idxMeta.getString("TABLE_NAME"));
3750:                idx.setColumnName(idxMeta.getString("COLUMN_NAME"));
3751:                idx.setName(idxMeta.getString("INDEX_NAME"));
3752:                idx.setUnique(!idxMeta.getBoolean("NON_UNIQUE"));
3753:                return idx;
3754:            }
3755:
3756:            /**
3757:             * Reflect on the schema to return foreign keys imported by the given
3758:             * table pattern.
3759:             */
3760:            public ForeignKey[] getImportedKeys(DatabaseMetaData meta,
3761:                    String catalog, String schemaName, String tableName,
3762:                    Connection conn) throws SQLException {
3763:                if (!supportsForeignKeys)
3764:                    return null;
3765:                if (tableName == null && !supportsNullTableForGetImportedKeys)
3766:                    return null;
3767:
3768:                beforeMetadataOperation(conn);
3769:                ResultSet keys = null;
3770:                try {
3771:                    keys = meta.getImportedKeys(
3772:                            getCatalogNameForMetadata(catalog),
3773:                            getSchemaNameForMetadata(schemaName),
3774:                            getTableNameForMetadata(tableName));
3775:
3776:                    List importedKeyList = new ArrayList();
3777:                    while (keys != null && keys.next())
3778:                        importedKeyList.add(newForeignKey(keys));
3779:                    return (ForeignKey[]) importedKeyList
3780:                            .toArray(new ForeignKey[importedKeyList.size()]);
3781:                } finally {
3782:                    if (keys != null)
3783:                        try {
3784:                            keys.close();
3785:                        } catch (Exception e) {
3786:                        }
3787:                }
3788:            }
3789:
3790:            /**
3791:             * Create a new foreign key from the information in the schema metadata.
3792:             */
3793:            protected ForeignKey newForeignKey(ResultSet fkMeta)
3794:                    throws SQLException {
3795:                ForeignKey fk = new ForeignKey();
3796:                fk.setSchemaName(fkMeta.getString("FKTABLE_SCHEM"));
3797:                fk.setTableName(fkMeta.getString("FKTABLE_NAME"));
3798:                fk.setColumnName(fkMeta.getString("FKCOLUMN_NAME"));
3799:                fk.setName(fkMeta.getString("FK_NAME"));
3800:                fk.setPrimaryKeySchemaName(fkMeta.getString("PKTABLE_SCHEM"));
3801:                fk.setPrimaryKeyTableName(fkMeta.getString("PKTABLE_NAME"));
3802:                fk.setPrimaryKeyColumnName(fkMeta.getString("PKCOLUMN_NAME"));
3803:                fk.setKeySequence(fkMeta.getShort("KEY_SEQ"));
3804:                fk
3805:                        .setDeferred(fkMeta.getShort("DEFERRABILITY") == DatabaseMetaData.importedKeyInitiallyDeferred);
3806:
3807:                int del = fkMeta.getShort("DELETE_RULE");
3808:                switch (del) {
3809:                case DatabaseMetaData.importedKeySetNull:
3810:                    fk.setDeleteAction(ForeignKey.ACTION_NULL);
3811:                    break;
3812:                case DatabaseMetaData.importedKeySetDefault:
3813:                    fk.setDeleteAction(ForeignKey.ACTION_DEFAULT);
3814:                    break;
3815:                case DatabaseMetaData.importedKeyCascade:
3816:                    fk.setDeleteAction(ForeignKey.ACTION_CASCADE);
3817:                    break;
3818:                default:
3819:                    fk.setDeleteAction(ForeignKey.ACTION_RESTRICT);
3820:                    break;
3821:                }
3822:                return fk;
3823:            }
3824:
3825:            /**
3826:             * Returns the table name that will be used for obtaining information
3827:             * from {@link DatabaseMetaData}.
3828:             */
3829:            protected String getTableNameForMetadata(String tableName) {
3830:                return convertSchemaCase(tableName);
3831:            }
3832:
3833:            /**
3834:             * Returns the schema name that will be used for obtaining information
3835:             * from {@link DatabaseMetaData}.
3836:             */
3837:            protected String getSchemaNameForMetadata(String schemaName) {
3838:                if (schemaName == null)
3839:                    schemaName = conf.getSchema();
3840:                return convertSchemaCase(schemaName);
3841:            }
3842:
3843:            /**
3844:             * Returns the catalog name that will be used for obtaining information
3845:             * from {@link DatabaseMetaData}.
3846:             */
3847:            protected String getCatalogNameForMetadata(String catalogName) {
3848:                return convertSchemaCase(catalogName);
3849:            }
3850:
3851:            /**
3852:             * Returns the column name that will be used for obtaining information
3853:             * from {@link DatabaseMetaData}.
3854:             */
3855:            protected String getColumnNameForMetadata(String columnName) {
3856:                return convertSchemaCase(columnName);
3857:            }
3858:
3859:            /**
3860:             * Convert the specified schema name to a name that the database will
3861:             * be able to understand.
3862:             */
3863:            protected String convertSchemaCase(String objectName) {
3864:                if (objectName == null)
3865:                    return null;
3866:
3867:                String scase = getSchemaCase();
3868:                if (SCHEMA_CASE_LOWER.equals(scase))
3869:                    return objectName.toLowerCase();
3870:                if (SCHEMA_CASE_PRESERVE.equals(scase))
3871:                    return objectName;
3872:                return objectName.toUpperCase();
3873:            }
3874:
3875:            /**
3876:             * Return DB specific schemaCase 
3877:             */
3878:            public String getSchemaCase() {
3879:                return schemaCase;
3880:            }
3881:
3882:            /**
3883:             * Prepared the connection for metadata operations.
3884:             */
3885:            private void beforeMetadataOperation(Connection c) {
3886:                if (requiresAutoCommitForMetaData) {
3887:                    try {
3888:                        c.rollback();
3889:                    } catch (SQLException sqle) {
3890:                    }
3891:                    try {
3892:                        if (!c.getAutoCommit())
3893:                            c.setAutoCommit(true);
3894:                    } catch (SQLException sqle) {
3895:                    }
3896:                }
3897:            }
3898:
3899:            /////////////////////////////
3900:            // Sequences and Auto-Assign
3901:            /////////////////////////////
3902:
3903:            /**
3904:             * Return the last generated value for the given column.
3905:             * Throws an exception by default if {@link #lastGeneratedKeyQuery} is null.
3906:             */
3907:            public Object getGeneratedKey(Column col, Connection conn)
3908:                    throws SQLException {
3909:                if (lastGeneratedKeyQuery == null)
3910:                    throw new StoreException(_loc.get("no-auto-assign"));
3911:
3912:                // replace things like "SELECT MAX({0}) FROM {1}"
3913:                String query = lastGeneratedKeyQuery;
3914:                if (query.indexOf('{') != -1) // only if the token is in the string
3915:                {
3916:                    query = MessageFormat.format(query, new Object[] {
3917:                            col.getName(), getFullName(col.getTable(), false),
3918:                            getGeneratedKeySequenceName(col), });
3919:                }
3920:
3921:                PreparedStatement stmnt = prepareStatement(conn, query);
3922:                ResultSet rs = null;
3923:                try {
3924:                    rs = executeQuery(conn, stmnt, query);
3925:                    return getKey(rs, col);
3926:                } finally {
3927:                    if (rs != null)
3928:                        try {
3929:                            rs.close();
3930:                        } catch (SQLException se) {
3931:                        }
3932:                    if (stmnt != null)
3933:                        try {
3934:                            stmnt.close();
3935:                        } catch (SQLException se) {
3936:                        }
3937:                }
3938:            }
3939:
3940:            /**
3941:             * Return the sequence name used by databases for the given autoassigned
3942:             * column. This is only used by databases that require an explicit name
3943:             * to be used for auto-assign support.
3944:             */
3945:            protected String getGeneratedKeySequenceName(Column col) {
3946:                String tname = col.getTableName();
3947:                String cname = col.getName();
3948:                int max = maxAutoAssignNameLength;
3949:                int extraChars = -max + tname.length() + 1 // <tname> + '_'
3950:                        + cname.length() + 4; // <cname> + '_SEQ'
3951:                if (extraChars > 0) {
3952:                    // this assumes that tname is longer than extraChars
3953:                    tname = tname.substring(0, tname.length() - extraChars);
3954:                }
3955:                StringBuffer buf = new StringBuffer(max);
3956:                buf.append(tname).append("_").append(cname).append("_SEQ");
3957:                return buf.toString();
3958:            }
3959:
3960:            ///////////////////////////////
3961:            // Configurable implementation
3962:            ///////////////////////////////
3963:
3964:            public void setConfiguration(Configuration conf) {
3965:                this .conf = (JDBCConfiguration) conf;
3966:                this .log = this .conf.getLog(JDBCConfiguration.LOG_JDBC);
3967:
3968:                // warn about unsupported dicts
3969:                if (log.isWarnEnabled() && !isSupported())
3970:                    log.warn(_loc.get("dict-not-supported", getClass()));
3971:            }
3972:
3973:            private boolean isSupported() {
3974:                // if this is a custom dict, traverse to whatever openjpa dict it extends
3975:                Class c = getClass();
3976:                while (!c.getName().startsWith("org.apache.openjpa."))
3977:                    c = c.getSuperclass();
3978:
3979:                // the generic dbdictionary is not considered a supported dict; all
3980:                // other concrete dictionaries are
3981:                if (c == DBDictionary.class)
3982:                    return false;
3983:                return true;
3984:            }
3985:
3986:            public void startConfiguration() {
3987:            }
3988:
3989:            public void endConfiguration() {
3990:                // initialize the set of reserved SQL92 words from resource
3991:                InputStream in = DBDictionary.class
3992:                        .getResourceAsStream("sql-keywords.rsrc");
3993:                try {
3994:                    String keywords = new BufferedReader(new InputStreamReader(
3995:                            in)).readLine();
3996:                    in.close();
3997:                    reservedWordSet.addAll(Arrays.asList(Strings.split(
3998:                            keywords, ",", 0)));
3999:                } catch (IOException ioe) {
4000:                    throw new GeneralException(ioe);
4001:                } finally {
4002:                    try {
4003:                        in.close();
4004:                    } catch (IOException e) {
4005:                    }
4006:                }
4007:
4008:                // add additional reserved words set by user
4009:                if (reservedWords != null)
4010:                    reservedWordSet.addAll(Arrays.asList(Strings.split(
4011:                            reservedWords.toUpperCase(), ",", 0)));
4012:
4013:                // add system schemas set by user
4014:                if (systemSchemas != null)
4015:                    systemSchemaSet.addAll(Arrays.asList(Strings.split(
4016:                            systemSchemas.toUpperCase(), ",", 0)));
4017:
4018:                // add system tables set by user
4019:                if (systemTables != null)
4020:                    systemTableSet.addAll(Arrays.asList(Strings.split(
4021:                            systemTables.toUpperCase(), ",", 0)));
4022:
4023:                // add fixed size type names set by the user
4024:                if (fixedSizeTypeNames != null)
4025:                    fixedSizeTypeNameSet.addAll(Arrays.asList(Strings.split(
4026:                            fixedSizeTypeNames.toUpperCase(), ",", 0)));
4027:
4028:                // if user has unset sequence sql, null it out so we know sequences
4029:                // aren't supported
4030:                nextSequenceQuery = StringUtils.trimToNull(nextSequenceQuery);
4031:
4032:                if (selectWords != null)
4033:                    selectWordSet.addAll(Arrays.asList(Strings.split(
4034:                            selectWords.toUpperCase(), ",", 0)));
4035:            }
4036:
4037:            //////////////////////////////////////
4038:            // ConnectionDecorator implementation
4039:            //////////////////////////////////////
4040:
4041:            /**
4042:             * Decorate the given connection if needed. Some databases require special
4043:             * handling for JDBC bugs. This implementation issues any
4044:             * {@link #initializationSQL} that has been set for the dictionary but
4045:             * does not decoreate the connection.
4046:             */
4047:            public Connection decorate(Connection conn) throws SQLException {
4048:                if (!connected)
4049:                    connectedConfiguration(conn);
4050:                if (!StringUtils.isEmpty(initializationSQL)) {
4051:                    PreparedStatement stmnt = null;
4052:                    try {
4053:                        stmnt = conn.prepareStatement(initializationSQL);
4054:                        stmnt.execute();
4055:                    } catch (Exception e) {
4056:                        if (log.isTraceEnabled())
4057:                            log.trace(e.toString(), e);
4058:                    } finally {
4059:                        if (stmnt != null)
4060:                            try {
4061:                                stmnt.close();
4062:                            } catch (SQLException se) {
4063:                            }
4064:                    }
4065:                }
4066:                return conn;
4067:            }
4068:
4069:            /**
4070:             * Implementation of the
4071:             * {@link LoggingConnectionDecorator.SQLWarningHandler} interface
4072:             * that allows customization of the actions to perform when a
4073:             * {@link SQLWarning} occurs at any point on a {@link Connection},
4074:             * {@link Statement}, or {@link ResultSet}. This method may
4075:             * be used determine those warnings the application wants to
4076:             * consider critical failures, and throw the warning in those
4077:             * cases. By default, this method does nothing.
4078:             *
4079:             * @see LoggingConnectionDecorator#setWarningAction
4080:             * @see LoggingConnectionDecorator#setWarningHandler
4081:             */
4082:            public void handleWarning(SQLWarning warning) throws SQLException {
4083:            }
4084:
4085:            /**
4086:             * Return a new exception that wraps <code>causes</code>.
4087:             * However, the details of exactly what type of exception is returned can
4088:             * be determined by the implementation. This may take into account
4089:             * DB-specific exception information in <code>causes</code>.
4090:             */
4091:            public OpenJPAException newStoreException(String msg,
4092:                    SQLException[] causes, Object failed) {
4093:                if (causes != null && causes.length > 0) {
4094:                    OpenJPAException ret = SQLExceptions.narrow(msg, causes[0],
4095:                            this );
4096:                    ret.setFailedObject(failed).setNestedThrowables(causes);
4097:                    return ret;
4098:                }
4099:                return new StoreException(msg).setFailedObject(failed)
4100:                        .setNestedThrowables(causes);
4101:            }
4102:
4103:            /**
4104:             * Gets the list of String, each represents an error that can help 
4105:             * to narrow down a SQL exception to specific type of StoreException.<br>
4106:             * For example, error code <code>"23000"</code> represents referential
4107:             * integrity violation and hence can be narrowed down to 
4108:             * {@link ReferentialIntegrityException} rather than more general
4109:             * {@link StoreException}.<br>
4110:             * JDBC Drivers are not uniform in return values of SQLState for the same
4111:             * error and hence each database specific Dictionary can specialize.<br>
4112:             * 
4113:             * 
4114:             * @return an <em>unmodifiable</em> list of Strings representing supposedly 
4115:             * uniform SQL States for a given type of StoreException. 
4116:             * Default behavior is to return an empty list.
4117:             */
4118:            public List/*<String>*/getSQLStates(int exceptionType) {
4119:                if (exceptionType >= 0
4120:                        && exceptionType < SQL_STATE_CODES.length)
4121:                    return SQL_STATE_CODES[exceptionType];
4122:                return EMPTY_STRING_LIST;
4123:            }
4124:
4125:            /**
4126:             * Closes the specified {@link DataSource} and releases any
4127:             * resources associated with it.
4128:             *
4129:             * @param dataSource the DataSource to close
4130:             */
4131:            public void closeDataSource(DataSource dataSource) {
4132:                DataSourceFactory.closeDataSource(dataSource);
4133:            }
4134:
4135:            /**
4136:             * Used by some mappings to represent data that has already been
4137:             * serialized so that we don't have to serialize multiple times.
4138:             */
4139:            public static class SerializedData {
4140:
4141:                public final byte[] bytes;
4142:
4143:                public SerializedData(byte[] bytes) {
4144:                    this .bytes = bytes;
4145:                }
4146:            }
4147:
4148:            /**
4149:             * Return version column name
4150:             * @param column
4151:             * @param tableAlias : this is needed for platform specific version column
4152:             * @return
4153:             */
4154:            public String getVersionColumn(Column column, String tableAlias) {
4155:                return column.toString();
4156:            }
4157:
4158:            public void insertBlobForStreamingLoad(Row row, Column col)
4159:                    throws SQLException {
4160:                row.setBinaryStream(col, new ByteArrayInputStream(new byte[0]),
4161:                        0);
4162:            }
4163:
4164:            public void insertClobForStreamingLoad(Row row, Column col)
4165:                    throws SQLException {
4166:                row
4167:                        .setCharacterStream(col, new CharArrayReader(
4168:                                new char[0]), 0);
4169:            }
4170:
4171:            public void updateBlob(Select sel, JDBCStore store, InputStream is)
4172:                    throws SQLException {
4173:                SQLBuffer sql = sel.toSelect(true, store
4174:                        .getFetchConfiguration());
4175:                ResultSet res = null;
4176:                Connection conn = store.getConnection();
4177:                PreparedStatement stmnt = null;
4178:                try {
4179:                    stmnt = sql.prepareStatement(conn, store
4180:                            .getFetchConfiguration(),
4181:                            ResultSet.TYPE_SCROLL_SENSITIVE,
4182:                            ResultSet.CONCUR_UPDATABLE);
4183:                    res = stmnt.executeQuery();
4184:                    if (!res.next()) {
4185:                        throw new InternalException(_loc
4186:                                .get("stream-exception"));
4187:                    }
4188:                    Blob blob = res.getBlob(1);
4189:                    OutputStream os = blob.setBinaryStream(1);
4190:                    copy(is, os);
4191:                    os.close();
4192:                    res.updateBlob(1, blob);
4193:                    res.updateRow();
4194:
4195:                } catch (IOException ioe) {
4196:                    throw new StoreException(ioe);
4197:                } finally {
4198:                    if (res != null)
4199:                        try {
4200:                            res.close();
4201:                        } catch (SQLException e) {
4202:                        }
4203:                    if (stmnt != null)
4204:                        try {
4205:                            stmnt.close();
4206:                        } catch (SQLException e) {
4207:                        }
4208:                    if (conn != null)
4209:                        try {
4210:                            conn.close();
4211:                        } catch (SQLException e) {
4212:                        }
4213:                }
4214:            }
4215:
4216:            public void updateClob(Select sel, JDBCStore store, Reader reader)
4217:                    throws SQLException {
4218:                SQLBuffer sql = sel.toSelect(true, store
4219:                        .getFetchConfiguration());
4220:                ResultSet res = null;
4221:                Connection conn = store.getConnection();
4222:                PreparedStatement stmnt = null;
4223:                try {
4224:                    stmnt = sql.prepareStatement(conn, store
4225:                            .getFetchConfiguration(),
4226:                            ResultSet.TYPE_SCROLL_SENSITIVE,
4227:                            ResultSet.CONCUR_UPDATABLE);
4228:                    res = stmnt.executeQuery();
4229:                    if (!res.next()) {
4230:                        throw new InternalException(_loc
4231:                                .get("stream-exception"));
4232:                    }
4233:                    Clob clob = res.getClob(1);
4234:                    Writer writer = clob.setCharacterStream(1);
4235:                    copy(reader, writer);
4236:                    writer.close();
4237:                    res.updateClob(1, clob);
4238:                    res.updateRow();
4239:
4240:                } catch (IOException ioe) {
4241:                    throw new StoreException(ioe);
4242:                } finally {
4243:                    if (res != null)
4244:                        try {
4245:                            res.close();
4246:                        } catch (SQLException e) {
4247:                        }
4248:                    if (stmnt != null)
4249:                        try {
4250:                            stmnt.close();
4251:                        } catch (SQLException e) {
4252:                        }
4253:                    if (conn != null)
4254:                        try {
4255:                            conn.close();
4256:                        } catch (SQLException e) {
4257:                        }
4258:                }
4259:            }
4260:
4261:            protected long copy(InputStream in, OutputStream out)
4262:                    throws IOException {
4263:                byte[] copyBuffer = new byte[blobBufferSize];
4264:                long bytesCopied = 0;
4265:                int read = -1;
4266:
4267:                while ((read = in.read(copyBuffer, 0, copyBuffer.length)) != -1) {
4268:                    out.write(copyBuffer, 0, read);
4269:                    bytesCopied += read;
4270:                }
4271:                return bytesCopied;
4272:            }
4273:
4274:            protected long copy(Reader reader, Writer writer)
4275:                    throws IOException {
4276:                char[] copyBuffer = new char[clobBufferSize];
4277:                long bytesCopied = 0;
4278:                int read = -1;
4279:
4280:                while ((read = reader.read(copyBuffer, 0, copyBuffer.length)) != -1) {
4281:                    writer.write(copyBuffer, 0, read);
4282:                    bytesCopied += read;
4283:                }
4284:
4285:                return bytesCopied;
4286:            }
4287:
4288:            /**
4289:             * Attach CAST to the current function if necessary
4290:             * 
4291:             * @param val operand value
4292:             * @parma func the sql function statement
4293:             * @return a String with the correct CAST function syntax
4294:             */
4295:            public String getCastFunction(Val val, String func) {
4296:                return func;
4297:            }
4298:
4299:            /**
4300:             * Create an index if necessary for some database tables
4301:             */
4302:            public void createIndexIfNecessary(Schema schema, String table,
4303:                    Column pkColumn) {
4304:            }
4305:
4306:            /**
4307:             * Return the batchLimit
4308:             */
4309:            public int getBatchLimit() {
4310:                return batchLimit;
4311:            }
4312:
4313:            /**
4314:             * Set the batchLimit value
4315:             */
4316:            public void setBatchLimit(int limit) {
4317:                batchLimit = limit;
4318:            }
4319:
4320:            /**
4321:             * Validate the batch process. In some cases, we can't batch the statements
4322:             * due to some restrictions. For example, if the GeneratedType=IDENTITY,
4323:             * we have to disable the batch process because we need to get the ID value
4324:             * right away for the in-memory entity to use.
4325:             */
4326:            public boolean validateBatchProcess(RowImpl row,
4327:                    Column[] autoAssign, OpenJPAStateManager sm,
4328:                    ClassMapping cmd) {
4329:                boolean disableBatch = false;
4330:                if (getBatchLimit() == 0)
4331:                    return false;
4332:                if (autoAssign != null && sm != null) {
4333:                    FieldMetaData[] fmd = cmd.getPrimaryKeyFields();
4334:                    int i = 0;
4335:                    while (!disableBatch && i < fmd.length) {
4336:                        if (fmd[i].getValueStrategy() == ValueStrategies.AUTOASSIGN)
4337:                            disableBatch = true;
4338:                        i++;
4339:                    }
4340:                }
4341:                // go to each Dictionary to validate the batch capability
4342:                if (!disableBatch)
4343:                    disableBatch = validateDBSpecificBatchProcess(disableBatch,
4344:                            row, autoAssign, sm, cmd);
4345:                return disableBatch;
4346:            }
4347:
4348:            /**
4349:             * Allow each Dictionary to validate its own batch process. 
4350:             */
4351:            public boolean validateDBSpecificBatchProcess(boolean disableBatch,
4352:                    RowImpl row, Column[] autoAssign, OpenJPAStateManager sm,
4353:                    ClassMapping cmd) {
4354:                return disableBatch;
4355:            }
4356:
4357:            /**
4358:             * This method is to provide override for non-JDBC or JDBC-like 
4359:             * implementation of executing query.
4360:             */
4361:            protected ResultSet executeQuery(Connection conn,
4362:                    PreparedStatement stmnt, String sql) throws SQLException {
4363:                return stmnt.executeQuery();
4364:            }
4365:
4366:            /**
4367:             * This method is to provide override for non-JDBC or JDBC-like 
4368:             * implementation of preparing statement.
4369:             */
4370:            protected PreparedStatement prepareStatement(Connection conn,
4371:                    String sql) throws SQLException {
4372:                return conn.prepareStatement(sql);
4373:            }
4374:
4375:            /**
4376:             * This method is to provide override for non-JDBC or JDBC-like 
4377:             * implementation of getting sequence from the result set.
4378:             */
4379:            protected Sequence[] getSequence(ResultSet rs) throws SQLException {
4380:                List seqList = new ArrayList();
4381:                while (rs != null && rs.next())
4382:                    seqList.add(newSequence(rs));
4383:                return (Sequence[]) seqList
4384:                        .toArray(new Sequence[seqList.size()]);
4385:            }
4386:
4387:            /**
4388:             * This method is to provide override for non-JDBC or JDBC-like 
4389:             * implementation of getting key from the result set.
4390:             */
4391:            protected Object getKey(ResultSet rs, Column col)
4392:                    throws SQLException {
4393:                if (!rs.next())
4394:                    throw new StoreException(_loc.get("no-genkey"));
4395:                Object key = rs.getObject(1);
4396:                if (key == null)
4397:                    log.warn(_loc.get("invalid-genkey", col));
4398:                return key;
4399:            }
4400:
4401:            /**
4402:             * This method is to provide override for non-JDBC or JDBC-like 
4403:             * implementation of calculating value.
4404:             */
4405:            protected void calculateValue(Val val, Select sel, ExpContext ctx,
4406:                    ExpState state, Path path, ExpState pathState) {
4407:                val.calculateValue(sel, ctx, state, (Val) path, pathState);
4408:            }
4409:
4410:            /**
4411:             * Determine whether the provided <code>sql</code> may be treated as a 
4412:             * select statement on this database.
4413:             *  
4414:             * @param sql   A sql statement. 
4415:             * 
4416:             * @return true if <code>sql</code> represents a select statement.
4417:             */
4418:            public boolean isSelect(String sql) {
4419:                Iterator i = selectWordSet.iterator();
4420:                String cur;
4421:                while (i.hasNext()) {
4422:                    cur = (String) i.next();
4423:                    if (sql.length() >= cur.length()
4424:                            && sql.substring(0, cur.length()).equalsIgnoreCase(
4425:                                    cur)) {
4426:                        return true;
4427:                    }
4428:                }
4429:                return false;
4430:            }
4431:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.