KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > hp > hpl > jena > db > impl > DriverRDB


1 /*
2   (c) Copyright 2003, 2004, 2005 Hewlett-Packard Development Company, LP
3   [See end of file]
4 */

5
6 package com.hp.hpl.jena.db.impl;
7
8 import java.sql.Connection JavaDoc;
9 import java.sql.DatabaseMetaData JavaDoc;
10 import java.sql.PreparedStatement JavaDoc;
11 import java.sql.ResultSet JavaDoc;
12 import java.sql.SQLException JavaDoc;
13 import java.util.ArrayList JavaDoc;
14 import java.util.Iterator JavaDoc;
15 import java.util.List JavaDoc;
16 import java.util.zip.CRC32 JavaDoc;
17 import java.lang.Thread JavaDoc;
18
19 import com.hp.hpl.jena.datatypes.RDFDatatype;
20 import com.hp.hpl.jena.datatypes.TypeMapper;
21 import com.hp.hpl.jena.db.GraphRDB;
22 import com.hp.hpl.jena.db.IDBConnection;
23 import com.hp.hpl.jena.db.RDFRDBException;
24 import com.hp.hpl.jena.graph.Graph;
25 import com.hp.hpl.jena.graph.Node;
26 import com.hp.hpl.jena.graph.Node_Literal;
27 import com.hp.hpl.jena.graph.Node_URI;
28 import com.hp.hpl.jena.graph.Node_Variable;
29 import com.hp.hpl.jena.graph.impl.LiteralLabel;
30 import com.hp.hpl.jena.graph.query.ExpressionFunctionURIs;
31
32 import com.hp.hpl.jena.rdf.model.AnonId;
33 import com.hp.hpl.jena.shared.*;
34
35 import com.hp.hpl.jena.vocabulary.RDF;
36
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.apache.xerces.util.XMLChar;
40
41 //=======================================================================
42
/**
43 * Base database driver for implementing SpecializedGraphs.
44 * Different drivers are needed for different databases and different
45 * layout schemes.
46 * <p>
47 * This driver is a base implemention from which database-specific
48 * drivers can inherit. It is not generic in the sense that it will work
49 * on any minimal SQL store and so should be treated as if it were
50 * an abstract class.
51 * <p>The SQL statements which implement each of the functions are
52 * loaded in a separate file etc/[layout]_[database].sql from the classpath.
53 *
54 * @author hkuno modification of Jena1 code by Dave Reynolds (der)
55 * @version $Revision: 1.49 $ on $Date: 2005/04/15 11:11:39 $
56 */

