Refactoring of select statement generation code into Relation.get*Select() methods in order to fix bug 667. Also remove some dead code.

This commit is contained in:
hns 2009-05-29 13:47:15 +00:00
parent 3401440d3b
commit e12c90a529
2 changed files with 210 additions and 349 deletions

View file

@ -877,48 +877,32 @@ public final class NodeManager {
* loaded later on demand. * loaded later on demand.
*/ */
public List getNodeIDs(Node home, Relation rel) throws Exception { public List getNodeIDs(Node home, Relation rel) throws Exception {
DbMapping type = rel == null ? null : rel.otherType;
if ((rel == null) || (rel.otherType == null) || !rel.otherType.isRelational()) { if (type == null || !type.isRelational()) {
// this should never be called for embedded nodes // this should never be called for embedded nodes
throw new RuntimeException("NodeMgr.getNodeIDs called for non-relational node " + throw new RuntimeException("getNodeIDs called for non-relational node " + home);
home); }
} else {
List retval = new ArrayList(); List retval = new ArrayList();
// if we do a groupby query (creating an intermediate layer of groupby nodes), // if we do a groupby query (creating an intermediate layer of groupby nodes),
// retrieve the value of that field instead of the primary key // retrieve the value of that field instead of the primary key
String idfield = (rel.groupby == null) ? rel.otherType.getIDField() Connection con = type.getConnection();
: rel.groupby;
Connection con = rel.otherType.getConnection();
// set connection to read-only mode // set connection to read-only mode
if (!con.isReadOnly()) con.setReadOnly(true); if (!con.isReadOnly()) con.setReadOnly(true);
String table = rel.otherType.getTableName();
Statement stmt = null; Statement stmt = null;
long logTimeStart = logSql ? System.currentTimeMillis() : 0; long logTimeStart = logSql ? System.currentTimeMillis() : 0;
String query = null; String query = null;
try { try {
StringBuffer b = new StringBuffer("SELECT "); StringBuffer b = rel.getIdSelect();
if (rel.queryHints != null) {
b.append(rel.queryHints).append(" ");
}
if (idfield.indexOf('(') == -1 && idfield.indexOf('.') == -1) {
b.append(table).append('.');
}
b.append(idfield).append(" FROM ").append(table);
rel.appendAdditionalTables(b);
if (home.getSubnodeRelation() != null) { if (home.getSubnodeRelation() != null) {
// subnode relation was explicitly set // subnode relation was explicitly set
query = b.append(" ").append(home.getSubnodeRelation()).toString(); query = b.append(" ").append(home.getSubnodeRelation()).toString();
} else { } else {
// let relation object build the query // let relation object build the query
rel.buildQuery(b, home, null, " WHERE ", true); rel.buildQuery(b, home, true, false);
query = b.toString(); query = b.toString();
} }
@ -960,7 +944,7 @@ public final class NodeManager {
} finally { } finally {
if (logSql) { if (logSql) {
long logTimeStop = System.currentTimeMillis(); long logTimeStop = System.currentTimeMillis();
logSqlStatement("SQL SELECT_IDS", table, logSqlStatement("SQL SELECT_IDS", type.getTableName(),
logTimeStart, logTimeStop, query); logTimeStart, logTimeStop, query);
} }
if (stmt != null) { if (stmt != null) {
@ -973,7 +957,6 @@ public final class NodeManager {
return retval; return retval;
} }
}
/** /**
* Loades subnodes via subnode relation. This is similar to getNodeIDs, but it * Loades subnodes via subnode relation. This is similar to getNodeIDs, but it
@ -986,7 +969,7 @@ public final class NodeManager {
if ((rel == null) || (rel.otherType == null) || !rel.otherType.isRelational()) { if ((rel == null) || (rel.otherType == null) || !rel.otherType.isRelational()) {
// this should never be called for embedded nodes // this should never be called for embedded nodes
throw new RuntimeException("NodeMgr.getNodes called for non-relational node " + throw new RuntimeException("getNodes called for non-relational node " +
home); home);
} }
@ -1010,7 +993,7 @@ public final class NodeManager {
b.append(home.getSubnodeRelation()); b.append(home.getSubnodeRelation());
} else { } else {
// let relation object build the query // let relation object build the query
rel.buildQuery(b, home, null, " WHERE ", true); rel.buildQuery(b, home, true, false);
} }
query = b.toString(); query = b.toString();
@ -1053,152 +1036,6 @@ public final class NodeManager {
return retval; return retval;
} }
/**
* Update a UpdateableSubnodeList retrieving all values having
* higher Values according to the updateCriteria's set for this Collection's Relation
* The returned Map-Object has two Properties:
* addedNodes = an Integer representing the number of Nodes added to this collection
* newNodes = an Integer representing the number of Records returned by the Select-Statement
* These two values may be different if a max-size is defined for this Collection and a new
* node would be outside of this Border because of the ordering of this collection.
* @param home the home of this subnode-list
* @param rel the relation the home-node has to the nodes contained inside the subnodelist
* @return A map having two properties of type String (newNodes (number of nodes retreived by the select-statment), addedNodes (nodes added to the collection))
* @throws Exception
*/
/* public int updateSubnodeList(Node home, Relation rel) throws Exception {
if ((rel == null) || (rel.otherType == null) || !rel.otherType.isRelational()) {
// this should never be called for embedded nodes
throw new RuntimeException("NodeMgr.updateSubnodeList called for non-relational node " +
home);
} else {
List list = home.getSubnodeList();
if (list == null)
list = home.createSubnodeList();
if (!(list instanceof UpdateableSubnodeList))
throw new RuntimeException ("unable to update SubnodeList not marked as updateable (" + rel.propName + ")");
UpdateableSubnodeList sublist = (UpdateableSubnodeList) list;
// FIXME: grouped subnodes aren't supported yet
if (rel.groupby != null)
throw new RuntimeException ("update not yet supported on grouped collections");
String idfield = rel.otherType.getIDField();
Connection con = rel.otherType.getConnection();
String table = rel.otherType.getTableName();
Statement stmt = null;
try {
String q = null;
StringBuffer b = new StringBuffer();
if (rel.loadAggressively()) {
b.append (rel.otherType.getSelect(rel));
} else {
b.append ("SELECT ");
if (rel.queryHints != null) {
b.append(rel.queryHints).append(" ");
}
b.append(table).append('.')
.append(idfield).append(" FROM ")
.append(table);
rel.appendAdditionalTables(b);
}
String updateCriteria = sublist.getUpdateCriteria();
if (home.getSubnodeRelation() != null) {
if (updateCriteria != null) {
b.append (" WHERE ");
b.append (sublist.getUpdateCriteria());
b.append (" AND ");
b.append (home.getSubnodeRelation());
} else {
b.append (" WHERE ");
b.append (home.getSubnodeRelation());
}
} else {
if (updateCriteria != null) {
b.append (" WHERE ");
b.append (updateCriteria);
rel.buildQuery(b, home, null, " AND ", true);
} else {
rel.buildQuery(b, home, null, " WHERE ", true);
}
q = b.toString();
}
long logTimeStart = logSql ? System.currentTimeMillis() : 0;
stmt = con.createStatement();
if (rel.maxSize > 0) {
stmt.setMaxRows(rel.maxSize);
}
ResultSet result = stmt.executeQuery(q);
if (logSql) {
long logTimeStop = System.currentTimeMillis();
logSqlStatement("SQL SELECT_UPDATE_SUBNODE_LIST", table,
logTimeStart, logTimeStop, q);
}
// problem: how do we derive a SyntheticKey from a not-yet-persistent Node?
// Key k = (rel.groupby != null) ? home.getKey() : null;
// int cntr = 0;
DbColumn[] columns = rel.loadAggressively() ? rel.otherType.getColumns() : null;
List newNodes = new ArrayList(rel.maxSize);
while (result.next()) {
String kstr = result.getString(1);
// jump over null values - this can happen especially when the selected
// column is a group-by column.
if (kstr == null) {
continue;
}
// make the proper key for the object, either a generic DB key or a groupby key
Key key;
if (rel.loadAggressively()) {
Node node = createNode(rel.otherType, result, columns, 0);
if (node == null) {
continue;
}
key = node.getKey();
registerNewNode(node, null);
} else {
key = new DbKey(rel.otherType, kstr);
}
newNodes.add(new NodeHandle(key));
// if these are groupby nodes, evict nullNode keys
if (rel.groupby != null) {
Node n = (Node) cache.get(key);
if ((n != null) && n.isNullNode()) {
evictKey(key);
}
}
}
// System.err.println("GOT NEW NODES: " + newNodes);
if (!newNodes.isEmpty())
sublist.addAll(newNodes);
return newNodes.size();
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (Exception ignore) {
}
}
}
}
} */
protected List collectMissingKeys(SubnodeList list, int start, int length) { protected List collectMissingKeys(SubnodeList list, int start, int length) {
List retval = null; List retval = null;
for (int i = start; i < start + length; i++) { for (int i = start; i < start + length; i++) {
@ -1360,46 +1197,35 @@ public final class NodeManager {
* which is defined by Relation rel. * which is defined by Relation rel.
*/ */
public int countNodes(Node home, Relation rel) throws Exception { public int countNodes(Node home, Relation rel) throws Exception {
if ((rel == null) || (rel.otherType == null) || !rel.otherType.isRelational()) { DbMapping type = rel == null ? null : rel.otherType;
if (type == null || !type.isRelational()) {
// this should never be called for embedded nodes // this should never be called for embedded nodes
throw new RuntimeException("NodeMgr.countNodes called for non-relational node " + throw new RuntimeException("countNodes called for non-relational node " + home);
home); }
} else {
int retval = 0; int retval = 0;
Connection con = rel.otherType.getConnection(); Connection con = type.getConnection();
// set connection to read-only mode // set connection to read-only mode
if (!con.isReadOnly()) con.setReadOnly(true); if (!con.isReadOnly()) con.setReadOnly(true);
String table = rel.otherType.getTableName();
Statement stmt = null; Statement stmt = null;
long logTimeStart = logSql ? System.currentTimeMillis() : 0; long logTimeStart = logSql ? System.currentTimeMillis() : 0;
String query = null; String query = null;
try { try {
StringBuffer tables = new StringBuffer(table); StringBuffer b = rel.getCountSelect();
rel.appendAdditionalTables(tables);
// NOTE: we explicitly convert tables StringBuffer to a String
// before appending to be compatible with JDK 1.3
StringBuffer b = new StringBuffer("SELECT count(*) FROM ")
.append(tables.toString());
if (home.getSubnodeRelation() != null) { if (home.getSubnodeRelation() != null) {
// use the manually set subnoderelation of the home node // use the manually set subnoderelation of the home node
query = b.append(" ").append(home.getSubnodeRelation()).toString(); query = b.append(" ").append(home.getSubnodeRelation()).toString();
} else { } else {
// let relation object build the query // let relation object build the query
rel.buildQuery(b, home, null, " WHERE ", false); rel.buildQuery(b, home, false, true);
query = b.toString(); query = b.toString();
} }
stmt = con.createStatement(); stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(query); ResultSet rs = stmt.executeQuery(query);
if (!rs.next()) { if (!rs.next()) {
retval = 0; retval = 0;
} else { } else {
@ -1408,7 +1234,7 @@ public final class NodeManager {
} finally { } finally {
if (logSql) { if (logSql) {
long logTimeStop = System.currentTimeMillis(); long logTimeStop = System.currentTimeMillis();
logSqlStatement("SQL SELECT_COUNT", table, logSqlStatement("SQL SELECT_COUNT", type.getTableName(),
logTimeStart, logTimeStop, query); logTimeStart, logTimeStop, query);
} }
if (stmt != null) { if (stmt != null) {
@ -1421,31 +1247,23 @@ public final class NodeManager {
return (rel.maxSize > 0) ? Math.min(rel.maxSize, retval) : retval; return (rel.maxSize > 0) ? Math.min(rel.maxSize, retval) : retval;
} }
}
/** /**
* Similar to getNodeIDs, but returns a List that contains the nodes property names instead of IDs * Similar to getNodeIDs, but returns a List that contains the nodes property names instead of IDs
*/ */
public Vector getPropertyNames(Node home, Relation rel) public Vector getPropertyNames(Node home, Relation rel)
throws Exception { throws Exception {
if ((rel == null) || (rel.otherType == null) || !rel.otherType.isRelational()) { DbMapping type = rel == null ? null : rel.otherType;
if (type == null || !type.isRelational()) {
// this should never be called for embedded nodes // this should never be called for embedded nodes
throw new RuntimeException("NodeMgr.getPropertyNames called for non-relational node " + throw new RuntimeException("getPropertyNames called for non-relational node " + home);
home); }
} else {
Vector retval = new Vector(); Vector retval = new Vector();
// if we do a groupby query (creating an intermediate layer of groupby nodes),
// retrieve the value of that field instead of the primary key
String namefield = (rel.groupby == null) ? rel.accessName : rel.groupby;
Connection con = rel.otherType.getConnection(); Connection con = rel.otherType.getConnection();
// set connection to read-only mode // set connection to read-only mode
if (!con.isReadOnly()) con.setReadOnly(true); if (!con.isReadOnly()) con.setReadOnly(true);
String table = rel.otherType.getTableName();
StringBuffer tables = new StringBuffer(table);
rel.appendAdditionalTables(tables);
Statement stmt = null; Statement stmt = null;
long logTimeStart = logSql ? System.currentTimeMillis() : 0; long logTimeStart = logSql ? System.currentTimeMillis() : 0;
String query = null; String query = null;
@ -1453,15 +1271,13 @@ public final class NodeManager {
try { try {
// NOTE: we explicitly convert tables StringBuffer to a String // NOTE: we explicitly convert tables StringBuffer to a String
// before appending to be compatible with JDK 1.3 // before appending to be compatible with JDK 1.3
StringBuffer b = new StringBuffer("SELECT ").append(namefield) StringBuffer b = rel.getNamesSelect();
.append(" FROM ")
.append(tables.toString());
if (home.getSubnodeRelation() != null) { if (home.getSubnodeRelation() != null) {
b.append(" ").append(home.getSubnodeRelation()); b.append(" ").append(home.getSubnodeRelation());
} else { } else {
// let relation object build the query // let relation object build the query
rel.buildQuery(b, home, null, " WHERE ", true); rel.buildQuery(b, home, true, false);
} }
stmt = con.createStatement(); stmt = con.createStatement();
@ -1480,7 +1296,7 @@ public final class NodeManager {
} finally { } finally {
if (logSql) { if (logSql) {
long logTimeStop = System.currentTimeMillis(); long logTimeStop = System.currentTimeMillis();
logSqlStatement("SQL SELECT_ACCESSNAMES", table, logSqlStatement("SQL SELECT_ACCESSNAMES", type.getTableName(),
logTimeStart, logTimeStop, query); logTimeStart, logTimeStop, query);
} }
@ -1494,7 +1310,6 @@ public final class NodeManager {
return retval; return retval;
} }
}
/////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////
// private getNode methods // private getNode methods
@ -1622,7 +1437,7 @@ public final class NodeManager {
b.append(")"); b.append(")");
} }
} else { } else {
rel.buildQuery(b, home, dbm, kstr, " WHERE ", false); rel.buildQuery(b, home, dbm, kstr, false, false);
} }
stmt = con.createStatement(); stmt = con.createStatement();

View file

@ -873,13 +873,58 @@ public final class Relation {
return vr; return vr;
} }
public StringBuffer getIdSelect() {
StringBuffer buf = new StringBuffer("SELECT ");
if (queryHints != null) {
buf.append(queryHints).append(" ");
}
String table = otherType.getTableName();
String idfield = (groupby == null) ? otherType.getIDField() : groupby;
if (idfield.indexOf('(') == -1 && idfield.indexOf('.') == -1) {
buf.append(table).append('.');
}
buf.append(idfield).append(" FROM ").append(table);
appendAdditionalTables(buf);
return buf;
}
public StringBuffer getCountSelect() {
StringBuffer buf = new StringBuffer();
if (otherType.isOracle() && maxSize > 0) {
buf.append("SELECT * FROM ");
} else {
buf.append("SELECT count(*) FROM ");
}
buf.append(otherType.getTableName());
appendAdditionalTables(buf);
return buf;
}
public StringBuffer getNamesSelect() {
// if we do a groupby query (creating an intermediate layer of groupby nodes),
// retrieve the value of that field instead of the primary key
String namefield = (groupby == null) ? accessName : groupby;
String table = otherType.getTableName();
StringBuffer buf = new StringBuffer("SELECT ");
buf.append(namefield).append(" FROM ").append(table);
appendAdditionalTables(buf);
return buf;
}
/** /**
* Build the second half of an SQL select statement according to this relation * Build the second half of an SQL select statement according to this relation
* and a local object. * and a local object.
*/ */
public void buildQuery(StringBuffer q, Node home, String kstr, String pre, boolean useOrder) public void buildQuery(StringBuffer q, Node home, boolean useOrder, boolean isCount)
throws SQLException, ClassNotFoundException { throws SQLException, ClassNotFoundException {
buildQuery(q, home, otherType, kstr, pre, useOrder); buildQuery(q, home, otherType, null, useOrder, isCount);
} }
/** /**
@ -887,9 +932,9 @@ public final class Relation {
* and a local object. * and a local object.
*/ */
public void buildQuery(StringBuffer q, Node home, DbMapping otherDbm, String kstr, public void buildQuery(StringBuffer q, Node home, DbMapping otherDbm, String kstr,
String pre, boolean useOrder) boolean useOrder, boolean isCount)
throws SQLException, ClassNotFoundException { throws SQLException, ClassNotFoundException {
String prefix = pre; String prefix = " WHERE ";
Node nonvirtual = home.getNonVirtualParent(); Node nonvirtual = home.getNonVirtualParent();
if (kstr != null && !isComplexReference()) { if (kstr != null && !isComplexReference()) {
@ -922,11 +967,12 @@ public final class Relation {
if (maxSize > 0) { if (maxSize > 0) {
if (otherType.isOracle()) { if (otherType.isOracle()) {
// see http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html // see http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html
String selectItem = isCount ? "count(*)" : "*";
if (offset > 0) { if (offset > 0) {
q.insert(0, "SELECT * FROM ( SELECT /*+ FIRST_ROWS(n) */ a.*, ROWNUM rnum FROM ("); q.insert(0, "SELECT " + selectItem + " FROM ( SELECT /*+ FIRST_ROWS(n) */ a.*, ROWNUM rnum FROM (");
q.append(") a WHERE ROWNUM <= ").append(offset + maxSize).append(") WHERE rnum > ").append(offset); q.append(") a WHERE ROWNUM <= ").append(offset + maxSize).append(") WHERE rnum > ").append(offset);
} else { } else {
q.insert(0, "SELECT /*+ FIRST_ROWS(n) */ * FROM ("); q.insert(0, "SELECT /*+ FIRST_ROWS(n) */ " + selectItem + " FROM (");
q.append(") WHERE ROWNUM <= ").append(maxSize); q.append(") WHERE ROWNUM <= ").append(maxSize);
} }
} else { } else {