/* * Copyright Aduna (http://www.aduna-software.com/) (c) 2008. * * Licensed under the Aduna BSD-style license. */ package org.openrdf.sail.rdbms.schema; import java.sql.SQLException; import java.util.List; import java.util.Map; /** * Manages the life-cycle of the rows in a single predicate table. * * @author James Leigh * */ public class TripleTable { public static int tables_created; public static int total_st; public static final boolean UNIQUE_INDEX_TRIPLES = true; private static final String[] PKEY = { "obj", "subj", "ctx", "expl" }; private static final String[] SUBJ_INDEX = { "subj" }; private static final String[] CTX_INDEX = { "ctx" }; private static final String[] PRED_PKEY = { "obj", "subj", "pred", "ctx", "expl" }; private static final String[] PRED_INDEX = { "pred" }; private static final String[] EXPL_INDEX = { "expl" }; private RdbmsTable table; private ValueTypes objTypes = new ValueTypes(); private ValueTypes subjTypes = new ValueTypes(); private boolean initialize; private boolean predColumnPresent; private boolean indexed; private IdSequence ids; public TripleTable(RdbmsTable table) { this.table = table; } public void setIdSequence(IdSequence ids) { this.ids = ids; } public boolean isPredColumnPresent() { return predColumnPresent; } public void setPredColumnPresent(boolean present) { predColumnPresent = present; } public void setIndexed(boolean indexingTriples) { indexed = true; } public synchronized void initTable() throws SQLException { if (initialize) return; table.createTransactionalTable(buildTableColumns()); tables_created++; total_st++; if (UNIQUE_INDEX_TRIPLES) { if (isPredColumnPresent()) { table.primaryIndex(PRED_PKEY); total_st++; } else { table.primaryIndex(PKEY); total_st++; } } if (indexed) { createIndex(); } initialize = true; } public void reload() throws SQLException { table.count(); if (table.size() > 0) { ValueType[] values = ValueType.values(); String[] OBJ_CONTAINS = new String[values.length]; String[] SUBJ_CONTAINS = new String[values.length]; StringBuilder sb = new StringBuilder(); for (int i = 0, n = values.length; i < n; i++) { sb.delete(0, sb.length()); ValueType code = values[i]; sb.append("MAX(CASE WHEN obj BETWEEN ").append(ids.minId(code)); sb.append(" AND ").append(ids.maxId(code)); sb.append(" THEN 1 ELSE 0 END)"); OBJ_CONTAINS[i] = sb.toString(); sb.delete(0, sb.length()); sb.append("MAX(CASE WHEN subj BETWEEN ").append(ids.minId(code)); sb.append(" AND ").append(ids.maxId(code)); sb.append(" THEN 1 ELSE 0 END)"); SUBJ_CONTAINS[i] = sb.toString(); } // int[] aggregate = table.aggregate(OBJ_CONTAINS); // for (int i = 0; i < aggregate.length; i++) { // if (aggregate[i] == 1) { // objTypes.add(values[i]); // } // } // aggregate = table.aggregate(SUBJ_CONTAINS); // for (int i = 0; i < aggregate.length; i++) { // if (aggregate[i] == 1) { // subjTypes.add(values[i]); // } // } for (int i = 0; i < values.length; i++) { objTypes.add(values[i]); subjTypes.add(values[i]); } } initialize = true; } public void close() throws SQLException { table.close(); } public boolean isIndexed() throws SQLException { return table.getIndexes().size() > 1; } public void createIndex() throws SQLException { if (isPredColumnPresent()) { table.index(PRED_INDEX); total_st++; } table.index(SUBJ_INDEX); total_st++; table.index(CTX_INDEX); total_st++; table.index(EXPL_INDEX); total_st++; } public void dropIndex() throws SQLException { for (Map.Entry<String, List<String>> e : table.getIndexes().entrySet()) { if (!e.getValue().contains("OBJ") && !e.getValue().contains("obj")) { table.dropIndex(e.getKey()); } } } public boolean isReady() { return initialize; } public void blockUntilReady() throws SQLException { if (initialize) return; initTable(); } public String getName() throws SQLException { return table.getName(); } public String getNameWhenReady() throws SQLException { blockUntilReady(); return table.getName(); } public ValueTypes getObjTypes() { return objTypes; } public void setObjTypes(ValueTypes valueTypes) { this.objTypes.merge(valueTypes); } public ValueTypes getSubjTypes() { return subjTypes; } public void setSubjTypes(ValueTypes valueTypes) { this.subjTypes.merge(valueTypes); } public void modified(int addedCount, int removedCount) throws SQLException { blockUntilReady(); table.modified(addedCount, removedCount); table.optimize(); if (isEmpty()) { objTypes.reset(); subjTypes.reset(); } } public boolean isEmpty() throws SQLException { blockUntilReady(); return table.size() == 0; } @Override public String toString() { return table.getName(); } public void drop() throws SQLException { blockUntilReady(); table.drop(); } protected CharSequence buildTableColumns() { StringBuilder sb = new StringBuilder(); sb.append(" ctx ").append(ids.getSqlType()).append(" NOT NULL,\n"); sb.append(" subj ").append(ids.getSqlType()).append(" NOT NULL,\n"); if (isPredColumnPresent()) { sb.append(" pred ").append(ids.getSqlType()).append(" NOT NULL,\n"); } sb.append(" obj ").append(ids.getSqlType()).append(" NOT NULL,\n"); sb.append(" expl ").append("BOOL").append(" NOT NULL\n"); return sb; } }