Use JDBC API directly for all queries. The only place where Village is still used is for inserts and updates.

This commit is contained in:
hns 2002-11-06 10:49:41 +00:00
parent 4529071cf4
commit dfc2431343
4 changed files with 207 additions and 132 deletions

View file

@ -52,6 +52,10 @@ public final class DbMapping implements Updatable {
HashMap prop2db;
// Map of db columns to Relations objects
HashMap db2prop;
// prerendered list of columns to fetch from db
String columns = null;
// pre-rendered select statement
String select = null;
// db field used as primary key
private String idField;
@ -135,7 +139,9 @@ public final class DbMapping implements Updatable {
* for rewire to work, all other db mappings must have been initialized and registered.
*/
public synchronized void update () {
// reset columns
columns = select = null;
// read in properties
table = props.getProperty ("_table");
idgen = props.getProperty ("_idgen");
// see if there is a field which specifies the prototype of objects, if different prototypes
@ -564,19 +570,71 @@ public final class DbMapping implements Updatable {
return schema;
}
/**
* Return a Village Schema object for this DbMapping.
*/
public synchronized String getColumns() throws ClassNotFoundException, SQLException {
if (!isRelational ())
throw new SQLException ("Can't get Schema for non-relational data mapping");
if (source == null && parentMapping != null)
return parentMapping.getColumns ();
// Use local variable s to avoid synchronization (schema may be nulled elsewhere)
if (columns == null) {
// we do two things here: set the SQL type on the Relation mappings
// and build a string of column names.
Connection con = getConnection ();
Statement stmt = con.createStatement ();
ResultSet rs = stmt.executeQuery ("select * from "+getTableName()+" where 1 = 0");
if (rs == null)
throw new SQLException ("Error retrieving DB scheme for "+this);
ResultSetMetaData meta = rs.getMetaData ();
// ok, we have the meta data, now loop through mapping...
// StringBuffer cbuffer = new StringBuffer (getIDField ());
for (Iterator i=getDBPropertyIterator(); i.hasNext(); ) {
Relation rel = (Relation) i.next ();
if (rel.reftype != Relation.PRIMITIVE && rel.reftype != Relation.REFERENCE)
continue;
// cbuffer.append (",");
// cbuffer.append (rel.getDbField());
int idx = rs.findColumn (rel.getDbField());
rel.setColumnType (meta.getColumnType (idx));
}
// columns = cbuffer.toString();
columns = " * ";
}
return columns;
}
public StringBuffer getSelect () throws SQLException, ClassNotFoundException {
String sel = select;
if (sel != null)
return new StringBuffer (sel);
StringBuffer s = new StringBuffer ("select ");
s.append (getColumns ());
s.append (" from ");
s.append (table);
s.append (" ");
// cache rendered string for later calls.
select = s.toString();
return s;
}
/**
* Return true if values for the column identified by the parameter need
* to be quoted in SQL queries.
*/
public boolean needsQuotes (String columnName) throws SQLException {
if (table == null && parentMapping != null)
return parentMapping.needsQuotes (columnName);
try {
Schema s = getSchema ();
if (s == null)
Relation rel = (Relation) db2prop.get (columnName);
if (rel == null)
throw new SQLException ("Error retrieving relational schema for "+this);
Column c = s.getColumn (columnName);
if (c == null)
throw new SQLException ("Column "+columnName+" not found in "+this);
switch (c.typeEnum()) {
// make sure columns are initialized and up to date
if (columns == null)
getColumns();
switch (rel.getColumnType()) {
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGVARCHAR:

View file

@ -12,11 +12,11 @@ import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;
import java.io.*;
import java.sql.Types;
import java.sql.*;
import helma.objectmodel.*;
import helma.util.*;
import helma.framework.IPathElement;
import com.workingdogs.village.*;
// import com.workingdogs.village.*;
/**
@ -234,16 +234,15 @@ public final class Node implements INode, Serializable {
/**
* Constructor used for nodes being stored in a relational database table.
*/
public Node (DbMapping dbm, Record rec, WrappedNodeManager nmgr) throws DataSetException {
public Node (DbMapping dbm, ResultSet rs, WrappedNodeManager nmgr) throws SQLException {
this.nmgr = nmgr;
// see what prototype/DbMapping this object should use
dbmap = dbm;
String protoField= dbmap.getPrototypeField ();
if (protoField != null) {
Value val = rec.getValue (protoField);
if (val != null && !val.isNull ()) {
String protoName = val.asString ();
String protoName = rs.getString (protoField);
if (protoName != null) {
dbmap = nmgr.getDbMapping (protoName);
if (dbmap == null) {
// invalid prototype name!
@ -254,10 +253,10 @@ public final class Node implements INode, Serializable {
}
setPrototype (dbmap.getTypeName ());
id = rec.getValue (dbmap.getIDField ()).asString ();
id = rs.getString (dbmap.getIDField ());
// checkWriteLock ();
String nameField = dbmap.getNameField ();
name = nameField == null ? id : rec.getValue (nameField).asString ();
name = nameField == null ? id : rs.getString (nameField);
if (name == null || name.length() == 0)
name = dbmap.getTypeName() + " " + id;
// set parent for user objects to internal userroot node
@ -276,60 +275,61 @@ public final class Node implements INode, Serializable {
if (rel.reftype != Relation.PRIMITIVE && rel.reftype != Relation.REFERENCE)
continue;
Value val = rec.getValue (rel.getDbField ());
// Value val = rec.getValue (rel.getDbField ());
// if (val.isNull ())
// continue;
Property newprop = new Property (rel.propName, this);
if (val.isNull ())
newprop.setStringValue (null);
else switch (val.type ()) {
// if (val.isNull ())
// newprop.setStringValue (null);
// else
switch (rel.getColumnType()) {
case Types.BIT:
newprop.setBooleanValue (val.asBoolean());
newprop.setBooleanValue (rs.getBoolean(rel.getDbField()));
break;
case Types.TINYINT:
case Types.BIGINT:
case Types.SMALLINT:
case Types.INTEGER:
newprop.setIntegerValue (val.asLong());
newprop.setIntegerValue (rs.getLong(rel.getDbField()));
break;
case Types.REAL:
case Types.FLOAT:
case Types.DOUBLE:
newprop.setFloatValue (val.asDouble());
newprop.setFloatValue (rs.getDouble(rel.getDbField()));
break;
case Types.DECIMAL:
case Types.NUMERIC:
java.math.BigDecimal num = val.asBigDecimal ();
java.math.BigDecimal num = rs.getBigDecimal (rel.getDbField());
if (num.scale() > 0)
newprop.setFloatValue (val.asDouble());
newprop.setFloatValue (rs.getDouble(rel.getDbField()));
else
newprop.setIntegerValue (val.asLong());
newprop.setIntegerValue (rs.getLong(rel.getDbField()));
break;
case Types.LONGVARBINARY:
case Types.VARBINARY:
case Types.BINARY:
newprop.setStringValue (val.asString());
newprop.setStringValue (rs.getString(rel.getDbField()));
break;
case Types.LONGVARCHAR:
case Types.CHAR:
case Types.VARCHAR:
case Types.OTHER:
newprop.setStringValue (val.asString());
newprop.setStringValue (rs.getString(rel.getDbField()));
break;
case Types.DATE:
case Types.TIME:
case Types.TIMESTAMP:
newprop.setDateValue (val.asTimestamp());
newprop.setDateValue (rs.getTimestamp(rel.getDbField()));
break;
case Types.NULL:
@ -338,10 +338,13 @@ public final class Node implements INode, Serializable {
// continue;
default:
newprop.setStringValue (val.asString());
newprop.setStringValue (rs.getString(rel.getDbField()));
break;
}
if (rs.wasNull())
newprop.setStringValue (null);
if(propMap == null)
propMap = new Hashtable ();
propMap.put (rel.propName.toLowerCase(), newprop);

View file

@ -601,26 +601,26 @@ public final class NodeManager {
// Transactor tx = (Transactor) Thread.currentThread ();
// tx.timer.beginEvent ("generateID "+map);
QueryDataSet qds = null;
String retval = null;
Statement stmt = null;
try {
Connection con = map.getConnection ();
String q = "SELECT MAX("+map.getIDField()+") FROM "+map.getTableName();
qds = new QueryDataSet (con, q);
qds.fetchRecords ();
stmt = con.createStatement ();
ResultSet rs = stmt.executeQuery (q);
// check for empty table
if (qds.size () == 0) {
if (!rs.next()) {
long currMax = map.getNewID (0);
retval = Long.toString (currMax);
} else {
long currMax = qds.getRecord (0).getValue (1).asLong ();
long currMax = rs.getLong (1);
currMax = map.getNewID (currMax);
retval = Long.toString (currMax);
}
} finally {
// tx.timer.endEvent ("generateID "+map);
if (qds != null) try {
qds.close ();
if (stmt != null) try {
stmt.close ();
} catch (Exception ignore) {}
}
return retval;
@ -635,18 +635,18 @@ public final class NodeManager {
// Transactor tx = (Transactor) Thread.currentThread ();
// tx.timer.beginEvent ("generateID "+map);
QueryDataSet qds = null;
Statement stmt = null;
String retval = null;
try {
Connection con = map.getConnection ();
String q = "SELECT "+map.getIDgen()+".nextval FROM dual";
qds = new QueryDataSet (con, q);
qds.fetchRecords ();
retval = qds.getRecord (0).getValue (1).asString ();
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery (q);
retval = rs.getString (1);
} finally {
// tx.timer.endEvent ("generateID "+map);
if (qds != null) try {
qds.close ();
if (stmt != null) try {
stmt.close ();
} catch (Exception ignore) {}
}
return retval;
@ -746,31 +746,31 @@ public final class NodeManager {
List retval = new ArrayList ();
DbMapping dbm = rel.otherType;
TableDataSet tds = new TableDataSet (dbm.getConnection (), dbm.getSchema (), dbm.getKeyDef ());
Connection con = dbm.getConnection ();
Statement stmt = con.createStatement ();
StringBuffer q = dbm.getSelect ();
try {
if (home.getSubnodeRelation() != null) {
// HACK: cut off the "where" part of manually set subnoderelation
tds.where (home.getSubnodeRelation().trim().substring(5));
q.append (home.getSubnodeRelation());
} else {
// let relation object build the query
tds.where (rel.buildQuery (home, home.getNonVirtualParent (), null, "", false));
q.append (" where ");
q.append (rel.buildQuery (home, home.getNonVirtualParent (), null, "", false));
if (rel.getOrder () != null)
tds.order (rel.getOrder ());
q.append (" "+rel.getOrder ());
}
if (logSql)
app.logEvent ("### getNodes: "+tds.getSelectString());
app.logEvent ("### getNodes: "+q.toString());
if (rel.maxSize > 0)
tds.fetchRecords (rel.maxSize);
else
tds.fetchRecords ();
stmt.setMaxRows (rel.maxSize);
for (int i=0; i<tds.size (); i++) {
ResultSet rs = stmt.executeQuery (q.toString ());
while (rs.next()) {
// create new Nodes.
Record rec = tds.getRecord (i);
Node node = new Node (rel.otherType, rec, safe);
Node node = new Node (rel.otherType, rs, safe);
Key primKey = node.getKey ();
retval.add (new NodeHandle (primKey));
// do we need to synchronize on primKey here?
@ -784,8 +784,8 @@ public final class NodeManager {
} finally {
// tx.timer.endEvent ("getNodes "+home);
if (tds != null) try {
tds.close ();
if (stmt != null) try {
stmt.close ();
} catch (Exception ignore) {}
}
return retval;
@ -804,42 +804,42 @@ public final class NodeManager {
} else {
int missing = cache.containsKeys (keys);
if (missing > 0) {
TableDataSet tds = new TableDataSet (dbm.getConnection (),
dbm.getSchema (),
dbm.getKeyDef ());
Connection con = dbm.getConnection ();
Statement stmt = con.createStatement ();
StringBuffer q = dbm.getSelect ();
try {
String idfield = rel.groupby != null ? rel.groupby : dbm.getIDField ();
boolean needsQuotes = dbm.needsQuotes (idfield);
StringBuffer whereBuffer = new StringBuffer (idfield);
whereBuffer.append (" in (");
q.append (" where ");
q.append (idfield);
q.append (" in (");
boolean first = true;
for (int i=0; i<keys.length; i++) {
if (keys[i] != null) {
if (!first)
whereBuffer.append (',');
q.append (',');
else
first = false;
if (needsQuotes) {
whereBuffer.append ("'");
whereBuffer.append (escape (keys[i].getID ()));
whereBuffer.append ("'");
q.append ("'");
q.append (escape (keys[i].getID ()));
q.append ("'");
} else {
whereBuffer.append (keys[i].getID ());
q.append (keys[i].getID ());
}
}
}
whereBuffer.append (')');
q.append (") ");
if (rel.groupby != null) {
whereBuffer.insert (0, rel.renderConstraints (home, home.getNonVirtualParent ()));
q.append (rel.renderConstraints (home, home.getNonVirtualParent ()));
if (rel.order != null)
whereBuffer.append (" ORDER BY "+rel.order);
q.append (" ORDER BY "+rel.order);
}
tds.where (whereBuffer.toString ());
if (logSql)
app.logEvent ("### prefetchNodes: "+tds.getSelectString());
app.logEvent ("### prefetchNodes: "+q.toString());
tds.fetchRecords ();
ResultSet rs = stmt.executeQuery (q.toString());;
String groupbyProp = null;
HashMap groupbySubnodes = null;
@ -852,10 +852,9 @@ public final class NodeManager {
if (rel.accessor != null && !rel.usesPrimaryKey ())
accessProp = dbm.columnNameToProperty (rel.accessor);
for (int i=0; i<tds.size (); i++) {
while (rs.next ()) {
// create new Nodes.
Record rec = tds.getRecord (i);
Node node = new Node (dbm, rec, safe);
Node node = new Node (dbm, rs, safe);
Key primKey = node.getKey ();
// for grouped nodes, collect subnode lists for the intermediary
@ -906,8 +905,8 @@ public final class NodeManager {
}
}
} finally {
if (tds != null) try {
tds.close ();
if (stmt != null) try {
stmt.close ();
} catch (Exception ignore) {}
}
}
@ -933,7 +932,7 @@ public final class NodeManager {
Connection con = rel.otherType.getConnection ();
String table = rel.otherType.getTableName ();
QueryDataSet qds = null;
Statement stmt = null;
try {
String q = null;
@ -948,18 +947,18 @@ public final class NodeManager {
if (logSql)
app.logEvent ("### countNodes: "+q);
qds = new QueryDataSet (con, q);
stmt = con.createStatement();
qds.fetchRecords ();
if (qds.size () == 0)
ResultSet rs = stmt.executeQuery (q);
if (!rs.next())
retval = 0;
else
retval = qds.getRecord (0).getValue (1).asInt ();
retval = rs.getInt (1);
} finally {
// tx.timer.endEvent ("countNodes "+home);
if (qds != null) try {
qds.close ();
if (stmt != null) try {
stmt.close ();
} catch (Exception ignore) {}
}
return rel.maxSize > 0 ? Math.min (rel.maxSize, retval) : retval;
@ -985,27 +984,26 @@ public final class NodeManager {
Connection con = rel.otherType.getConnection ();
String table = rel.otherType.getTableName ();
QueryDataSet qds = null;
Statement stmt = null;
try {
String q = "SELECT "+namefield+" FROM "+table+" ORDER BY "+namefield;
qds = new QueryDataSet (con, q);
stmt = con.createStatement ();
if (logSql)
app.logEvent ("### getPropertyNames: "+qds.getSelectString());
app.logEvent ("### getPropertyNames: "+q);
qds.fetchRecords ();
for (int i=0; i<qds.size (); i++) {
Record rec = qds.getRecord (i);
String n = rec.getValue (1).asString ();
ResultSet rs = stmt.executeQuery (q);
while (rs.next()) {
String n = rs.getString (1);
if (n != null)
retval.addElement (n);
}
} finally {
// tx.timer.endEvent ("getNodeIDs "+home);
if (qds != null) try {
qds.close ();
if (stmt != null) try {
stmt.close ();
} catch (Exception ignore) {}
}
return retval;
@ -1031,26 +1029,31 @@ public final class NodeManager {
} else {
String idfield =dbm.getIDField ();
TableDataSet tds = null;
Statement stmt = null;
try {
tds = new TableDataSet (dbm.getConnection (), dbm.getSchema (), dbm.getKeyDef ());
tds.where (idfield+" = "+kstr);
Connection con = dbm.getConnection ();
stmt = con.createStatement ();
StringBuffer q = dbm.getSelect ();
q.append (" where ");
q.append (idfield);
q.append (" = ");
q.append (kstr);
if (logSql)
app.logEvent ("### getNodeByKey: "+tds.getSelectString());
app.logEvent ("### getNodeByKey: "+q.toString());
tds.fetchRecords ();
ResultSet rs = stmt.executeQuery (q.toString());
if (tds.size () == 0)
if (!rs.next ())
return null;
if (tds.size () > 1)
if (!rs.isLast ())
throw new RuntimeException ("More than one value returned by query.");
Record rec = tds.getRecord (0);
node = new Node (dbm, rec, safe);
node = new Node (dbm, rs, safe);
} finally {
if (tds != null) try {
tds.close ();
if (stmt != null) try {
stmt.close ();
} catch (Exception ignore) {}
}
}
@ -1086,35 +1089,35 @@ public final class NodeManager {
return node;
} else {
TableDataSet tds = null;
Statement stmt = null;
try {
DbMapping dbm = rel.otherType;
tds = new TableDataSet (dbm.getConnection (), dbm.getSchema (), dbm.getKeyDef ());
Connection con = dbm.getConnection ();
StringBuffer q = dbm.getSelect ();
if (home.getSubnodeRelation () != null) {
// combine our key with the constraints in the manually set subnode relation
StringBuffer where = new StringBuffer ();
where.append (rel.accessor);
where.append (" = '");
where.append (escape(kstr));
where.append ("' AND ");
where.append (home.getSubnodeRelation ().trim().substring(5).trim());
tds.where (where.toString ());
} else
tds.where (rel.buildQuery (home, home.getNonVirtualParent (), kstr, "", false));
q.append (home.getSubnodeRelation ());
q.append (" and ");
q.append (rel.accessor);
q.append (" = '");
q.append (escape(kstr));
q.append ("'");
} else {
q.append (" where ");
q.append (rel.buildQuery (home, home.getNonVirtualParent (), kstr, "", false));
}
if (logSql)
app.logEvent ("### getNodeByRelation: "+tds.getSelectString());
app.logEvent ("### getNodeByRelation: "+q.toString());
tds.fetchRecords ();
stmt = con.createStatement ();
ResultSet rs = stmt.executeQuery (q.toString());
if (tds.size () == 0)
if (!rs.next ())
return null;
if (tds.size () > 1)
if (!rs.isLast ())
throw new RuntimeException ("More than one value returned by query.");
Record rec = tds.getRecord (0);
node = new Node (rel.otherType, rec, safe);
node = new Node (rel.otherType, rs, safe);
// Check if node is already cached with primary Key.
if (!rel.usesPrimaryKey()) {
@ -1126,8 +1129,8 @@ public final class NodeManager {
}
} finally {
if (tds != null) try {
tds.close ();
if (stmt != null) try {
stmt.close ();
} catch (Exception ignore) {}
}
}

View file

@ -35,6 +35,9 @@ public final class Relation {
// the DbMapping of the prototype we link to, unless this is a "primitive" (non-object) relation
DbMapping otherType;
// the column type, as defined in java.sql.Types
int columnType;
// if this relation defines a virtual node, we need to provide a DbMapping for these virtual nodes
DbMapping virtualMapping;
@ -240,6 +243,14 @@ public final class Relation {
return propName;
}
public void setColumnType (int ct) {
columnType = ct;
}
public int getColumnType () {
return columnType;
}
/**
* Add a constraint to the current list of constraints