57
58 public abstract class DriverRDB implements IRDBDriver {
59
60 //=======================================================================
61
// Cutomization variables
62
// =======================================================================
63
/**
64     * This Graph's db properties
65     */

66    protected DBPropDatabase m_dbProps;
67     
68    /**
69    * Name of this class's PSet_TripleStore_XXX class
70    */

71   protected String JavaDoc m_psetClassName;
72
73   /**
74   * Name of this class's PSet_TripleStore_XXX class
75   */

76  protected String JavaDoc m_psetReifierClassName;
77
78    /**
79     * Cached name of this class's SpecializedGraph_XXX class
80     */

81    protected String JavaDoc m_lsetClassName;
82    
83    /**
84     * Cached name of this class's SpecializedGraphReifer_XXX class
85     */

86    protected String JavaDoc m_lsetReifierClassName;
87    
88    /** The class name of the database driver (e.g. jdbc.sql.class)*/
89    protected String JavaDoc DRIVER_NAME;
90    // Dummy - needs replacing when instantiated?
91

92    /** The name of the database type this driver supports */
93    protected String JavaDoc DATABASE_TYPE;
94
95    /** The maximum size of index key (or a component of a key) */
96    protected int INDEX_KEY_LENGTH;
97
98    /** The maximum possible value for INDEX_KEY_LENGTH (db-dependent) */
99    protected int INDEX_KEY_LENGTH_MAX;
100
101    /** true if graphs using this database instance supports transactions.
102     * this is a user settable parameter. the underlying db engine may support
103     * transactions but an application may prefer to run without transactions
104     * for better performance. this can only be set before the db is formatted.
105     */

106    protected boolean IS_XACT_DB;
107
108    
109    protected boolean STRINGS_TRIMMED;
110    /** true if the database engine will trim trailing spaces in strings. to
111     * prevent this, append EOS to strings that should not be trimmed.
112     */

113    
114    protected String JavaDoc EOS = "";
115    protected char EOS_CHAR = ':';
116    protected int EOS_LEN = 0;
117    /** EOS is appended to most RDB strings to deal with string trimming. if
118     * STRINGS_TRIMMED is false, EOS is null. otherwise, EOS is EOS_CHAR.
119     * EOS_LEN is the length of EOS (0 or 1).
120     */

121    
122    protected char QUOTE_CHAR = '\"';
123    /** the quote character used to delimit characters and strings.
124     */

125    
126    /**
127     * Indicates whether search pattern used to select system objects by name should be upper-case.
128     */

129    protected boolean DB_NAMES_TO_UPPER = false;
130   
131
132    /** true if URI's are to be compressed by storing prefixes (an approximation
133     * of a namespace) in the JENA_PREFIX table. note that "short" prefixes are
134     * not stored, i.e., the prefix length not more than URI_COMPRESS_LENGTH.
135     */

136    protected boolean URI_COMPRESS;
137
138    
139    protected int URI_COMPRESS_LENGTH = 100;
140    /** if URI_COMPRESS is true, compress prefixes that are longer than this.
141
142    /** The maximum size of an object that can be stored in a Statement table */

143    protected int LONG_OBJECT_LENGTH;
144    
145    /** The maximum possible value for LONG_OBJECT_LENGTH (db-dependent) */
146    protected int LONG_OBJECT_LENGTH_MAX;
147
148    /** The SQL type to use for storing ids (compatible with wrapDBID) */
149    protected String JavaDoc ID_SQL_TYPE;
150    
151    /** Set to true if the insert operations already check for duplications */
152    protected boolean SKIP_DUPLICATE_CHECK;
153
154    /** Set to true if IDs are allocated prior to insert */
155    protected boolean PRE_ALLOCATE_ID;
156     
157    /** The name of the sql definition file for this database/layout combo */
158    protected String JavaDoc SQL_FILE;
159    
160    /** The name of the sql definition file for this database/layout combo */
161    protected String JavaDoc DEFAULT_SQL_FILE = "etc/generic_generic.sql";
162       
163    
164 // =======================================================================
165
// Common variables
166
// =======================================================================
167
/**
168     * Holds prefix for names of Jena database tables.
169     */

170    protected String JavaDoc TABLE_NAME_PREFIX = "jena_";
171    
172    /**
173     * Holds maximum length of table and index names in database.
174     */

175    protected int TABLE_NAME_LENGTH_MAX;
176       
177    /** Suffixes for asserted and reified table names. */
178    protected String JavaDoc STMT_TABLE_NAME_SUFFIX = "_stmt";
179    protected String JavaDoc REIF_TABLE_NAME_SUFFIX = "_reif";
180    
181    /** Maximum number of index columns. can be changed. */
182    protected int MAXIMUM_INDEX_COLUMNS = 3;
183   
184    /** Number of required system tables. */
185    protected int SYSTEM_TABLE_CNT = 0;
186    
187    /** Names of jena system tables. */
188    public String JavaDoc [] SYSTEM_TABLE_NAME;
189   
190    /** Set to true to enable cache of pre-prepared statements */
191    protected boolean CACHE_PREPARED_STATEMENTS = true;
192
193    /** The name of the layout type this driver supports */
194    protected String JavaDoc LAYOUT_TYPE = "TripleStore";
195
196    /** Default name of the table that holds system property graph asserted statements **/
197    protected String JavaDoc SYSTEM_STMT_TABLE;
198    
199    /** Name of the long literal table **/
200    protected String JavaDoc LONG_LIT_TABLE;
201    
202    /** Name of the long URI table **/
203    protected String JavaDoc LONG_URI_TABLE;
204
205    /** Name of the prefix table **/
206    protected String JavaDoc PREFIX_TABLE;
207
208       /** Name of the graph table **/
209    protected String JavaDoc GRAPH_TABLE;
210     
211    /** Name of the mutex table **/
212    protected String JavaDoc MUTEX_TABLE;
213     
214     /** If not null, newly-created graphs share tables with the identified graph **/
215    protected String JavaDoc STORE_WITH_MODEL = null;
216     
217    /** Name of the graph holding default properties (the one's that a newly-created
218     * graph will have by default **/

219    protected final String JavaDoc DEFAULT_PROPS = "JENA_DEFAULT_GRAPH_PROPERTIES";
220    
221    /** Unique numeric identifier of the graph holding default properties **/
222    protected final int DEFAULT_ID = 0;
223
224         
225    /** Driver version number */
226    protected final String JavaDoc VERSION = "2.0alpha";
227    
228    /** Database layout version */
229    protected String JavaDoc LAYOUT_VERSION = "2.0";
230    
231    protected static Log logger = LogFactory.getLog( PSet_ReifStore_RDB.class );
232     
233 // =======================================================================
234
// Instance variables
235
// =======================================================================
236

237     /**
238      * Instance of SQLCache used by Driver for hard-coded db commands
239      */

240     protected SQLCache m_sql = null;
241
242     /** Cache a reference to the system property graph (java) **/
243     protected SpecializedGraph m_sysProperties = null;
244     
245     protected IDBConnection m_dbcon = null;
246     
247     protected LRUCache prefixCache = null;
248     
249     public static final int PREFIX_CACHE_SIZE = 50;
250     
251     //===================================
252
// for transaction support
253
//===================================
254

255     
256     // caches whether or not underlying connection supports transactions
257
private Boolean JavaDoc m_transactionsSupported;
258     
259     /** flag to indicate that there is a transaction active on the associated connection */
260     private boolean inTransaction = false;
261
262
263
264 // =======================================================================
265
// Constructor
266
// =======================================================================
267

268
269     /**
270      * Create a bare instance of the driver. It is not functional until a
271      * database connection has been supplied via setConnection.
272      */

273     public DriverRDB() {
274     }
275     
276 // =======================================================================
277
// Methods
278
// =======================================================================
279

280     /**
281      * Return the connection
282      */

283     public IDBConnection getConnection() {
284         return m_dbcon;
285     }
286     
287     /**
288      * Return the specialized graph used to store system properties.
289      * (Constuct a new one if necessary). if the database is not
290      * properly formatted, then if doInit is true, the database will
291      * be formatted, else null is returned and the (unformatted
292      * database is unchanged).
293      */

294     public SpecializedGraph getSystemSpecializedGraph(boolean doInit) {
295
296         SpecializedGraph res = null;
297         
298         if (m_sysProperties != null) {
299             return m_sysProperties;
300         }
301
302         if (!isDBFormatOK()) {
303             // another thread could be formatting database
304
// so get the mutex and try again
305
lockDB();
306             if (!isDBFormatOK()) {
307                 if (doInit) {
308                     try {
309                         // Format the DB
310
// throw new JenaException("The database is not
311
// formatted.\n");
312
doCleanDB(false);
313                         prefixCache = new LRUCache(PREFIX_CACHE_SIZE);
314                         res = formatAndConstructSystemSpecializedGraph();
315                     } catch (Exception JavaDoc e) {
316                         unlockDB();
317                         // We see an error during format testing, might be
318
// a dead connection rather than an unformated
319
// database so abort
320
throw new JenaException(
321                         "The database appears to be unformatted or corrupted and\n"
322                         + "an attempt to automatically format the database has failed\n", e);
323                     }
324                 }
325                 unlockDB();
326                 return res;
327             }
328             // after second try, DB is found to be correctly formatted.
329
unlockDB();
330         }
331
332         prefixCache = new LRUCache(PREFIX_CACHE_SIZE);
333         getDbInitTablesParams(); //this call is a hack. it's needed because
334
// it has the side effect of initializing some vars (e.g., EOS).
335
IPSet pSet = createIPSetInstanceFromName(m_psetClassName,
336                 SYSTEM_STMT_TABLE);
337         m_sysProperties = createLSetInstanceFromName(m_lsetClassName, pSet,
338                 DEFAULT_ID);
339         m_dbProps = new DBPropDatabase(m_sysProperties);
340
341         // now reset the configuration parameters
342
checkEngine(m_dbProps);
343         checkDriverVersion(m_dbProps);
344         checkLayoutVersion(m_dbProps);
345         String JavaDoc val = m_dbProps.getLongObjectLength();
346         if (val == null)
347             throwBadFormat("long object length");
348         else
349             LONG_OBJECT_LENGTH = Integer.parseInt(val);
350         val = m_dbProps.getIndexKeyLength();
351         if (val == null)
352             throwBadFormat("index key length");
353         else
354             INDEX_KEY_LENGTH = Integer.parseInt(val);
355         val = m_dbProps.getIsTransactionDb();
356         if (val == null)
357             throwBadFormat("database supports transactions");
358         else
359             IS_XACT_DB = Boolean.valueOf(val).booleanValue();
360         val = m_dbProps.getDoCompressURI();
361         if (val == null)
362             throwBadFormat("compress URIs");
363         else
364             URI_COMPRESS = Boolean.valueOf(val).booleanValue();
365         val = m_dbProps.getCompressURILength();
366         if (val == null)
367             throwBadFormat("URI compress length");
368         else
369             URI_COMPRESS_LENGTH = Integer.parseInt(val);
370         val = m_dbProps.getTableNamePrefix();
371         if (val == null)
372             throwBadFormat("table name prefix");
373         else
374             TABLE_NAME_PREFIX = val;
375
376         return m_sysProperties;
377     }
378     
379     private void checkEngine ( DBProp dbProps ) {
380         String JavaDoc dbtype = m_dbProps.getEngineType();
381         if ( dbtype == null ) throwBadFormat("database type");
382         if ( !dbtype.equals(DATABASE_TYPE) ) {
383             throw new JenaException(
384             "Database created with incompatible database type for this version of Jena: "
385             + dbtype);
386         }
387     }
388     
389     private void checkDriverVersion ( DBProp dbProps ) {
390         String JavaDoc vers = m_dbProps.getDriverVersion();
391         if ( vers == null ) throwBadFormat("database version");
392         if ( !vers.equals(VERSION) ) {
393             throw new JenaException(
394             "Models in the database were created with an incompatible version of Jena: "
395             + vers);
396         }
397     }
398     
399     private void checkLayoutVersion ( DBProp dbProps ) {
400         String JavaDoc layout = m_dbProps.getLayoutVersion();
401         if ( layout == null ) throwBadFormat("database layout");
402         if ( !layout.equals(LAYOUT_VERSION) ) {
403             throw new JenaException(
404             "The database layout cannot be processed by this version of Jena: "
405             + layout);
406         }
407
408     }
409     
410     private void throwBadFormat ( String JavaDoc prop ) {
411         throw new JenaException(
412         "The database appears to be unformatted or corrupted - could not find value\n" +
413         " for \"" + prop + "\" in Jena system properties table.\n" +
414         "If possible, call IDBConnection.cleanDB(). \n" +
415         "Warning: cleanDB will remove all Jena models from the databases.");
416     }
417
418     
419     /**
420      * Format the database and construct a brand new system specialized graph.
421      */

422     protected SpecializedGraph formatAndConstructSystemSpecializedGraph() {
423         String JavaDoc errMsg = null;
424         if (xactOp(xactIsActive))
425             throw new RDFRDBException(
426                     "Cannot intialize database while transaction is active.\n"
427                             + "Commit or abort transaction before intializing database.");
428
429         boolean autoIsOn = xactOp(xactAutoOff);
430         try {
431             String JavaDoc[] params = getDbInitTablesParams();
432             m_sql.runSQLGroup("initDBtables", params);
433             m_sql.runSQLGroup("initDBgenerators");// m_sql.runSQLGroup("initDBprocedures");
434
} catch (SQLException JavaDoc e) {
435             logger.warn("Problem formatting database", e);
436             errMsg = e.toString();
437         }
438
439         if (errMsg == null)
440             try {
441                 xactOp(xactCommit);
442                 xactOp(xactBegin);
443
444                 // Construct the system properties
445
IPSet pSet = createIPSetInstanceFromName(m_psetClassName,
446                         SYSTEM_STMT_TABLE);
447                 m_sysProperties = createLSetInstanceFromName(m_lsetClassName,
448                         pSet, DEFAULT_ID);
449
450                 // The following call constructs a new set of database
451
// properties and
452
// adds them to the m_sysProperties specialized graph.
453
m_dbProps = new DBPropDatabase(m_sysProperties, m_dbcon
454                         .getDatabaseType(), VERSION, LAYOUT_VERSION, String
455                         .valueOf(LONG_OBJECT_LENGTH), String
456                         .valueOf(INDEX_KEY_LENGTH), String.valueOf(IS_XACT_DB),
457                         String.valueOf(URI_COMPRESS), String
458                                 .valueOf(URI_COMPRESS_LENGTH),
459                         TABLE_NAME_PREFIX);
460
461                 // Now we also need to construct the parameters that will be the
462
// default settings for any graph added to this database
463
DBPropGraph def_prop = new DBPropGraph(m_sysProperties,
464                         DEFAULT_PROPS, "generic");
465
466                 def_prop.addGraphId(DEFAULT_ID);
467
468                 xactOp(xactCommit);
469                 if (autoIsOn)
470                     xactOp(xactAutoOn);
471             } catch (Exception JavaDoc e) {
472                 errMsg = e.toString();
473             }
474
475         if (errMsg != null) {
476             doCleanDB(false);
477             m_sysProperties = null;
478             throw new RDFRDBException(errMsg);
479         }
480
481         return m_sysProperties;
482     }
483     
484     abstract String JavaDoc[] getDbInitTablesParams();
485     
486     abstract String JavaDoc[] getCreateTableParams( int graphId, boolean isReif );
487     
488     abstract public int graphIdAlloc ( String JavaDoc graphName );
489     
490     
491     
492     /**
493      * Construct and return a new specialized graph.
494      */

495     public List JavaDoc createSpecializedGraphs(String JavaDoc graphName,
496             Graph requestedProperties) {
497
498         /*
499          * create the specialized graphs for the new graph. this includes
500          * updating the database for the new graph (allocating a new graph
501          * identifier, updating the jena system tables and creating tables, if
502          * necessary. this should be done atomically to avoid corrupting the
503          * database but a single transaction is not sufficient because some
504          * database engines (e.g., oracle) require create table statements to
505          * run as a separate transaction, i.e., a create table statement in the
506          * middle of a group of updates will cause an automatic commit of the
507          * updates prior to the create table statement.
508          *
509          * fortunately, we can run most of the updates in a single transaction.
510          * however, allocation of the graph indentifier must be done prior to
511          * creating the statement tables. so, if any subsequent operation fails,
512          * we must run a compensating transaction to deallocate the graph
513          * identifier.
514          *
515          * because of the above, we assume that there is no active transaction
516          * when this routine is called.
517          */

518
519         // String graphName = graphProperties.getName();
520
String JavaDoc stmtTbl = null;
521         String JavaDoc reifTbl = null;
522         String JavaDoc dbSchema = STORE_WITH_MODEL;
523         boolean didGraphIdAlloc = false;
524         boolean didTableCreate = false;
525         String JavaDoc errMsg = null;
526         DBPropGraph graphProperties = null;
527
528         SpecializedGraph sysGraph = getSystemSpecializedGraph(false);
529         // should have already create sys graph.
530

531         if (xactOp(xactIsActive))
532             throw new RDFRDBException(
533                     "Cannot create graph while transaction is active.\n"
534                             + "Commit or abort transaction before creating graph");
535
536         boolean autoOn = xactOp(xactAutoOff);
537         int graphId = -1; // bogus initialization to make java happy
538

539         try {
540             xactOp(xactBegin);
541             graphId = graphIdAlloc(graphName);
542             didGraphIdAlloc = true;
543             xactOp(xactCommit);
544             xactOp(xactBegin);
545             boolean useDefault = false;
546
547             // dbSchema = graphProperties.getDBSchema();
548
// use the default schema if:
549
// 1) no schema is specified and we are creating the default
550
// (unnamed) graph
551
// 2) a schema is specified and it is the default (unnamed) graph
552
if (((dbSchema == null) && graphName.equals(GraphRDB.DEFAULT))) {
553                 useDefault = true;
554                 dbSchema = DEFAULT_PROPS; // default graph should use default
555
// tables
556
}
557             // else if ( ((dbSchema != null) &&
558
// dbSchema.equals(GraphRDB.DEFAULT)) ) {
559
// useDefault = true;
560
// dbSchema = DEFAULT_PROPS; // default graph should use default
561
// tables
562
// }
563
if (dbSchema != null) {
564                 DBPropGraph schProp = DBPropGraph.findPropGraphByName(sysGraph,
565                         dbSchema);
566                 if (schProp != null) {
567                     reifTbl = schProp.getReifTable();
568                     stmtTbl = schProp.getStmtTable();
569                 }
570                 if (((reifTbl == null) || (stmtTbl == null))
571                         && (useDefault == false))
572                     // schema not found. this is ok ONLY IF it's the DEFAULT
573
// schema
574
throw new RDFRDBException("Creating graph " + graphName
575                             + ": referenced schema not found: " + dbSchema);
576             }
577             if ((reifTbl == null) || (stmtTbl == null)) {
578                 didTableCreate = true;
579                 reifTbl = createTable(graphId, true);
580                 stmtTbl = createTable(graphId, false);
581                 if ((reifTbl == null) || (stmtTbl == null))
582                     throw new RDFRDBException("Creating graph " + graphName
583                             + ": cannot create tables");
584             }
585             xactOp(xactCommit); // may not be needed but it doesn't hurt
586
} catch (Exception JavaDoc e) {
587             errMsg = e.toString();
588         }
589
590         // we can now start a new transaction and update the metadata.
591
// we should already be committed but we commit again just in case
592

593         if (errMsg == null)
594             try {
595                 xactOp(xactBegin);
596
597                 graphProperties = new DBPropGraph(sysGraph, graphName,
598                         requestedProperties);
599                 graphProperties.addGraphId(graphId);
600                 graphProperties.addStmtTable(stmtTbl);
601                 graphProperties.addReifTable(reifTbl);
602
603                 DBPropDatabase dbprop = new DBPropDatabase(
604                         getSystemSpecializedGraph(true));
605                 dbprop.addGraph(graphProperties);
606
607                 // Add the reifier first
608
DBPropPSet pSetReifier = new DBPropPSet(m_sysProperties,
609                         m_psetReifierClassName, reifTbl);
610                 DBPropLSet lSetReifier = new DBPropLSet(m_sysProperties,
611                         "LSET_" + graphProperties.getName() + "_REIFIER",
612                         m_lsetReifierClassName);
613                 lSetReifier.setPSet(pSetReifier);
614                 graphProperties.addLSet(lSetReifier);
615
616                 // Now add support for all non-reified triples
617
DBPropPSet pSet = new DBPropPSet(m_sysProperties,
618                         m_psetClassName, stmtTbl);
619                 DBPropLSet lSet = new DBPropLSet(m_sysProperties, "LSET_"
620                         + graphProperties.getName(), m_lsetClassName);
621                 lSet.setPSet(pSet);
622                 graphProperties.addLSet(lSet);
623
624                 xactOp(xactCommit);
625                 if (autoOn) xactOp(xactAutoOn);
626             } catch (Exception JavaDoc e) {
627                 errMsg = e.toString();
628             }
629
630         if (errMsg == null)
631             return recreateSpecializedGraphs(graphProperties);
632         else {
633             xactOp(xactCommit); // maybe not needed but doesn't hurt
634
xactOp(xactBegin);
635             try {
636             // clean-up
637
if (didGraphIdAlloc) {
638                 graphIdDealloc(graphId);
639             }
640             } catch ( Exception JavaDoc e ) {
641             }
642             if (didTableCreate) {
643                 // make sure the order below matches
644
// the order of creation above.
645
if (reifTbl != null)
646                     try { deleteTable(reifTbl); }
647                     catch ( Exception JavaDoc e ) {};
648                 if (stmtTbl != null)
649                     try { deleteTable(stmtTbl); }
650                     catch ( Exception JavaDoc e ) {};
651             }
652             xactOp(xactCommit);
653             if (autoOn) xactOp(xactAutoOn);
654             return null;
655         }
656     }
657     
658     /**
659      * Construct and return a list of specialized graphs to match those in the
660      * store.
661      *
662      * @param graphProperties
663      * A set of customization properties for the graph.
664      */

665     public List JavaDoc recreateSpecializedGraphs(DBPropGraph graphProperties) {
666         
667         List JavaDoc result = new ArrayList JavaDoc();
668         int dbGraphId = graphProperties.getGraphId();
669
670         // to ensure that reifier graphs occur before stmt graphs, make two passes
671
String JavaDoc[] lsetTypes = {m_lsetClassName, m_lsetReifierClassName};
672         int i;
673         for(i=0;i<2;i++) {
674             Iterator JavaDoc it = graphProperties.getAllLSets();
675             while(it.hasNext() ) {
676                 DBPropLSet lSetProps = (DBPropLSet)it.next();
677                 if ( lSetProps.getType().equals(lsetTypes[i]) ) continue;
678                 DBPropPSet pSetProps = lSetProps.getPset();
679
680                 IPSet pSet = createIPSetInstanceFromName(pSetProps.getType(), pSetProps.getTable());
681                 result.add( createLSetInstanceFromName( lSetProps.getType(), pSet, dbGraphId));
682             }
683         }
684         
685         return result;
686     }
687     
688     /**
689      * Create a new IPSet instance of the named implementation class and set the db connection.
690      *
691      * @param pName name of a class that implements IPSet.
692      * @return an instance of the named class with the db connection set.
693      */

694     private IPSet createIPSetInstanceFromName(String JavaDoc className, String JavaDoc tblName) {
695         IPSet pSet = null;
696         try {
697             // get PSet
698
pSet = (IPSet) Class.forName(className).newInstance();
699             pSet.setDriver(this);
700             pSet.setSQLType(ID_SQL_TYPE);
701             pSet.setSkipDuplicateCheck(SKIP_DUPLICATE_CHECK);
702             pSet.setSQLCache(m_sql);
703             pSet.setCachePreparedStatements(CACHE_PREPARED_STATEMENTS);
704             pSet.setTblName(tblName);
705         } catch (Exception JavaDoc e) {
706             logger.warn("Unable to create IPSet instance ", e);
707         }
708         return pSet;
709     }
710         
711     private SpecializedGraph createLSetInstanceFromName(String JavaDoc lSetName, IPSet pset, int dbGraphID) {
712         SpecializedGraph sg = null;
713         try {
714             Class JavaDoc cls = Class.forName(lSetName);
715             Class JavaDoc[] params = {IPSet.class, Integer JavaDoc.class};
716             java.lang.reflect.Constructor JavaDoc con = cls.getConstructor(params);
717             Object JavaDoc[] args = {pset, new Integer JavaDoc(dbGraphID)};
718             sg = (SpecializedGraph) con.newInstance(args);
719         } catch (Exception JavaDoc e) {
720             logger.error("Unable to create instance of SpecializedGraph ", e);
721         }
722         return sg;
723     }
724
725     /**
726      * Remove the specialized graph, erasing all trace of a Graph.
727      * @param graphId The identity of the Graph which these specialized graphs should hold
728      * @param graphProperties The properties for the graph to be removed.
729      */

730     public void removeSpecializedGraphs( DBPropGraph graphProperties,
731         List JavaDoc specializedGraphs) {
732             
733         int graphId = graphProperties.getGraphId();
734         
735         if (xactOp(xactIsActive))
736             throw new RDFRDBException(
737                     "Cannot remove graph while transaction is active.\n"
738                     + "Commit or abort transaction before removing graph");
739
740         boolean autoIsOn = xactOp(xactAutoOff);
741         xactOp(xactCommit);
742         xactOp(xactBegin);
743         
744         // remove graph metadata from jena sys table in a xact
745
String JavaDoc stmtTbl = graphProperties.getStmtTable();
746         String JavaDoc reifTbl = graphProperties.getReifTable();
747         
748         // remove from system properties table
749
// It is sufficient just to remove the lSet properties (it will
750
// take care of deleting any pset properties automatically).
751
m_dbProps.removeGraph(graphProperties);
752         
753         if ( graphId != DEFAULT_ID ) graphIdDealloc(graphId);
754         
755         xactOp(xactCommit);
756         xactOp(xactBegin);
757         
758         /* now remove triples from statement tables.
759         * if the graph is stored in its own tables, we
760         * can simply delete those tables. else, the graph
761         * shares tables with other graphs so we have to
762         * remove each statement. */

763         
764         // check to see if statement tables for graph are shared
765
boolean stInUse = true;
766         boolean rtInUse = true;
767         
768         if ( graphId != DEFAULT_ID ) {
769             stInUse = false;
770             rtInUse = false;
771             Iterator JavaDoc it = m_dbProps.getAllGraphs();
772             while ( it.hasNext() ) {
773                 DBPropGraph gp = (DBPropGraph) it.next();
774                 if ( gp.getStmtTable().equals(stmtTbl) ) stInUse = true;
775                 if ( gp.getReifTable().equals(reifTbl) ) rtInUse = true;
776             }
777         }
778         // now remove the statement tables or else delete all triples.
779
if ( stInUse || rtInUse ) {
780             Iterator JavaDoc it = specializedGraphs.iterator();
781             while (it.hasNext()){
782                SpecializedGraph sg = (SpecializedGraph) it.next();
783                removeSpecializedGraph(sg);
784             }
785         } else {
786             deleteTable(stmtTbl);
787             deleteTable(reifTbl);
788         }
789         xactOp(xactCommit);
790         if ( autoIsOn ) xactOp(xactAutoOn);
791     }
792     
793     
794     /**
795      * Remove specialized graph from the datastore.
796      * @param graph is the graph to be removed.
797      */

798     private void removeSpecializedGraph(SpecializedGraph graph) {
799         graph.clear();
800     }
801
802     /**
803      * Method setDatabaseProperties.
804      *
805      * Sets the current properties for the database.
806      *
807      * @param databaseProperties is a Graph containing a full set of database properties
808      */

809     public void setDatabaseProperties(Graph databaseProperties) {
810         SpecializedGraph toGraph = getSystemSpecializedGraph(true);
811         // really need to start a transaction here
812

813         // Here add code to check if the database has been used - if so,
814
// it's too late to change the properties, so throw an exception
815

816         toGraph.clear();
817         SpecializedGraph.CompletionFlag complete = new SpecializedGraph.CompletionFlag();
818         toGraph.add(databaseProperties, complete);
819
820         // Now test the properties to see if it's a valid set - if not,
821
// throw an exception - it's okay to check some things later (there's
822
// no guarantee that every error will be caught here).
823

824         // end transaction here.
825
}
826
827         
828     /**
829      * Method getDefaultModelProperties
830      *
831      * Return the default properties for a new model stored in this database.
832      * If none are stored, then load default properties into the database.
833      * @return Graph containg the default properties for a new model
834      */

835     public DBPropGraph getDefaultModelProperties() {
836         SpecializedGraph sg = getSystemSpecializedGraph(true);
837         DBPropGraph result = DBPropGraph.findPropGraphByName(sg, DEFAULT_PROPS);
838         if (result == null) {
839             logger.error("No default Model Properties found");
840             // Construct the parameters that will be the
841
// default settings for any graph added to this database
842
//new DBPropGraph( m_sysProperties, "default", "generic");
843
//result = DBPropGraph.findPropGraph(sg, "default");
844
}
845         return result;
846     }
847     
848     /**
849      * Test if the database has previously been formatted.
850      *
851      * @return boolean true if database is correctly formatted, false on any error.
852      */

853     public boolean isDBFormatOK() throws RDFRDBException {
854         boolean result = true;
855         boolean[] found = new boolean[SYSTEM_TABLE_CNT];
856         int i = 0;
857         for (i = 0; i < SYSTEM_TABLE_CNT; i++) found[i] = false;
858         try {
859             // check that all required system tables exist
860
ResultSet JavaDoc alltables = getAllTables();
861             while (alltables.next()) {
862                 String JavaDoc tblName = alltables.getString("TABLE_NAME");
863                 for (i = 0; i < SYSTEM_TABLE_CNT; i++)
864                     if (SYSTEM_TABLE_NAME[i].equals(tblName))
865                         found[i] = true;
866             }
867             alltables.close();
868             for (i = 0; i < SYSTEM_TABLE_CNT; i++) {
869                 if (!found[i]) {
870                     // mutex table is not required
871
if (SYSTEM_TABLE_NAME[i].equals(MUTEX_TABLE))
872                         continue;
873                     result = false;
874                 }
875             }
876         } catch (Exception JavaDoc e1) {
877             // An exception might be an unformatted or corrupt
878
// db or a connection problem.
879
throw new RDFRDBException(
880                 "Exception while checking db format - " + e1);
881         }
882         return result;
883     }
884     
885     /**
886      * Converts string to form accepted by database.
887      */

888     public String JavaDoc stringToDBname(String JavaDoc aName) {
889         String JavaDoc result = (DB_NAMES_TO_UPPER) ? aName.toUpperCase() : aName;
890         return(result);
891     }
892     
893     private static final int lockTryMax = 5; // max attempts to acquire/release lock
894

895     
896     /**
897      * return true if the mutex is acquired, else false
898      */

899
900     public boolean tryLockDB() {
901         boolean res = true;
902         try {
903             m_sql.runSQLGroup("lockDatabase", MUTEX_TABLE);
904         } catch (SQLException JavaDoc e) {
905             res = false;
906         }
907         return res;
908     }
909
910     
911     public void lockDB() throws RDFRDBException {
912         String JavaDoc err = "";
913         int cnt = 0;
914         while ( cnt++ < lockTryMax ) {
915             if ( tryLockDB() )
916                 break;
917             try {
918                 Thread.sleep((long)5000);
919             } catch (InterruptedException JavaDoc e) {
920                 err = err + " lockDB sleep interrupted" + e;
921             }
922         }
923         if ( cnt >= lockTryMax ) {
924             err = "Failed to lock database after "+ lockTryMax + " attempts.\n"
925             + err + "\n."
926             + "Try later or else call DriverRDB.unlockDB() after ensuring\n" +
927             "that no other Jena applications are using the database.";
928             throw new RDFRDBException(err);
929         }
930     }
931     
932     /**
933      * Release the mutex lock in the database.
934      */

935     
936     public void unlockDB() throws RDFRDBException {
937         String JavaDoc err;
938         int cnt = 0;
939         while ( cnt++ < lockTryMax ) {
940         try {
941             m_sql.runSQLGroup("unlockDatabase", MUTEX_TABLE);
942             break;
943         } catch (SQLException JavaDoc e) {
944             err = "Failed to unlock database after "+ lockTryMax + " attempts - " + e;
945             try {
946                 Thread.sleep((long)5000);
947             } catch (InterruptedException JavaDoc e1) {
948                 err = err + " sleep failed" + e;
949             }
950         }
951         if ( cnt >= lockTryMax )
952             throw new RDFRDBException(err);
953         }
954     }
955     
956     
957     /* return true if the mutex is held. */
958     
959     public boolean DBisLocked() throws RDFRDBException {
960         try {
961             DatabaseMetaData JavaDoc dbmd = m_dbcon.getConnection().getMetaData();
962             String JavaDoc[] tableTypes = { "TABLE" };
963             String JavaDoc prefixMatch = stringToDBname(TABLE_NAME_PREFIX + "%");
964             ResultSet JavaDoc iter = dbmd.getTables(null, null, MUTEX_TABLE, tableTypes);
965             try { return iter.next(); } finally { iter.close(); }
966         } catch (SQLException JavaDoc e1) {
967             throw new RDFRDBException("Internal SQL error in driver" + e1);
968         }
969     }
970
971     /* (non-Javadoc)
972      * @see com.hp.hpl.jena.graphRDB.IRDBDriver#cleanDB()
973      */

974     public void cleanDB() {
975
976         // assumes database lock is not held.
977
try {
978             lockDB();
979         } catch (RDFRDBException e) {
980             throw new RDFRDBException(
981                     "DriverRDB.cleanDB() failed to acquire database lock:\n"
982                             + "("
983                             + e
984                             + ")\n."
985                             + "Try again or call DriverRDB.unlockDB() if necessary.");
986         }
987         // now clean the database
988
doCleanDB(true);
989     }
990     
991     /*
992      * internal routine that does the actual work for cleanDB().
993      * it assumes that the mutex is held and throws and exception
994      * if not. it will optionally remove the mutex if dropMutex
995      * is true.
996      */

997     
998     protected void doCleanDB( boolean dropMutex ) throws RDFRDBException {
999         try {
1000            if ( !DBisLocked() ) {
1001                throw new RDFRDBException(
1002                "Internal error in driver - database not locked for cleaning.\n");
1003            }
1004        } catch ( RDFRDBException e ) {
1005            throw new RDFRDBException(
1006            "Exception when checking for database lock - \n"
1007            + e);
1008        }
1009        try {
1010            ResultSet JavaDoc alltables = getAllTables();
1011            List JavaDoc tablesPresent = new ArrayList JavaDoc(10);
1012            while (alltables.next()) {
1013                tablesPresent.add(alltables.getString("TABLE_NAME"));
1014            }
1015            alltables.close();
1016            Iterator JavaDoc it = tablesPresent.iterator();
1017            while (it.hasNext()) {
1018                String JavaDoc tblName = (String JavaDoc) it.next();
1019                if ( tblName.equals(MUTEX_TABLE) && (dropMutex == false) )
1020                    continue;
1021                m_sql.runSQLGroup("dropTable", tblName);
1022            }
1023            if (PRE_ALLOCATE_ID) {
1024                clearSequences();
1025            }
1026        } catch (SQLException JavaDoc e1) {
1027            throw new RDFRDBException("Internal error in driver while cleaning database\n"
1028                    + "(" + e1 + ").\n"
1029                    + "Database may be corrupted. Try cleanDB() again.");
1030        }
1031        m_sysProperties = null;
1032        if ( prefixCache != null ) prefixCache.clear();
1033        prefixCache = null;
1034    }
1035
1036    private ResultSet JavaDoc getAllTables() {
1037        try {
1038            DatabaseMetaData JavaDoc dbmd = m_dbcon.getConnection().getMetaData();
1039            String JavaDoc[] tableTypes = { "TABLE" };
1040            String JavaDoc prefixMatch = stringToDBname(TABLE_NAME_PREFIX + "%");
1041            return dbmd.getTables(null, null, prefixMatch, tableTypes);
1042        } catch (SQLException JavaDoc e1) {
1043            throw new RDFRDBException("Internal SQL error in driver - " + e1);
1044        }
1045    }
1046    
1047    /**
1048     * Drop all Jena-related sequences from database, if necessary.
1049     * Override in subclass if sequences must be explicitly deleted.
1050     */

1051    public void clearSequences() {
1052    }
1053    
1054    /**
1055     * Removes named sequence from the database, if it exists.
1056     * @param seqName
1057     */

1058    public void removeSequence(String JavaDoc seqName) {
1059        if (sequenceExists(seqName)) {
1060            try {
1061                m_sql.runSQLGroup("DropSequence",seqName);
1062            } catch (Exception JavaDoc e) {
1063                logger.warn("Unable to drop sequence " + seqName, e);
1064            }
1065        }
1066    }
1067
1068    /**
1069     * Check database and see if named sequence exists.
1070     * @param seqName
1071     */

1072    public boolean sequenceExists(String JavaDoc seqName) {
1073        Object JavaDoc[] args = {seqName};
1074        boolean result = false;
1075        try {
1076            String JavaDoc op = "SelectSequenceName";
1077            PreparedStatement JavaDoc ps = m_sql.getPreparedSQLStatement(op);
1078            ps.setString(1,seqName);
1079            ResultSet JavaDoc rs = ps.executeQuery();
1080            result = rs.next();
1081            rs.close();
1082            m_sql.returnPreparedSQLStatement(ps);
1083        } catch (Exception JavaDoc e) {
1084          logger.error("Unable to select sequence " + seqName, e);
1085            }
1086        return result;
1087    }
1088
1089    /**
1090     * Check database and see if named sequence exists.
1091     * @param seqName
1092     */

1093    public List JavaDoc getSequences() {
1094        List JavaDoc results = new ArrayList JavaDoc(10);
1095        Object JavaDoc[] args = {};
1096        try {
1097            String JavaDoc opname = "SelectJenaSequences";
1098            PreparedStatement JavaDoc ps = m_sql.getPreparedSQLStatement(opname, TABLE_NAME_PREFIX);
1099            ResultSet JavaDoc rs = ps.executeQuery();
1100            while (rs.next()) results.add( rs.getString(1) );
1101            rs.close();
1102            m_sql.returnPreparedSQLStatement(ps);
1103        } catch (Exception JavaDoc e) {
1104          logger.error("Unable to select Jena sequences: ", e);
1105         }
1106        return results;
1107    }
1108    
1109    /**
1110     * Initialise a database ready to store RDF tables.
1111     * @throws RDFDBException if the is a problem opening the connection or an internal SQL error.
1112     * @deprecated Since Jena 2.0 this call is no longer needed - formatting
1113     * happens automatically as a side effect of creating Models - there should
1114     * be no need for an application to interact directly with the driver.
1115     */

1116    public void formatDB() throws RDFRDBException {
1117    }
1118    
1119    /**
1120     * Create a table for storing asserted or reified statements.
1121     *
1122     * @param graphId the graph which the table is created.
1123     * @param isReif true if table stores reified statements.
1124     * @return the name of the new table
1125     *
1126     */

1127    public String JavaDoc createTable( int graphId, boolean isReif) {
1128        String JavaDoc opname = isReif ? "createReifStatementTable" : "createStatementTable";
1129        int i = 0;
1130        String JavaDoc params[];
1131        while ( true ) {
1132            params = getCreateTableParams(graphId, isReif);
1133            try {
1134                m_sql.runSQLGroup(opname, params);
1135                break;
1136            } catch (SQLException JavaDoc e) {
1137                i++;
1138                if ( i > 5 ) {
1139                    logger.warn("Problem creating table", e);
1140                    throw new RDFRDBException("Failed to create table: " + params[0], e);
1141                }
1142            }
1143        }
1144        return params[0];
1145    }
1146
1147
1148    /**
1149     * Delete a table.
1150     *
1151     * @param tableName the name of the table to delete. *
1152     */

1153    public void deleteTable( String JavaDoc tableName ) {
1154        
1155        String JavaDoc opname = "dropTable";
1156        try {
1157            PreparedStatement JavaDoc ps = m_sql.getPreparedSQLStatement(opname, tableName);
1158            ps.executeUpdate();
1159            return;
1160        } catch (Exception JavaDoc e1) {
1161            throw new RDFRDBException("Failed to delete table ", e1);
1162        }
1163    }
1164
1165
1166
1167    /**
1168     * Throws an UnsupportedOperation exception.
1169     *
1170     * @param opName name of the operation that's not supported.
1171     */

1172    private void notSupported(String JavaDoc opName)
1173        { throw new UnsupportedOperationException JavaDoc(opName); }
1174        
1175
1176    protected static final int xactBegin = 0;
1177    protected static final int xactCommit = 1;
1178    protected static final int xactAbort = 2;
1179    protected static final int xactIsActive = 3;
1180    protected static final int xactAutoOff = 4;
1181    protected static final int xactAutoOn = 5;
1182
1183    
1184    /**
1185     * Perform a transaction operation. For begin/commit/abort,
1186     * return true if success, false if fail. for xactIsActive,
1187     * return true if this driver has an active transaction,
1188     * else return false.
1189     */

1190    protected synchronized boolean xactOp(int op) throws RDFRDBException {
1191        boolean ret = true;
1192        try {
1193            if (op == xactBegin) {
1194                // start a transaction
1195
// always return true
1196
if (!inTransaction) {
1197                    xactBegin();
1198                    inTransaction = true;
1199                }
1200            } else if (op == xactCommit) {
1201                // commit a transaction
1202
// always return true
1203
if (inTransaction) {
1204                    xactCommit();
1205                    inTransaction = false;
1206                }
1207            } else if (op == xactAbort) {
1208                // rollback a transaction
1209
// always return true
1210
if (inTransaction) {
1211                    xactAbort();
1212                    inTransaction = false;
1213                }
1214            } else if (op == xactIsActive) {
1215                // return true if xact is active, else false
1216
ret = inTransaction;
1217            } else if (op == xactAutoOff) {
1218                // disable autocommit
1219
// return true if autocommit is on, else false
1220
// begins a new transaction
1221
Connection JavaDoc c = m_sql.getConnection();
1222                ret = c.getAutoCommit();
1223                if ( ret )
1224                    xactBegin();
1225                inTransaction = true;
1226            } else if (op == xactAutoOn) {
1227                // enable autocommit
1228
// always return true
1229
if ( inTransaction )
1230                    throw new JenaException("Can't enable AutoCommit in middle of existing transaction");
1231                Connection JavaDoc c = m_sql.getConnection();
1232                c.setAutoCommit(true);
1233                ret = true;
1234            } else
1235                throw new JenaException("Unknown transaction operation: " + op);
1236        } catch (SQLException JavaDoc e) {
1237            throw new JenaException("Transaction support failed: ", e);
1238        }
1239        return ret;
1240    }
1241
1242    private void xactBegin() throws RDFRDBException {
1243        try {
1244            Connection JavaDoc c = m_sql.getConnection();
1245            c.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
1246            c.setAutoCommit(false);
1247            // Starting a transaction could require us to lose any
1248
// cached prepared statements
1249
// for some jdbc drivers, currently I think all the drivers
1250
// we use are safe and
1251
// is a major performance hit so commented out for now.
1252
//m_sql.flushPreparedStatementCache();
1253
} catch (SQLException JavaDoc e) {
1254            throw new JenaException("Transaction begin failed: ", e);
1255        }
1256    }
1257    
1258    private void xactAbort() throws RDFRDBException {
1259        try {
1260            Connection JavaDoc c = m_sql.getConnection();
1261            c.rollback();
1262            c.commit();
1263            c.setAutoCommit(true);
1264        } catch (SQLException JavaDoc e) {
1265            throw new JenaException("Transaction rollback failed: ", e);
1266        }
1267    }
1268    
1269    private void xactCommit() throws RDFRDBException {
1270        try {
1271            Connection JavaDoc c = m_sql.getConnection();
1272            c.commit();
1273            c.setAutoCommit(true);
1274            // not sure why read_uncommitted is set, below. commented
1275
// out by kw.
1276
// c.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
1277
} catch (SQLException JavaDoc e) {
1278            throw new JenaException("Transaction commit failed: ", e);
1279        }
1280    }
1281
1282        
1283    /**
1284     * If the underlying database connection supports transactions, turn
1285     * autocommit off, then begin a new transaction. Note that transactions are
1286     * associated with connections, not with Models. This
1287     */

1288    public synchronized void begin() throws RDFRDBException {
1289        if (transactionsSupported()) {
1290            xactOp(xactBegin);
1291        } else {
1292            notSupported("begin transaction");
1293        }
1294    }
1295
1296    /**
1297     * If the underlying database connection supports transactions, call
1298     * commit(), then turn autocommit on.
1299     */

1300    public void commit() throws RDFRDBException {
1301        if (transactionsSupported()) {
1302            xactOp(xactCommit);
1303        } else {
1304            notSupported("commit transaction");
1305        }
1306    }
1307
1308    /**
1309     * If underlying database connection supports transactions, call abort() on
1310     * the connection, then turn autocommit on.
1311     */

1312    public synchronized void abort() throws RDFRDBException {
1313        if (transactionsSupported()) {
1314            xactOp(xactAbort);
1315        } else {
1316            notSupported("abort transaction");
1317        }
1318    }
1319        
1320
1321        
1322    /**
1323     * Return a string identifying underlying database type.
1324     *
1325     */

1326    public String JavaDoc getDatabaseType() {
1327        return(DATABASE_TYPE);
1328    }
1329
1330    /**
1331     * Returns true if the underlying database supports transactions.
1332     */

1333    public boolean transactionsSupported() {
1334        if (m_transactionsSupported != null) {
1335            return(m_transactionsSupported.booleanValue());
1336        }
1337        
1338        if (m_dbcon != null) {
1339            try {
1340                Connection JavaDoc c = m_sql.getConnection();
1341                if ( c != null) {
1342                    m_transactionsSupported = new Boolean JavaDoc(c.getMetaData().supportsMultipleTransactions());
1343                    return(m_transactionsSupported.booleanValue());
1344                }
1345            } catch (SQLException JavaDoc e) {
1346                logger.error("SQL Exception caught ", e);
1347            }
1348        }
1349        return (false);
1350            
1351        }
1352
1353
1354
1355    //--------------------------------------------------jena 1 backward compatability
1356

1357    /**
1358     * Close the driver
1359     *
1360     * Nothing to do for now.
1361     *
1362     * @throws RDFDBException if there is an access problem
1363     * @deprecated Since Jena 2.0 this call is no longer required - just
1364     * close the DBConnection - there should be no need for an application
1365     * to interact directly with the driver.
1366     *
1367     */

1368
1369    public void close() throws RDFRDBException {
1370    }
1371
1372
1373    /**
1374     * Returns true if the database layout supports multiple RDF models
1375     * in the same database.
1376     * @deprecated Since Jena 2.0 all databases support multiple models.
1377     */

1378
1379    public boolean supportsMultipleModels() {
1380        return true;
1381    }
1382
1383    /**
1384     * Returns true if the database layout supports implicit reification
1385     * of statements (i.e. statements can be treated as resources).
1386     * @deprecated Since Jena 2.0 the reification API has changed. The
1387     * new API is supported in all models, but the old Jena 1 API is no
1388     * longer supported. This call will return false to indicate
1389     * to old code that the old style of jena reification is not supported.
1390     */

1391
1392    public boolean supportsJenaReification() {
1393        return false;
1394    }
1395        
1396    
1397    /*
1398     * The following routines are responsible for encoding nodes
1399     * as database structures. For each node type stored (currently,
1400     * literals, URI, blank), there are two possible encodings
1401     * depending on the node size. Small nodes may be stored
1402     * within a statement table. If the node is long (will not
1403     * fit within the statement table), it is be stored in a
1404     * separate table for that node type.
1405     *
1406     * In addition, for resources (URI, blank nodes), the URI
1407     * may be optionally compressed. Below, the possibilites
1408     * are enumerated.
1409     *
1410     * Literal Encoding in Statement Tables
1411     * Short Literal: Lv:[langLen]:[datatypeLen]:[langString][datatypeString]value[:]
1412     * Long Literal: Lr:dbid
1413     * Literal Encoding in Long Literal Table
1414     * Literal: Lv:[langLen]:[datatypeLen]:[langString][datatypeString]head[:] hash tail
1415     *
1416     * Comments:
1417     * L indicates a literal
1418     * v indicates a value
1419     * r indicates a reference to another table
1420     * : is used as a delimiter. note that MySQL trims trailing white space for
1421     * certain VARCHAR columns so an extra delimiter is appended when necessary
1422     * for those columns. it is not required for dbid, however.
1423     * dbid references the long literal table
1424     * langLen is the length of the language identifier for the literal
1425     * langString is the language identifier
1426     * datatypeLen is the length of the datatype for the literal
1427     * datatypeString is the datatype for the literal
1428     * value is the lexical form of the string
1429     * head is a prefix of value that can be indexed
1430     * hash is the CRC32 hash value for the tail
1431     * tail is the remainder of the value that cannot be indexed
1432     *
1433     *
1434     *
1435     * URI Encoding in Statement Tables
1436     * Short URI: Uv:[pfx_dbid]:URI[:]
1437     * Long URI: Ur:[pfx_dbid]:dbid
1438     * URI Encoding in Long URI Table
1439     * URI: Uv:head[:] hash tail
1440     *
1441     * Comments:
1442     * U indicates a URI
1443     * pfx_dbid references the prefix table. if the prefix is too
1444     * short (i.e., the length of the prefix is less than
1445     * URI_COMPRESS_LENGTH), the URI is not compressed and
1446     * pfx_dbid is null.
1447     * URI is the complete URI
1448     * other notation same as for literal encoding
1449     *
1450     * Blank Node Encoding in Statement Tables
1451     * Short URI: Bv:[pfx_dbid]:bnid[:]
1452     * Long URI: Br:[pfx_dbid]:dbid
1453     * Blank Encoding in Long URI Table
1454     * URI: Bv:head[:] hash tail
1455     *
1456     * Comments:
1457     * B indicates a blank node
1458     * bnid is the blank node identifier
1459     * other notation same as above
1460     * Note: currently, blank nodes are always stored uncompressed (pfix_dbid is null).
1461     *
1462     * Variable Node Encoding in Statement Tables
1463     * Variable Node: Vv:name
1464     *
1465     * Comments:
1466     * V indicates a variable node
1467     * v indicates a value
1468     * name is the variable name
1469     * Note: the length must be less than LONG_OBJECT_LENGTH
1470     *
1471     * ANY Node Encoding in Statement Tables
1472     * Variable Node: Av:
1473     *
1474     * Prefix Encoding in Prefix Table
1475     * Prefix: Pv:val[:] [hash] [tail]
1476     *
1477     * Comments:
1478     * P indicates a prefix
1479     * other notation same as above
1480     * hash and tail are only required for long prefixes.
1481     *
1482     */

1483     
1484     
1485     
1486    protected static String JavaDoc RDBCodeURI = "U";
1487    protected static String JavaDoc RDBCodeBlank = "B";
1488    protected static String JavaDoc RDBCodeLiteral = "L";
1489    protected static String JavaDoc RDBCodeVariable = "V";
1490    protected static String JavaDoc RDBCodeANY = "A";
1491    protected static String JavaDoc RDBCodePrefix = "P";
1492    protected static String JavaDoc RDBCodeValue = "v";
1493    protected static String JavaDoc RDBCodeRef = "r";
1494    protected static String JavaDoc RDBCodeDelim = ":";
1495    protected static char RDBCodeDelimChar = ':';
1496    protected static String JavaDoc RDBCodeInvalid = "X";
1497
1498
1499        
1500    
1501    /**
1502    * Convert a node to a string to be stored in a statement table.
1503    * @param Node The node to convert to a string. Must be a concrete node.
1504    * @param addIfLong If the node is a long object and is not in the database, add it.
1505    * @return the string or null if failure.
1506    */

1507    public String JavaDoc nodeToRDBString ( Node node, boolean addIfLong ) throws RDFRDBException {
1508        String JavaDoc res = null;
1509        if ( node.isURI() ) {
1510            String JavaDoc uri = new String JavaDoc(((Node_URI) node).getURI());
1511            if ( uri.startsWith(RDBCodeURI) ) {
1512                throw new RDFRDBException ("URI Node looks like a blank node: " + uri );
1513            }
1514            // TODO: need to write special version of splitNamespace for rdb.
1515
// or else, need a guarantee that splitNamespace never changes.
1516
// the problem is that if the splitNamespace algorithm changes,
1517
// then URI's may be encoded differently. so, URI's in existing
1518
// databases may become inaccessible.
1519
int pos = 0;
1520            boolean noCompress;
1521            String JavaDoc pfx;
1522            String JavaDoc qname;
1523            if ( URI_COMPRESS == true ) {
1524                pos = dbSplitNamespace(uri);
1525                noCompress = (pos == uri.length()) || (pos <= URI_COMPRESS_LENGTH);
1526            } else
1527                noCompress = true;
1528            if ( noCompress ) {
1529                pfx = RDBCodeDelim + RDBCodeDelim;
1530                qname = uri;
1531            } else {
1532                // see if it's cached
1533
DBIDInt pfxid = URItoPrefix(uri, pos, addIfLong);
1534                if ( pfxid == null ) return res;
1535                pfx = RDBCodeDelim + ((DBIDInt)pfxid).getIntID() + RDBCodeDelim;
1536                qname = uri.substring(pos);
1537            }
1538            int encodeLen = RDBCodeURI.length() + 1 + pfx.length() + EOS_LEN;
1539            boolean URIisLong = objectIsLong(encodeLen,qname);
1540            if ( URIisLong ) {
1541                int dbid;
1542                // belongs in URI table
1543
DBIDInt URIid = getURIID(qname,addIfLong);
1544                if ( URIid == null ) return res;
1545                dbid = URIid.getIntID();
1546                res = new String JavaDoc(RDBCodeURI + RDBCodeRef + pfx + dbid);
1547            } else {
1548                res = RDBCodeURI + RDBCodeValue + pfx + qname + EOS;
1549            }
1550        } else if ( node.isLiteral() ){
1551            // TODO: may need to encode literal value when datatype is not a string.
1552
Node_Literal litNode = (Node_Literal) node;
1553            LiteralLabel ll = litNode.getLiteral();
1554            String JavaDoc lval = ll.getLexicalForm();
1555            String JavaDoc lang = ll.language();
1556            String JavaDoc dtype = ll.getDatatypeURI();
1557            String JavaDoc ld = litLangTypeToRDBString(lang,dtype);
1558            int encodeLen = RDBCodeLiteral.length() + 2 + ld.length() + EOS_LEN;
1559            boolean litIsLong = objectIsLong(encodeLen,lval);
1560            if ( litIsLong ) {
1561                int dbid;
1562                // belongs in literal table
1563
DBIDInt lid = getLiteralID(litNode,addIfLong);
1564                if ( lid == null ) return res;
1565                dbid = lid.getIntID();
1566                res = new String JavaDoc(RDBCodeLiteral + RDBCodeRef + RDBCodeDelim + dbid);
1567            } else {
1568                res = new String JavaDoc(RDBCodeLiteral + RDBCodeValue + RDBCodeDelim + ld + lval + EOS);
1569            }
1570        } else if ( node.isBlank() ) {
1571            String JavaDoc bnid = node.getBlankNodeId().toString();
1572            String JavaDoc delims = "::";
1573            int encodeLen = RDBCodeBlank.length() + 1 + delims.length() + EOS_LEN;
1574            boolean BisLong = objectIsLong(encodeLen,bnid);
1575            if ( BisLong ) {
1576                int dbid;
1577                // belongs in URI table
1578
DBIDInt URIid = getBlankID(bnid,addIfLong);
1579                if ( URIid == null ) return res;
1580                dbid = URIid.getIntID();
1581                res = new String JavaDoc(RDBCodeBlank + RDBCodeRef + delims + dbid);
1582            } else {
1583                res = new String JavaDoc(RDBCodeBlank + RDBCodeValue + delims + bnid + EOS);
1584            }
1585            
1586        } else if ( node.isVariable() ){
1587            String JavaDoc name = ((Node_Variable)node).getName();
1588            int len = name.length();
1589            if ( (len + 3 + EOS_LEN) > LONG_OBJECT_LENGTH )
1590                throw new JenaException ("Variable name too long: " + name );
1591            res = RDBCodeVariable + RDBCodeValue + RDBCodeDelim + name + EOS;
1592        } else if ( node.equals(Node.ANY) ) {
1593            res = RDBCodeANY + RDBCodeValue + RDBCodeDelim;
1594        } else {
1595            throw new RDFRDBException ("Expected Concrete Node, got " + node.toString() );
1596        }
1597        return res;
1598    }
1599    
1600    /**
1601    * Convert an RDB string to the node that it encodes. Return null if failure.
1602    * @param RDBstring The string to convert to a node.
1603    * @return The node or null if failure.
1604    */

1605    public Node RDBStringToNode ( String JavaDoc RDBString ) throws RDFRDBException {
1606        Node res = null;
1607        int len = RDBString.length();
1608        if ( len < 3 )
1609            throw new RDFRDBException("Bad RDBString Header: " + RDBString);
1610        String JavaDoc nodeType = RDBString.substring(0,1);
1611        String JavaDoc valType = RDBString.substring(1,2);
1612        if ( (!(valType.equals(RDBCodeRef) || valType.equals(RDBCodeValue))) ||
1613                (RDBString.charAt(2) != RDBCodeDelimChar) )
1614                throw new RDFRDBException("Bad RDBString Header: " + RDBString);
1615
1616        int pos = 3;
1617        int npos;
1618        
1619        if ( nodeType.equals(RDBCodeURI) ) {
1620            ParseInt pi = new ParseInt(pos);
1621            String JavaDoc prefix = "";
1622            RDBStringParseInt(RDBString, pi, false);
1623            if ( pi.val != null ) {
1624                if ( URI_COMPRESS == false )
1625                    throw new RDFRDBException("Bad URI: Prefix Compression Disabled: " + RDBString);
1626                prefix = IDtoPrefix(pi.val.intValue());
1627                if ( prefix == null )
1628                    throw new RDFRDBException("Bad URI Prefix: " + RDBString);
1629            }
1630            pos = pi.pos + 1;
1631            String JavaDoc qname;
1632            if ( valType.equals(RDBCodeRef) ) {
1633                qname = IDtoURI(RDBString.substring(pos));
1634                if ( qname == null )
1635                    throw new RDFRDBException("Bad URI: " + RDBString);
1636            } else
1637                qname = RDBString.substring(pos,len - EOS_LEN);
1638
1639            res = Node.createURI(prefix + qname);
1640            
1641        } else if ( nodeType.equals(RDBCodeLiteral) ) {
1642            ParseInt pi = new ParseInt(pos);
1643            String JavaDoc litString = null;
1644            if ( valType.equals(RDBCodeRef) ) {
1645                RDBStringParseInt(RDBString,pi,true);
1646                if ( pi.val != null )
1647                    litString = IDtoLiteral(pi.val.intValue());
1648                if ( litString == null )
1649                    throw new RDFRDBException("Bad Literal Reference: " + RDBString);
1650            } else
1651                litString = RDBString.substring(pos,len-EOS_LEN);
1652            len = litString.length();
1653            String JavaDoc lang;
1654            String JavaDoc dtype;
1655            int langLen = 0;
1656            int dtypeLen = 0;
1657            LiteralLabel llabel;
1658            pi.pos = 0;
1659            RDBStringParseInt(litString, pi, false);
1660            if ( pi.val == null ) langLen = 0;
1661            else langLen = pi.val.intValue();
1662            pi.pos = pi.pos + 1;
1663            RDBStringParseInt(litString, pi, false);
1664            if ( pi.val == null ) dtypeLen = 0;
1665            else dtypeLen = pi.val.intValue();
1666            pos = pi.pos + 1;
1667            if ( (pos + langLen + dtypeLen) > len )
1668                    throw new RDFRDBException("Malformed Literal: " + litString);
1669            lang = litString.substring(pos,pos+langLen);
1670            pos = pos + langLen;
1671            dtype = litString.substring(pos,pos+dtypeLen);
1672            pos = pos + dtypeLen;
1673            
1674            String JavaDoc val = litString.substring(pos);
1675            
1676            if ( (dtype == null) || (dtype.equals("")) ) {
1677                llabel = new LiteralLabel(val, lang == null ? "" : lang);
1678            } else {
1679                RDFDatatype dt = TypeMapper.getInstance().getSafeTypeByName(dtype);
1680                llabel = new LiteralLabel(val, lang == null ? "" : lang, dt);
1681            }
1682            res = Node.createLiteral(llabel);
1683            
1684        } else if ( nodeType.equals(RDBCodeBlank) ) {
1685            String JavaDoc bstr = null;
1686            if ( valType.equals(RDBCodeValue) ) {
1687                bstr = RDBString.substring(4,len-EOS_LEN);
1688            } else {
1689                bstr = IDtoBlank(RDBString.substring(4));
1690                if ( bstr == null )
1691                    throw new RDFRDBException("Bad URI: " + RDBString);
1692            }
1693            res = Node.createAnon( new AnonId (bstr) );
1694                        
1695        } else if ( nodeType.equals(RDBCodeVariable) ) {
1696            String JavaDoc vname = RDBString.substring(3,len-EOS_LEN);
1697            res = Node.createVariable(vname);
1698            
1699        } else if ( nodeType.equals(RDBCodeANY) ) {
1700            res = Node.ANY;
1701            
1702        } else
1703            throw new RDFRDBException ("Invalid RDBString Prefix, " + RDBString );
1704        return res;
1705    }
1706    
1707    /** This is cuurently a copy of Util.splitNamespace. It was
1708     * copied rather than used directly for two reasons. 1) in the
1709     * future it may be desirable to use a different split algorithm
1710     * for persistence. 2) the util version could change at any time,
1711     * which would render existing databases inaccessible. having a
1712     * copy allows the db version to evolve in a controlled way.
1713     *
1714     * Given an absolute URI, determine the split point between the namespace part
1715     * and the localname part.
1716     * If there is no valid localname part then the length of the
1717     * string is returned.
1718     * The algorithm tries to find the longest NCName at the end
1719     * of the uri, not immediately preceeded by the first colon
1720     * in the string.
1721     * @param uri
1722     * @return the index of the first character of the localname
1723     */

1724    public static int dbSplitNamespace(String JavaDoc uri) {
1725        char ch;
1726        int lg = uri.length();
1727        if (lg == 0)
1728            return 0;
1729        int j;
1730        int i;
1731        for (i = lg - 1; i >= 1; i--) {
1732            ch = uri.charAt(i);
1733            if (!XMLChar.isNCName(ch))
1734                break;
1735        }
1736        for (j = i + 1; j < lg; j++) {
1737            ch = uri.charAt(j);
1738            if (XMLChar.isNCNameStart(ch)) {
1739                if (uri.charAt(j - 1) == ':'
1740                    && uri.lastIndexOf(':', j - 2) == -1)
1741                    continue; // split "mailto:me" as "mailto:m" and "e" !
1742
else
1743                    break;
1744            }
1745        }
1746        return j;
1747    }
1748
1749    
1750    class ParseInt {
1751        int pos;
1752        Integer JavaDoc val;
1753        ParseInt(int p) {pos = p;}
1754    }
1755
1756    protected void RDBStringParseInt ( String JavaDoc RDBString, ParseInt pi, boolean toEnd ) {
1757        int npos = toEnd ? RDBString.length() : RDBString.indexOf(RDBCodeDelimChar,pi.pos);
1758        if ( npos < 0 ) {
1759            throw new RDFRDBException("Bad RDB String: " + RDBString);
1760        }
1761        String JavaDoc intStr = RDBString.substring(pi.pos,npos);
1762        pi.pos = npos;
1763        if ( intStr.equals("") )
1764            pi.val = null;
1765        else try {
1766            pi.val = new Integer JavaDoc(intStr);
1767        } catch (NumberFormatException JavaDoc e1) {
1768            throw new RDFRDBException("Bad RDB String: " + RDBString);
1769        }
1770        return;
1771    }
1772    
1773    
1774
1775    DBIDInt URItoPrefix ( String JavaDoc uri, int pos, boolean add ) {
1776        DBIDInt res;
1777        Object JavaDoc key = prefixCache.getByValue(uri.substring(0,pos));
1778        if ( key == null ) {
1779            RDBLongObject lobj = PrefixToLongObject(uri,pos);
1780            res = getLongObjectID(lobj, PREFIX_TABLE, add);
1781            if ( res != null )
1782                prefixCache.put(res,uri.substring(0,pos));
1783        } else
1784            res = (DBIDInt) key;
1785        return res;
1786    }
1787    
1788    protected RDBLongObject PrefixToLongObject ( String JavaDoc prefix, int split ) {
1789        RDBLongObject res = new RDBLongObject();
1790        int headLen;
1791        int avail;
1792
1793        res.head = RDBCodePrefix + RDBCodeValue + RDBCodeDelim;
1794        headLen = res.head.length();
1795        avail = INDEX_KEY_LENGTH - (headLen + EOS_LEN);
1796        if ( split > avail ) {
1797            res.head = res.head + prefix.substring(0,avail);
1798            res.tail = prefix.substring(avail,split);
1799            res.hash = stringToHash(res.tail);
1800        } else {
1801            res.head = res.head + prefix.substring(0,split);
1802            res.tail = "";
1803        }
1804        res.head = res.head + EOS;
1805        return res;
1806    }
1807
1808    /**
1809    * Encode a literal node's lang and datatype as a string of the
1810    * form ":[langLen]:[datatypeLen]:[langString][dataTypeString]"
1811    * @return the string.
1812    */

1813    public String JavaDoc litLangTypeToRDBString ( String JavaDoc lang, String JavaDoc dtype ) throws RDFRDBException {
1814        String JavaDoc res = RDBCodeDelim;
1815        res = ((lang == null) ? "" : Integer.toString(lang.length())) + RDBCodeDelim;
1816        res = res + ((dtype == null) ? "" : Integer.toString(dtype.length())) + RDBCodeDelim;
1817        res = res + (lang == null ? "" : lang) + (dtype == null ? "" : dtype);
1818        return res;
1819    }
1820    
1821    /**
1822    * Check if an object is long, i.e., it exceeds the length
1823    * limit for storing in a statement table.
1824    * @return true if literal is long, else false.
1825    */

1826    protected boolean objectIsLong ( int encodingLen, String JavaDoc objAsString ) {
1827        return ( (encodingLen + objAsString.length()) > LONG_OBJECT_LENGTH);
1828    }
1829    
1830    class RDBLongObject {
1831        String JavaDoc head; /* prefix of long object that can be indexed */
1832        long hash; /* hash encoding of tail */
1833        String JavaDoc tail; /* remainder of long object */
1834    }
1835    
1836    protected RDBLongObject literalToLongObject ( Node_Literal node ) {
1837        RDBLongObject res = new RDBLongObject();
1838        int headLen;
1839        int avail;
1840        LiteralLabel l = node.getLiteral();
1841        String JavaDoc lang = l.language();
1842        String JavaDoc dtype = l.getDatatypeURI();
1843        String JavaDoc val = l.getLexicalForm();
1844        String JavaDoc langType = litLangTypeToRDBString(lang,dtype);
1845
1846        res.head = RDBCodeLiteral + RDBCodeValue + RDBCodeDelim + langType;
1847        headLen = res.head.length();
1848        avail = INDEX_KEY_LENGTH - (headLen + EOS_LEN);
1849        if ( val.length() > avail ) {
1850            res.head = res.head + val.substring(0,avail);
1851            res.tail = val.substring(avail);
1852            res.hash = stringToHash(res.tail);
1853        } else {
1854            res.head = res.head + val;
1855            res.tail = "";
1856        }
1857        res.head = res.head + EOS;
1858        return res;
1859    }
1860    
1861        
1862    protected long stringToHash ( String JavaDoc str ) {
1863        CRC32 JavaDoc checksum = new CRC32 JavaDoc();
1864        checksum.update(str.getBytes());
1865        return checksum.getValue();
1866    }
1867    
1868    /**
1869     * Return the database ID for the URI, if it exists
1870     */

1871    public DBIDInt getBlankID(String JavaDoc bstr, boolean add) throws RDFRDBException {
1872        RDBLongObject lobj = URIToLongObject (bstr,RDBCodeBlank);
1873        return getLongObjectID(lobj, LONG_URI_TABLE, add);
1874    }
1875    
1876    /**
1877     * Return the database ID for the URI, if it exists
1878     */

1879    public DBIDInt getURIID(String JavaDoc qname, boolean add) throws RDFRDBException {
1880        RDBLongObject lobj = URIToLongObject (qname,RDBCodeURI);
1881        return getLongObjectID(lobj, LONG_URI_TABLE, add);
1882    }
1883
1884    protected RDBLongObject URIToLongObject ( String JavaDoc qname, String JavaDoc code ) {
1885        RDBLongObject res = new RDBLongObject();
1886        int headLen;
1887        int avail;
1888
1889        res.head = code + RDBCodeValue + RDBCodeDelim;
1890        headLen = res.head.length();
1891        avail = INDEX_KEY_LENGTH - (headLen + EOS_LEN);
1892        if ( qname.length() > avail ) {
1893            res.head = res.head + qname.substring(0,avail);
1894            res.tail = qname.substring(avail);
1895            res.hash = stringToHash(res.tail);
1896        } else {
1897            res.head = res.head + qname;
1898            res.tail = "";
1899        }
1900        res.head = res.head + EOS;
1901        return res;
1902    }
1903            
1904    
1905    /**
1906     * Return the database ID for the literal, if it exists
1907     */

1908    public DBIDInt getLiteralID(Node_Literal lnode, boolean add) throws RDFRDBException {
1909        RDBLongObject lobj = literalToLongObject (lnode);
1910        return getLongObjectID(lobj, LONG_LIT_TABLE, add);
1911    }
1912            
1913    public DBIDInt getLongObjectID(RDBLongObject lobj, String JavaDoc table, boolean add) throws RDFRDBException {
1914        try {
1915            String JavaDoc opName = "getLongObjectID";
1916            if ( lobj.tail.length() > 0 )
1917                opName += "withChkSum";
1918            PreparedStatement JavaDoc ps = m_sql.getPreparedSQLStatement(opName, table);
1919            ps.setString(1,lobj.head);
1920            if ( lobj.tail.length() > 0 )
1921                ps.setLong(2, lobj.hash);
1922            
1923            ResultSet JavaDoc rs = ps.executeQuery();
1924            DBIDInt result = null;
1925            if (rs.next()) {
1926                result = wrapDBID(rs.getObject(1));
1927            } else {
1928                if ( add )
1929                    result = addRDBLongObject(lobj, table);
1930            }
1931            rs.close();
1932            m_sql.returnPreparedSQLStatement(ps);
1933            return result;
1934        } catch (SQLException JavaDoc e1) {
1935            // /* DEBUG */ System.out.println("Literal truncation (" + l.toString().length() + ") " + l.toString().substring(0, 150));
1936
throw new RDFRDBException("Failed to find literal", e1);
1937        }
1938    }
1939 
1940    /**
1941     * Insert a long object into the database.
1942     * This assumes the object is not already in the database.
1943     * @return the db index of the added literal
1944     */

1945    public DBIDInt addRDBLongObject(RDBLongObject lobj, String JavaDoc table) throws RDFRDBException {
1946        try {
1947            int argi = 1;
1948            String JavaDoc opname = "insertLongObject";
1949            PreparedStatement JavaDoc ps = m_sql.getPreparedSQLStatement(opname, table);
1950            int dbid = 0; // init only needed to satisy java compiler
1951
if ( PRE_ALLOCATE_ID ) {
1952                dbid = getInsertID(table);
1953                ps.setInt(argi++,dbid);
1954            }
1955             ps.setString(argi++, lobj.head);
1956             if ( lobj.tail.length() > 0 ) {
1957                ps.setLong(argi++, lobj.hash);
1958                ps.setString(argi++, lobj.tail);
1959             } else {
1960                ps.setNull(argi++,java.sql.Types.BIGINT);
1961                ps.setNull(argi++,java.sql.Types.VARCHAR);
1962             }
1963/* if (isBlob || (len == 0) ) {
1964                // First convert the literal to a UTF-16 encoded byte array
1965                // (this wouldn't be needed for jdbc 2.0 drivers but not all db's have them)
1966                byte[] temp = lit.getBytes("UTF-8");
1967                int lenb = temp.length;
1968                //System.out.println("utf-16 len = " + lenb);
1969                byte[] litData = new byte[lenb + 4];
1970                litData[0] = (byte)(lenb & 0xff);
1971                litData[1] = (byte)((lenb >> 8) & 0xff);
1972                litData[2] = (byte)((lenb >> 16) & 0xff);
1973                litData[3] = (byte)((lenb >> 24) & 0xff);
1974                System.arraycopy(temp, 0, litData, 4, lenb);
1975                
1976                // Oracle has its own way to insert Blobs
1977                if (isBlob && m_driver.getDatabaseType().equalsIgnoreCase("Oracle")) {
1978                    //TODO fix to use Blob
1979                    // For now, we do not support Blobs under Oracle
1980                    throw new RDFRDBException("Oracle driver does not currently support large literals.");
1981                } else {
1982                    ps.setBinaryStream(argi++, new ByteArrayInputStream(litData), litData.length);
1983                }
1984            }
1985*/

1986            ps.executeUpdate();
1987            //m_sql.returnPreparedSQLStatement(ps,opname);
1988
if ( !PRE_ALLOCATE_ID ) dbid = getInsertID(table);
1989            return wrapDBID(new Integer JavaDoc(dbid));
1990        } catch (Exception JavaDoc e1) {
1991            /* DEBUG */ System.out.println("Problem on long object (l=" + lobj.head + ") " + e1 );
1992            // System.out.println("ID is: " + id);
1993
throw new RDFRDBException("Failed to add long object ", e1);
1994        }
1995    }
1996    
1997    /**
1998     * Return the prefix string that has the given prefix id.
1999     * @param prefixID - the dbid of the prefix.
2000     * @return the prefix string or null if it does not exist.
2001     */

2002    protected String JavaDoc IDtoPrefix ( int prefixID ) {
2003        // check cache
2004
DBIDInt dbid = new DBIDInt(prefixID);
2005        Object JavaDoc res = prefixCache.get(dbid);
2006        if ( res != null)
2007            return (String JavaDoc) res;
2008        else
2009            return IDtoString ( prefixID, PREFIX_TABLE, RDBCodePrefix);
2010    }
2011    
2012    /**
2013    * Return the Blank node string that has the given database id.
2014    * @param bnID - the dbid of the blank node, as a string.
2015    * @return the Blank node string or null if it does not exist.
2016    */

2017    protected String JavaDoc IDtoBlank(String JavaDoc bnID) {
2018        return IDtoString(bnID, LONG_URI_TABLE, RDBCodeBlank);
2019    }
2020    /**
2021        * Return the URI string that has the given database id.
2022        * @param uriID - the dbid of the uri, as a string.
2023        * @return the uri string or null if it does not exist.
2024        */

2025    protected String JavaDoc IDtoURI(String JavaDoc uriID) {
2026        return IDtoString(uriID, LONG_URI_TABLE, RDBCodeURI);
2027    }
2028
2029    /**
2030    * Return the long literal string that has the given database id.
2031    * @param litID - the dbid of the literal..
2032    * @return the long literal string or null if it does not exist.
2033    */

2034    protected String JavaDoc IDtoLiteral ( int litID ) {
2035        return IDtoString ( litID, LONG_LIT_TABLE, RDBCodeLiteral);
2036    }
2037    
2038
2039    
2040    protected String JavaDoc IDtoString ( String JavaDoc dbidAsString, String JavaDoc table, String JavaDoc RDBcode ) {
2041        int dbID;
2042        String JavaDoc res = null;
2043        try {
2044            dbID = Integer.parseInt(dbidAsString);
2045        } catch (NumberFormatException JavaDoc e1) {
2046            throw new RDFRDBException("Invalid Object ID: " + dbidAsString);
2047        }
2048        return IDtoString (dbID, table, RDBcode);
2049    }
2050
2051    protected String JavaDoc IDtoString ( int dbID, String JavaDoc table, String JavaDoc RDBcode ) {
2052        String JavaDoc res = null;
2053        RDBLongObject lobj = IDtoLongObject(dbID, table);
2054        if ( lobj == null )
2055            throw new RDFRDBException("Invalid Object ID: " + dbID);
2056        // debug check
2057
if ( !lobj.head.substring(0,3).equals(RDBcode + RDBCodeValue + RDBCodeDelim) )
2058            throw new RDFRDBException("Malformed URI in Database: " + lobj.head);
2059        res = lobj.head.substring(3,lobj.head.length() - EOS_LEN);
2060        if ( lobj.tail != null )
2061            res = res + lobj.tail;
2062        return res;
2063    }
2064
2065    
2066    protected RDBLongObject IDtoLongObject ( int dbid, String JavaDoc table ) {
2067        RDBLongObject res = null;
2068        try {
2069            String JavaDoc opName = "getLongObject";
2070            PreparedStatement JavaDoc ps = m_sql.getPreparedSQLStatement(opName, table);
2071            ps.setInt(1,dbid);
2072            ResultSet JavaDoc rs = ps.executeQuery();
2073            if (rs.next()) {
2074                res = new RDBLongObject();
2075                res.head = rs.getString(1);
2076                res.tail = rs.getString(2);
2077            }
2078            rs.close();
2079            m_sql.returnPreparedSQLStatement(ps);
2080        } catch (SQLException JavaDoc e1) {
2081            // /* DEBUG */ System.out.println("Literal truncation (" + l.toString().length() + ") " + l.toString().substring(0, 150));
2082
throw new RDFRDBException("Failed to find literal", e1);
2083        }
2084        return res;
2085    }
2086    
2087    protected RDBLongObject IDtoLongObject ( String JavaDoc idAsString, String JavaDoc table ) {
2088        RDBLongObject res = null;
2089        int dbid;
2090        try {
2091            dbid = Integer.parseInt(idAsString);
2092        } catch (NumberFormatException JavaDoc e1) {
2093            throw new RDFRDBException("Invalid Object ID: " + idAsString);
2094        }
2095        return IDtoLongObject(dbid,table);
2096    }
2097    
2098 
2099    /**
2100     * Convert the raw SQL object used to store a database identifier into a java object
2101     * which meets the DBIDInt interface.
2102     */

2103    public DBIDInt wrapDBID(Object JavaDoc id) throws RDFRDBException {
2104        if (id instanceof Number JavaDoc) {
2105            return new DBIDInt(((Number JavaDoc)id).intValue());
2106        } else if (id == null) {
2107            return null;
2108        } else {
2109            throw new RDFRDBException("Unexpected DB identifier type: " + id);
2110            //return null;
2111
}
2112    }
2113    
2114    public String JavaDoc genSQLReifQualStmt () {
2115        return "stmt = ?";
2116    }
2117    
2118    public String JavaDoc genSQLReifQualAnyObj( boolean objIsStmt) {
2119        return "( subj = ? OR prop = ? OR obj = ?" + (objIsStmt ? " OR hasType = " +
2120            QUOTE_CHAR + "T" + QUOTE_CHAR + " )" : " )");
2121    }
2122    
2123    public String JavaDoc genSQLReifQualObj ( char reifProp, boolean hasObj ) {
2124        String JavaDoc qual = "";
2125        if ( reifProp == 'T' ) {
2126            qual = "hasType = " + QUOTE_CHAR + "T" + QUOTE_CHAR;
2127        } else {
2128            String JavaDoc cmp = (hasObj ? " = ?" : " is not null");
2129            String JavaDoc col = null;
2130            if ( reifProp == 'S' ) col = "subj";
2131            else if ( reifProp == 'P' ) col = "prop";
2132            else if ( reifProp == 'O' ) col = "obj";
2133            else throw new JenaException("Undefined reification property");
2134        
2135            qual = col + cmp;
2136        }
2137        return qual;
2138    }
2139    
2140    protected String JavaDoc colidToColname ( char colid ) {
2141        if ( colid == 'G' ) return "GraphID";
2142        if ( colid == 'P' ) return "Prop";
2143        if ( colid == 'S' ) return "Subj";
2144        if ( colid == 'O' ) return "Obj";
2145        if ( colid == 'N' ) return "Stmt";
2146        if ( colid == 'T' ) return "HasType";
2147        throw new JenaException("Invalid column identifer: '" + colid + "\'");
2148    }
2149    
2150    protected String JavaDoc aliasToString ( int alias ) {
2151        return "A" + alias;
2152    }
2153    
2154    protected String JavaDoc colAliasToString ( int alias, char colid ) {
2155        return aliasToString(alias) + "." + colidToColname(colid);
2156    }
2157
2158    /*
2159     * there's a bug in the code below in that the literal is converted to
2160     * a string BEFORE the query is run. consequently, there's a race
2161     * condition. if the (long) literal is not in the database
2162     * when the query is compiled but is added prior to running the
2163     * query, then the query will (incorrectly) return no results.
2164     * for now, we'll ignore this case and document it as a bug.
2165     */

2166    
2167    public String JavaDoc genSQLQualConst ( int alias, char pred, Node lit ) {
2168        String JavaDoc val = nodeToRDBString(lit, false);
2169        if ( val == "" )
2170            // constant not in database.
2171
// should really optimize this and not
2172
// even run the query but ok for now.
2173
val = RDBCodeInvalid;
2174        return colAliasToString(alias,pred) + "=" + QUOTE_CHAR + val + QUOTE_CHAR;
2175    }
2176
2177    public String JavaDoc genSQLReifQualConst ( int alias, char pred, Node lit ) {
2178        String JavaDoc val = "";
2179        if ( (pred == 'T') && (lit.equals(RDF.Nodes.Statement)) )
2180            val = "T";
2181        else
2182            val = nodeToRDBString(lit, false);
2183        return colAliasToString(alias,pred) + "=" + QUOTE_CHAR + val + QUOTE_CHAR;
2184    }
2185    
2186    public String JavaDoc genSQLQualParam( int alias, char pred ) {
2187        return colAliasToString(alias,pred) + "=?";
2188    }
2189
2190    public String JavaDoc genSQLQualGraphId( int alias, int graphId ) {
2191        return colAliasToString(alias,'G') + "=" + graphId;
2192    }
2193
2194    public String JavaDoc genSQLJoin( int lhsAlias, char lhsCol,
2195        int rhsAlias, char rhsCol ) {
2196            return colAliasToString(lhsAlias,lhsCol) + "=" +
2197            colAliasToString(rhsAlias,rhsCol);
2198    }
2199
2200    public String JavaDoc genSQLStringMatch( int alias, char col,
2201        String JavaDoc fun, String JavaDoc stringToMatch ) {
2202        boolean ignCase =
2203           fun.equals(ExpressionFunctionURIs.J_startsWithInsensitive) ||
2204           fun.equals(ExpressionFunctionURIs.J_endsWithInsensitive);
2205        boolean pfxMatch =
2206           fun.equals(ExpressionFunctionURIs.J_startsWith) ||
2207           fun.equals(ExpressionFunctionURIs.J_startsWithInsensitive);
2208        String JavaDoc var = colAliasToString(alias,col);
2209        // generate string match operation for short literal or URI
2210
String JavaDoc qual = " ( " + genSQLStringMatchLHS(ignCase,var);
2211        qual += " " + genSQLStringMatchOp(ignCase,fun);
2212        qual += " " + genSQLStringMatchRHS(ignCase,pfxMatch,stringToMatch);
2213        // now match long URI or Bnode or, if object col, long literal
2214
qual += " " + genSQLOrKW() + genSQLStringMatchLHS(false,var);
2215        qual += " " + genSQLStringMatchOp(false,fun);
2216        qual += " " + genSQLStringMatchLong() + " )";
2217    
2218        return qual;
2219    }
2220    
2221    public String JavaDoc genSQLStringMatchLHS( boolean ignCase, String JavaDoc var ) {
2222        return ignCase ? genSQLStringMatchLHS_IC(var): var;
2223    }
2224
2225    public String JavaDoc genSQLStringMatchLong( ) {
2226        return QUOTE_CHAR + stringMatchAnyChar() + stringMatchLongObj() +
2227                stringMatchAllChar() + QUOTE_CHAR;
2228    }
2229
2230    public String JavaDoc genSQLStringMatchOp( boolean ignCase, String JavaDoc fun ) {
2231        return ignCase ? genSQLStringMatchOp_IC(fun):
2232                         genSQLStringMatchOp(fun);
2233    }
2234
2235    public String JavaDoc stringMatchAllChar() { return "%"; }
2236    public String JavaDoc stringMatchAnyChar() { return "_"; }
2237    public String JavaDoc stringMatchEscapeChar() { return "\\\\"; }
2238    public String JavaDoc stringMatchLongObj() { return "r"; }
2239    public String JavaDoc stringMatchShortObj() { return "v"; }
2240
2241    public String JavaDoc genSQLStringMatchRHS( boolean ignCase, boolean pfxMatch,
2242                                    String JavaDoc strToMatch ) {
2243        boolean isEscaped = stringMatchNeedsEscape(strToMatch);
2244        if ( isEscaped ) strToMatch = addEscape(strToMatch);
2245        // for now, don't optimize for prefix match
2246
/*
2247        strToMatch = pfxMatch ? strToMatch + stringMatchAllChar() :
2248                        stringMatchAllChar() + strToMatch;
2249        strToMatch = stringMatchAllChar() + strToMatch;
2250        strToMatch = nodeToRDBString(Node.createLiteral(strToMatch),false);
2251        if ( pfxMatch && STRINGS_TRIMMED )
2252            strToMatch = strToMatch.substring(0,strToMatch.length()-1);
2253        */

2254        strToMatch = stringMatchAnyChar() + stringMatchShortObj() +
2255                stringMatchAllChar() + strToMatch + stringMatchAllChar();
2256        strToMatch = QUOTE_CHAR + strToMatch + QUOTE_CHAR;
2257        String JavaDoc qual = ignCase ? genSQLStringMatchRHS_IC(strToMatch): strToMatch;
2258        if ( isEscaped ) qual += genSQLStringMatchEscape();
2259
2260        return qual;
2261    }
2262    
2263    public String JavaDoc genSQLStringMatchLHS_IC(String JavaDoc var) {
2264        return var;
2265    }
2266
2267    public String JavaDoc genSQLStringMatchRHS_IC(String JavaDoc strToMatch) {
2268        return strToMatch;
2269    }
2270
2271    public String JavaDoc genSQLStringMatchOp( String JavaDoc fun ) {
2272        return genSQLLikeKW();
2273    }
2274
2275    public String JavaDoc genSQLStringMatchOp_IC( String JavaDoc fun ) {
2276        return genSQLLikeKW();
2277    }
2278    
2279    public boolean stringMatchNeedsEscape ( String JavaDoc strToMatch ) {
2280        return strToMatch.indexOf('_') >= 0;
2281    }
2282
2283    public String JavaDoc addEscape ( String JavaDoc strToMatch ) {
2284        int i = strToMatch.indexOf('_');
2285        return strToMatch.substring(0,i) + stringMatchEscapeChar() +
2286                    strToMatch.substring(i);
2287    }
2288    
2289    public String JavaDoc genSQLStringMatchEscape() {
2290        return "";
2291    }
2292    
2293    public String JavaDoc genSQLResList( int resIndex[], VarDesc[] binding ) {
2294        String JavaDoc resList = "";
2295        int i,j;
2296        for(i=0,j=0;i<binding.length;i++) {
2297            VarDesc b = binding[i];
2298            if ( !b.isArgVar() ) {
2299                // next result variable
2300
resList += (j>0?", ":"") + colAliasToString(b.alias,b.column);
2301                if ( j >= resIndex.length )
2302                    throw new JenaException("Too many result columns");
2303                resIndex[j++] = b.mapIx;
2304            }
2305        }
2306        return resList;
2307    }
2308    
2309    public String JavaDoc genSQLFromList( int aliasCnt, String JavaDoc table ) {
2310        int i;
2311        String JavaDoc resList = "";
2312        for(i=0;i<aliasCnt;i++) {
2313            resList += (i>0?", ":"") + table + " " + aliasToString(i);
2314        }
2315        return resList;
2316
2317    }
2318    
2319    public String JavaDoc genSQLLikeKW() {
2320        return "Like ";
2321    }
2322
2323    public String JavaDoc genSQLEscapeKW() {
2324        return "Escape ";
2325    }
2326
2327    public String JavaDoc genSQLSelectKW() {
2328        return "Select ";
2329    }
2330    
2331    public String JavaDoc genSQLFromKW() {
2332        return "From ";
2333    }
2334    
2335    public String JavaDoc genSQLWhereKW() {
2336        return "Where ";
2337    }
2338    
2339    public String JavaDoc genSQLOrKW() {
2340        return "Or ";
2341    }
2342    
2343
2344    
2345    public String JavaDoc genSQLSelectStmt( String JavaDoc res, String JavaDoc from, String JavaDoc qual ) {
2346        return genSQLSelectKW() + res + " " +
2347            genSQLFromKW() + from + " " +
2348            (qual.length() == 0 ? qual :genSQLWhereKW()) + qual;
2349    }
2350
2351    
2352    protected int getTableCount(int graphId) {
2353        try {
2354            DatabaseMetaData JavaDoc dbmd = m_dbcon.getConnection().getMetaData();
2355            String JavaDoc[] tableTypes = { "TABLE" };
2356            int res = 0;
2357            String JavaDoc tblPattern =
2358                TABLE_NAME_PREFIX + "g" + Integer.toString(graphId) + "%";
2359            tblPattern = stringToDBname(tblPattern);
2360            ResultSet JavaDoc alltables =
2361                dbmd.getTables(null, null, tblPattern, tableTypes);
2362            while (alltables.next()) {
2363                res += 1;
2364            }
2365            alltables.close();
2366            return res;
2367        } catch (SQLException JavaDoc e1) {
2368            throw new RDFRDBException("Internal SQL error in driver - " + e1);
2369        }
2370    }
2371    
2372    /*
2373     * getters and setters for database options
2374     */

2375     
2376     public int getLongObjectLength () {
2377        return LONG_OBJECT_LENGTH;
2378     }
2379     
2380     public void setLongObjectLength ( int len ) {
2381        checkDbUninitialized();
2382        if ( len > LONG_OBJECT_LENGTH_MAX )
2383            throw new JenaException("IndexKeyLength exceeds maximum value for database");
2384        LONG_OBJECT_LENGTH = len;
2385    }
2386
2387    public int getIndexKeyLength () {
2388        return INDEX_KEY_LENGTH;
2389    }
2390     
2391    public void setIndexKeyLength ( int len ) {
2392        checkDbUninitialized();
2393        if ( len > INDEX_KEY_LENGTH_MAX )
2394            throw new JenaException("IndexKeyLength exceeds maximum value for database");
2395        INDEX_KEY_LENGTH = len;
2396    }
2397    
2398    public boolean getIsTransactionDb () {
2399        return IS_XACT_DB;
2400    }
2401     
2402    public void setIsTransactionDb ( boolean bool ) {
2403        checkDbUninitialized();
2404        if ( bool == false )
2405            throw new JenaException("setIsTransactionDb unsupported for this database engine");
2406    }
2407
2408    public boolean getDoCompressURI () {
2409            return URI_COMPRESS;
2410    }
2411    
2412    public void setDoCompressURI ( boolean bool ) {
2413        checkDbUninitialized();
2414        URI_COMPRESS = bool;
2415    }
2416    
2417    public int getCompressURILength() {
2418        return URI_COMPRESS_LENGTH;
2419    }
2420    
2421    public void setCompressURILength ( int len ) {
2422        checkDbUninitialized();
2423        URI_COMPRESS_LENGTH = len;
2424    }
2425    
2426    public boolean getDoDuplicateCheck() {
2427        return !SKIP_DUPLICATE_CHECK;
2428    }
2429    
2430    public void setDoDuplicateCheck(boolean bool) {
2431        SKIP_DUPLICATE_CHECK = !bool;
2432    }
2433
2434    protected boolean dbIsOpen() {
2435        return (m_sysProperties != null);
2436    }
2437
2438    protected void checkDbIsOpen() {
2439        if ( !dbIsOpen() )
2440            throw new JenaException("Database not open");
2441    }
2442    
2443    protected void checkDbUninitialized() {
2444        if ( dbIsOpen() || isDBFormatOK() )
2445            throw new JenaException("Database configuration option cannot be set after database is formatted");
2446    }
2447
2448    public String JavaDoc getTableNamePrefix() {
2449        return TABLE_NAME_PREFIX;
2450    }
2451
2452    public void setTableNamePrefix ( String JavaDoc prefix ) {
2453        if ( dbIsOpen() )
2454            throw new JenaException("Table name prefix must be set before opening or connecting to a model.");
2455        /* sanity check that the new prefix length is not too long.
2456         * we have to add a few characters to the given prefix to
2457         * account for the index names (see the createStatementTable
2458         * template in the etc/<db>.sql files).
2459         */

2460        String JavaDoc sav = TABLE_NAME_PREFIX;
2461        String JavaDoc testpfx = prefix;
2462        int i;
2463        for ( i=0;i<MAXIMUM_INDEX_COLUMNS;i++) testpfx += "X";
2464        setTableNames(testpfx);
2465        // now see if the table names will be too long with this "prefix".
2466
try {
2467            String JavaDoc s = genTableName(10,10,true);
2468            s = genTableName(10,10,false);
2469        } catch ( RDFRDBException e ) {
2470            setTableNames(sav);
2471            throw new JenaException("New prefix (\"" + prefix +
2472                "\") is too long and will cause table names \n" +
2473                "to exceed maximum length for database (" + TABLE_NAME_LENGTH_MAX + ").");
2474        }
2475        // all ok. switch to the new prefix.
2476
setTableNames(prefix);
2477    }
2478    
2479    
2480    /** generate a table name and verify that it does not
2481     * exceed the maximum length.
2482     */

2483    
2484    protected String JavaDoc genTableName( int graphId, int tblId, boolean isReif )
2485    {
2486        String JavaDoc res = stringToDBname(TABLE_NAME_PREFIX +
2487                "g" + Integer.toString(graphId) +
2488                "t" + Integer.toString(tblId) +
2489                (isReif ? REIF_TABLE_NAME_SUFFIX : STMT_TABLE_NAME_SUFFIX));
2490        if ( res.length() > TABLE_NAME_LENGTH_MAX )
2491            throw new RDFRDBException("New table name (\"" + res +
2492            "\") exceeds maximum length for database (" + TABLE_NAME_LENGTH_MAX + ").");
2493        return res;
2494    }
2495    
2496    
2497       /** Names of jena system tables.
2498       protected String [] SYSTEM_TABLE_NAME; */

2499    
2500    protected void setTableNames ( String JavaDoc prefix ) {
2501        TABLE_NAME_PREFIX = stringToDBname(prefix);
2502        int i = 0;
2503        SYSTEM_TABLE_NAME = new String JavaDoc[6];
2504        SYSTEM_TABLE_NAME[i++] = SYSTEM_STMT_TABLE = stringToDBname(TABLE_NAME_PREFIX + "sys_stmt");
2505        SYSTEM_TABLE_NAME[i++] = LONG_LIT_TABLE = stringToDBname(TABLE_NAME_PREFIX + "long_lit");
2506        SYSTEM_TABLE_NAME[i++] = LONG_URI_TABLE = stringToDBname(TABLE_NAME_PREFIX + "long_uri");
2507        SYSTEM_TABLE_NAME[i++] = PREFIX_TABLE = stringToDBname(TABLE_NAME_PREFIX + "prefix");
2508        SYSTEM_TABLE_NAME[i++] = GRAPH_TABLE = stringToDBname(TABLE_NAME_PREFIX + "graph");
2509        SYSTEM_TABLE_NAME[i++] = MUTEX_TABLE = stringToDBname(TABLE_NAME_PREFIX + "mutex");
2510        SYSTEM_TABLE_CNT = i;
2511    }
2512    
2513    /**
2514     * Return the number of system tables.
2515     */

2516
2517    public int getSystemTableCount() {
2518        return SYSTEM_TABLE_CNT;
2519    }
2520    
2521    /**
2522     * Return the name of a system table
2523     */

2524
2525    public String JavaDoc getSystemTableName ( int i ) {
2526        return ((i < 0) || (i >= SYSTEM_TABLE_CNT)) ?
2527            null : SYSTEM_TABLE_NAME[i];
2528    }
2529
2530    
2531    public String JavaDoc getStoreWithModel() {
2532        return STORE_WITH_MODEL;
2533    }
2534
2535    public void setStoreWithModel(String JavaDoc modelName) {
2536        String JavaDoc name = null;
2537        if ((modelName != null) && !modelName.equals(""))
2538            name = modelName;
2539        STORE_WITH_MODEL = name;
2540    }
2541
2542    public int getCompressCacheSize() {
2543        checkDbIsOpen();
2544        return prefixCache.getLimit();
2545    }
2546
2547    public void setCompressCacheSize(int count) {
2548        checkDbIsOpen();
2549        prefixCache.setLimit(count);
2550    }
2551
2552}
2553
2554
2555
2556/*
2557 * (c) Copyright 2003, 2004, 2005 Hewlett-Packard Development Company, LP
2558 * All rights reserved.
2559 *
2560 * Redistribution and use in source and binary forms, with or without
2561 * modification, are permitted provided that the following conditions
2562 * are met:
2563 * 1. Redistributions of source code must retain the above copyright
2564 * notice, this list of conditions and the following disclaimer.
2565 * 2. Redistributions in binary form must reproduce the above copyright
2566 * notice, this list of conditions and the following disclaimer in the
2567 * documentation and/or other materials provided with the distribution.
2568 * 3. The name of the author may not be used to endorse or promote products
2569 * derived from this software without specific prior written permission.
2570
2571 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2572 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2573 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2574 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2575 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2576 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2577 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2578 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2579 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2580 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2581 */

2582
Popular Tags