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("