Source Code Cross Referenced for DriverRDB.java in  » RSS-RDF » Jena-2.5.5 » com » hp » hpl » jena » db » impl » 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 » RSS RDF » Jena 2.5.5 » com.hp.hpl.jena.db.impl 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:          (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
0003:          [See end of file]
0004:         */
0005:
0006:        package com.hp.hpl.jena.db.impl;
0007:
0008:        import java.sql.*;
0009:        import java.util.*;
0010:        import java.util.zip.CRC32;
0011:        import java.io.UnsupportedEncodingException;
0012:        import java.lang.Thread;
0013:
0014:        import com.hp.hpl.jena.datatypes.RDFDatatype;
0015:        import com.hp.hpl.jena.datatypes.TypeMapper;
0016:        import com.hp.hpl.jena.db.GraphRDB;
0017:        import com.hp.hpl.jena.db.IDBConnection;
0018:        import com.hp.hpl.jena.db.RDFRDBException;
0019:        import com.hp.hpl.jena.graph.*;
0020:        import com.hp.hpl.jena.graph.query.ExpressionFunctionURIs;
0021:
0022:        import com.hp.hpl.jena.rdf.model.AnonId;
0023:        import com.hp.hpl.jena.shared.*;
0024:
0025:        import com.hp.hpl.jena.vocabulary.RDF;
0026:        import com.hp.hpl.jena.vocabulary.DB;
0027:
0028:        import org.apache.commons.logging.Log;
0029:        import org.apache.commons.logging.LogFactory;
0030:        import org.apache.xerces.util.XMLChar;
0031:
0032:        //=======================================================================
0033:        /**
0034:         * Base database driver for implementing SpecializedGraphs.
0035:         * Different drivers are needed for different databases and different
0036:         * layout schemes.
0037:         * <p>
0038:         * This driver is a base implemention from which database-specific
0039:         * drivers can inherit. It is not generic in the sense that it will work
0040:         * on any minimal SQL store and so should be treated as if it were
0041:         * an abstract class.
0042:         * <p>The SQL statements which implement each of the functions are
0043:         * loaded in a separate file etc/[layout]_[database].sql from the classpath.
0044:         *
0045:         * @author hkuno modification of Jena1 code by Dave Reynolds (der)
0046:         * @version $Revision: 1.69 $ on $Date: 2008/01/02 12:08:22 $
0047:         */
0048:
0049:        public abstract class DriverRDB implements  IRDBDriver {
0050:
0051:            //=======================================================================
0052:            // Cutomization variables
0053:            // =======================================================================
0054:            /**
0055:             * This Graph's db properties
0056:             */
0057:            protected DBPropDatabase m_dbProps;
0058:
0059:            /**
0060:             * Name of this class's PSet_TripleStore_XXX class
0061:             */
0062:            protected String m_psetClassName;
0063:
0064:            /**
0065:             * Name of this class's PSet_TripleStore_XXX class
0066:             */
0067:            protected String m_psetReifierClassName;
0068:
0069:            /**
0070:             * Cached name of this class's SpecializedGraph_XXX class
0071:             */
0072:            protected String m_lsetClassName;
0073:
0074:            /**
0075:             * Cached name of this class's SpecializedGraphReifer_XXX class
0076:             */
0077:            protected String m_lsetReifierClassName;
0078:
0079:            /** The class name of the database driver (e.g. jdbc.sql.class)*/
0080:            protected String DRIVER_NAME;
0081:            // Dummy - needs replacing when instantiated?
0082:
0083:            /** The name of the database type this driver supports */
0084:            protected String DATABASE_TYPE;
0085:
0086:            /** The maximum size of index key (or a component of a key) */
0087:            protected int INDEX_KEY_LENGTH;
0088:
0089:            /** The maximum possible value for INDEX_KEY_LENGTH (db-dependent) */
0090:            protected int INDEX_KEY_LENGTH_MAX;
0091:
0092:            /** true if graphs using this database instance supports transactions.
0093:             * this is a user settable parameter. the underlying db engine may support
0094:             * transactions but an application may prefer to run without transactions
0095:             * for better performance. this can only be set before the db is formatted.
0096:             */
0097:            protected boolean IS_XACT_DB;
0098:
0099:            protected boolean STRINGS_TRIMMED;
0100:            /** true if the database engine will trim trailing spaces in strings. to
0101:             *  prevent this, append EOS to strings that should not be trimmed.
0102:             */
0103:
0104:            protected String EOS = "";
0105:            protected char EOS_CHAR = ':';
0106:            protected int EOS_LEN = 0;
0107:            /** EOS is appended to most RDB strings to deal with string trimming. if
0108:             *  STRINGS_TRIMMED is false, EOS is null. otherwise, EOS is EOS_CHAR.
0109:             *  EOS_LEN is the length of EOS (0 or 1).
0110:             */
0111:
0112:            protected char QUOTE_CHAR = '\"';
0113:            /** the quote character used to delimit characters and strings.
0114:             */
0115:
0116:            /**
0117:             * Indicates whether search pattern used to select system objects by name should be upper-case.
0118:             */
0119:            protected boolean DB_NAMES_TO_UPPER = false;
0120:
0121:            /** true if URI's are to be compressed by storing prefixes (an approximation
0122:             *  of a namespace) in the JENA_PREFIX table. note that "short" prefixes are
0123:             *  not stored, i.e., the prefix length not more than URI_COMPRESS_LENGTH.
0124:             */
0125:            protected boolean URI_COMPRESS;
0126:
0127:            protected int URI_COMPRESS_LENGTH = 100;
0128:            /** if URI_COMPRESS is true, compress prefixes that are longer than this.
0129:
0130:            /** The maximum size of an object that can be stored in a Statement table */
0131:            protected int LONG_OBJECT_LENGTH;
0132:
0133:            /** The maximum possible value for LONG_OBJECT_LENGTH (db-dependent) */
0134:            protected int LONG_OBJECT_LENGTH_MAX;
0135:
0136:            /** The SQL type to use for storing ids (compatible with wrapDBID) */
0137:            protected String ID_SQL_TYPE;
0138:
0139:            /** Set to true if the insert operations already check for duplications */
0140:            protected boolean SKIP_DUPLICATE_CHECK;
0141:
0142:            /** Set to true if IDs are allocated prior to insert */
0143:            protected boolean PRE_ALLOCATE_ID;
0144:
0145:            /** The name of the sql definition file for this database/layout combo */
0146:            protected String SQL_FILE;
0147:
0148:            /** The name of the sql definition file for this database/layout combo */
0149:            protected String DEFAULT_SQL_FILE = "etc/generic_generic.sql";
0150:
0151:            // =======================================================================
0152:            //	Common variables
0153:            // =======================================================================
0154:            /**
0155:             * Holds prefix for names of Jena database tables.
0156:             */
0157:            protected String TABLE_NAME_PREFIX = "jena_";
0158:
0159:            /**
0160:             * Holds maximum length of table and index names in database.
0161:             */
0162:            protected int TABLE_NAME_LENGTH_MAX;
0163:
0164:            /** Suffixes for asserted and reified table names. */
0165:            protected String STMT_TABLE_NAME_SUFFIX = "_stmt";
0166:            protected String REIF_TABLE_NAME_SUFFIX = "_reif";
0167:
0168:            /** Maximum number of index columns. can be changed. */
0169:            protected int MAXIMUM_INDEX_COLUMNS = 3;
0170:
0171:            /** Number of required system tables. */
0172:            protected int SYSTEM_TABLE_CNT = 0;
0173:
0174:            /** Names of jena system tables. */
0175:            public String[] SYSTEM_TABLE_NAME;
0176:
0177:            /** Set to true to enable cache of pre-prepared statements */
0178:            protected boolean CACHE_PREPARED_STATEMENTS = true;
0179:
0180:            /** The name of the layout type this driver supports */
0181:            protected String LAYOUT_TYPE = "TripleStore";
0182:
0183:            /** Default name of the table that holds system property graph asserted statements **/
0184:            protected String SYSTEM_STMT_TABLE;
0185:
0186:            /** Name of the long literal table **/
0187:            protected String LONG_LIT_TABLE;
0188:
0189:            /** Name of the long URI table **/
0190:            protected String LONG_URI_TABLE;
0191:
0192:            /** Name of the prefix table **/
0193:            protected String PREFIX_TABLE;
0194:
0195:            /** Name of the graph table **/
0196:            protected String GRAPH_TABLE;
0197:
0198:            /** Name of the mutex table **/
0199:            protected String MUTEX_TABLE;
0200:
0201:            /** If not null, newly-created graphs share tables with the identified graph **/
0202:            protected String STORE_WITH_MODEL = null;
0203:
0204:            /** Name of the graph holding default properties (the one's that a newly-created
0205:             *  graph will have by default **/
0206:            protected final String DEFAULT_PROPS = "JENA_DEFAULT_GRAPH_PROPERTIES";
0207:
0208:            /** Unique numeric identifier of the graph holding default properties **/
0209:            protected final int DEFAULT_ID = 0;
0210:
0211:            /** Driver version number */
0212:            protected final String VERSION = "2.0alpha";
0213:
0214:            /** Database layout version */
0215:            protected String LAYOUT_VERSION = "2.0";
0216:
0217:            protected static Log logger = LogFactory.getLog(DriverRDB.class);
0218:
0219:            // =======================================================================
0220:            //	Instance variables
0221:            // =======================================================================
0222:
0223:            /**
0224:             * Instance of SQLCache used by Driver for hard-coded db commands
0225:             */
0226:            protected SQLCache m_sql = null;
0227:
0228:            /** Cache a reference to the system property graph (java) **/
0229:            protected SpecializedGraph m_sysProperties = null;
0230:
0231:            protected IDBConnection m_dbcon = null;
0232:
0233:            protected LRUCache prefixCache = null;
0234:
0235:            public static final int PREFIX_CACHE_SIZE = 50;
0236:
0237:            //===================================
0238:            // for transaction support
0239:            //===================================
0240:
0241:            // caches whether or not underlying connection supports transactions
0242:            private Boolean m_transactionsSupported;
0243:
0244:            /** flag to indicate that there is a transaction active on the associated connection */
0245:            private boolean inTransaction = false;
0246:
0247:            //	=======================================================================
0248:            //	 Constructor
0249:            //	=======================================================================
0250:
0251:            /**
0252:             * Create a bare instance of the driver. It is not functional until a
0253:             * database connection has been supplied via setConnection.
0254:             */
0255:            public DriverRDB() {
0256:            }
0257:
0258:            //	=======================================================================
0259:            //	 Methods
0260:            //	=======================================================================
0261:
0262:            /**
0263:             * Return the connection
0264:             */
0265:            public IDBConnection getConnection() {
0266:                return m_dbcon;
0267:            }
0268:
0269:            /**
0270:             * Return the specialized graph used to store system properties.
0271:             * (Constuct a new one if necessary). if the database is not
0272:             * properly formatted, then if doInit is true, the database will
0273:             * be formatted, else null is returned and the (unformatted
0274:             * database is unchanged).
0275:             */
0276:            public SpecializedGraph getSystemSpecializedGraph(boolean doInit) {
0277:
0278:                SpecializedGraph res = null;
0279:
0280:                if (m_sysProperties != null) {
0281:                    return m_sysProperties;
0282:                }
0283:
0284:                if (!isDBFormatOK()) {
0285:                    // another thread could be formatting database
0286:                    // so get the mutex and try again
0287:                    lockDB();
0288:                    if (!isDBFormatOK()) {
0289:                        if (doInit) {
0290:                            try {
0291:                                // Format the DB
0292:                                // throw new JenaException("The database is not
0293:                                // formatted.\n");
0294:                                doCleanDB(false);
0295:                                prefixCache = new LRUCache(PREFIX_CACHE_SIZE);
0296:                                res = formatAndConstructSystemSpecializedGraph();
0297:                            } catch (Exception e) {
0298:                                unlockDB();
0299:                                // We see an error during format testing, might be
0300:                                // a dead connection rather than an unformated
0301:                                // database so abort
0302:                                throw new JenaException(
0303:                                        "The database appears to be unformatted or corrupted and\n"
0304:                                                + "an attempt to automatically format the database has failed\n",
0305:                                        e);
0306:                            }
0307:                        }
0308:                        unlockDB();
0309:                        return res;
0310:                    }
0311:                    // after second try, DB is found to be correctly formatted.
0312:                    unlockDB();
0313:                }
0314:
0315:                prefixCache = new LRUCache(PREFIX_CACHE_SIZE);
0316:                getDbInitTablesParams(); //this call is a hack. it's needed because
0317:                // it has the side effect of initializing some vars (e.g., EOS).
0318:                IPSet pSet = createIPSetInstanceFromName(m_psetClassName,
0319:                        SYSTEM_STMT_TABLE);
0320:                m_sysProperties = createLSetInstanceFromName(m_lsetClassName,
0321:                        pSet, DEFAULT_ID);
0322:                m_dbProps = new DBPropDatabase(m_sysProperties);
0323:
0324:                // need to get initial values for encoding parameters
0325:                String longObjLen = m_dbProps.getInitLongObjectLength();
0326:                String indexKeyLen = m_dbProps.getInitIndexKeyLength();
0327:                String compURI = m_dbProps.getInitDoCompressURI();
0328:                String compURILen = m_dbProps.getInitCompressURILength();
0329:
0330:                if (longObjLen == null)
0331:                    throwBadFormat("long object length");
0332:                else
0333:                    LONG_OBJECT_LENGTH = Integer.parseInt(longObjLen);
0334:                if (indexKeyLen == null)
0335:                    throwBadFormat("index key length");
0336:                else
0337:                    INDEX_KEY_LENGTH = Integer.parseInt(indexKeyLen);
0338:                if (compURI == null)
0339:                    throwBadFormat("compress URIs");
0340:                else
0341:                    URI_COMPRESS = Boolean.valueOf(compURI).booleanValue();
0342:                if (compURILen == null)
0343:                    throwBadFormat("URI compress length");
0344:                else
0345:                    URI_COMPRESS_LENGTH = Integer.parseInt(compURILen);
0346:
0347:                // now reset the configuration parameters
0348:                checkEngine(m_dbProps);
0349:                checkDriverVersion(m_dbProps);
0350:                checkLayoutVersion(m_dbProps);
0351:                String val = null;
0352:                val = m_dbProps.getIsTransactionDb();
0353:                if (val == null)
0354:                    throwBadFormat("database supports transactions");
0355:                else
0356:                    IS_XACT_DB = Boolean.valueOf(val).booleanValue();
0357:                val = m_dbProps.getTableNamePrefix();
0358:                if (val == null)
0359:                    throwBadFormat("table name prefix");
0360:                else
0361:                    TABLE_NAME_PREFIX = val;
0362:
0363:                return m_sysProperties;
0364:            }
0365:
0366:            private void checkEngine(DBProp dbProps) {
0367:                String dbtype = m_dbProps.getEngineType();
0368:                if (dbtype == null)
0369:                    throwBadFormat("database type");
0370:                if (!dbtype.equals(DATABASE_TYPE)) {
0371:                    throw new JenaException(
0372:                            "Database created with incompatible database type for this version of Jena: "
0373:                                    + dbtype);
0374:                }
0375:            }
0376:
0377:            private void checkDriverVersion(DBProp dbProps) {
0378:                String vers = m_dbProps.getDriverVersion();
0379:                if (vers == null)
0380:                    throwBadFormat("database version");
0381:                if (!vers.equals(VERSION)) {
0382:                    throw new JenaException(
0383:                            "Models in the database were created with an incompatible version of Jena: "
0384:                                    + vers);
0385:                }
0386:            }
0387:
0388:            private void checkLayoutVersion(DBProp dbProps) {
0389:                String layout = m_dbProps.getLayoutVersion();
0390:                if (layout == null)
0391:                    throwBadFormat("database layout");
0392:                if (!layout.equals(LAYOUT_VERSION)) {
0393:                    throw new JenaException(
0394:                            "The database layout cannot be processed by this version of Jena: "
0395:                                    + layout);
0396:                }
0397:
0398:            }
0399:
0400:            private void throwBadFormat(String prop) {
0401:                throw new JenaException(
0402:                        "The database appears to be unformatted or corrupted - could not find value\n"
0403:                                + " for \""
0404:                                + prop
0405:                                + "\" in Jena system properties table.\n"
0406:                                + "If possible, call IDBConnection.cleanDB(). \n"
0407:                                + "Warning: cleanDB will remove all Jena models from the databases.");
0408:            }
0409:
0410:            /**
0411:             * Format the database and construct a brand new system specialized graph.
0412:             */
0413:            protected SpecializedGraph formatAndConstructSystemSpecializedGraph() {
0414:                String errMsg = null;
0415:                if (xactOp(xactIsActive))
0416:                    throw new RDFRDBException(
0417:                            "Cannot intialize database while transaction is active.\n"
0418:                                    + "Commit or abort transaction before intializing database.");
0419:
0420:                boolean autoIsOn = xactOp(xactAutoOff);
0421:                try {
0422:                    String[] params = getDbInitTablesParams();
0423:                    m_sql.runSQLGroup("initDBtables", params);
0424:                    m_sql.runSQLGroup("initDBgenerators");//			m_sql.runSQLGroup("initDBprocedures");
0425:                } catch (SQLException e) {
0426:                    logger.warn("Problem formatting database", e);
0427:                    errMsg = e.toString();
0428:                }
0429:
0430:                if (errMsg == null)
0431:                    try {
0432:                        xactOp(xactCommit);
0433:                        xactOp(xactBegin);
0434:
0435:                        // Construct the system properties
0436:                        IPSet pSet = createIPSetInstanceFromName(
0437:                                m_psetClassName, SYSTEM_STMT_TABLE);
0438:                        m_sysProperties = createLSetInstanceFromName(
0439:                                m_lsetClassName, pSet, DEFAULT_ID);
0440:
0441:                        // The following call constructs a new set of database
0442:                        // properties and
0443:                        // adds them to the m_sysProperties specialized graph.
0444:
0445:                        // Ugh: m_dbcon.getDatabaseType(), not this.getDatabaseType()
0446:                        m_dbProps = new DBPropDatabase(m_sysProperties, m_dbcon
0447:                                .getDatabaseType(), VERSION, LAYOUT_VERSION,
0448:                                String.valueOf(LONG_OBJECT_LENGTH), String
0449:                                        .valueOf(INDEX_KEY_LENGTH), String
0450:                                        .valueOf(IS_XACT_DB), String
0451:                                        .valueOf(URI_COMPRESS), String
0452:                                        .valueOf(URI_COMPRESS_LENGTH),
0453:                                TABLE_NAME_PREFIX);
0454:
0455:                        // Now we also need to construct the parameters that will be the
0456:                        // default settings for any graph added to this database
0457:                        DBPropGraph def_prop = new DBPropGraph(m_sysProperties,
0458:                                DEFAULT_PROPS, "generic");
0459:
0460:                        def_prop.addGraphId(DEFAULT_ID);
0461:
0462:                        xactOp(xactCommit);
0463:                        if (autoIsOn)
0464:                            xactOp(xactAutoOn);
0465:                    } catch (Exception e) {
0466:                        errMsg = e.toString();
0467:                    }
0468:
0469:                if (errMsg != null) {
0470:                    doCleanDB(false);
0471:                    m_sysProperties = null;
0472:                    throw new RDFRDBException(errMsg);
0473:                }
0474:
0475:                return m_sysProperties;
0476:            }
0477:
0478:            abstract String[] getDbInitTablesParams();
0479:
0480:            abstract String[] getCreateTableParams(int graphId, boolean isReif);
0481:
0482:            abstract public int graphIdAlloc(String graphName);
0483:
0484:            /**
0485:             * Construct and return a new specialized graph.
0486:             */
0487:            public List createSpecializedGraphs(String graphName,
0488:                    Graph requestedProperties) {
0489:
0490:                /*
0491:                 * create the specialized graphs for the new graph. this includes
0492:                 * updating the database for the new graph (allocating a new graph
0493:                 * identifier, updating the jena system tables and creating tables, if
0494:                 * necessary. this should be done atomically to avoid corrupting the
0495:                 * database but a single transaction is not sufficient because some
0496:                 * database engines (e.g., oracle) require create table statements to
0497:                 * run as a separate transaction, i.e., a create table statement in the
0498:                 * middle of a group of updates will cause an automatic commit of the
0499:                 * updates prior to the create table statement.
0500:                 * 
0501:                 * fortunately, we can run most of the updates in a single transaction.
0502:                 * however, allocation of the graph indentifier must be done prior to
0503:                 * creating the statement tables. so, if any subsequent operation fails,
0504:                 * we must run a compensating transaction to deallocate the graph
0505:                 * identifier.
0506:                 * 
0507:                 * because of the above, we assume that there is no active transaction
0508:                 * when this routine is called.
0509:                 */
0510:
0511:                // String graphName = graphProperties.getName();
0512:                String stmtTbl = null;
0513:                String reifTbl = null;
0514:                String dbSchema = STORE_WITH_MODEL;
0515:                boolean didGraphIdAlloc = false;
0516:                boolean didTableCreate = false;
0517:                String errMsg = null;
0518:                DBPropGraph graphProperties = null;
0519:
0520:                SpecializedGraph sysGraph = getSystemSpecializedGraph(false);
0521:                // should have already create sys graph.
0522:
0523:                if (xactOp(xactIsActive))
0524:                    throw new RDFRDBException(
0525:                            "Cannot create graph while transaction is active.\n"
0526:                                    + "Commit or abort transaction before creating graph");
0527:
0528:                boolean autoOn = xactOp(xactAutoOff);
0529:                int graphId = -1; // bogus initialization to make java happy
0530:
0531:                try {
0532:                    xactOp(xactBegin);
0533:                    graphId = graphIdAlloc(graphName);
0534:                    didGraphIdAlloc = true;
0535:                    xactOp(xactCommit);
0536:                    xactOp(xactBegin);
0537:                    boolean useDefault = false;
0538:
0539:                    // dbSchema = graphProperties.getDBSchema();
0540:                    // use the default schema if:
0541:                    // 1) no schema is specified and we are creating the default
0542:                    // (unnamed) graph
0543:                    // 2) a schema is specified and it is the default (unnamed) graph
0544:                    if (((dbSchema == null) && graphName
0545:                            .equals(GraphRDB.DEFAULT))) {
0546:                        useDefault = true;
0547:                        dbSchema = DEFAULT_PROPS; // default graph should use default
0548:                        // tables
0549:                    }
0550:                    // else if ( ((dbSchema != null) &&
0551:                    // dbSchema.equals(GraphRDB.DEFAULT)) ) {
0552:                    // 	useDefault = true;
0553:                    //	dbSchema = DEFAULT_PROPS; // default graph should use default
0554:                    // tables
0555:                    // }
0556:                    if (dbSchema != null) {
0557:                        DBPropGraph schProp = DBPropGraph.findPropGraphByName(
0558:                                sysGraph, dbSchema);
0559:                        if (schProp != null) {
0560:                            reifTbl = schProp.getReifTable();
0561:                            stmtTbl = schProp.getStmtTable();
0562:                        }
0563:                        if (((reifTbl == null) || (stmtTbl == null))
0564:                                && (useDefault == false))
0565:                            // schema not found. this is ok ONLY IF it's the DEFAULT
0566:                            // schema
0567:                            throw new RDFRDBException("Creating graph "
0568:                                    + graphName
0569:                                    + ": referenced schema not found: "
0570:                                    + dbSchema);
0571:                    }
0572:                    if ((reifTbl == null) || (stmtTbl == null)) {
0573:                        didTableCreate = true;
0574:                        reifTbl = createTable(graphId, true);
0575:                        stmtTbl = createTable(graphId, false);
0576:                        if ((reifTbl == null) || (stmtTbl == null))
0577:                            throw new RDFRDBException("Creating graph "
0578:                                    + graphName + ": cannot create tables");
0579:                    }
0580:                    xactOp(xactCommit); // may not be needed but it doesn't hurt
0581:                } catch (Exception e) {
0582:                    errMsg = e.toString();
0583:                }
0584:
0585:                // we can now start a new transaction and update the metadata.
0586:                // we should already be committed but we commit again just in case
0587:
0588:                if (errMsg == null)
0589:                    try {
0590:                        xactOp(xactBegin);
0591:
0592:                        graphProperties = new DBPropGraph(sysGraph, graphName,
0593:                                requestedProperties);
0594:                        graphProperties.addGraphId(graphId);
0595:                        graphProperties.addStmtTable(stmtTbl);
0596:                        graphProperties.addReifTable(reifTbl);
0597:
0598:                        DBPropDatabase dbprop = new DBPropDatabase(
0599:                                getSystemSpecializedGraph(true));
0600:                        dbprop.addGraph(graphProperties);
0601:
0602:                        // Add the reifier first
0603:                        DBPropPSet pSetReifier = new DBPropPSet(
0604:                                m_sysProperties, m_psetReifierClassName,
0605:                                reifTbl);
0606:                        DBPropLSet lSetReifier = new DBPropLSet(
0607:                                m_sysProperties, "LSET_"
0608:                                        + graphProperties.getName()
0609:                                        + "_REIFIER", m_lsetReifierClassName);
0610:                        lSetReifier.setPSet(pSetReifier);
0611:                        graphProperties.addLSet(lSetReifier);
0612:
0613:                        // Now add support for all non-reified triples
0614:                        DBPropPSet pSet = new DBPropPSet(m_sysProperties,
0615:                                m_psetClassName, stmtTbl);
0616:                        DBPropLSet lSet = new DBPropLSet(m_sysProperties,
0617:                                "LSET_" + graphProperties.getName(),
0618:                                m_lsetClassName);
0619:                        lSet.setPSet(pSet);
0620:                        graphProperties.addLSet(lSet);
0621:
0622:                        xactOp(xactCommit);
0623:                        if (autoOn)
0624:                            xactOp(xactAutoOn);
0625:                    } catch (Exception e) {
0626:                        errMsg = e.toString();
0627:                    }
0628:
0629:                if (errMsg == null)
0630:                    return recreateSpecializedGraphs(graphProperties);
0631:                else {
0632:                    xactOp(xactCommit); // maybe not needed but doesn't hurt
0633:                    xactOp(xactBegin);
0634:                    try {
0635:                        // clean-up
0636:                        if (didGraphIdAlloc) {
0637:                            graphIdDealloc(graphId);
0638:                        }
0639:                    } catch (Exception e) {
0640:                    }
0641:                    if (didTableCreate) {
0642:                        // make sure the order below matches
0643:                        // the order of creation above.
0644:                        if (reifTbl != null)
0645:                            try {
0646:                                deleteTable(reifTbl);
0647:                            } catch (Exception e) {
0648:                            }
0649:                        ;
0650:                        if (stmtTbl != null)
0651:                            try {
0652:                                deleteTable(stmtTbl);
0653:                            } catch (Exception e) {
0654:                            }
0655:                        ;
0656:                    }
0657:                    xactOp(xactCommit);
0658:                    if (autoOn)
0659:                        xactOp(xactAutoOn);
0660:                    return null;
0661:                }
0662:            }
0663:
0664:            /**
0665:             * Construct and return a list of specialized graphs to match those in the
0666:             * store.
0667:             * 
0668:             * @param graphProperties
0669:             *            A set of customization properties for the graph.
0670:             */
0671:            public List recreateSpecializedGraphs(DBPropGraph graphProperties) {
0672:
0673:                List result = new ArrayList();
0674:                int dbGraphId = graphProperties.getGraphId();
0675:
0676:                // to ensure that reifier graphs occur before stmt graphs, make two passes
0677:                String[] lsetTypes = { m_lsetClassName, m_lsetReifierClassName };
0678:                int i;
0679:                for (i = 0; i < 2; i++) {
0680:                    Iterator it = graphProperties.getAllLSets();
0681:                    while (it.hasNext()) {
0682:                        DBPropLSet lSetProps = (DBPropLSet) it.next();
0683:                        if (lSetProps.getType().equals(lsetTypes[i]))
0684:                            continue;
0685:                        DBPropPSet pSetProps = lSetProps.getPset();
0686:
0687:                        IPSet pSet = createIPSetInstanceFromName(pSetProps
0688:                                .getType(), pSetProps.getTable());
0689:                        result.add(createLSetInstanceFromName(lSetProps
0690:                                .getType(), pSet, dbGraphId));
0691:                    }
0692:                }
0693:
0694:                return result;
0695:            }
0696:
0697:            /**
0698:             * Create a new IPSet instance of the named implementation class and set the db connection.
0699:             * 
0700:             * @param pName name of a class that implements IPSet.
0701:             * @return an instance of the named class with the db connection set.
0702:             */
0703:            private IPSet createIPSetInstanceFromName(String className,
0704:                    String tblName) {
0705:                IPSet pSet = null;
0706:                try {
0707:                    // get PSet
0708:                    pSet = (IPSet) Class.forName(className).newInstance();
0709:                    pSet.setDriver(this );
0710:                    pSet.setSQLType(ID_SQL_TYPE);
0711:                    pSet.setSkipDuplicateCheck(SKIP_DUPLICATE_CHECK);
0712:                    pSet.setSQLCache(m_sql);
0713:                    pSet.setCachePreparedStatements(CACHE_PREPARED_STATEMENTS);
0714:                    pSet.setTblName(tblName);
0715:                } catch (Exception e) {
0716:                    logger.warn("Unable to create IPSet instance ", e);
0717:                }
0718:                return pSet;
0719:            }
0720:
0721:            private SpecializedGraph createLSetInstanceFromName(
0722:                    String lSetName, IPSet pset, int dbGraphID) {
0723:                SpecializedGraph sg = null;
0724:                try {
0725:                    Class cls = Class.forName(lSetName);
0726:                    Class[] params = { IPSet.class, Integer.class };
0727:                    java.lang.reflect.Constructor con = cls
0728:                            .getConstructor(params);
0729:                    Object[] args = { pset, new Integer(dbGraphID) };
0730:                    sg = (SpecializedGraph) con.newInstance(args);
0731:                } catch (Exception e) {
0732:                    logger
0733:                            .error(
0734:                                    "Unable to create instance of SpecializedGraph ",
0735:                                    e);
0736:                }
0737:                return sg;
0738:            }
0739:
0740:            /**
0741:             * Remove the specialized graph, erasing all trace of a Graph.
0742:             * @param graphId The identity of the Graph which these specialized graphs should hold
0743:             * @param graphProperties The properties for the graph to be removed.
0744:             */
0745:            public void removeSpecializedGraphs(DBPropGraph graphProperties,
0746:                    List specializedGraphs) {
0747:
0748:                int graphId = graphProperties.getGraphId();
0749:
0750:                if (xactOp(xactIsActive))
0751:                    throw new RDFRDBException(
0752:                            "Cannot remove graph while transaction is active.\n"
0753:                                    + "Commit or abort transaction before removing graph");
0754:
0755:                boolean autoIsOn = xactOp(xactAutoOff);
0756:                xactOp(xactCommit);
0757:                xactOp(xactBegin);
0758:
0759:                // remove graph metadata from jena sys table in a xact
0760:                String stmtTbl = graphProperties.getStmtTable();
0761:                String reifTbl = graphProperties.getReifTable();
0762:
0763:                // remove from system properties table
0764:                // It is sufficient just to remove the lSet properties (it will
0765:                // take care of deleting any pset properties automatically).			
0766:                m_dbProps.removeGraph(graphProperties);
0767:
0768:                if (graphId != DEFAULT_ID)
0769:                    graphIdDealloc(graphId);
0770:
0771:                xactOp(xactCommit);
0772:                xactOp(xactBegin);
0773:
0774:                /* now remove triples from statement tables.
0775:                 *  if the graph is stored in its own tables, we
0776:                 *  can simply delete those tables. else, the graph
0777:                 *  shares tables with other graphs so we have to
0778:                 *  remove each statement. */
0779:
0780:                // check to see if statement tables for graph are shared
0781:                boolean stInUse = true;
0782:                boolean rtInUse = true;
0783:
0784:                if (graphId != DEFAULT_ID) {
0785:                    stInUse = false;
0786:                    rtInUse = false;
0787:                    Iterator it = m_dbProps.getAllGraphs();
0788:                    while (it.hasNext()) {
0789:                        DBPropGraph gp = (DBPropGraph) it.next();
0790:                        if (gp.getStmtTable().equals(stmtTbl))
0791:                            stInUse = true;
0792:                        if (gp.getReifTable().equals(reifTbl))
0793:                            rtInUse = true;
0794:                    }
0795:                }
0796:                // now remove the statement tables or else delete all triples.
0797:                if (stInUse || rtInUse) {
0798:                    Iterator it = specializedGraphs.iterator();
0799:                    while (it.hasNext()) {
0800:                        SpecializedGraph sg = (SpecializedGraph) it.next();
0801:                        removeSpecializedGraph(sg);
0802:                    }
0803:                } else {
0804:                    deleteTable(stmtTbl);
0805:                    deleteTable(reifTbl);
0806:                }
0807:                xactOp(xactCommit);
0808:                if (autoIsOn)
0809:                    xactOp(xactAutoOn);
0810:            }
0811:
0812:            /**
0813:             * Remove specialized graph from the datastore.
0814:             * @param graph is the graph to be removed.
0815:             */
0816:            private void removeSpecializedGraph(SpecializedGraph graph) {
0817:                graph.clear();
0818:            }
0819:
0820:            /**
0821:             * Method setDatabaseProperties.
0822:             * 
0823:             * Sets the current properties for the database.
0824:             * 
0825:             * @param databaseProperties is a Graph containing a full set of database properties
0826:             */
0827:            public void setDatabaseProperties(Graph databaseProperties) {
0828:                SpecializedGraph toGraph = getSystemSpecializedGraph(true);
0829:                // really need to start a transaction here
0830:
0831:                // Here add code to check if the database has been used - if so,
0832:                // it's too late to change the properties, so throw an exception
0833:
0834:                toGraph.clear();
0835:                SpecializedGraph.CompletionFlag complete = new SpecializedGraph.CompletionFlag();
0836:                toGraph.add(databaseProperties, complete);
0837:
0838:                // Now test the properties to see if it's a valid set - if not,
0839:                // throw an exception - it's okay to check some things later (there's
0840:                // no guarantee that every error will be caught here).
0841:
0842:                // end transaction here.
0843:            }
0844:
0845:            /**
0846:             * Method getDefaultModelProperties 
0847:             * 
0848:             * Return the default properties for a new model stored in this database.
0849:             * If none are stored, then load default properties into the database.
0850:             * @return Graph containg the default properties for a new model
0851:             */
0852:            public DBPropGraph getDefaultModelProperties() {
0853:                SpecializedGraph sg = getSystemSpecializedGraph(true);
0854:                DBPropGraph result = DBPropGraph.findPropGraphByName(sg,
0855:                        DEFAULT_PROPS);
0856:                if (result == null) {
0857:                    logger.error("No default Model Properties found");
0858:                    // Construct the parameters that will be the
0859:                    // default settings for any graph added to this database
0860:                    //new DBPropGraph( m_sysProperties, "default", "generic");
0861:                    //result = DBPropGraph.findPropGraph(sg, "default");	
0862:                }
0863:                return result;
0864:            }
0865:
0866:            /**
0867:             * Test if the database has previously been formatted.
0868:             * 
0869:             * @return boolean true if database is correctly formatted, false on any error.
0870:             */
0871:            public boolean isDBFormatOK() throws RDFRDBException {
0872:                boolean result = true;
0873:                boolean[] found = new boolean[SYSTEM_TABLE_CNT];
0874:                int i = 0;
0875:                for (i = 0; i < SYSTEM_TABLE_CNT; i++)
0876:                    found[i] = false;
0877:                try {
0878:                    for (Iterator iter = getAllTables().iterator(); iter
0879:                            .hasNext();) {
0880:                        String tblName = (String) iter.next();
0881:                        for (i = 0; i < SYSTEM_TABLE_CNT; i++)
0882:                            if (SYSTEM_TABLE_NAME[i].equals(tblName))
0883:                                found[i] = true;
0884:                    }
0885:
0886:                    for (i = 0; i < SYSTEM_TABLE_CNT; i++) {
0887:                        if (!found[i]) {
0888:                            // mutex table is not required
0889:                            if (SYSTEM_TABLE_NAME[i].equals(MUTEX_TABLE))
0890:                                continue;
0891:                            result = false;
0892:                        }
0893:                    }
0894:                } catch (Exception e1) {
0895:                    // An exception might be an unformatted or corrupt
0896:                    // db or a connection problem.
0897:                    throw new RDFRDBException(
0898:                            "Exception while checking db format - " + e1, e1);
0899:                }
0900:                return result;
0901:            }
0902:
0903:            /**
0904:             * Converts string to form accepted by database.
0905:             */
0906:            public String stringToDBname(String aName) {
0907:                String result = (DB_NAMES_TO_UPPER) ? aName.toUpperCase()
0908:                        : aName;
0909:                return (result);
0910:            }
0911:
0912:            private static final int lockTryMax = 5; // max attempts to acquire/release lock
0913:
0914:            /**
0915:             * return true if the mutex is acquired, else false 
0916:             */
0917:
0918:            public boolean tryLockDB() {
0919:                boolean res = true;
0920:                try {
0921:                    m_sql.runSQLGroup("lockDatabase", MUTEX_TABLE);
0922:                } catch (SQLException e) {
0923:                    res = false;
0924:                }
0925:                return res;
0926:            }
0927:
0928:            public void lockDB() throws RDFRDBException {
0929:                String err = "";
0930:                int cnt = 0;
0931:                while (cnt++ < lockTryMax) {
0932:                    if (tryLockDB())
0933:                        break;
0934:                    try {
0935:                        Thread.sleep((long) 5000);
0936:                    } catch (InterruptedException e) {
0937:                        err = err + " lockDB sleep interrupted" + e;
0938:                    }
0939:                }
0940:                if (cnt >= lockTryMax) {
0941:                    err = "Failed to lock database after "
0942:                            + lockTryMax
0943:                            + " attempts.\n"
0944:                            + err
0945:                            + "\n"
0946:                            + "Try later or else call DriverRDB.unlockDB() after ensuring\n"
0947:                            + "that no other Jena applications are using the database.";
0948:                    throw new RDFRDBException(err);
0949:                }
0950:            }
0951:
0952:            /**
0953:             * Release the mutex lock in the database.
0954:             */
0955:
0956:            public void unlockDB() throws RDFRDBException {
0957:                String err;
0958:                int cnt = 0;
0959:                while (cnt++ < lockTryMax) {
0960:                    try {
0961:                        m_sql.runSQLGroup("unlockDatabase", MUTEX_TABLE);
0962:                        break;
0963:                    } catch (SQLException e) {
0964:                        err = "Failed to unlock database after " + lockTryMax
0965:                                + " attempts - " + e;
0966:                        try {
0967:                            Thread.sleep((long) 5000);
0968:                        } catch (InterruptedException e1) {
0969:                            err = err + " sleep failed" + e;
0970:                        }
0971:                    }
0972:                    if (cnt >= lockTryMax)
0973:                        throw new RDFRDBException(err);
0974:                }
0975:            }
0976:
0977:            /* return true if the mutex is held. */
0978:
0979:            public boolean DBisLocked() throws RDFRDBException {
0980:                try {
0981:                    DatabaseMetaData dbmd = m_dbcon.getConnection()
0982:                            .getMetaData();
0983:                    String[] tableTypes = { "TABLE" };
0984:                    String prefixMatch = stringToDBname(TABLE_NAME_PREFIX + "%");
0985:                    ResultSet iter = dbmd.getTables(null, null, MUTEX_TABLE,
0986:                            tableTypes);
0987:                    try {
0988:                        return iter.next();
0989:                    } finally {
0990:                        iter.close();
0991:                    }
0992:                } catch (SQLException e1) {
0993:                    throw new RDFRDBException("Internal SQL error in driver"
0994:                            + e1);
0995:                }
0996:            }
0997:
0998:            /* (non-Javadoc)
0999:             * @see com.hp.hpl.jena.graphRDB.IRDBDriver#cleanDB()
1000:             */
1001:            public void cleanDB() {
1002:
1003:                // assumes database lock is not held.
1004:                try {
1005:                    lockDB();
1006:                } catch (RDFRDBException e) {
1007:                    throw new RDFRDBException(
1008:                            "DriverRDB.cleanDB() failed to acquire database lock:\n"
1009:                                    + "("
1010:                                    + e
1011:                                    + ")\n."
1012:                                    + "Try again or call DriverRDB.unlockDB() if necessary.");
1013:                }
1014:                // now clean the database
1015:                doCleanDB(true);
1016:            }
1017:
1018:            /*
1019:             * internal routine that does the actual work for cleanDB().
1020:             * it assumes that the mutex is held and throws and exception
1021:             * if not. it will optionally remove the mutex if dropMutex
1022:             * is true.
1023:             */
1024:
1025:            protected void doCleanDB(boolean dropMutex) throws RDFRDBException {
1026:                try {
1027:                    if (!DBisLocked()) {
1028:                        throw new RDFRDBException(
1029:                                "Internal error in driver - database not locked for cleaning.\n");
1030:                    }
1031:                } catch (RDFRDBException e) {
1032:                    throw new RDFRDBException(
1033:                            "Exception when checking for database lock - \n"
1034:                                    + e);
1035:                }
1036:                //ResultSet alltables=null;
1037:                try {
1038:                    List tablesPresent = getAllTables();
1039:                    Iterator it = tablesPresent.iterator();
1040:                    // Do the MUTEX clean after all other tables.
1041:                    while (it.hasNext()) {
1042:                        String tblName = (String) it.next();
1043:                        if (tblName.equals(MUTEX_TABLE))
1044:                            continue;
1045:                        m_sql.runSQLGroup("dropTable", tblName);
1046:                    }
1047:
1048:                    // Mutex to be removed as well?
1049:                    if (dropMutex && tablesPresent.contains(MUTEX_TABLE))
1050:                        m_sql.runSQLGroup("dropTable", MUTEX_TABLE);
1051:
1052:                    if (PRE_ALLOCATE_ID)
1053:                        clearSequences();
1054:
1055:                } catch (SQLException e1) {
1056:                    throw new RDFRDBException(
1057:                            "Internal error in driver while cleaning database\n"
1058:                                    + "("
1059:                                    + e1
1060:                                    + ").\n"
1061:                                    + "Database may be corrupted. Try cleanDB() again.");
1062:                }
1063:                m_sysProperties = null;
1064:                if (prefixCache != null)
1065:                    prefixCache.clear();
1066:                prefixCache = null;
1067:            }
1068:
1069:            protected List getAllTables() {
1070:                try {
1071:                    DatabaseMetaData dbmd = m_dbcon.getConnection()
1072:                            .getMetaData();
1073:                    String[] tableTypes = { "TABLE" };
1074:                    String prefixMatch = stringToDBname(TABLE_NAME_PREFIX + "%");
1075:                    ResultSet rs = dbmd.getTables(null, null, prefixMatch,
1076:                            tableTypes);
1077:                    List tables = new ArrayList();
1078:                    while (rs.next())
1079:                        tables.add(rs.getString("TABLE_NAME"));
1080:                    rs.close();
1081:                    return tables;
1082:                } catch (SQLException e1) {
1083:                    throw new RDFRDBException("Internal SQL error in driver - "
1084:                            + e1);
1085:                }
1086:            }
1087:
1088:            /**
1089:             * Drop all Jena-related sequences from database, if necessary.
1090:             * Override in subclass if sequences must be explicitly deleted.
1091:             */
1092:            public void clearSequences() {
1093:            }
1094:
1095:            /**
1096:             * Removes named sequence from the database, if it exists.
1097:             * @param seqName
1098:             */
1099:            public void removeSequence(String seqName) {
1100:                if (sequenceExists(seqName)) {
1101:                    try {
1102:                        m_sql.runSQLGroup("DropSequence", seqName);
1103:                    } catch (Exception e) {
1104:                        logger.warn("Unable to drop sequence " + seqName, e);
1105:                    }
1106:                }
1107:            }
1108:
1109:            /**
1110:             * Check database and see if named sequence exists.
1111:             * @param seqName
1112:             */
1113:            public boolean sequenceExists(String seqName) {
1114:                Object[] args = { seqName };
1115:                ResultSet rs = null;
1116:                boolean result = false;
1117:                PreparedStatement ps = null;
1118:                try {
1119:                    String op = "SelectSequenceName";
1120:                    ps = m_sql.getPreparedSQLStatement(op);
1121:                    ps.setString(1, seqName);
1122:                    rs = ps.executeQuery();
1123:                    result = rs.next();
1124:                } catch (Exception e) {
1125:                    logger.error("Unable to select sequence " + seqName, e);
1126:                } finally {
1127:                    if (rs != null)
1128:                        try {
1129:                            rs.close();
1130:                        } catch (SQLException e1) {
1131:                            throw new RDFRDBException(
1132:                                    "Failed to get last inserted ID: " + e1);
1133:                        }
1134:                    if (ps != null)
1135:                        m_sql.returnPreparedSQLStatement(ps);
1136:                }
1137:                return result;
1138:            }
1139:
1140:            /**
1141:             * Check database and see if named sequence exists.
1142:             * @param seqName
1143:             */
1144:            public List getSequences() {
1145:                List results = new ArrayList(10);
1146:                Object[] args = {};
1147:                ResultSet rs = null;
1148:                PreparedStatement ps = null;
1149:                try {
1150:                    String opname = "SelectJenaSequences";
1151:                    ps = m_sql.getPreparedSQLStatement(opname,
1152:                            TABLE_NAME_PREFIX);
1153:                    rs = ps.executeQuery();
1154:                    while (rs.next())
1155:                        results.add(rs.getString(1));
1156:                    //rs.close();   //Removed after jena 2.4. 
1157:                } catch (Exception e) {
1158:                    logger.error("Unable to select Jena sequences: ", e);
1159:                } finally {
1160:                    if (rs != null)
1161:                        try {
1162:                            rs.close();
1163:                        } catch (SQLException e1) {
1164:                            throw new RDFRDBException(
1165:                                    "Failed to get last inserted ID: " + e1);
1166:                        }
1167:                    if (ps != null)
1168:                        m_sql.returnPreparedSQLStatement(ps);
1169:                }
1170:                return results;
1171:            }
1172:
1173:            /**
1174:             * Initialise a database ready to store RDF tables.
1175:             * @throws RDFDBException if the is a problem opening the connection or an internal SQL error.
1176:             * @deprecated Since Jena 2.0 this call is no longer needed - formatting 
1177:             * happens automatically as a side effect of creating Models - there should
1178:             * be no need for an application to interact directly with the driver.
1179:             */
1180:            public void formatDB() throws RDFRDBException {
1181:            }
1182:
1183:            /**
1184:             * Create a table for storing asserted or reified statements.
1185:             * 
1186:             * @param graphId the graph which the table is created.
1187:             * @param isReif true if table stores reified statements.
1188:             * @return the name of the new table 
1189:             * 
1190:             */
1191:            public String createTable(int graphId, boolean isReif) {
1192:                String opname = isReif ? "createReifStatementTable"
1193:                        : "createStatementTable";
1194:                int i = 0;
1195:                String params[];
1196:                while (true) {
1197:                    params = getCreateTableParams(graphId, isReif);
1198:                    try {
1199:                        m_sql.runSQLGroup(opname, params);
1200:                        break;
1201:                    } catch (SQLException e) {
1202:                        i++;
1203:                        if (i > 5) {
1204:                            logger.warn("Problem creating table", e);
1205:                            throw new RDFRDBException(
1206:                                    "Failed to create table: " + params[0], e);
1207:                        }
1208:                    }
1209:                }
1210:                return params[0];
1211:            }
1212:
1213:            /**
1214:             * Delete a table.
1215:             * 
1216:             * @param tableName the name of the table to delete.	 * 
1217:             */
1218:            public void deleteTable(String tableName) {
1219:
1220:                String opname = "dropTable";
1221:                PreparedStatement ps = null;
1222:                try {
1223:                    ps = m_sql.getPreparedSQLStatement(opname, tableName);
1224:                    ps.executeUpdate();
1225:                    return;
1226:                } catch (Exception e1) {
1227:                    throw new RDFRDBException("Failed to delete table ", e1);
1228:                } finally {
1229:                    if (ps != null)
1230:                        m_sql.returnPreparedSQLStatement(ps);
1231:                }
1232:            }
1233:
1234:            /**
1235:             * Throws an UnsupportedOperation exception.
1236:             * 
1237:             * @param opName name of the operation that's not supported.
1238:             */
1239:            private void notSupported(String opName) {
1240:                throw new UnsupportedOperationException(opName);
1241:            }
1242:
1243:            protected static final int xactBegin = 0;
1244:            protected static final int xactCommit = 1;
1245:            protected static final int xactAbort = 2;
1246:            protected static final int xactIsActive = 3;
1247:            protected static final int xactAutoOff = 4;
1248:            protected static final int xactAutoOn = 5;
1249:            protected static final int xactBeginIfNone = 6;
1250:
1251:            /**
1252:             * Perform a transaction operation.  For begin/commit/abort,
1253:             * return true if success, false if fail. for xactIsActive,
1254:             * return true if this driver has an active transaction,
1255:             * else return false.
1256:             * for beginIfNone, if there is a transaction running, return false, otherwise
1257:             * 
1258:             */
1259:            protected synchronized boolean xactOp(int op)
1260:                    throws RDFRDBException {
1261:                try {
1262:                    return xaxtOpRaw(op);
1263:                } catch (SQLException e) {
1264:                    throw new JenaException("Transaction support failed: ", e);
1265:                }
1266:            }
1267:
1268:            private boolean xaxtOpRaw(int op) throws SQLException {
1269:                boolean ret = true;
1270:                if (op == xactBegin) {
1271:                    // start a transaction
1272:                    // always return true
1273:                    if (!inTransaction) {
1274:                        xactBegin();
1275:                        inTransaction = true;
1276:                    }
1277:                } else if (op == xactBeginIfNone) {
1278:                    if (inTransaction)
1279:                        ret = false;
1280:                    else {
1281:                        xactBegin();
1282:                        inTransaction = true;
1283:                    }
1284:                } else if (op == xactCommit) {
1285:                    // commit a transaction
1286:                    // always return true
1287:                    if (inTransaction) {
1288:                        xactCommit();
1289:                        inTransaction = false;
1290:                    }
1291:                } else if (op == xactAbort) {
1292:                    // rollback a transaction
1293:                    // always return true
1294:                    if (inTransaction) {
1295:                        xactAbort();
1296:                        inTransaction = false;
1297:                    }
1298:                } else if (op == xactIsActive) {
1299:                    // return true if xact is active, else false
1300:                    ret = inTransaction;
1301:                } else if (op == xactAutoOff) {
1302:                    // disable autocommit
1303:                    // return true if autocommit is on, else false
1304:                    // begins a new transaction
1305:                    Connection c = m_sql.getConnection();
1306:                    ret = c.getAutoCommit();
1307:                    if (ret)
1308:                        xactBegin();
1309:                    inTransaction = true;
1310:                } else if (op == xactAutoOn) {
1311:                    // enable autocommit
1312:                    // always return true
1313:                    if (inTransaction)
1314:                        throw new JenaException(
1315:                                "Can't enable AutoCommit in middle of existing transaction");
1316:                    Connection c = m_sql.getConnection();
1317:                    c.setAutoCommit(true);
1318:                    ret = true;
1319:                } else
1320:                    throw new JenaException("Unknown transaction operation: "
1321:                            + op);
1322:                return ret;
1323:            }
1324:
1325:            private void xactBegin() throws RDFRDBException {
1326:                try {
1327:                    Connection c = m_sql.getConnection();
1328:                    try {
1329:                        if (c.getTransactionIsolation() != Connection.TRANSACTION_READ_COMMITTED) {
1330:                            c
1331:                                    .setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
1332:                        }
1333:                        if (c.getAutoCommit()) {
1334:                            c.setAutoCommit(false);
1335:                        }
1336:                    } catch (Exception e) {
1337:                        e.printStackTrace();
1338:                    }
1339:                    // Starting a transaction could require us to lose any
1340:                    // cached prepared statements
1341:                    // for some jdbc drivers, currently I think all the drivers
1342:                    // we use are safe and
1343:                    // is a major performance hit so commented out for now.
1344:                    //m_sql.flushPreparedStatementCache();
1345:                } catch (SQLException e) {
1346:                    throw new JenaException("Transaction begin failed: ", e);
1347:                }
1348:            }
1349:
1350:            private void xactAbort() throws RDFRDBException {
1351:                try {
1352:                    Connection c = m_sql.getConnection();
1353:                    c.rollback();
1354:                    c.commit();
1355:                    c.setAutoCommit(true);
1356:                } catch (SQLException e) {
1357:                    throw new JenaException("Transaction rollback failed: ", e);
1358:                }
1359:            }
1360:
1361:            private void xactCommit() throws RDFRDBException {
1362:                try {
1363:                    Connection c = m_sql.getConnection();
1364:                    c.commit();
1365:                    try {
1366:                        c.setAutoCommit(true);
1367:                    } catch (Exception e) {
1368:                        e.printStackTrace();
1369:                    }
1370:                    // not sure why read_uncommitted is set, below. commented
1371:                    // out by kw.
1372:                    // c.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
1373:                } catch (SQLException e) {
1374:                    throw new JenaException("Transaction commit failed: ", e);
1375:                }
1376:            }
1377:
1378:            /**
1379:             * If the underlying database connection supports transactions, turn
1380:             * autocommit off, then begin a new transaction. Note that transactions are
1381:             * associated with connections, not with Models. This
1382:             */
1383:            public synchronized void begin() throws RDFRDBException {
1384:                if (transactionsSupported()) {
1385:                    xactOp(xactBegin);
1386:                } else {
1387:                    notSupported("begin transaction");
1388:                }
1389:            }
1390:
1391:            /**
1392:             * If the underlying database connection supports transactions, call
1393:             * commit(), then turn autocommit on.
1394:             */
1395:            public void commit() throws RDFRDBException {
1396:                if (transactionsSupported()) {
1397:                    xactOp(xactCommit);
1398:                } else {
1399:                    notSupported("commit transaction");
1400:                }
1401:            }
1402:
1403:            /**
1404:             * If underlying database connection supports transactions, call abort() on
1405:             * the connection, then turn autocommit on.
1406:             */
1407:            public synchronized void abort() throws RDFRDBException {
1408:                if (transactionsSupported()) {
1409:                    xactOp(xactAbort);
1410:                } else {
1411:                    notSupported("abort transaction");
1412:                }
1413:            }
1414:
1415:            /**
1416:             * Return a string identifying underlying database type.
1417:             *
1418:             */
1419:            public String getDatabaseType() {
1420:                return (DATABASE_TYPE);
1421:            }
1422:
1423:            /**
1424:             * Returns true if the underlying database supports transactions.
1425:             */
1426:            public boolean transactionsSupported() {
1427:                if (m_transactionsSupported != null) {
1428:                    return (m_transactionsSupported.booleanValue());
1429:                }
1430:
1431:                if (m_dbcon != null) {
1432:                    try {
1433:                        Connection c = m_sql.getConnection();
1434:                        if (c != null) {
1435:                            m_transactionsSupported = new Boolean(c
1436:                                    .getMetaData()
1437:                                    .supportsMultipleTransactions());
1438:                            return (m_transactionsSupported.booleanValue());
1439:                        }
1440:                    } catch (SQLException e) {
1441:                        logger.error("SQL Exception caught ", e);
1442:                    }
1443:                }
1444:                return (false);
1445:
1446:            }
1447:
1448:            //--------------------------------------------------jena 1 backward compatability
1449:
1450:            /**
1451:             * Close the driver 
1452:             * 
1453:             * Nothing to do for now.
1454:             * 
1455:             * @throws RDFDBException if there is an access problem
1456:             * @deprecated Since Jena 2.0 this call is no longer required - just 
1457:             * close the DBConnection - there should be no need for an application
1458:             * to interact directly with the driver.
1459:             * 
1460:             */
1461:
1462:            public void close() throws RDFRDBException {
1463:            }
1464:
1465:            /**
1466:             * Returns true if the database layout supports multiple RDF models
1467:             * in the same database.
1468:             * @deprecated Since Jena 2.0 all databases support multiple models.
1469:             */
1470:
1471:            public boolean supportsMultipleModels() {
1472:                return true;
1473:            }
1474:
1475:            /**
1476:             * Returns true if the database layout supports implicit reification
1477:             * of statements (i.e. statements can be treated as resources).
1478:             * @deprecated Since Jena 2.0 the reification API has changed.  The
1479:             * new API is supported in all models, but the old Jena 1 API is no
1480:             * longer supported.  This call will return false to indicate
1481:             * to old code that the old style of jena reification is not supported.
1482:             */
1483:
1484:            public boolean supportsJenaReification() {
1485:                return false;
1486:            }
1487:
1488:            /*
1489:             * The following routines are responsible for encoding nodes
1490:             * as database structures. For each node type stored (currently,
1491:             * literals, URI, blank), there are two possible encodings
1492:             * depending on the node size. Small nodes may be stored
1493:             * within a statement table. If the node is long (will not
1494:             * fit within the statement table), it is be stored in a
1495:             * separate table for that node type.
1496:             * 
1497:             * In addition, for resources (URI, blank nodes), the URI
1498:             * may be optionally compressed. Below, the possibilites
1499:             * are enumerated.
1500:             * 
1501:             * Literal Encoding in Statement Tables
1502:             * 	Short Literal:	Lv:[langLen]:[datatypeLen]:[langString][datatypeString]value[:]
1503:             * 	Long Literal:	Lr:dbid
1504:             * Literal Encoding in Long Literal Table
1505:             * 	Literal:		Lv:[langLen]:[datatypeLen]:[langString][datatypeString]head[:] hash tail
1506:             * 
1507:             * Comments:
1508:             * 		L indicates a literal
1509:             * 		v indicates a value
1510:             * 		r indicates a reference to another table
1511:             * 		: is used as a delimiter. note that MySQL trims trailing white space for
1512:             * 			certain VARCHAR columns so an extra delimiter is appended when necessary
1513:             * 			for those columns. it is not required for dbid, however. 
1514:             * 		dbid references the long literal table
1515:             * 		langLen is the length of the language identifier for the literal
1516:             * 		langString is the language identifier
1517:             * 		datatypeLen is the length of the datatype for the literal
1518:             * 		datatypeString is the datatype for the literal
1519:             * 		value is the lexical form of the string
1520:             * 		head is a prefix of value that can be indexed
1521:             * 		hash is the CRC32 hash value for the tail
1522:             * 		tail is the remainder of the value that cannot be indexed
1523:             * 		
1524:             * 
1525:             * 
1526:             * URI Encoding in Statement Tables
1527:             * 	Short URI:	Uv:[pfx_dbid]:URI[:]
1528:             * 	Long URI:	Ur:[pfx_dbid]:dbid
1529:             * URI Encoding in Long URI Table
1530:             * 	URI:		Uv:head[:] hash tail
1531:             * 
1532:             * Comments:
1533:             * 		U indicates a URI
1534:             * 		pfx_dbid references the prefix table. if the prefix is too
1535:             * 			short (i.e., the length of the prefix is less than
1536:             * 			URI_COMPRESS_LENGTH), the URI is not compressed and
1537:             * 			pfx_dbid is null.
1538:             * 		URI is the complete URI
1539:             * 		other notation same as for literal encoding
1540:             * 
1541:             * Blank Node Encoding in Statement Tables
1542:             * 	Short URI:	Bv:[pfx_dbid]:bnid[:]
1543:             * 	Long URI:	Br:[pfx_dbid]:dbid
1544:             * Blank Encoding in Long URI Table
1545:             * 	URI:		Bv:head[:] hash tail
1546:             * 
1547:             * Comments:
1548:             * 		B indicates a blank node
1549:             * 		bnid is the blank node identifier
1550:             * 		other notation same as above
1551:             * 		Note: currently, blank nodes are always stored uncompressed (pfix_dbid is null). 
1552:             *
1553:             * Variable Node Encoding in Statement Tables
1554:             * 	Variable Node:	Vv:name
1555:             * 
1556:             * Comments:
1557:             * 		V indicates a variable node
1558:             * 		v indicates a value
1559:             * 		name is the variable name
1560:             * 		Note: the length must be less than LONG_OBJECT_LENGTH
1561:             * 
1562:             * ANY Node Encoding in Statement Tables
1563:             * 	Variable Node:	Av:
1564:             *  
1565:             * Prefix Encoding in Prefix Table
1566:             * 	Prefix:	Pv:val[:] [hash] [tail]
1567:             * 
1568:             * Comments:
1569:             * 		P indicates a prefix
1570:             * 		other notation same as above
1571:             * 		hash and tail are only required for long prefixes.
1572:             * 
1573:             */
1574:
1575:            protected static String RDBCodeURI = "U";
1576:            protected static String RDBCodeBlank = "B";
1577:            protected static String RDBCodeLiteral = "L";
1578:            protected static String RDBCodeVariable = "V";
1579:            protected static String RDBCodeANY = "A";
1580:            protected static String RDBCodePrefix = "P";
1581:            protected static String RDBCodeValue = "v";
1582:            protected static String RDBCodeRef = "r";
1583:            protected static String RDBCodeDelim = ":";
1584:            protected static char RDBCodeDelimChar = ':';
1585:            protected static String RDBCodeInvalid = "X";
1586:
1587:            /**
1588:             * Convert a node to a string to be stored in a statement table.
1589:             * @param Node The node to convert to a string. Must be a concrete node.
1590:             * @param addIfLong If the node is a long object and is not in the database, add it.
1591:             * @return the string or null if failure.
1592:             */
1593:            public String nodeToRDBString(Node node, boolean addIfLong)
1594:                    throws RDFRDBException {
1595:                String res = null;
1596:                if (node.isURI()) {
1597:                    String uri = new String(((Node_URI) node).getURI());
1598:                    if (uri.startsWith(RDBCodeURI)) {
1599:                        throw new RDFRDBException(
1600:                                "URI Node looks like a blank node: " + uri);
1601:                    }
1602:                    // TODO: need to write special version of splitNamespace for rdb.
1603:                    //		or else, need a guarantee that splitNamespace never changes.
1604:                    //		the problem is that if the splitNamespace algorithm changes,
1605:                    //		then URI's may be encoded differently. so, URI's in existing
1606:                    //		databases may become inaccessible.
1607:                    int pos = 0;
1608:                    boolean noCompress;
1609:                    String pfx;
1610:                    String qname;
1611:                    if (URI_COMPRESS == true) {
1612:                        pos = dbSplitNamespace(uri);
1613:                        if (uri.startsWith(DB.uri))
1614:                            noCompress = true;
1615:                        else
1616:                            noCompress = (pos == uri.length())
1617:                                    || (pos <= URI_COMPRESS_LENGTH);
1618:                    } else
1619:                        noCompress = true;
1620:                    if (noCompress) {
1621:                        pfx = RDBCodeDelim + RDBCodeDelim;
1622:                        qname = uri;
1623:                    } else {
1624:                        // see if it's cached
1625:                        DBIDInt pfxid = URItoPrefix(uri, pos, addIfLong);
1626:                        if (pfxid == null)
1627:                            return res;
1628:                        pfx = RDBCodeDelim + ((DBIDInt) pfxid).getIntID()
1629:                                + RDBCodeDelim;
1630:                        qname = uri.substring(pos);
1631:                    }
1632:                    int encodeLen = RDBCodeURI.length() + 1 + pfx.length()
1633:                            + EOS_LEN;
1634:                    boolean URIisLong = objectIsLong(encodeLen, qname);
1635:                    if (URIisLong) {
1636:                        int dbid;
1637:                        // belongs in URI table
1638:                        DBIDInt URIid = getURIID(qname, addIfLong);
1639:                        if (URIid == null)
1640:                            return res;
1641:                        dbid = URIid.getIntID();
1642:                        res = new String(RDBCodeURI + RDBCodeRef + pfx + dbid);
1643:                    } else {
1644:                        res = RDBCodeURI + RDBCodeValue + pfx + qname + EOS;
1645:                    }
1646:                } else if (node.isLiteral()) {
1647:                    // TODO: may need to encode literal value when datatype is not a string.
1648:                    Node_Literal litNode = (Node_Literal) node;
1649:                    String lval = litNode.getLiteralLexicalForm();
1650:                    String lang = litNode.getLiteralLanguage();
1651:                    String dtype = litNode.getLiteralDatatypeURI();
1652:                    String ld = litLangTypeToRDBString(lang, dtype);
1653:                    int encodeLen = RDBCodeLiteral.length() + 2 + ld.length()
1654:                            + EOS_LEN;
1655:                    boolean litIsLong = objectIsLong(encodeLen, lval);
1656:
1657:                    if (litIsLong) {
1658:                        int dbid;
1659:
1660:                        //System.err.println("Long literal("+lval.length()+" => "+encodeLen+")") ;
1661:
1662:                        // belongs in literal table
1663:                        DBIDInt lid = getLiteralID(litNode, addIfLong);
1664:                        if (lid == null)
1665:                            return res;
1666:                        dbid = lid.getIntID();
1667:                        res = new String(RDBCodeLiteral + RDBCodeRef
1668:                                + RDBCodeDelim + dbid);
1669:                    } else {
1670:                        res = new String(RDBCodeLiteral + RDBCodeValue
1671:                                + RDBCodeDelim + ld + lval + EOS);
1672:                    }
1673:                } else if (node.isBlank()) {
1674:                    String bnid = node.getBlankNodeId().toString();
1675:                    String delims = "::";
1676:                    int encodeLen = RDBCodeBlank.length() + 1 + delims.length()
1677:                            + EOS_LEN;
1678:                    boolean BisLong = objectIsLong(encodeLen, bnid);
1679:                    if (BisLong) {
1680:                        int dbid;
1681:                        // belongs in URI table
1682:                        DBIDInt URIid = getBlankID(bnid, addIfLong);
1683:                        if (URIid == null)
1684:                            return res;
1685:                        dbid = URIid.getIntID();
1686:                        res = new String(RDBCodeBlank + RDBCodeRef + delims
1687:                                + dbid);
1688:                    } else {
1689:                        res = new String(RDBCodeBlank + RDBCodeValue + delims
1690:                                + bnid + EOS);
1691:                    }
1692:
1693:                } else if (node.isVariable()) {
1694:                    String name = ((Node_Variable) node).getName();
1695:                    int len = name.length();
1696:                    if ((len + 3 + EOS_LEN) > LONG_OBJECT_LENGTH)
1697:                        throw new JenaException("Variable name too long: "
1698:                                + name);
1699:                    res = RDBCodeVariable + RDBCodeValue + RDBCodeDelim + name
1700:                            + EOS;
1701:                } else if (node.equals(Node.ANY)) {
1702:                    res = RDBCodeANY + RDBCodeValue + RDBCodeDelim;
1703:                } else {
1704:                    throw new RDFRDBException("Expected Concrete Node, got "
1705:                            + node.toString());
1706:                }
1707:                return res;
1708:            }
1709:
1710:            /**
1711:             * Convert an RDB string to the node that it encodes. Return null if failure.
1712:             * @param RDBstring The string to convert to a node.
1713:             * @return The node or null if failure.
1714:             */
1715:            public Node RDBStringToNode(String RDBString)
1716:                    throws RDFRDBException {
1717:                Node res = null;
1718:                int len = RDBString.length();
1719:                if (len < 3)
1720:                    throw new RDFRDBException("Bad RDBString Header: "
1721:                            + RDBString);
1722:                String nodeType = RDBString.substring(0, 1);
1723:                String valType = RDBString.substring(1, 2);
1724:                if ((!(valType.equals(RDBCodeRef) || valType
1725:                        .equals(RDBCodeValue)))
1726:                        || (RDBString.charAt(2) != RDBCodeDelimChar))
1727:                    throw new RDFRDBException("Bad RDBString Header: "
1728:                            + RDBString);
1729:
1730:                int pos = 3;
1731:                int npos;
1732:
1733:                if (nodeType.equals(RDBCodeURI)) {
1734:                    ParseInt pi = new ParseInt(pos);
1735:                    String prefix = "";
1736:                    RDBStringParseInt(RDBString, pi, false);
1737:                    if (pi.val != null) {
1738:                        if (URI_COMPRESS == false)
1739:                            throw new RDFRDBException(
1740:                                    "Bad URI: Prefix Compression Disabled: "
1741:                                            + RDBString);
1742:                        prefix = IDtoPrefix(pi.val.intValue());
1743:                        if (prefix == null)
1744:                            throw new RDFRDBException("Bad URI Prefix: "
1745:                                    + RDBString);
1746:                    }
1747:                    pos = pi.pos + 1;
1748:                    String qname;
1749:                    if (valType.equals(RDBCodeRef)) {
1750:                        qname = IDtoURI(RDBString.substring(pos));
1751:                        if (qname == null)
1752:                            throw new RDFRDBException("Bad URI: " + RDBString);
1753:                    } else
1754:                        qname = RDBString.substring(pos, len - EOS_LEN);
1755:
1756:                    res = Node.createURI(prefix + qname);
1757:
1758:                } else if (nodeType.equals(RDBCodeLiteral)) {
1759:                    res = RDBLiteralStringToLiteralNode(RDBString, len,
1760:                            valType, pos);
1761:
1762:                } else if (nodeType.equals(RDBCodeBlank)) {
1763:                    String bstr = null;
1764:                    if (valType.equals(RDBCodeValue)) {
1765:                        bstr = RDBString.substring(4, len - EOS_LEN);
1766:                    } else {
1767:                        bstr = IDtoBlank(RDBString.substring(4));
1768:                        if (bstr == null)
1769:                            throw new RDFRDBException("Bad URI: " + RDBString);
1770:                    }
1771:                    res = Node.createAnon(new AnonId(bstr));
1772:
1773:                } else if (nodeType.equals(RDBCodeVariable)) {
1774:                    String vname = RDBString.substring(3, len - EOS_LEN);
1775:                    res = Node.createVariable(vname);
1776:
1777:                } else if (nodeType.equals(RDBCodeANY)) {
1778:                    res = Node.ANY;
1779:
1780:                } else
1781:                    throw new RDFRDBException("Invalid RDBString Prefix, "
1782:                            + RDBString);
1783:                return res;
1784:            }
1785:
1786:            /**
1787:                Answer a literal Node constructed according to the RDB String.
1788:                
1789:             	@param RDBString
1790:             	@param len
1791:             	@param valType
1792:             	@param pos
1793:             	@return
1794:             */
1795:            protected Node RDBLiteralStringToLiteralNode(String RDBString,
1796:                    int len, String valType, int pos) {
1797:                ParseInt pi = new ParseInt(pos);
1798:                String litString = null;
1799:                if (valType.equals(RDBCodeRef)) {
1800:                    RDBStringParseInt(RDBString, pi, true);
1801:                    if (pi.val != null)
1802:                        litString = IDtoLiteral(pi.val.intValue());
1803:                    if (litString == null)
1804:                        throw new RDFRDBException("Bad Literal Reference: "
1805:                                + RDBString);
1806:                } else
1807:                    litString = RDBString.substring(pos, len - EOS_LEN);
1808:                len = litString.length();
1809:                pi.pos = 0;
1810:                RDBStringParseInt(litString, pi, false);
1811:                int langLen = pi.val == null ? 0 : pi.val.intValue();
1812:                pi.pos = pi.pos + 1;
1813:                RDBStringParseInt(litString, pi, false);
1814:                int dtypeLen = pi.val == null ? 0 : pi.val.intValue();
1815:                pos = pi.pos + 1;
1816:                if ((pos + langLen + dtypeLen) > len)
1817:                    throw new RDFRDBException("Malformed Literal: " + litString);
1818:                String lang = litString.substring(pos, pos + langLen);
1819:                pos = pos + langLen;
1820:                String dtype = litString.substring(pos, pos + dtypeLen);
1821:                String val = litString.substring(pos + dtypeLen);
1822:                return createLiteral(val, lang, dtype);
1823:            }
1824:
1825:            /**
1826:                Answer a Node literal with the indicated lexical form, language,
1827:                and datatype. If the datatype is the empty string, there is no
1828:                datatype. If the language is the empty string, there is no language.
1829:                
1830:             	@param val
1831:             	@param lang
1832:             	@param dtype
1833:             	@return
1834:             */
1835:            protected Node createLiteral(String val, String lang, String dtype) {
1836:                if (dtype.equals("")) {
1837:                    return Node.createLiteral(val, lang, null);
1838:                } else {
1839:                    RDFDatatype dt = TypeMapper.getInstance()
1840:                            .getSafeTypeByName(dtype);
1841:                    return Node.createLiteral(val, lang, dt);
1842:                }
1843:            }
1844:
1845:            /** This is cuurently a copy of Util.splitNamespace.  It was
1846:             * copied rather than used directly for two reasons. 1) in the
1847:             * future it may be desirable to use a different split algorithm
1848:             * for persistence. 2) the util version could change at any time,
1849:             * which would render existing databases inaccessible. having a
1850:             * copy allows the db version to evolve in a controlled way.
1851:             * 
1852:             * Given an absolute URI, determine the split point between the namespace part
1853:             * and the localname part.
1854:             * If there is no valid localname part then the length of the
1855:             * string is returned.
1856:             * The algorithm tries to find the longest NCName at the end
1857:             * of the uri, not immediately preceeded by the first colon
1858:             * in the string.
1859:             * @param uri
1860:             * @return the index of the first character of the localname
1861:             */
1862:            public static int dbSplitNamespace(String uri) {
1863:                char ch;
1864:                int lg = uri.length();
1865:                if (lg == 0)
1866:                    return 0;
1867:                int j;
1868:                int i;
1869:                for (i = lg - 1; i >= 1; i--) {
1870:                    ch = uri.charAt(i);
1871:                    if (!XMLChar.isNCName(ch))
1872:                        break;
1873:                }
1874:                for (j = i + 1; j < lg; j++) {
1875:                    ch = uri.charAt(j);
1876:                    if (XMLChar.isNCNameStart(ch)) {
1877:                        if (uri.charAt(j - 1) == ':'
1878:                                && uri.lastIndexOf(':', j - 2) == -1)
1879:                            continue; // split "mailto:me" as "mailto:m" and "e" !
1880:                        else
1881:                            break;
1882:                    }
1883:                }
1884:                return j;
1885:            }
1886:
1887:            class ParseInt {
1888:                int pos;
1889:                Integer val;
1890:
1891:                ParseInt(int p) {
1892:                    pos = p;
1893:                }
1894:            }
1895:
1896:            protected void RDBStringParseInt(String RDBString, ParseInt pi,
1897:                    boolean toEnd) {
1898:                int npos = toEnd ? RDBString.length() : RDBString.indexOf(
1899:                        RDBCodeDelimChar, pi.pos);
1900:                if (npos < 0) {
1901:                    throw new RDFRDBException("Bad RDB String: " + RDBString);
1902:                }
1903:                String intStr = RDBString.substring(pi.pos, npos);
1904:                pi.pos = npos;
1905:                if (intStr.equals(""))
1906:                    pi.val = null;
1907:                else
1908:                    try {
1909:                        pi.val = new Integer(intStr);
1910:                    } catch (NumberFormatException e1) {
1911:                        throw new RDFRDBException("Bad RDB String: "
1912:                                + RDBString);
1913:                    }
1914:                return;
1915:            }
1916:
1917:            DBIDInt URItoPrefix(String uri, int pos, boolean add) {
1918:                DBIDInt res;
1919:                Object key = prefixCache.getByValue(uri.substring(0, pos));
1920:                if (key == null) {
1921:                    RDBLongObject lobj = PrefixToLongObject(uri, pos);
1922:                    res = getLongObjectID(lobj, PREFIX_TABLE, add);
1923:                    if (res != null)
1924:                        prefixCache.put(res, uri.substring(0, pos));
1925:                } else
1926:                    res = (DBIDInt) key;
1927:                return res;
1928:            }
1929:
1930:            protected RDBLongObject PrefixToLongObject(String prefix, int split) {
1931:                RDBLongObject res = new RDBLongObject();
1932:                int headLen;
1933:                int avail;
1934:
1935:                res.head = RDBCodePrefix + RDBCodeValue + RDBCodeDelim;
1936:                headLen = res.head.length();
1937:                avail = INDEX_KEY_LENGTH - (headLen + EOS_LEN);
1938:                if (split > avail) {
1939:                    res.head = res.head + prefix.substring(0, avail);
1940:                    res.tail = prefix.substring(avail, split);
1941:                    res.hash = stringToHash(res.tail);
1942:                } else {
1943:                    res.head = res.head + prefix.substring(0, split);
1944:                    res.tail = "";
1945:                }
1946:                res.head = res.head + EOS;
1947:                return res;
1948:            }
1949:
1950:            /**
1951:             * Encode a literal node's lang and datatype as a string of the
1952:             * form ":[langLen]:[datatypeLen]:[langString][dataTypeString]"
1953:             * @return the string.
1954:             */
1955:            public String litLangTypeToRDBString(String lang, String dtype)
1956:                    throws RDFRDBException {
1957:                String res = RDBCodeDelim;
1958:                res = ((lang == null) ? "" : Integer.toString(lang.length()))
1959:                        + RDBCodeDelim;
1960:                res = res
1961:                        + ((dtype == null) ? "" : Integer.toString(dtype
1962:                                .length())) + RDBCodeDelim;
1963:                res = res + (lang == null ? "" : lang)
1964:                        + (dtype == null ? "" : dtype);
1965:                return res;
1966:            }
1967:
1968:            /**
1969:             * Check if an object is long, i.e., it exceeds the length
1970:             * limit for storing in a statement table.
1971:             * @return true if literal is long, else false.
1972:             */
1973:            protected boolean objectIsLong(int encodingLen, String objAsString) {
1974:                return ((encodingLen + objAsString.length()) > LONG_OBJECT_LENGTH);
1975:            }
1976:
1977:            class RDBLongObject {
1978:                String head; /* prefix of long object that can be indexed */
1979:                long hash; /* hash encoding of tail */
1980:                String tail; /* remainder of long object */
1981:            }
1982:
1983:            protected RDBLongObject literalToLongObject(Node_Literal node) {
1984:                RDBLongObject res = new RDBLongObject();
1985:                int headLen;
1986:                int avail;
1987:                String lang = node.getLiteralLanguage();
1988:                String dtype = node.getLiteralDatatypeURI();
1989:                String val = node.getLiteralLexicalForm();
1990:                String langType = litLangTypeToRDBString(lang, dtype);
1991:
1992:                res.head = RDBCodeLiteral + RDBCodeValue + RDBCodeDelim
1993:                        + langType;
1994:                headLen = res.head.length();
1995:                avail = INDEX_KEY_LENGTH - (headLen + EOS_LEN);
1996:                if (val.length() > avail) {
1997:                    res.head = res.head + val.substring(0, avail);
1998:                    res.tail = val.substring(avail);
1999:                    res.hash = stringToHash(res.tail);
2000:                } else {
2001:                    res.head = res.head + val;
2002:                    res.tail = "";
2003:                }
2004:                res.head = res.head + EOS;
2005:                return res;
2006:            }
2007:
2008:            protected long stringToHash(String str) {
2009:                CRC32 checksum = new CRC32();
2010:                checksum.update(str.getBytes());
2011:                return checksum.getValue();
2012:            }
2013:
2014:            /**
2015:             * Return the database ID for the URI, if it exists
2016:             */
2017:            public DBIDInt getBlankID(String bstr, boolean add)
2018:                    throws RDFRDBException {
2019:                RDBLongObject lobj = URIToLongObject(bstr, RDBCodeBlank);
2020:                return getLongObjectID(lobj, LONG_URI_TABLE, add);
2021:            }
2022:
2023:            /**
2024:             * Return the database ID for the URI, if it exists
2025:             */
2026:            public DBIDInt getURIID(String qname, boolean add)
2027:                    throws RDFRDBException {
2028:                RDBLongObject lobj = URIToLongObject(qname, RDBCodeURI);
2029:                return getLongObjectID(lobj, LONG_URI_TABLE, add);
2030:            }
2031:
2032:            protected RDBLongObject URIToLongObject(String qname, String code) {
2033:                RDBLongObject res = new RDBLongObject();
2034:                int headLen;
2035:                int avail;
2036:
2037:                res.head = code + RDBCodeValue + RDBCodeDelim;
2038:                headLen = res.head.length();
2039:                avail = INDEX_KEY_LENGTH - (headLen + EOS_LEN);
2040:                if (qname.length() > avail) {
2041:                    res.head = res.head + qname.substring(0, avail);
2042:                    res.tail = qname.substring(avail);
2043:                    res.hash = stringToHash(res.tail);
2044:                } else {
2045:                    res.head = res.head + qname;
2046:                    res.tail = "";
2047:                }
2048:                res.head = res.head + EOS;
2049:                return res;
2050:            }
2051:
2052:            /**
2053:             * Return the database ID for the literal, if it exists
2054:             */
2055:            public DBIDInt getLiteralID(Node_Literal lnode, boolean add)
2056:                    throws RDFRDBException {
2057:                RDBLongObject lobj = literalToLongObject(lnode);
2058:                return getLongObjectID(lobj, LONG_LIT_TABLE, add);
2059:            }
2060:
2061:            public DBIDInt getLongObjectID(RDBLongObject lobj, String table,
2062:                    boolean add) throws RDFRDBException {
2063:                ResultSet rs = null;
2064:                PreparedStatement ps = null;
2065:                try {
2066:                    String opName = "getLongObjectID";
2067:                    if (lobj.tail.length() > 0)
2068:                        opName += "withChkSum";
2069:                    ps = m_sql.getPreparedSQLStatement(opName, table);
2070:                    ps.setString(1, lobj.head);
2071:                    if (lobj.tail.length() > 0)
2072:                        ps.setLong(2, lobj.hash);
2073:
2074:                    rs = ps.executeQuery();
2075:                    DBIDInt result = null;
2076:                    if (rs.next()) {
2077:                        result = wrapDBID(rs.getObject(1));
2078:                    } else {
2079:                        if (add)
2080:                            result = addRDBLongObject(lobj, table);
2081:                    }
2082:
2083:                    return result;
2084:                } catch (SQLException e1) {
2085:                    // /* DEBUG */ System.out.println("Literal truncation (" + l.toString().length() + ") " + l.toString().substring(0, 150));
2086:                    throw new RDFRDBException("Failed to find literal", e1);
2087:                } finally {
2088:                    if (rs != null)
2089:                        try {
2090:                            rs.close();
2091:                        } catch (SQLException e1) {
2092:                            throw new RDFRDBException(
2093:                                    "Failed to get last inserted ID: " + e1);
2094:                        }
2095:                    if (ps != null)
2096:                        m_sql.returnPreparedSQLStatement(ps);
2097:                }
2098:            }
2099:
2100:            /**
2101:             * Insert a long object into the database.  
2102:             * This assumes the object is not already in the database.
2103:             * @return the db index of the added literal 
2104:             */
2105:            public DBIDInt addRDBLongObject(RDBLongObject lobj, String table)
2106:                    throws RDFRDBException {
2107:                PreparedStatement ps = null;
2108:
2109:                //        // Because the long object bound has been reset to less than the actual table allocation.
2110:                //        if ( lobj.tail == null || lobj.tail.equals("") )
2111:                //            System.err.println("Unexpected : empty tail") ;
2112:
2113:                try {
2114:                    int argi = 1;
2115:                    String opname = "insertLongObject";
2116:                    // If not pre-allocated , 1-Head / 2-Hash / 3-Tail
2117:                    // If pre-allocated , 1-Id, / 2-Head / 3-Hash [/ 4-Tail]
2118:                    ps = m_sql.getPreparedSQLStatement(opname, table);
2119:                    int dbid = 0; // init only needed to satisfy java compiler
2120:                    if (PRE_ALLOCATE_ID) {
2121:                        dbid = getInsertID(table);
2122:                        ps.setInt(argi++, dbid);
2123:                    }
2124:                    ps.setString(argi++, lobj.head);
2125:
2126:                    // Do the tail - this can be a large text-holding column, or a binary column
2127:                    // depending on the database.
2128:
2129:                    setLongObjectHashAndTail(ps, argi, lobj);
2130:                    argi += 2; // Hash and tail.
2131:
2132:                    ps.executeUpdate();
2133:                    if (!PRE_ALLOCATE_ID)
2134:                        dbid = getInsertID(table);
2135:                    return wrapDBID(new Integer(dbid));
2136:
2137:                } catch (Exception e1) {
2138:                    /* DEBUG */System.out.println("Problem on long object (l="
2139:                            + lobj.head + ") " + e1);
2140:                    // System.out.println("ID is: " + id);
2141:                    throw new RDFRDBException("Failed to add long object ", e1);
2142:                } finally {
2143:                    if (ps != null)
2144:                        m_sql.returnPreparedSQLStatement(ps);
2145:                }
2146:            }
2147:
2148:            // Common way to get the sequence ID, even though the SQL statements are quite different. 
2149:            // MySQL is different (it overrides this in Driver_MySQL).
2150:
2151:            public int getInsertID(String tableName) {
2152:                DBIDInt result = null;
2153:                PreparedStatement ps = null;
2154:                try {
2155:                    ps = m_sql
2156:                            .getPreparedSQLStatement("getInsertID", tableName);
2157:                    ResultSet rs = ps.executeQuery();
2158:                    if (rs.next()) {
2159:                        result = wrapDBID(rs.getObject(1));
2160:                    } else
2161:                        throw new RDFRDBException("No insert ID");
2162:                } catch (SQLException e) {
2163:                    throw new RDFRDBException("Failed to insert ID: " + e);
2164:                } finally {
2165:                    if (ps != null)
2166:                        m_sql.returnPreparedSQLStatement(ps);
2167:                }
2168:                return result.getIntID();
2169:            }
2170:
2171:            // Different ways of inserting the tail value
2172:            // 1/ As a text field, using .setString and letting JDBC encode the characters
2173:            // 2/ As a binary field, using a BLOB of UTF-8 encoded bytes
2174:
2175:            protected void setLongObjectHashAndTail(PreparedStatement ps,
2176:                    int argi, RDBLongObject lobj) throws SQLException {
2177:                setLongObjectHashAndTail_Text(ps, argi, lobj);
2178:            }
2179:
2180:            protected void setLongObjectHashAndTail_Text(PreparedStatement ps,
2181:                    int argi, RDBLongObject lobj) throws SQLException {
2182:                if (lobj.tail.length() > 0) {
2183:                    ps.setLong(argi++, lobj.hash);
2184:                    ps.setString(argi++, lobj.tail);
2185:                } else {
2186:                    ps.setNull(argi++, java.sql.Types.BIGINT);
2187:                    ps.setNull(argi++, java.sql.Types.VARCHAR);
2188:                }
2189:
2190:            }
2191:
2192:            protected void setLongObjectHashAndTail_Binary(
2193:                    PreparedStatement ps, int argi, RDBLongObject lobj)
2194:                    throws SQLException {
2195:                if (lobj.tail.length() > 0)
2196:                    ps.setLong(argi++, lobj.hash);
2197:                else
2198:                    ps.setNull(argi++, java.sql.Types.BIGINT);
2199:
2200:                byte[] b = null;
2201:                try {
2202:                    b = lobj.tail.getBytes("UTF-8");
2203:                } catch (UnsupportedEncodingException ex) {
2204:                    // Can't happen - UTF-8 is required by Java.
2205:                    throw new RDFRDBException(
2206:                            "No UTF-8 encoding (setLongObjectHashAndTail_Binary)");
2207:                }
2208:                //System.out.println("bytes in : "+b.length) ;
2209:                ps.setBytes(argi++, b);
2210:            }
2211:
2212:            /**
2213:             * Return the prefix string that has the given prefix id.
2214:             * @param prefixID - the dbid of the prefix.
2215:             * @return the prefix string or null if it does not exist.
2216:             */
2217:            protected String IDtoPrefix(int prefixID) {
2218:                // check cache
2219:                DBIDInt dbid = new DBIDInt(prefixID);
2220:                String res = (String) prefixCache.get(dbid);
2221:                if (res != null)
2222:                    return res;
2223:                else {
2224:                    res = IDtoString(prefixID, PREFIX_TABLE, RDBCodePrefix);
2225:                    prefixCache.put(dbid, res);
2226:                    return res;
2227:                }
2228:            }
2229:
2230:            /**
2231:             * Return the Blank node string that has the given database id.
2232:             * @param bnID - the dbid of the blank node, as a string.
2233:             * @return the Blank node string or null if it does not exist.
2234:             */
2235:            protected String IDtoBlank(String bnID) {
2236:                return IDtoString(bnID, LONG_URI_TABLE, RDBCodeBlank);
2237:            }
2238:
2239:            /**
2240:             * Return the URI string that has the given database id.
2241:             * @param uriID - the dbid of the uri, as a string.
2242:             * @return the uri string or null if it does not exist.
2243:             */
2244:            protected String IDtoURI(String uriID) {
2245:                return IDtoString(uriID, LONG_URI_TABLE, RDBCodeURI);
2246:            }
2247:
2248:            /**
2249:             * Return the long literal string that has the given database id.
2250:             * @param litID - the dbid of the literal..
2251:             * @return the long literal string or null if it does not exist.
2252:             */
2253:            protected String IDtoLiteral(int litID) {
2254:                return IDtoString(litID, LONG_LIT_TABLE, RDBCodeLiteral);
2255:            }
2256:
2257:            protected String IDtoString(String dbidAsString, String table,
2258:                    String RDBcode) {
2259:                int dbID;
2260:                String res = null;
2261:                try {
2262:                    dbID = Integer.parseInt(dbidAsString);
2263:                } catch (NumberFormatException e1) {
2264:                    throw new RDFRDBException("Invalid Object ID: "
2265:                            + dbidAsString);
2266:                }
2267:                return IDtoString(dbID, table, RDBcode);
2268:            }
2269:
2270:            protected String IDtoString(int dbID, String table, String RDBcode) {
2271:                String res = null;
2272:                RDBLongObject lobj = IDtoLongObject(dbID, table);
2273:                if (lobj == null)
2274:                    throw new RDFRDBException("Invalid Object ID: " + dbID);
2275:                // debug check
2276:                if (!lobj.head.substring(0, 3).equals(
2277:                        RDBcode + RDBCodeValue + RDBCodeDelim))
2278:                    throw new RDFRDBException("Malformed URI in Database: "
2279:                            + lobj.head);
2280:                res = lobj.head.substring(3, lobj.head.length() - EOS_LEN);
2281:                if (lobj.tail != null)
2282:                    res = res + lobj.tail;
2283:                return res;
2284:            }
2285:
2286:            // Get whatever is strong under a long id. 
2287:            protected RDBLongObject IDtoLongObject(int dbid, String table) {
2288:                RDBLongObject res = null;
2289:                ResultSet rs = null;
2290:                PreparedStatement ps = null;
2291:                try {
2292:                    String opName = "getLongObject";
2293:                    ps = m_sql.getPreparedSQLStatement(opName, table);
2294:                    ps.setInt(1, dbid);
2295:                    rs = ps.executeQuery();
2296:                    if (rs.next()) {
2297:                        res = new RDBLongObject();
2298:                        res.head = rs.getString(1);
2299:
2300:                        switch (rs.getMetaData().getColumnType(2)) {
2301:                        case Types.VARCHAR:
2302:                        case Types.LONGVARCHAR:
2303:                        case Types.CHAR:
2304:                            res.tail = rs.getString(2);
2305:                            if (res.tail == null)
2306:                                res.tail = "";
2307:                            break;
2308:                        case Types.BLOB:
2309:                        case Types.LONGVARBINARY:
2310:                            byte[] b2 = rs.getBytes(2);
2311:                            if (b2 == null)
2312:                                // The meaning of "" is mixed in SQL. 
2313:                                // Should not happen - we never store empty strings it the tail
2314:                                res.tail = "";
2315:                            else
2316:                                try {
2317:                                    res.tail = new String(b2, 0, b2.length,
2318:                                            "UTF-8");
2319:                                } catch (UnsupportedEncodingException ex) {
2320:                                    ex.printStackTrace();
2321:                                }
2322:                            break;
2323:                        default:
2324:                            logger
2325:                                    .fatal("Long object is of unexpected SQL type: "
2326:                                            + rs.getMetaData().getColumnType(2));
2327:                            throw new RDFRDBException(
2328:                                    "Long object is of unexpected SQL type: "
2329:                                            + rs.getMetaData().getColumnType(2));
2330:                        }
2331:                    }
2332:                } catch (SQLException e1) {
2333:                    // /* DEBUG */ System.out.println("Literal truncation (" + l.toString().length() + ") " + l.toString().substring(0, 150));
2334:                    throw new RDFRDBException("Failed to find literal", e1);
2335:                } finally {
2336:                    if (rs != null)
2337:                        try {
2338:                            rs.close();
2339:                        } catch (SQLException e1) {
2340:                            throw new RDFRDBException(
2341:                                    "Failed to get last inserted ID: " + e1);
2342:                        }
2343:                    if (ps != null)
2344:                        m_sql.returnPreparedSQLStatement(ps);
2345:                }
2346:                return res;
2347:            }
2348:
2349:            protected RDBLongObject IDtoLongObject(String idAsString,
2350:                    String table) {
2351:                RDBLongObject res = null;
2352:                int dbid;
2353:                try {
2354:                    dbid = Integer.parseInt(idAsString);
2355:                } catch (NumberFormatException e1) {
2356:                    throw new RDFRDBException("Invalid Object ID: "
2357:                            + idAsString);
2358:                }
2359:                return IDtoLongObject(dbid, table);
2360:            }
2361:
2362:            /**
2363:             * Convert the raw SQL object used to store a database identifier into a java object
2364:             * which meets the DBIDInt interface.
2365:             */
2366:            public DBIDInt wrapDBID(Object id) throws RDFRDBException {
2367:                if (id instanceof  Number) {
2368:                    return new DBIDInt(((Number) id).intValue());
2369:                } else if (id == null) {
2370:                    return null;
2371:                } else {
2372:                    throw new RDFRDBException("Unexpected DB identifier type: "
2373:                            + id);
2374:                    //return null;
2375:                }
2376:            }
2377:
2378:            public String genSQLReifQualStmt() {
2379:                return "stmt = ?";
2380:            }
2381:
2382:            public String genSQLReifQualAnyObj(boolean objIsStmt) {
2383:                return "( subj = ? OR prop = ? OR obj = ?"
2384:                        + (objIsStmt ? " OR hasType = " + QUOTE_CHAR + "T"
2385:                                + QUOTE_CHAR + " )" : " )");
2386:            }
2387:
2388:            public String genSQLReifQualObj(char reifProp, boolean hasObj) {
2389:                String qual = "";
2390:                if (reifProp == 'T') {
2391:                    qual = "hasType = " + QUOTE_CHAR + "T" + QUOTE_CHAR;
2392:                } else {
2393:                    String cmp = (hasObj ? " = ?" : " is not null");
2394:                    String col = null;
2395:                    if (reifProp == 'S')
2396:                        col = "subj";
2397:                    else if (reifProp == 'P')
2398:                        col = "prop";
2399:                    else if (reifProp == 'O')
2400:                        col = "obj";
2401:                    else
2402:                        throw new JenaException(
2403:                                "Undefined reification property");
2404:
2405:                    qual = col + cmp;
2406:                }
2407:                return qual;
2408:            }
2409:
2410:            protected String colidToColname(char colid) {
2411:                if (colid == 'G')
2412:                    return "GraphID";
2413:                if (colid == 'P')
2414:                    return "Prop";
2415:                if (colid == 'S')
2416:                    return "Subj";
2417:                if (colid == 'O')
2418:                    return "Obj";
2419:                if (colid == 'N')
2420:                    return "Stmt";
2421:                if (colid == 'T')
2422:                    return "HasType";
2423:                throw new JenaException("Invalid column identifer: '" + colid
2424:                        + "\'");
2425:            }
2426:
2427:            protected String aliasToString(int alias) {
2428:                return "A" + alias;
2429:            }
2430:
2431:            protected String colAliasToString(int alias, char colid) {
2432:                return aliasToString(alias) + "." + colidToColname(colid);
2433:            }
2434:
2435:            /** Apply SQL escapes to a string */
2436:            private String escapeQuoteSQLString(String str) {
2437:                StringBuffer sBuff = new StringBuffer(str.length() + 10);
2438:                sBuff.append(QUOTE_CHAR);
2439:                for (int i = 0; i < str.length(); i++) {
2440:                    char ch = str.charAt(i);
2441:                    // Double up quotes
2442:                    if (ch == QUOTE_CHAR)
2443:                        sBuff.append(QUOTE_CHAR);
2444:                    sBuff.append(ch);
2445:                }
2446:                sBuff.append(QUOTE_CHAR);
2447:                return sBuff.toString();
2448:            }
2449:
2450:            /*
2451:             * there's a bug in the code below in that the literal is converted to
2452:             * a string BEFORE the query is run. consequently, there's a race
2453:             * condition. if the (long) literal is not in the database
2454:             * when the query is compiled but is added prior to running the
2455:             * query, then the query will (incorrectly) return no results.
2456:             * for now, we'll ignore this case and document it as a bug.
2457:             */
2458:
2459:            public String genSQLQualConst(int alias, char pred, Node lit) {
2460:                String val = nodeToRDBString(lit, false);
2461:                if (val == null)
2462:                    // constant not in database.
2463:                    // should really optimize this and not
2464:                    // even run the query but ok for now.
2465:                    val = RDBCodeInvalid;
2466:                String qval = escapeQuoteSQLString(val);
2467:                return colAliasToString(alias, pred) + "=" + qval;
2468:            }
2469:
2470:            public String genSQLReifQualConst(int alias, char pred, Node lit) {
2471:                String val = "";
2472:                if ((pred == 'T') && (lit.equals(RDF.Nodes.Statement)))
2473:                    val = "T";
2474:                else
2475:                    val = nodeToRDBString(lit, false);
2476:                String qval = escapeQuoteSQLString(val);
2477:                return colAliasToString(alias, pred) + "=" + qval;
2478:            }
2479:
2480:            public String genSQLQualParam(int alias, char pred) {
2481:                return colAliasToString(alias, pred) + "=?";
2482:            }
2483:
2484:            public String genSQLQualGraphId(int alias, int graphId) {
2485:                return colAliasToString(alias, 'G') + "=" + graphId;
2486:            }
2487:
2488:            public String genSQLJoin(int lhsAlias, char lhsCol, int rhsAlias,
2489:                    char rhsCol) {
2490:                return colAliasToString(lhsAlias, lhsCol) + "="
2491:                        + colAliasToString(rhsAlias, rhsCol);
2492:            }
2493:
2494:            public String genSQLStringMatch(int alias, char col, String fun,
2495:                    String stringToMatch) {
2496:                boolean ignCase = fun
2497:                        .equals(ExpressionFunctionURIs.J_startsWithInsensitive)
2498:                        || fun
2499:                                .equals(ExpressionFunctionURIs.J_endsWithInsensitive)
2500:                        || fun
2501:                                .equals(ExpressionFunctionURIs.J_containsInsensitive);
2502:                boolean pfxMatch = fun
2503:                        .equals(ExpressionFunctionURIs.J_startsWith)
2504:                        || fun
2505:                                .equals(ExpressionFunctionURIs.J_startsWithInsensitive);
2506:                String var = colAliasToString(alias, col);
2507:                // generate string match operation for short literal or URI
2508:                String qual = " ( " + genSQLStringMatchLHS(ignCase, var);
2509:                qual += " " + genSQLStringMatchOp(ignCase, fun);
2510:                qual += " "
2511:                        + genSQLStringMatchRHS(ignCase, pfxMatch, stringToMatch);
2512:                // now match long URI or Bnode or, if object col, long literal
2513:                qual += " " + genSQLOrKW() + genSQLStringMatchLHS(false, var);
2514:                qual += " " + genSQLStringMatchOp(false, fun);
2515:                qual += " " + genSQLStringMatchLong() + " )";
2516:
2517:                return qual;
2518:            }
2519:
2520:            public String genSQLStringMatchLHS(boolean ignCase, String var) {
2521:                return ignCase ? genSQLStringMatchLHS_IC(var) : var;
2522:            }
2523:
2524:            public String genSQLStringMatchLong() {
2525:                return QUOTE_CHAR + stringMatchAnyChar() + stringMatchLongObj()
2526:                        + stringMatchAllChar() + QUOTE_CHAR;
2527:            }
2528:
2529:            public String genSQLStringMatchOp(boolean ignCase, String fun) {
2530:                return ignCase ? genSQLStringMatchOp_IC(fun)
2531:                        : genSQLStringMatchOp(fun);
2532:            }
2533:
2534:            public String stringMatchAllChar() {
2535:                return "%";
2536:            }
2537:
2538:            public String stringMatchAnyChar() {
2539:                return "_";
2540:            }
2541:
2542:            public String stringMatchEscapeChar() {
2543:                return "\\\\";
2544:            }
2545:
2546:            public String stringMatchLongObj() {
2547:                return "r";
2548:            }
2549:
2550:            public String stringMatchShortObj() {
2551:                return "v";
2552:            }
2553:
2554:            public String genSQLStringMatchRHS(boolean ignCase,
2555:                    boolean pfxMatch, String strToMatch) {
2556:                boolean isEscaped = stringMatchNeedsEscape(strToMatch);
2557:                if (isEscaped)
2558:                    strToMatch = addEscape(strToMatch);
2559:                // for now, don't optimize for prefix match
2560:                /*
2561:                strToMatch = pfxMatch ? strToMatch + stringMatchAllChar() : 
2562:                				stringMatchAllChar() + strToMatch;
2563:                strToMatch = stringMatchAllChar() + strToMatch;
2564:                strToMatch = nodeToRDBString(Node.createLiteral(strToMatch),false);
2565:                if ( pfxMatch && STRINGS_TRIMMED ) 
2566:                	strToMatch = strToMatch.substring(0,strToMatch.length()-1);
2567:                 */
2568:                strToMatch = stringMatchAnyChar() + stringMatchShortObj()
2569:                        + stringMatchAllChar() + strToMatch
2570:                        + stringMatchAllChar();
2571:                strToMatch = QUOTE_CHAR + strToMatch + QUOTE_CHAR;
2572:                String qual = ignCase ? genSQLStringMatchRHS_IC(strToMatch)
2573:                        : strToMatch;
2574:                if (isEscaped)
2575:                    qual += genSQLStringMatchEscape();
2576:
2577:                return qual;
2578:            }
2579:
2580:            public String genSQLStringMatchLHS_IC(String var) {
2581:                return var;
2582:            }
2583:
2584:            public String genSQLStringMatchRHS_IC(String strToMatch) {
2585:                return strToMatch;
2586:            }
2587:
2588:            public String genSQLStringMatchOp(String fun) {
2589:                return genSQLLikeKW();
2590:            }
2591:
2592:            public String genSQLStringMatchOp_IC(String fun) {
2593:                return genSQLLikeKW();
2594:            }
2595:
2596:            public boolean stringMatchNeedsEscape(String strToMatch) {
2597:                return strToMatch.indexOf('_') >= 0;
2598:            }
2599:
2600:            public String addEscape(String strToMatch) {
2601:                int i = strToMatch.indexOf('_');
2602:                return strToMatch.substring(0, i) + stringMatchEscapeChar()
2603:                        + strToMatch.substring(i);
2604:            }
2605:
2606:            public String genSQLStringMatchEscape() {
2607:                return "";
2608:            }
2609:
2610:            public String genSQLResList(int resIndex[], VarDesc[] binding) {
2611:                String resList = "";
2612:                int i, j;
2613:                for (i = 0, j = 0; i < binding.length; i++) {
2614:                    VarDesc b = binding[i];
2615:                    if (!b.isArgVar()) {
2616:                        // next result variable
2617:                        resList += (j > 0 ? ", " : "")
2618:                                + colAliasToString(b.alias, b.column);
2619:                        if (j >= resIndex.length)
2620:                            throw new JenaException("Too many result columns");
2621:                        resIndex[j++] = b.mapIx;
2622:                    }
2623:                }
2624:                return resList;
2625:            }
2626:
2627:            public String genSQLFromList(int aliasCnt, String table) {
2628:                int i;
2629:                String resList = "";
2630:                for (i = 0; i < aliasCnt; i++) {
2631:                    resList += (i > 0 ? ", " : "") + table + " "
2632:                            + aliasToString(i);
2633:                }
2634:                return resList;
2635:
2636:            }
2637:
2638:            public String genSQLLikeKW() {
2639:                return "Like ";
2640:            }
2641:
2642:            public String genSQLEscapeKW() {
2643:                return "Escape ";
2644:            }
2645:
2646:            public String genSQLSelectKW() {
2647:                return "Select ";
2648:            }
2649:
2650:            public String genSQLFromKW() {
2651:                return "From ";
2652:            }
2653:
2654:            public String genSQLWhereKW() {
2655:                return "Where ";
2656:            }
2657:
2658:            public String genSQLOrKW() {
2659:                return "Or ";
2660:            }
2661:
2662:            public String genSQLSelectStmt(String res, String from, String qual) {
2663:                return genSQLSelectKW() + res + " " + genSQLFromKW() + from
2664:                        + " " + (qual.length() == 0 ? qual : genSQLWhereKW())
2665:                        + qual;
2666:            }
2667:
2668:            protected int getTableCount(int graphId) {
2669:                ResultSet alltables = null;
2670:                try {
2671:                    DatabaseMetaData dbmd = m_dbcon.getConnection()
2672:                            .getMetaData();
2673:                    String[] tableTypes = { "TABLE" };
2674:                    int res = 0;
2675:                    String tblPattern = TABLE_NAME_PREFIX + "g"
2676:                            + Integer.toString(graphId) + "%";
2677:                    tblPattern = stringToDBname(tblPattern);
2678:                    alltables = dbmd.getTables(null, null, tblPattern,
2679:                            tableTypes);
2680:                    while (alltables.next()) {
2681:                        res += 1;
2682:                    }
2683:                    return res;
2684:                } catch (SQLException e1) {
2685:                    throw new RDFRDBException("Internal SQL error in driver - "
2686:                            + e1);
2687:                } finally {
2688:                    if (alltables != null)
2689:                        try {
2690:                            alltables.close();
2691:                        } catch (SQLException e1) {
2692:                            throw new RDFRDBException(
2693:                                    "Failed to get last inserted ID: " + e1);
2694:                        }
2695:                }
2696:            }
2697:
2698:            /*
2699:             * getters and setters for database options
2700:             */
2701:
2702:            public int getLongObjectLengthMax() {
2703:                return LONG_OBJECT_LENGTH_MAX;
2704:            }
2705:
2706:            public int getLongObjectLength() {
2707:                return LONG_OBJECT_LENGTH;
2708:            }
2709:
2710:            public void setLongObjectLength(int len) {
2711:                checkDbUninitialized();
2712:                if (len > LONG_OBJECT_LENGTH_MAX)
2713:                    throw new JenaException(
2714:                            "LongObjectLength exceeds maximum value for database ("
2715:                                    + +LONG_OBJECT_LENGTH_MAX + ")");
2716:                LONG_OBJECT_LENGTH = len;
2717:            }
2718:
2719:            public int getIndexKeyLengthMax() {
2720:                return INDEX_KEY_LENGTH_MAX;
2721:            }
2722:
2723:            public int getIndexKeyLength() {
2724:                return INDEX_KEY_LENGTH;
2725:            }
2726:
2727:            public void setIndexKeyLength(int len) {
2728:                checkDbUninitialized();
2729:                if (len > INDEX_KEY_LENGTH_MAX)
2730:                    throw new JenaException(
2731:                            "IndexKeyLength exceeds maximum value for database ("
2732:                                    + INDEX_KEY_LENGTH_MAX + ")");
2733:                INDEX_KEY_LENGTH = len;
2734:            }
2735:
2736:            public boolean getIsTransactionDb() {
2737:                return IS_XACT_DB;
2738:            }
2739:
2740:            public void setIsTransactionDb(boolean bool) {
2741:                checkDbUninitialized();
2742:                if (bool == false)
2743:                    throw new JenaException(
2744:                            "setIsTransactionDb unsupported for this database engine");
2745:            }
2746:
2747:            public boolean getDoCompressURI() {
2748:                return URI_COMPRESS;
2749:            }
2750:
2751:            public void setDoCompressURI(boolean bool) {
2752:                checkDbUninitialized();
2753:                URI_COMPRESS = bool;
2754:            }
2755:
2756:            public int getCompressURILength() {
2757:                return URI_COMPRESS_LENGTH;
2758:            }
2759:
2760:            public void setCompressURILength(int len) {
2761:                checkDbUninitialized();
2762:                URI_COMPRESS_LENGTH = len;
2763:            }
2764:
2765:            public boolean getDoDuplicateCheck() {
2766:                return !SKIP_DUPLICATE_CHECK;
2767:            }
2768:
2769:            public void setDoDuplicateCheck(boolean bool) {
2770:                SKIP_DUPLICATE_CHECK = !bool;
2771:            }
2772:
2773:            protected boolean dbIsOpen() {
2774:                return (m_sysProperties != null);
2775:            }
2776:
2777:            protected void checkDbIsOpen() {
2778:                if (!dbIsOpen())
2779:                    throw new JenaException("Database not open");
2780:            }
2781:
2782:            protected void checkDbUninitialized() {
2783:                if (dbIsOpen() || isDBFormatOK())
2784:                    throw new JenaException(
2785:                            "Database configuration option cannot be set after database is formatted");
2786:            }
2787:
2788:            public String getTableNamePrefix() {
2789:                return TABLE_NAME_PREFIX;
2790:            }
2791:
2792:            public void setTableNamePrefix(String prefix) {
2793:                if (dbIsOpen())
2794:                    throw new JenaException(
2795:                            "Table name prefix must be set before opening or connecting to a model.");
2796:                /* sanity check that the new prefix length is not too long.
2797:                 * we have to add a few characters to the given prefix to
2798:                 * account for the index names (see the createStatementTable
2799:                 * template in the etc/<db>.sql files).
2800:                 */
2801:                String sav = TABLE_NAME_PREFIX;
2802:                String testpfx = prefix;
2803:                int i;
2804:                for (i = 0; i < MAXIMUM_INDEX_COLUMNS; i++)
2805:                    testpfx += "X";
2806:                setTableNames(testpfx);
2807:                // now see if the table names will be too long with this "prefix".
2808:                try {
2809:                    String s = genTableName(10, 10, true);
2810:                    s = genTableName(10, 10, false);
2811:                } catch (RDFRDBException e) {
2812:                    setTableNames(sav);
2813:                    throw new JenaException("New prefix (\"" + prefix
2814:                            + "\") is too long and will cause table names \n"
2815:                            + "to exceed maximum length for database ("
2816:                            + TABLE_NAME_LENGTH_MAX + ").");
2817:                }
2818:                // all ok. switch to the new prefix.
2819:                setTableNames(prefix);
2820:            }
2821:
2822:            /** generate a table name and verify that it does not
2823:             * exceed the maximum length.
2824:             */
2825:
2826:            protected String genTableName(int graphId, int tblId, boolean isReif) {
2827:                String res = stringToDBname(TABLE_NAME_PREFIX
2828:                        + "g"
2829:                        + Integer.toString(graphId)
2830:                        + "t"
2831:                        + Integer.toString(tblId)
2832:                        + (isReif ? REIF_TABLE_NAME_SUFFIX
2833:                                : STMT_TABLE_NAME_SUFFIX));
2834:                if (res.length() > TABLE_NAME_LENGTH_MAX)
2835:                    throw new RDFRDBException("New table name (\"" + res
2836:                            + "\") exceeds maximum length for database ("
2837:                            + TABLE_NAME_LENGTH_MAX + ").");
2838:                return res;
2839:            }
2840:
2841:            /** Names of jena system tables.
2842:            protected String [] SYSTEM_TABLE_NAME; */
2843:
2844:            protected void setTableNames(String prefix) {
2845:                TABLE_NAME_PREFIX = stringToDBname(prefix);
2846:                int i = 0;
2847:                SYSTEM_TABLE_NAME = new String[6];
2848:                SYSTEM_TABLE_NAME[i++] = SYSTEM_STMT_TABLE = stringToDBname(TABLE_NAME_PREFIX
2849:                        + "sys_stmt");
2850:                SYSTEM_TABLE_NAME[i++] = LONG_LIT_TABLE = stringToDBname(TABLE_NAME_PREFIX
2851:                        + "long_lit");
2852:                SYSTEM_TABLE_NAME[i++] = LONG_URI_TABLE = stringToDBname(TABLE_NAME_PREFIX
2853:                        + "long_uri");
2854:                SYSTEM_TABLE_NAME[i++] = PREFIX_TABLE = stringToDBname(TABLE_NAME_PREFIX
2855:                        + "prefix");
2856:                SYSTEM_TABLE_NAME[i++] = GRAPH_TABLE = stringToDBname(TABLE_NAME_PREFIX
2857:                        + "graph");
2858:                SYSTEM_TABLE_NAME[i++] = MUTEX_TABLE = stringToDBname(TABLE_NAME_PREFIX
2859:                        + "mutex");
2860:                SYSTEM_TABLE_CNT = i;
2861:            }
2862:
2863:            /**
2864:             * Return the number of system tables.
2865:             */
2866:
2867:            public int getSystemTableCount() {
2868:                return SYSTEM_TABLE_CNT;
2869:            }
2870:
2871:            /**
2872:             * Return the name of a system table
2873:             */
2874:
2875:            public String getSystemTableName(int i) {
2876:                return ((i < 0) || (i >= SYSTEM_TABLE_CNT)) ? null
2877:                        : SYSTEM_TABLE_NAME[i];
2878:            }
2879:
2880:            public String getStoreWithModel() {
2881:                return STORE_WITH_MODEL;
2882:            }
2883:
2884:            public void setStoreWithModel(String modelName) {
2885:                String name = null;
2886:                if ((modelName != null) && !modelName.equals(""))
2887:                    name = modelName;
2888:                STORE_WITH_MODEL = name;
2889:            }
2890:
2891:            public int getCompressCacheSize() {
2892:                checkDbIsOpen();
2893:                return prefixCache.getLimit();
2894:            }
2895:
2896:            public void setCompressCacheSize(int count) {
2897:                checkDbIsOpen();
2898:                prefixCache.setLimit(count);
2899:            }
2900:
2901:        }
2902:
2903:        /*
2904:         *  (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
2905:         *  All rights reserved.
2906:         *
2907:         * Redistribution and use in source and binary forms, with or without
2908:         * modification, are permitted provided that the following conditions
2909:         * are met:
2910:         * 1. Redistributions of source code must retain the above copyright
2911:         *    notice, this list of conditions and the following disclaimer.
2912:         * 2. Redistributions in binary form must reproduce the above copyright
2913:         *    notice, this list of conditions and the following disclaimer in the
2914:         *    documentation and/or other materials provided with the distribution.
2915:         * 3. The name of the author may not be used to endorse or promote products
2916:         *    derived from this software without specific prior written permission.
2917:
2918:         * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2919:         * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2920:         * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2921:         * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2922:         * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2923:         * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2924:         * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2925:         * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2926:         * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2927:         * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2928:         */
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.