📄 sqlpredicate.java
字号:
/*
* Copyright (C) 1999-2004 <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</a>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.mandarax.sql;
import java.sql.*;
import javax.sql.DataSource;
import org.mandarax.util.logging.LogCategories;
import org.mandarax.kernel.*;
import org.mandarax.util.ClauseIterator;
import org.mandarax.util.PredicateUtils;
/**
* Implementation of a predicate based on a SQL query.
* The query defines the structure of the predicate, SQL types are mapped via
* a DBMapping object to java types. The query does not have a WHERE clause,
* since the where clause would only define the extension (= the rows in the result set),
* not the structure itself. The where clause comes in when clause sets are defined
* on top of the predicate.
* <p>
* As from version 1.7.1, SQLPredicates can be performed (@see org.mandarax.kernel.SemanticsSupport).
* @see java.sql.ResultSet
* @see org.mandarax.sql.SQLTypeMapping
* @author <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</A>
* @version 3.4 <7 March 05>
* @since 1.5
*/
public class SQLPredicate implements Predicate, LogCategories {
private String name = null;
private DataSource dataSource = null;
private String query = null;
private SQLTypeMapping typeMapping = new DefaultTypeMapping();
private Class[] structure = null;
private String[] slotNames = null;
/**
* Constructor.
*/
public SQLPredicate() {
super();
}
/**
* Get the structure of the predicate, i.e. the types associated with the columns
* in the result set of the query. We obtain the information by issuing a query,
* therefore the database must be 'live'.
*/
public void fetchStructure() throws SQLException {
if (dataSource != null) {
Connection con = dataSource.getConnection();
Statement stmt = con.createStatement();
java.sql.ResultSet rs = stmt.executeQuery(query);
ResultSetMetaData metaData = rs.getMetaData();
int cols = metaData.getColumnCount();
Class[] clazzes = new Class[cols];
for (int i = 1; i <= cols; i++) {
try {
if (typeMapping == null) {
clazzes[i - 1] = Class.forName(metaData.getColumnClassName(i));
}
else {
clazzes[i - 1] = typeMapping.getType(metaData.getColumnType(i), i);
}
}
catch (ClassNotFoundException x) {
con.close();
throw new SQLException("Result set meta data returns unknown java type " + metaData.getColumnClassName(i) + " at position " + i);
}
}
structure = clazzes;
}
}
/**
* Set the data source.
* @return a data source.
*/
public DataSource getDataSource() {
return dataSource;
}
/**
* Get the name of the predicate.
* @return the name of the predicate
*/
public String getName() {
return name;
}
/**
* Get the query string.
* @return a query
*/
public String getQuery() {
return query;
}
/**
* Get the type structure of the object, e.g. the types of terms
* that can be used with this constructor.
* @return an array of classes
*/
public java.lang.Class[] getStructure() {
if (structure == null) {
try {
fetchStructure();
}
catch (SQLException x) {
LOG_SQL.error("Error fetching structure from meta data, perhaps the JDBC driver does not support this", x);
}
}
return structure;
}
/**
* Set the structure of the predicates, i.e. the types of the terms.
* Should be handled with care since it must be consistent with the type mapping
* used and the (SQL) type and number of columns in the result set.
* @param an array of classes
*/
public void setStructure(Class[] struct) {
structure = struct;
}
/**
* Set the type mapping used.
* @param map a type mapping
*/
public void setTypeMapping(SQLTypeMapping map) {
typeMapping = map;
}
/**
* Get the new type mapping.
* @return a type mapping
*/
public SQLTypeMapping getTypeMapping() {
return typeMapping;
}
/**
* Perform the predicate using an array of terms as parameters.
* If the terms can be resolved, we iterate over the result set and look for matching records.
* If such a record is found, Boolean.TRUE is returned. Boolean.FALSE is returned otherwise.
* Note that this operation can be slow! @todo: Figure out performance improvments by adding a WHERE clause.
* @return the result of the perform operation
* @param parameter an array of terms
* @param session a session object
* @throws java.lang.UnsupportedOperationException thrown if this constructor does not have a sematics and this operation cannot be supported
* @throws java.lang.IllegalArgumentException
*/
public Object perform(org.mandarax.kernel.Term[] parameter,Session session) throws UnsupportedOperationException, IllegalArgumentException {
Object[] objects = new Object[parameter.length];
for (int i = 0; i < parameter.length; i++) {
objects[i] = parameter[i].resolve(session);
}
try {
SQLClauseSet cs = new SQLClauseSet(this, SQLClauseSet.NO_CACHE);
Term[] terms = null;
ConstantTerm t = null;
int i = 0;
for (ClauseIterator clauses = cs.clauses(); clauses.hasMoreClauses();) {
Fact f = (Fact) clauses.nextClause();
// compare
terms = f.getTerms();
boolean result = true;
i = 0;
while (result && i < terms.length) {
t = (ConstantTerm) terms[i];
if (!objects[i].equals(t.getObject()))
result = false;
i = i + 1;
}
if (result)
return Boolean.TRUE;
}
}
catch (Exception x) {
LOG_SQL.debug("Exception evaluating SQL predicate", x);
throw new IllegalArgumentException("Cannot evaluate predicate with these set of parameters");
}
return Boolean.FALSE;
}
/**
* Set the data source.
* @param ds a data source.
*/
public void setDataSource(DataSource ds) {
dataSource = ds;
}
/**
* Set the query.
* @param q a query string (a SELECT statement <em>without</em> an WHERE clause
*/
public void setQuery(String q) {
query = q;
}
/**
* Constructor.
* @param n a name
* @param q a query
* @param ds a data source
*/
public SQLPredicate(String n, String q, DataSource ds) {
super();
name = n;
query = q;
dataSource = ds;
}
/**
* Constructor with a given connection manager.
*
* @param n a name
* @param q a query
* @param conMan the given connection manager.
*/
public SQLPredicate(String n, String q, SQLConnectionManager conMan) {
this (n, q, conMan.getDataSource ());
}
/**
* Set the name.
* @param n a name
*/
public void setName(String n) {
name = n;
}
/**
* Convert the object to a string.
* @return a string
*/
public String toString() {
return (name == null) ? super.toString() : name;
}
/**
* Indicates whether the object (usually a term or a clause set) can be performed
* using the java semantics.
* @return false
*/
public boolean isExecutable() {
return true;
}
/**
* Compare objects.
* @param obj another object
* @return a boolean
*/
public boolean equals(Object obj) {
if ((obj != null) && (obj instanceof SQLPredicate)) {
SQLPredicate p = (SQLPredicate) obj;
boolean result = true;
// compare query, name and data source
// bugfix in 1.8 - thanks to chenjb@gsta.com
result = (name == null) ? (p.name == null) : name.equals(p.name);
result = result && ((dataSource == null) ? (p.dataSource == null) : dataSource.equals(p.dataSource));
result = result && ((query == null) ? (p.query == null) : query.equals(p.query));
result = result && ((typeMapping == null) ? (p.typeMapping == null) : typeMapping.equals(p.typeMapping));
Class[] c1 = p.structure;
Class[] c2 = structure;
if (c1 == null) {
result = c2 == null;
}
else {
result = result && (c1.length == c2.length);
for (int i = 0; i < c1.length; i++) {
result = result && (c1[i] == c2[i]);
}
}
return result;
}
else {
return false;
}
}
/**
* Get the hashcode of the object.
* @return the hash code of the object
*/
public int hashCode() {
return ((name == null) ? 0 : name.hashCode()) ^ ((query == null) ? 0 : query.hashCode()) ^ ((dataSource == null) ? 0 : dataSource.hashCode());
}
/**
* Get the slot names.
* @return an array of strings, the length of the array is the same as
* the length of the array of terms (the structure of the predicate)
*/
public String[] getSlotNames() {
if (slotNames==null) {
slotNames = new String[getStructure().length];
for (int i=0;i<slotNames.length;i++) slotNames[i] = PredicateUtils.getSlotName(this,i);
}
return slotNames;
}
/**
* Set the slot names.
* @param names an array of strings, the length of the array is the same as
* the length of the array of terms (the structure of the predicate)
*/
public void setSlotNames(String[] names) {
if (names!=null && names.length!=getStructure().length) throw new IllegalArgumentException("Number of slot names and number of slots must match - cannot set slot names for predicate " + this);
this.slotNames = names;
}
/**
* Indicates whether the slot names can be modified.
* @return a boolean
*/
public boolean slotNamesCanBeEdited() {
return true;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -