Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: nl/aidministrator/rdf/ral/rdbms/SQLRAL.java


1   /*  Sesame - Storage and Querying architecture for RDF and RDF Schema
2    *  Copyright (C) 2002 Aidministrator Nederland b.v.
3    *
4    *  Contact: 
5    *  Aidministrator Nederland b.v.
6    *  Julianaplein 14b 
7    *  3817 CS Amersfoort
8    *  The Netherlands
9    *  tel. +31(0)33 4659987
10   *  fax. +31(0)33 4659987
11   *  sesame@aidministrator.nl
12   *
13   *   http://www.aidministrator.nl/
14   *  
15   *  This library is free software; you can redistribute it and/or
16   *  modify it under the terms of the GNU Lesser General Public
17   *  License as published by the Free Software Foundation; either
18   *  version 2.1 of the License, or (at your option) any later version.
19   *
20   *  This library is distributed in the hope that it will be useful,
21   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23   *  Lesser General Public License for more details.
24   *
25   *  You should have received a copy of the GNU Lesser General Public
26   *  License along with this library; if not, write to the Free Software
27   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28   */
29  
30  package nl.aidministrator.rdf.ral.rdbms;
31  
32  import nl.aidministrator.rdf.sail.model.*;
33  import nl.aidministrator.rdf.ral.*;
34  import nl.aidministrator.rdf.rql.MalformedQueryException;
35  import nl.aidministrator.rdf.ral.util.*;
36  import nl.aidministrator.rdf.vocabulary.*;
37  import nl.aidministrator.util.jdbc.ConnectionPool;
38  import nl.aidministrator.util.servlets.ServletLog;
39  import nl.aidministrator.util.StringUtil;
40  import java.sql.*;
41  import java.util.*;
42  
43  /**
44   * An implementation of the Repository Abstraction Layer based on SQL, also
45   * SQL92 or SQL2, that implements an relational databaseschema developed in the
46   * project Sesame Advance at AIdministrator.
47   * Each DBMS has its own SQL dialect. For example each DBMS differs in
48   * datatypes, the variable length character datatype is defined in Oracle as
49   * nvarchar2(n) and in MySQL as varchar(n). This means that for each DBMS each
50   * SQL query must multiple times be defined. This is solved as described next.
51   * SQLRAL defines static final Strings, like ID_INT. Each time the integer
52   * datatype is used in a SQL query it is substituted by ID_INT. For each DBMS
53   * there is a subclass of SQLRAL defined. ID_INT is initialized in the subclass
54   * of SQLRAL for the specific DBMS. For example ID_INT for MySQL is initialized
55   * as int unsigned, for PostgreSQL as int4.
56   * SQLRAL is an abstract class, no instances of SQLRAL can be created.
57   *
58   * @author Peter van 't Hof
59   * @version 1.13, 01/30/02
60   */
61  public abstract class SQLRAL implements RAL {
62  /*----------+
63  | Constants  |
64  +----------*/
65    // Names of tables in database.
66    /**
67     * Name of table containing namespaces. */
68    public static final String NAMESPACES_TABLE = "namespaces";
69    /**
70     * Name of table containing resources. */
71    public static final String RESOURCES_TABLE = "resources";
72    /**
73     * Name of table containing literals. */
74    public static final String LITERALS_TABLE = "literals";
75    /**
76     * Name of table containing classes.  */
77    public static final String CLASS_TABLE = "class";
78    /**
79     * Name of table containing properties. */
80    public static final String PROPERTY_TABLE = "property";
81    /**
82     * Name of table containing statements where predicate is rdfs:subClassOf */
83    public static final String SUBCLASSOF_TABLE = "subclassof";
84    /**
85     * Name of table containing statements where predicate is rdfs:subPropertyOf.
86     */
87    public static final String SUBPROPERTYOF_TABLE = "subpropertyof";
88    /**
89     * Name of table containing domains. */
90    public static final String DOMAIN_TABLE = "domain";
91    /**
92     * Name of table containing ranges. */
93    public static final String RANGE_TABLE = "range";
94    /**
95     * Name of table containing statements where predicate is rdf:type. */
96    public static final String TYPE_TABLE = "type";
97    /**
98     * Name of table containing comments. */
99    public static final String COMMENT_TABLE = "comment";
100   /**
101    * Name of table containing labels. */
102   public static final String LABEL_TABLE = "label";
103   /**
104    * Name of table containing all statements. */
105   public static final String TRIPLES_TABLE = "triples";
106 
107   // Database dependent datatypes.
108   /**
109    * Integer datatype. */
110   protected String ID_INT = null;
111   /**
112    * Datatype of localname of resource. varchar(64) is default datatype for
113    * Postgres and MySQL.
114    */
115   protected String LOCALNAME = "varchar(255)";
116   /**
117    * Datatype of language of literal. varchar(4) is default datatype for
118    * Postgres and MySQL.
119    */
120   protected String LANGUAGE = "varchar(4)";
121   /**
122    * Datatype of value of literal. text is default datatype for Postgres and
123    * MySQL.
124    */
125   protected String VALUE = "text";
126   /**
127    * Datatype of prefix of namespace. varchar(16) default datatype for Postgres
128    * and MySQL.
129    */
130   protected String PREFIX = "varchar(16)";
131   /**
132    * Datatype of name of namespace. text is default datatype for Postgres and
133    * MySQL.
134    */
135   protected String NAME = "text";
136   /**
137    * Datatype of boolean. bool is default datatype for Postgres and MySQL. */
138   protected String IS_DERIVED = "bool";
139   /**
140    * Datatype of comment. text is default datatype for Postgres and MySQL. */
141   protected String COMMENT = "text";
142   /**
143    * Datatype of label. varchar(64) is default datatype for Postgres and MySQL.
144    */
145   protected String LABEL = "varchar(64)";
146   /**
147    * Length of an index. Used by MySQL only when an index is created on a
148    * column with datatype text.
149    */
150   protected String INDEXLENGTH = "";
151   /**
152    * Boolean value true.  */
153   protected String TRUE = null;
154   /**
155    * Boolean value false. */
156   protected String FALSE = null;
157   
158 /*----------+
159 | Variables  |
160 +----------*/
161 
162   /**
163    * Repositoryname identifying repository. */
164   protected String _reposName;
165   /**
166    * ConnectionPool between DBMS and RAL. */
167   protected ConnectionPool _conPool;
168 
169   /**
170    * Eliminating the need of querying the namespaces table looking for the next
171    * id to insert.
172    */
173   protected int _nextNamespaceId;
174   /**
175    * Eliminating the need of querying the resources and literals tables looking
176    * for the next id to insert.
177    */
178   protected int _nextValueId;
179  
180   // Variables for caching frequently used id 's.
181   /**
182    * Id of rdf:Property. */
183   protected int _rdfPropertyId;
184   /**
185    * Id of rdf:Type. */
186   protected int _rdfTypeId;
187 
188   /**
189    * Id of rdfs:Resource. */
190   protected int _rdfsResourceId;
191   /**
192    * Id of rdfs:Literal. */
193   protected int _rdfsLiteralId;
194   /**
195    * Id of rdfs:Class. */
196   protected int _rdfsClassId;
197   /**
198    * Id of rdfs:subPropertyOf. */
199   protected int _rdfsSubPropertyOfId;
200   /**
201    * Id of rdfs:subClassOf. */
202   protected int _rdfsSubClassOfId;
203   /**
204    * Id of rdfs:domain. */
205   protected int _rdfsDomainId;
206   /**
207    * Id of rdfs:range. */
208   protected int _rdfsRangeId;
209   /**
210    * Id of rdfs:comment. */
211   protected int _rdfsCommentId;
212   /**
213    * Id of rdfs:label. */
214   protected int _rdfsLabelId;
215 
216   /**
217    * Map with as key namespace names, and as values Namespace object.
218    * Acts as a cache. */
219   protected Map _namespaceTable;
220 
221 /*-------------------+
222 | Initialization RAL |
223 +-------------------*/
224   /**
225    * Constructor. Initializes the namespace cache.
226    */
227   public SQLRAL() {
228     _namespaceTable = new HashMap();
229     _nextValueId = 0;
230 
231     ServletLog.trace("new SQLRAL created");
232   }
233 
234   /**
235    * Needed parameters (both key and value of type String):<br>
236    *
237    * jdbcDriver : The String representing the JDBC-driver class,
238    * e.g. "org.gjt.mm.mysql.Driver"<br>
239    *
240    * jdbcUrl : The String representing the JDBC-url of the database
241    * to connect to, e.g. "jdbc:mysql://localhost/sesame"<br>
242    *
243    * dbUser : The username that can be used to connect to the DBMS<br>
244    *
245    * dbPassword : The password of the user in the DBMS<br>
246    **/
247   public void initialize(Map configParams)
248     throws Exception
249   {
250     ServletLog.trace("initializing SQLRAL");  
251 
252     // Get initialization parameters
253     String jdbcDriver = (String)configParams.get("jdbcDriver");
254     String jdbcUrl = (String)configParams.get("jdbcUrl");
255     String dbUser = (String)configParams.get("dbUser");
256     String dbPassword = (String)configParams.get("dbPassword");
257 
258     if (jdbcDriver == null) {
259       throw new Exception("parameter 'jdbcDriver' missing");
260     }
261     if (jdbcUrl == null) {
262       throw new Exception("parameter 'jdbcUrl' missing");
263     }
264     if (dbUser == null) {
265       throw new Exception("parameter 'dbUser' missing");
266     }
267     if (dbPassword == null) {
268       throw new Exception("parameter 'dbPassword' missing");
269     }
270 
271     // Load jdbc driver
272     Class.forName(jdbcDriver);
273 
274     // Create a new ConnectionPool
275     _conPool = new ConnectionPool(jdbcUrl, dbUser, dbPassword);
276 
277     _initDatabase();
278 
279     ServletLog.trace("SQLRAL initialized");
280   }
281 
282   public void shutDown() {
283     _conPool.drain();
284   }
285 /*------------------------+
286 | Initialization database |
287 +------------------------*/
288 
289   /**
290    * Initializes the database. _initDatabase() creates tables, indexes and
291    * inserts default values into the database.
292    */
293   protected void _initDatabase()
294     throws SQLException {
295     Connection con = _conPool.getConnection();
296     StringBuffer createTable = null;  // Used multiple times, is re-initialized every time.
297     StringBuffer createIndex = null;  // Used several times, is re-initialized every time.
298 
299     try {
300       java.sql.Statement st = con.createStatement();
301 
302       if (!_tableExists(NAMESPACES_TABLE)) { // Create namespaces table.
303         createTable = new StringBuffer();
304 
305         createTable.append("CREATE TABLE " + NAMESPACES_TABLE + " ");
306         createTable.append("(id " + ID_INT + " PRIMARY KEY, ");
307         createTable.append("prefix " +  PREFIX + " UNIQUE, ");
308         createTable.append("name " + NAME  + ")");
309 
310         st.executeUpdate(createTable.toString());
311 
312         createIndex = new StringBuffer();
313 
314         createIndex.append("CREATE INDEX name_ind ON " +
315             NAMESPACES_TABLE + " (name" + INDEXLENGTH + ")");
316 
317         st.executeUpdate(createIndex.toString());
318 
319         _nextNamespaceId = 0;
320 
321         // Inserting default namespace values.
322 
323         _addNamespace("rdf", RDF.NAMESPACE);
324         _addNamespace("rdfs", RDFS.NAMESPACE);
325       }
326       else {
327         _initNamespaceTable();
328       }
329 
330       if (!_tableExists(RESOURCES_TABLE)) { // Create resources table.
331         createTable = new StringBuffer();
332 
333         createTable.append("CREATE TABLE " + RESOURCES_TABLE + " ");
334         createTable.append("(id " + ID_INT + " PRIMARY KEY, ");
335         createTable.append("namespace " + ID_INT +
336             " NOT NULL REFERENCES " + NAMESPACES_TABLE + "(id), ");
337         createTable.append("localname " + LOCALNAME + " NOT NULL, ");
338         createTable.append( "UNIQUE(namespace, localname))");
339 
340         st.executeUpdate(createTable.toString());
341 
342         createIndex = new StringBuffer();
343 
344         createIndex.append("CREATE INDEX localname_ind ON " +
345             RESOURCES_TABLE + " (localname)");
346         
347         st.executeUpdate(createIndex.toString());
348       }
349 
350       if (!_tableExists(LITERALS_TABLE)) { // Create literals table.
351         createTable = new StringBuffer();
352 
353         createTable.append("CREATE TABLE " + LITERALS_TABLE + " ");
354         createTable.append("(id " + ID_INT + " PRIMARY KEY, ");
355         createTable.append("language " + LANGUAGE + " , ");
356         createTable.append("value " + VALUE + " NOT NULL");
357         createTable.append(")");
358 
359         st.executeUpdate(createTable.toString());
360 
361         createIndex = new StringBuffer();
362 
363         createIndex.append("CREATE INDEX value_ind ON " +
364             LITERALS_TABLE + " (value" + INDEXLENGTH + ")");
365 
366         st.executeUpdate(createIndex.toString());
367       }
368 
369       if (!_tableExists(CLASS_TABLE)) { // Create class table.
370         createTable = new StringBuffer();
371 
372         createTable.append("CREATE TABLE " + CLASS_TABLE + " ");
373         createTable.append("(id " + ID_INT + " PRIMARY KEY " + 
374             "REFERENCES " + RESOURCES_TABLE + "(id), ");
375         createTable.append("is_derived " + IS_DERIVED + " NOT NULL)");
376 
377         st.executeUpdate(createTable.toString());
378       }
379 
380       if (!_tableExists(PROPERTY_TABLE)) { // Create property table.
381         createTable = new StringBuffer();
382 
383         createTable.append("CREATE TABLE " + PROPERTY_TABLE + " ");
384         createTable.append("(id " + ID_INT + " PRIMARY KEY " +
385             "REFERENCES " + RESOURCES_TABLE + "(id), ");
386         createTable.append("is_derived " + IS_DERIVED + " NOT NULL)");
387 
388         st.executeUpdate(createTable.toString());
389       }
390 
391       if (!_tableExists(SUBCLASSOF_TABLE)) { // Create subClassOf table.
392         createTable = new StringBuffer();
393 
394         createTable.append("CREATE TABLE " + SUBCLASSOF_TABLE + " ");
395         createTable.append("(sub " + ID_INT + " NOT NULL REFERENCES " +
396             CLASS_TABLE + "(id), ");
397         createTable.append("super " + ID_INT + " NOT NULL REFERENCES " +
398             CLASS_TABLE + "(id), ");
399         createTable.append("is_derived " + IS_DERIVED + " NOT NULL, ");
400         createTable.append("UNIQUE(sub, super))");
401 
402         st.executeUpdate(createTable.toString());
403       }
404 
405       if (!_tableExists(SUBPROPERTYOF_TABLE)) { // Create subPropertyOf table.
406         createTable = new StringBuffer();
407 
408         createTable.append("CREATE TABLE " + SUBPROPERTYOF_TABLE + " ");
409         createTable.append("(sub " + ID_INT + " NOT NULL REFERENCES " +
410             PROPERTY_TABLE + "(id), ");
411         createTable.append("super " + ID_INT + " NOT NULL REFERENCES " +
412             PROPERTY_TABLE + "(id), ");
413         createTable.append("is_derived " + IS_DERIVED + " NOT NULL, ");
414         createTable.append("UNIQUE(sub, super))");
415 
416         st.executeUpdate(createTable.toString());
417       }
418 
419       if (!_tableExists(DOMAIN_TABLE)) { // Create domain table.
420         createTable = new StringBuffer();
421 
422         createTable.append("CREATE TABLE " + DOMAIN_TABLE + " ");
423         createTable.append("(property " + ID_INT + " NOT NULL " +
424             "REFERENCES " + PROPERTY_TABLE + "(id), ");
425         createTable.append("class  " + ID_INT + " NOT NULL " + 
426             "REFERENCES " + CLASS_TABLE + "(id), ");
427         createTable.append("is_derived " + IS_DERIVED + " NOT NULL, ");
428         createTable.append("UNIQUE(property, class))");
429 
430         st.executeUpdate(createTable.toString());
431       }
432 
433       if (!_tableExists(RANGE_TABLE)) { // Create Range table.
434         createTable = new StringBuffer();
435 
436         createTable.append("CREATE TABLE " + RANGE_TABLE + " ");
437         createTable.append("(property " + ID_INT + " NOT NULL " + 
438             "REFERENCES " + PROPERTY_TABLE + "(id), ");
439         createTable.append("class " + ID_INT + " NOT NULL " +
440             "REFERENCES " +CLASS_TABLE + "(id), ");
441         createTable.append("is_derived " + IS_DERIVED + " NOT NULL, ");
442         createTable.append("UNIQUE(property, class))");
443 
444         st.executeUpdate(createTable.toString());
445       }
446 
447       if (!_tableExists(TYPE_TABLE)) { // Create type table.
448         createTable = new StringBuffer();
449         createTable.append("CREATE TABLE " + TYPE_TABLE + " ");
450         // Should reference to literals or resources table.
451         createTable.append("(val " + ID_INT + " NOT NULL, ");
452         createTable.append("class " + ID_INT + " NOT NULL " +
453             "REFERENCES " + CLASS_TABLE + "(id), ");
454         createTable.append("is_derived " + IS_DERIVED + " NOT NULL, ");
455         createTable.append("UNIQUE(val, class))");
456 
457         st.executeUpdate(createTable.toString());
458       }
459 
460       if (!_tableExists(COMMENT_TABLE)) { // Create comment table.
461         createTable = new StringBuffer();
462 
463         createTable.append("CREATE TABLE " + COMMENT_TABLE + " ");
464         createTable.append("(resource " + ID_INT + " NOT NULL " +
465             "REFERENCES " + RESOURCES_TABLE + "(id), ");
466         createTable.append("literal " + ID_INT + " NOT NULL " +
467             "REFERENCES " + LITERALS_TABLE + "(id),  ");
468         createTable.append("is_derived " + IS_DERIVED + " NOT NULL, ");
469         createTable.append("UNIQUE(resource, literal))");
470 
471         st.executeUpdate(createTable.toString());
472       }
473 
474       if (!_tableExists(LABEL_TABLE)) { // Create label table.
475         createTable = new StringBuffer();
476 
477         createTable.append("CREATE TABLE " + LABEL_TABLE + " ");
478         createTable.append("(resource " + ID_INT + " NOT NULL " +
479             "REFERENCES " + RESOURCES_TABLE + "(id), ");
480         createTable.append("literal " + ID_INT + " NOT NULL " +
481             "REFERENCES " + LITERALS_TABLE + "(id),  ");
482         createTable.append("is_derived " + IS_DERIVED + " NOT NULL, ");
483         createTable.append("UNIQUE(resource, literal))");
484 
485         st.executeUpdate(createTable.toString());
486       }
487 
488       if (!_tableExists(TRIPLES_TABLE)) {  // Create triples table.
489         createTable = new StringBuffer();
490 
491         createTable.append("CREATE TABLE " + TRIPLES_TABLE + " ");
492         createTable.append("(subject " + ID_INT + " NOT NULL " +
493             "REFERENCES " + RESOURCES_TABLE + "(id), ");
494         createTable.append("predicate " + ID_INT + " NOT NULL " +
495             "REFERENCES " + PROPERTY_TABLE + "(id), ");
496         // Should reference to literals or resources table.
497         createTable.append("object " + ID_INT + " NOT NULL, ");
498         createTable.append("is_derived " + IS_DERIVED + " NOT NULL, ");
499         createTable.append("UNIQUE(subject, predicate, object))");
500 
501         st.executeUpdate(createTable.toString());
502       }
503 
504       // Look for next id of value to insert.
505          _nextValueId = _getNextValueId();
506 
507       _initData();  // Insert rdf en rdfs primitives needed by SQLRAL.
508 
509       st.close();
510     }
511     finally {
512       con.close();
513     }
514   }
515 
516   /* rdf and rdfs primitives cannot be inserted using the public methods.
517    * Whenever an id is created for a resource (or literal, we will take
518    * rdfs:Resource as an example), addInstance(int, int, boolean) is called.
519    * A derived statement 'x is of type rdfs:Resource' is stored within the type
520    * table. Before this statement can be stored, rdfs:Resource must exist as a
521    * class. addClass(Resource) is called with rdfs:Resource as the parameter.
522    * When this method is first called, rdfs:Resource doesn 't exist yet. So
523    * within addClass(Resource) an id is created for rdfs:Resource, within
524    * createIdForResource(Resource) addInstance(int, int, boolean) is -again-
525    * called to add the derived statement 'rdfs:Resource is of type
526    * rdfs:Resource'. But rdfs:Resource doesn 't exist yet, so
527    * addClass(Resource) is called again...etc. ect. 
528    * Whatever rdf or rdfs primitive you begin with, you will always end up
529    * like this. (Try it out for yourself:)
530    * This is why you cannot make use of the default methods and must define
531    * private methods for adding rdf and rdfs primitives. For example,
532    * createIdForPrimitive(Resource) doesn 't call
533    * addInstance(int, int, boolean) in its body, addInstance is called some
534    * time afterwards.
535    */
536   private void _initData()
537     throws SQLException {
538     _rdfsResourceId = _createIdForPrimitive(Resource.RDFS_RESOURCE);
539 
540     if (!_isClassOrProperty(_rdfsResourceId, CLASS_TABLE)) {
541       // Insert rdfs:Resource as a class.
542       _addRow(CLASS_TABLE, _rdfsResourceId, true);
543     }
544     _rdfTypeId = _createIdForPrimitive(Resource.RDF_TYPE);
545 
546     if (!_isClassOrProperty(_rdfTypeId, PROPERTY_TABLE)) {
547       // Insert rdf:Type as a property.
548       _addRow(PROPERTY_TABLE, _rdfTypeId, true);
549     }
550     // rdfs:Resource is of type rdfs:Resource.
551     _addInstance(_rdfsResourceId, _rdfsResourceId);
552     // rdf:Type is of type rdfs:Resource.
553     _addInstance(_rdfTypeId, _rdfsResourceId);
554     
555     // The remaining id 's can now make use of createIdForResource(Resource).
556 
557     _rdfPropertyId = _createIdForResource(Resource.RDF_PROPERTY);
558 
559     _rdfsLiteralId = _createIdForResource(Resource.RDFS_LITERAL);
560     _rdfsClassId = _createIdForResource(Resource.RDFS_CLASS);
561     _rdfsSubPropertyOfId = _createIdForResource(Resource.RDFS_SUBPROPERTYOF);
562     _rdfsSubClassOfId = _createIdForResource(Resource.RDFS_SUBCLASSOF);
563     _rdfsDomainId = _createIdForResource(Resource.RDFS_DOMAIN);
564     _rdfsRangeId = _createIdForResource(Resource.RDFS_RANGE);
565     _rdfsCommentId = _createIdForResource(Resource.RDFS_COMMENT);
566     _rdfsLabelId = _createIdForResource(Resource.RDFS_LABEL);
567 
568     _addClass(_rdfsClassId);
569     _addClass(_rdfPropertyId);
570     _addClass(_rdfsResourceId);
571     _addClass(_rdfsLiteralId);
572 
573     _addProperty(_rdfsSubPropertyOfId);
574     _addProperty(_rdfsSubClassOfId);
575     _addProperty(_rdfsDomainId);
576     _addProperty(_rdfsRangeId);
577     _addProperty(_rdfsCommentId);
578     _addProperty(_rdfsLabelId);
579 
580     _addInstance(_rdfsResourceId, _rdfsClassId);
581     _addInstance(_rdfTypeId, _rdfPropertyId);
582   }
583 
584   /* This method is different from _createIdForResource(Resource), because
585    * _createIdForPrimitive(Resource) does not call _addInstance(int, int)
586    * after _addResource(String, String).
587    */
588   private int _createIdForPrimitive(Resource resource)
589     throws SQLException {
590     int namespaceId = _createIdForNamespace(resource.getNamespace());
591     int primitiveId = _getResourceId(resource);
592     
593     // resourceId is -1 if resource is not found.
594     if (primitiveId == -1) {
595       primitiveId = _addResource(namespaceId, _escapeString(resource.getLocalName()));
596     }
597     return primitiveId;
598   }
599 
600   /* Used by _initData() to add a rdf or rdfs primitive as a instance. This
601    * method is different from its public and private equivalents! It uses two
602    * id 's and checks if the instances already exists. 
603    */
604   private void _addInstance(int valueId, int classId)
605     throws SQLException {
606     if (!_isRow(TYPE_TABLE, "val", valueId, "class", classId)) {
607       _addInstance(valueId, classId, true);
608     }
609   }
610 
611   /* Used by _initData() to add a rdf or rdfs primitive as a property. This
612    * method is different from its public equivalent! It uses an id and checks
613    * if the property already exists.
614    */
615   private void _addProperty(int propertyId)
616     throws SQLException {
617     if (!_isClassOrProperty(propertyId, PROPERTY_TABLE)) {
618       _addRow(PROPERTY_TABLE, propertyId, true);
619       _addInstance(propertyId, _rdfPropertyId, true);
620     }    
621   }
622 
623   /* Used by _initData() to add a rdf or rdfs primitive as a class. This
624    * method is different from its public equivalent! It uses an id and
625    * checks if the class already exists.
626    */
627   private void _addClass(int classId)
628     throws SQLException {
629     if (!_isClassOrProperty(classId, CLASS_TABLE)) {
630       _addRow(CLASS_TABLE, classId, true);
631       _addInstance(classId, _rdfsClassId, true);
632     }
633   }
634 
635   private void _initNamespaceTable()
636     throws SQLException {
637     StringBuffer query = new StringBuffer();
638 
639     query.append("SELECT id, prefix, name ");
640     query.append("FROM " + NAMESPACES_TABLE);
641 
642     Connection con = _conPool.getConnection();
643   
644     try {
645       java.sql.Statement st = con.createStatement();
646       ResultSet rs = st.executeQuery(query.toString());
647       int maximum = _nextNamespaceId;
648 
649       while (rs.next()) {
650         int id = rs.getInt(1);
651         String prefix = rs.getString(2);
652         String name = rs.getString(3);
653 
654         _namespaceTable.put(name, new Namespace(id, prefix, name));
655         
656         if (id > maximum) {
657           maximum = id;
658         }
659       }
660       _nextNamespaceId = maximum;
661 
662       rs.close();
663       st.close();
664     }
665     finally {
666       con.close();
667       }
668   }
669 
670 /*---------------------+
671 | Add/(delete) methods |
672 +---------------------*/
673 
674   public void addDataStatement(Resource subject, Resource predicate, Value object)
675     throws SQLException  {
676     //    try {
677       _addDataStatement(_createIdForResource(subject), _getResourceId(predicate),  _createIdForValue(object), false);
678       //    }
679       //    catch (SQLException e) {
680       // FIXME: should throw a RalException
681 
682       //      System.err.println("SQLException in addDataStatement(Resource, Resource, Value)...");
683       //    }
684   }
685   
686   public void addProperty(Resource property)
687         throws SQLException  {
688     //    try {
689       int propertyId = _createIdForResource(property);
690 
691       _addRow(PROPERTY_TABLE, propertyId, false);
692       _addInstance(propertyId, _rdfPropertyId, false);
693       //    }
694       //    catch (SQLException e) {
695       // FIXME: should throw a RalException
696 
697       //      System.err.println("SQLException in addProperty(Property)...");
698       //    }
699   }
700 
701   public void addClass(Resource classResource)
702     throws SQLException  {
703     //    try {
704       int classId = _createIdForResource(classResource);
705       
706       _addRow(CLASS_TABLE, classId, false);
707       _addInstance(classId, _rdfsClassId, false);
708 
709       _addSubClass(classId, _rdfsResourceId, true);
710       //    }
711       //    catch (SQLException e) {
712       // FIXME: should throw a RalException
713 
714       //      System.err.println("SQLException in addClass(Resource)...");
715       //    }
716   }
717 
718   public void addInstance(Value dataValue, Resource classResource)
719         throws SQLException  {
720     //    try {
721     int valueId = _createIdForValue(dataValue);
722 
723     /* dataValue of type rfds:Resource or rdfs:Literal is already defined by
724      * createIdForValue(Value)
725      */
726     if (!classResource.equals(Resource.RDFS_RESOURCE) && !classResource.equals(Resource.RDFS_LITERAL)) {
727       int classId = _getResourceId(classResource);
728     
729       _addInstance(valueId, classId, false);
730     }
731       //    }
732       //    catch (SQLException e) {
733       // FIXME: should throw a RalException
734 
735       //      System.err.println("SQLException in addInstance(Value, Resource)...");
736       //    }
737   }
738 
739   public void addSubProperty(Resource subProp, Resource superProp)
740     throws SQLException {
741   //    try {
742     int subPropertyId = _getResourceId(subProp);
743     int superPropertyId = _getResourceId(superProp);
744 
745     _addRow(SUBPROPERTYOF_TABLE, subPropertyId, superPropertyId, false);
746     _addDataStatement(subPropertyId, _rdfsSubPropertyOfId, superPropertyId, false);
747   //    }
748   //    catch (SQLException e) {
749     // FIXME: should throw a RalException
750 
751     //      System.err.println("SQLException in addSubProperty(Resource, Resource)...");    
752   //    }
753   }
754 
755   public void addSubClass(Resource subClass, Resource superClass)
756         throws SQLException  {
757   //    try {
758     int subClassId = _getResourceId(subClass);
759     int superClassId = _getResourceId(superClass);
760 
761     boolean isSubClassOf = false;
762 
763     StringBuffer query = new StringBuffer();
764 
765     query.append("SELECT sub, super ");
766     query.append("FROM " + SUBCLASSOF_TABLE + " ");
767     query.append("WHERE sub = " + subClassId + " AND ");
768     query.append("super = " + _rdfsResourceId + " AND ");
769     query.append("is_derived = " + TRUE);
770         
771     isSubClassOf = _queryHasResults(query.toString());
772 
773     if (isSubClassOf) {  // Is subClass subClassOf rdfs:Resource?
774       StringBuffer update = new StringBuffer();
775 
776       update.append("UPDATE " + SUBCLASSOF_TABLE + " ");
777       update.append("SET super = " + superClassId + ", ");
778       update.append("is_derived = " + FALSE + " ");
779       update.append("WHERE sub = " + subClassId + " AND ");
780       update.append("super = " + _rdfsResourceId + " AND ");
781       update.append("is_derived = " + TRUE);
782       
783       _executeUpdate(update.toString());
784     
785       update = new StringBuffer();
786       
787       update.append("UPDATE " + TRIPLES_TABLE + " ");
788       update.append("SET object = " + superClassId + ", ");
789       update.append("is_derived = " + FALSE + " ");
790       update.append("WHERE subject = " + subClassId + " AND ");
791       update.append("predicate = " + _rdfsSubClassOfId + " AND ");
792       update.append("object = " + _rdfsResourceId + " AND ");
793       update.append("is_derived = " + TRUE);
794       
795       _executeUpdate(update.toString());
796     }
797     else {
798       _addSubClass(subClassId, superClassId, false);
799     }
800   //    }
801   //    catch (SQLException e) {
802     // FIXME: should throw a RalException
803 
804     //      System.err.println("SQLException in addSubClass(Resource, Resource)...");    
805   //    }
806   }
807 
808   public void addDomain(Resource property, Resource domainClass)
809         throws SQLException  {
810     //    try {
811     int propertyId = _getResourceId(property);
812     int classId = _getResourceId(domainClass);
813 
814     _addRow(DOMAIN_TABLE, propertyId, classId, false);
815     _addDataStatement(propertyId, _rdfsDomainId, classId, false);
816   //    }
817   //    catch (SQLException e) {
818     // FIXME: should throw a RalException
819 
820     //      System.err.println("SQLException in addDomain(Resource, Resource)...");    
821   //    }
822   }
823 
824   public void addRange(Resource property, Resource rangeClass)
825     throws SQLException  {
826     //    try {
827     int propertyId = _getResourceId(property);
828     int classId = _getResourceId(rangeClass);
829 
830     _addRow(RANGE_TABLE, propertyId, classId, false);
831     _addDataStatement(propertyId, _rdfsRangeId, classId, false);
832   //    }
833   //    catch (SQLException e) {
834     // FIXME: should throw a RalException
835 
836     //      System.err.println("SQLException in addRange(Resource, Resource)...");    
837   //    }
838   }
839 
840   public void addComment(Resource resource, Literal comment)
841         throws SQLException  {
842     //    try {
843     int resourceId = _createIdForResource(resource);
844     int commentId = _createIdForLiteral(comment);
845 
846     _addRow(COMMENT_TABLE, resourceId, commentId, false);
847     _addDataStatement(resourceId, _rdfsCommentId, commentId, false);
848   //    }
849   //    catch (SQLException e) {
850     // FIXME: should throw a RalException
851 
852     //      System.err.println("SQLException in addComment(Resource, Literal)...");    
853   //    }
854   }
855 
856   public void addLabel(Resource resource, Literal label)
857         throws SQLException  {
858     //    try {
859     int resourceId = _createIdForResource(resource);
860     int labelId = _createIdForLiteral(label);
861 
862     _addRow(LABEL_TABLE, resourceId, labelId, false);
863     _addDataStatement(resourceId, _rdfsLabelId, labelId, false);
864   //    }
865   //    catch (SQLException e) {
866     // FIXME: should throw a RalException
867 
868     //      System.err.println("SQLException in addLabel(Resource. Literal)...");    
869   //    }
870   }
871 
872   public void clearRepository()
873     throws SQLException  {
874     //    try {
875     Connection con = _conPool.getConnection();
876 
877     try {
878       java.sql.Statement st = con.createStatement();
879 
880       _dropTable(st, TRIPLES_TABLE);      
881       _dropTable(st, LABEL_TABLE);
882       _dropTable(st, COMMENT_TABLE);
883       _dropTable(st, TYPE_TABLE);
884       _dropTable(st, RANGE_TABLE);
885       _dropTable(st, DOMAIN_TABLE);
886       _dropTable(st, SUBPROPERTYOF_TABLE);
887       _dropTable(st, SUBCLASSOF_TABLE);
888       _dropTable(st, PROPERTY_TABLE);
889       _dropTable(st, CLASS_TABLE);
890       _dropTable(st, LITERALS_TABLE);
891       _dropTable(st, RESOURCES_TABLE);
892       _dropTable(st, NAMESPACES_TABLE);
893       
894       st.close();
895     }
896     finally {
897       con.close();
898     }
899     //    }
900     //    catch (SQLException e) {
901     // FIXME: should throw a RalException
902 
903     //      System.err.println("SQLException in clearRepository()...");    
904     //    }
905     // Clear namespaces cache...
906     _namespaceTable.clear();
907     // Re-initialize database.
908     _initDatabase();
909   }
910 
911   public void removeDataStatements(Resource subject, Resource predicate, Value object)
912     throws SQLException {
913     // TODO: implement.
914   }
915 
916   private void _dropTable(java.sql.Statement statement, String tablename)
917     throws SQLException {
918     statement.executeUpdate("DROP TABLE " + tablename);
919   }
920 
921   private void _addSubClass(int subClassId, int superClassId, boolean is_derived)
922     throws SQLException {
923     _addRow(SUBCLASSOF_TABLE, subClassId, superClassId, is_derived);
924     _addDataStatement(subClassId, _rdfsSubClassOfId, superClassId, is_derived);    
925   }
926 
927   // Method used when id 's are known.
928   private void _addInstance(int valueId, int classId, boolean is_derived)
929     throws SQLException {
930     _addRow(TYPE_TABLE, valueId, classId, is_derived);
931     _addDataStatement(valueId, _rdfTypeId, classId, is_derived);
932   }
933 
934   /* Adds a row to a table tablename consisting of two colums. The first
935    * column has datatype integer, the second boolean.
936    */
937   private void _addRow(String tablename, int columnOne, boolean columnTwo)
938     throws SQLException {
939     StringBuffer update = new StringBuffer();
940 
941     update.append("INSERT INTO " + tablename + " VALUES(");
942     update.append(columnOne + ", ");
943     update.append(_convertBoolean(columnTwo) + ")");
944 
945     _executeUpdate(update.toString());
946   }
947 
948   /* Adds a row to a table tablename consisting of three columns. The first
949    * two columns have datatype integer, the last column has datatype boolean.
950    */
951     private void _addRow(String tablename, int columnOne, int columnTwo, boolean columnThree)
952     throws SQLException {
953     StringBuffer append = new StringBuffer();
954 
955     append.append("INSERT INTO " + tablename + " VALUES(");
956     append.append(columnOne + ", ");
957     append.append(columnTwo+ ", ");
958     append.append(_convertBoolean(columnThree) + ")");
959 
960     _executeUpdate(append.toString());
961   }
962   
963   private void _addDataStatement(int subjectId, int predicateId, int objectId, boolean is_derived)
964     throws SQLException {
965     StringBuffer update = new StringBuffer();
966 
967     update.append("INSERT INTO " + TRIPLES_TABLE + " VALUES(");
968     update.append(subjectId + ", ");
969     update.append(predicateId + ", ");
970     update.append(objectId + ", ");
971     update.append(_convertBoolean(is_derived) + ")");
972 
973     _executeUpdate(update.toString());
974   }
975 
976   private int _addResource(int namespaceId, String localname)
977     throws SQLException {
978     StringBuffer update = new StringBuffer();
979 
980     update.append("INSERT INTO " + RESOURCES_TABLE + " VALUES(");
981     update.append(_nextValueId + ", ");
982     update.append(namespaceId + ", ");
983     update.append("'" + localname + "')");
984 
985     _executeUpdate(update.toString());
986     _nextValueId++;
987 
988     return _nextValueId -1;
989   }
990 
991   private int _addLiteral(String language, String value)
992     throws SQLException {
993     StringBuffer update = new StringBuffer();
994 
995     update.append("INSERT INTO " + LITERALS_TABLE + " VALUES(");
996     update.append(_nextValueId + ", ");
997     
998     if (language == null) {
999       update.append(language + ", ");
1000    }
1001    else {
1002      update.append("'" + language + "', ");
1003    }
1004    update.append("'" + value + "')");
1005
1006    _executeUpdate(update.toString());
1007    _nextValueId++;
1008
1009    return _nextValueId -1;
1010  }
1011
1012  private int _addNamespace(String namespace)
1013    throws SQLException
1014  {
1015    return _addNamespace("ns" + _nextNamespaceId, namespace);
1016  }
1017
1018  private int _addNamespace(String prefix, String namespace)
1019    throws SQLException
1020  {
1021    StringBuffer update = new StringBuffer();
1022    String escapedName = _escapeString(namespace);
1023
1024    update.append("INSERT INTO " + NAMESPACES_TABLE + " VALUES (");
1025    update.append( _nextNamespaceId + ", ");
1026    update.append("'" + prefix + "', ");
1027    update.append("'" + escapedName + "'");
1028    update.append(")");
1029
1030    _executeUpdate(update.toString());
1031
1032    // Update _namespaceTable.
1033       _namespaceTable.put(namespace,
1034        new Namespace(_nextNamespaceId, prefix, namespace));
1035
1036    _nextNamespaceId++;
1037
1038    return _nextNamespaceId - 1;
1039  }
1040
1041  private int _createIdForValue(Value value)
1042    throws SQLException {
1043    if (value instanceof Resource) {
1044      return _createIdForResource((Resource)value);
1045    }
1046    return _createIdForLiteral((Literal)value);
1047  }
1048
1049  private int _createIdForResource(Resource resource)
1050    throws SQLException {
1051    int namespaceId = _createIdForNamespace(resource.getNamespace());
1052    int resourceId = _getResourceId(resource);
1053    
1054    // resourceId is -1 if resource is not found.
1055    if (resourceId == -1) {
1056      resourceId = _addResource(namespaceId, _escapeString(resource.getLocalName()));
1057      _addInstance(resourceId, _rdfsResourceId, true);
1058    }      
1059    return resourceId;    
1060  }
1061
1062  private int _createIdForLiteral(Literal literal)
1063    throws SQLException {
1064    int literalId = _getLiteralId(literal);
1065
1066    // literalId is -1 if literal is not found.
1067    if (literalId == -1) {
1068      literalId = _addLiteral(literal.getLang(), _escapeString(literal.getLabel()));
1069
1070      /* Literals are only inserted into the type table, not in the
1071       * triples table. This is because nothing is done with information
1072       * like 'x is of type rdfs:Literal' by Sesame.
1073       */
1074      _addRow(TYPE_TABLE, literalId, _rdfsLiteralId, true);
1075    }
1076    return literalId;
1077  }
1078
1079  private int _createIdForNamespace(String namespace)
1080    throws SQLException {
1081    int namespaceId = _getNamespaceId(namespace);
1082    
1083    // namespaceId is -1 if namespace is not found.
1084    if (namespaceId == -1) {
1085      namespaceId = _addNamespace(namespace);
1086    }
1087    return namespaceId;
1088  }
1089
1090/*--------------+
1091| Query methods |
1092+--------------*/
1093
1094  public NamespaceIterator getNamespaces() {
1095    // Namespaces are returned from cache.
1096    return new SQLNamespaceIterator(_namespaceTable);
1097  }
1098
1099  public StatementIterator getStatements(Resource source, Resource predicate, Value target, boolean recursive) {
1100    try {
1101      // No wildcards?
1102      if (source != null && predicate != null && target != null && !recursive)
1103      {
1104        // java.sql.Statement exists?
1105        if (isStatement(source, predicate, target, recursive)) {
1106          return new SingleStatementIterator(source, predicate, target); 
1107        }
1108      }
1109      else {
1110        /* The StatementIterator requires 2 queries, one where object of
1111         * triples is joined with id of resources and one where it is
1112         * joined with id of literals. Parts of both queries are
1113         * identical. Those are defined as fromClause, whereClausePrefix
1114         * and whereClauseSuffix.
1115         */
1116        StringBuffer queryOnResources = new StringBuffer();
1117
1118        queryOnResources.append("SELECT n1.name, r1.localname, n2.name, r2.localname, n3.name, r3.localname ");
1119
1120        StringBuffer fromClause = new StringBuffer();
1121
1122        fromClause.append("FROM " + NAMESPACES_TABLE + " n1, ");
1123        fromClause.append(RESOURCES_TABLE + " r1, ");
1124        fromClause.append(NAMESPACES_TABLE + " n2, ");
1125        fromClause.append(RESOURCES_TABLE + " r2, ");
1126
1127        queryOnResources.append(fromClause);
1128        queryOnResources.append(NAMESPACES_TABLE + " n3, ");
1129        queryOnResources.append(RESOURCES_TABLE + " r3, ");
1130
1131        StringBuffer whereClausePrefix = new StringBuffer();
1132
1133        whereClausePrefix.append(TRIPLES_TABLE + " t ");
1134        whereClausePrefix.append("WHERE n1.id = r1.namespace AND ");
1135        whereClausePrefix.append("r1.id = t.subject AND ");
1136        whereClausePrefix.append("n2.id = r2.namespace AND ");
1137        whereClausePrefix.append("r2.id = t.predicate AND ");
1138
1139        queryOnResources.append(whereClausePrefix);
1140        queryOnResources.append("n3.id = r3.namespace AND ");
1141        queryOnResources.append("r3.id = t.object");
1142
1143        StringBuffer whereClauseSuffix = new StringBuffer();
1144
1145        if (source != null) {
1146          int subjectId = _getResourceId(source);
1147          
1148          if (subjectId == -1) {
1149            return new EmptyStatementIterator();
1150          }
1151          whereClauseSuffix.append(" AND t.subject = " + subjectId);
1152        }
1153        if (predicate != null) {
1154          int predicateId = _getResourceId(predicate);
1155
1156          if (predicateId == -1) {
1157            return new EmptyStatementIterator();
1158          }
1159          whereClauseSuffix.append(" AND t.predicate ");
1160
1161          if (recursive) {
1162            ResourceIterator subProperties = _getSubClassesOrPropertiesOf(
1163                new IdResource(predicateId, predicate),
1164                true, SUBPROPERTYOF_TABLE);
1165
1166            whereClauseSuffix.append("IN (");
1167            _appendIds(subProperties, whereClauseSuffix);
1168            whereClauseSuffix.append(")");
1169            // Predicate is not fixed any more.
1170            predicate = null;
1171
1172            subProperties.close();
1173          }
1174          else {
1175            whereClauseSuffix.append("= " + predicateId);
1176          }
1177        }
1178        if (target != null) {
1179          int objectId = _getValueId(target);
1180
1181          if (objectId == -1) {
1182            return new EmptyStatementIterator();
1183          }
1184          whereClauseSuffix.append(" AND t.object = " + objectId);
1185        }
1186        queryOnResources.append(whereClauseSuffix);
1187
1188        StringBuffer queryOnLiterals  = new StringBuffer();
1189        
1190        queryOnLiterals.append("SELECT n1.name, r1.localname, n2.name, r2.localname, l.language, l.value ");
1191        queryOnLiterals.append(fromClause);
1192        queryOnLiterals.append(LITERALS_TABLE + " l, ");
1193        queryOnLiterals.append(whereClausePrefix);        
1194        queryOnLiterals.append("l.id = t.object");
1195        queryOnLiterals.append(whereClauseSuffix);
1196
1197        Connection con = _conPool.getConnection();
1198
1199        return new SQLStatementIterator(con,
1200            queryOnResources.toString(), queryOnLiterals.toString(),
1201            source, predicate, target);
1202      }
1203    }
1204    catch (SQLException e) {
1205      // FIXME: should throw a RalException
1206      
1207      System.err.println("SQLException in getStatements(Resource, Resource, Value, boolean)...");
1208    }
1209    return new EmptyStatementIterator();
1210  }
1211
1212  public ResourceIterator getClasses() {
1213    try {
1214      return _getClassesOrProperties(CLASS_TABLE);
1215    }
1216    catch (SQLException e) {
1217      // FIXME: should throw a RalException
1218
1219      System.err.println("SQLException in getClasses()...");
1220      return new EmptyResourceIterator();
1221    }
1222  }
1223
1224  public ResourceIterator getSubClassesOf(Resource classResource, boolean recursive) {
1225    try {
1226      return _getSubClassesOrPropertiesOf(classResource, recursive, SUBCLASSOF_TABLE);
1227    }
1228    catch (SQLException e) {
1229      // FIXME: should throw a RalException
1230
1231      System.err.println("SQLException in getSubClassesOf(Resource, boolean)...");
1232      return new EmptyResourceIterator();
1233    }
1234  }
1235
1236  public ResourceIterator getSuperClassesOf(Resource classResource, boolean recursive) {
1237    try {
1238      return _getSuperClassesOrPropertiesOf(classResource, recursive, SUBCLASSOF_TABLE);
1239    }
1240    catch (SQLException e) {
1241      // FIXME: should throw a RalException
1242
1243      System.err.println("SQLException in getSuperClassesOf(Resource, boolean)...");
1244      return new EmptyResourceIterator();
1245    }
1246  }
1247
1248  public ResourceIterator getProperties()  {
1249    try {
1250      return _getClassesOrProperties(PROPERTY_TABLE);
1251    }
1252    catch (SQLException e) {
1253      // FIXME: should throw a RalException
1254
1255      System.err.println("SQLException in getProperties()...");
1256      return new EmptyResourceIterator();
1257    }
1258  }
1259  
1260  public ResourceIterator getSubPropertiesOf(Resource propertyResource, boolean recursive) {
1261    try {
1262      return _getSubClassesOrPropertiesOf(propertyResource, recursive, SUBPROPERTYOF_TABLE);
1263    }
1264    catch (SQLException e) {
1265      // FIXME: should throw a RalException
1266
1267      System.err.println("SQLException in getSubPropertiesOf(Resource, boolean)...");
1268      return new EmptyResourceIterator();
1269    }
1270  }
1271
1272  public ResourceIterator getSuperPropertiesOf(Resource propertyResource, boolean recursive) {
1273    try {
1274      return _getSuperClassesOrPropertiesOf(propertyResource, recursive, SUBPROPERTYOF_TABLE);
1275    }
1276    catch (SQLException e) {
1277      // FIXME: should throw a RalException
1278
1279      System.err.println("SQLException in getSuperPropertiesOf(Resource, boolean)...");
1280      return new EmptyResourceIterator();
1281    }
1282  }
1283
1284  public Value getDomainFor(Resource propertyResource) {
1285    Value result = null;
1286    try {
1287      result = _getDomainOrRangeFor(propertyResource, DOMAIN_TABLE);
1288      
1289      if (result == null) {
1290        // Domain is not specified, default domain is rdfs:Resource.
1291        result = Resource.RDFS_RESOURCE;
1292      }
1293    }
1294    catch (SQLException e) {
1295      // FIXME: should throw a RalException
1296      
1297      System.err.println("SQLException in getDomainFor(Resource)...");
1298    }
1299    return result;
1300  }
1301  
1302  public Value getRangeFor(Resource propertyResource)  {
1303    Value result = null;
1304    try {
1305      result = _getDomainOrRangeFor(propertyResource, RANGE_TABLE);
1306
1307      if (result == null) {
1308        // Range is not specified, empty Intersection represents any value.
1309        result = new Intersection();
1310      }
1311    }
1312    catch (SQLException e) {
1313      // FIXME: should throw a RalException
1314      
1315      System.err.println("SQLException in getRangeFor(Resource)...");
1316    }
1317    return result;
1318  }
1319
1320  public ResourceIterator getInstancesOf(Resource classResource, boolean properInstances) {
1321    try {
1322      int classId = _getResourceId(classResource);
1323    
1324      if (classId != -1) {  // Class exists?
1325        StringBuffer query = new StringBuffer();
1326        Connection con = null;
1327        
1328        // if all instances of rdfs:Literal are requested, query and
1329        // iterator to be returned are different.
1330        // FIXME!!! if all instances of rdfs:Literal are requested, return contents of literals table...!
1331        if (classId == _rdfsLiteralId) {
1332          query.append("SELECT l.id, l.language, l.value ");
1333          query.append("FROM " + LITERALS_TABLE + " l, ");
1334          query.append(TYPE_TABLE + " t ");
1335          query.append("WHERE l.id = t.val AND ");
1336          query.append("t.class = " + classId);
1337        
1338          con = _conPool.getConnection();
1339
1340          return new SQLLiteralIterator(con, query.toString());        
1341        }
1342        else {
1343          query.append("SELECT r.id, n.name, r.localname ");
1344          query.append("FROM " + NAMESPACES_TABLE + " n, ");
1345          query.append(RESOURCES_TABLE + " r, ");
1346          query.append(TYPE_TABLE + " t ");
1347          query.append("WHERE n.id = r.namespace AND ");
1348          query.append("r.id = t.val AND ");
1349          
1350          // DEBUG...???
1351          query.append("t.is_derived = " +  FALSE + " AND ");
1352
1353          query.append("t.class IN (");
1354          
1355          if (!properInstances) {
1356            // Get all subclasses of class.
1357            ResourceIterator subClasses = _getSubClassesOrPropertiesOf(
1358                new IdResource(classId, classResource),
1359                true, SUBCLASSOF_TABLE);
1360            _appendIds(subClasses, query);
1361
1362            subClasses.close();
1363          }
1364          else {
1365            query.append(classId);
1366          }
1367          query.append(")");
1368
1369          con = _conPool.getConnection();
1370
1371          return new SQLResourceIterator(con, query.toString());
1372        }  
1373      }
1374      else {
1375        return new EmptyResourceIterator();
1376      }
1377    }
1378    catch (SQLException e) {
1379      // FIXME: should throw a RalException
1380      
1381      System.err.println("