* moved SQL generation to Relation class.

* DbKey is againonly used for primary keys.
* The Relation class is now able to check its constraints on
a parent node and a child node which was found in cache.
This commit is contained in:
hns 2001-08-20 14:55:26 +00:00
parent 96cad06996
commit 25c76b621e

View file

@ -182,21 +182,11 @@ public final class NodeManager {
node = getNodeByKey (tx.txn, (DbKey) key); node = getNodeByKey (tx.txn, (DbKey) key);
if (node != null) { if (node != null) {
Key primKey = node.getKey ();
boolean keyIsPrimary = primKey.equals (key);
synchronized (cache) { synchronized (cache) {
// check if node is already in cache with primary key Node oldnode = (Node) cache.put (node.getKey (), node);
Node oldnode = (Node) cache.put (primKey, node);
// no need to check for oldnode != node because we fetched a new node from db
if (oldnode != null && !oldnode.isNullNode() && oldnode.getState () != Node.INVALID) { if (oldnode != null && !oldnode.isNullNode() && oldnode.getState () != Node.INVALID) {
cache.put (primKey, oldnode); cache.put (node.getKey (), oldnode);
if (!keyIsPrimary) {
cache.put (key, oldnode);
}
node = oldnode; node = oldnode;
} else if (!keyIsPrimary) {
// cache node with secondary key
cache.put (key, node);
} }
} // synchronized } // synchronized
} }
@ -227,7 +217,7 @@ public final class NodeManager {
else else
// if a key for a node from within the DB // if a key for a node from within the DB
// FIXME: This should never apply, since for every relation-based loading Synthetic Keys are used. Right? // FIXME: This should never apply, since for every relation-based loading Synthetic Keys are used. Right?
key = new DbKey (rel.other, kstr); key = new DbKey (rel.otherType, kstr);
// See if Transactor has already come across this node // See if Transactor has already come across this node
Node node = tx.getVisitedNode (key); Node node = tx.getVisitedNode (key);
@ -245,12 +235,13 @@ public final class NodeManager {
// check if we can use the cached node without further checks. // check if we can use the cached node without further checks.
// we need further checks for subnodes fetched by name if the subnodes were changed. // we need further checks for subnodes fetched by name if the subnodes were changed.
if (!rel.virtual && rel.subnodesAreProperties && node != null && node.getState() != Node.INVALID) { if (!rel.virtual && !rel.usesPrimaryKey () && node != null && node.getState() != Node.INVALID) {
// check if node is null node (cached null) // check if node is null node (cached null)
if (node.isNullNode ()) { if (node.isNullNode ()) {
if (node.created() < rel.other.getLastDataChange ()) if (node.created() < rel.otherType.getLastDataChange ())
node = null; // cached null not valid anymore node = null; // cached null not valid anymore
} else if (app.doesSubnodeChecking () && home.contains (node) < 0) { // } else if (app.doesSubnodeChecking () && home.contains (node) < 0) {
} else if (!rel.checkConstraints (home, node)) {
node = null; node = null;
} }
} }
@ -382,7 +373,7 @@ public final class NodeManager {
rec.setValue (rel.getDbField(), p.getFloatValue ()); rec.setValue (rel.getDbField(), p.getFloatValue ());
break; break;
case IProperty.NODE: case IProperty.NODE:
if (rel.direction == Relation.FORWARD) { if (rel.reftype == Relation.REFERENCE) {
// INode n = p.getNodeValue (); // INode n = p.getNodeValue ();
// String foreignID = n == null ? null : n.getID (); // String foreignID = n == null ? null : n.getID ();
rec.setValue (rel.getDbField(), p.getStringValue ()); rec.setValue (rel.getDbField(), p.getStringValue ());
@ -434,7 +425,8 @@ public final class NodeManager {
Relation rel = dbm.propertyToRelation (propname); Relation rel = dbm.propertyToRelation (propname);
// skip properties that don't need to be updated before fetching them // skip properties that don't need to be updated before fetching them
if (rel != null && (rel.readonly || rel.virtual || (rel.direction != Relation.FORWARD && rel.direction != Relation.PRIMITIVE))) if (rel != null && (rel.readonly || rel.virtual ||
(rel.reftype != Relation.REFERENCE && rel.reftype != Relation.PRIMITIVE)))
continue; continue;
Property p = node.getProperty (propname, false); Property p = node.getProperty (propname, false);
@ -465,7 +457,7 @@ public final class NodeManager {
rec.setValue (rel.getDbField(), p.getFloatValue ()); rec.setValue (rel.getDbField(), p.getFloatValue ());
break; break;
case IProperty.NODE: case IProperty.NODE:
if (!rel.virtual && rel.direction == Relation.FORWARD) { if (!rel.virtual && rel.reftype == Relation.REFERENCE) {
// INode n = p.getNodeValue (); // INode n = p.getNodeValue ();
// String foreignID = n == null ? null : n.getID (); // String foreignID = n == null ? null : n.getID ();
updated++; updated++;
@ -593,42 +585,26 @@ public final class NodeManager {
Transactor tx = (Transactor) Thread.currentThread (); Transactor tx = (Transactor) Thread.currentThread ();
// tx.timer.beginEvent ("getNodeIDs "+home); // tx.timer.beginEvent ("getNodeIDs "+home);
if (rel == null || rel.other == null || !rel.other.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.getNodeIDs called for non-relational node "+home); throw new RuntimeException ("NodeMgr.getNodeIDs called for non-relational node "+home);
} else { } 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.other.getIDField () : rel.groupby; String idfield = rel.groupby == null ? rel.otherType.getIDField () : rel.groupby;
Connection con = rel.other.getConnection (); Connection con = rel.otherType.getConnection ();
String table = rel.other.getTableName (); String table = rel.otherType.getTableName ();
QueryDataSet qds = null; QueryDataSet qds = null;
try { try {
Relation subrel = rel;
if (subrel.getSubnodeRelation () != null)
subrel = subrel.getSubnodeRelation ();
if (home.getSubnodeRelation() != null) { if (home.getSubnodeRelation() != null) {
// subnode relation was explicitly set // subnode relation was explicitly set
qds = new QueryDataSet (con, "SELECT "+idfield+" FROM "+table+" "+home.getSubnodeRelation()); qds = new QueryDataSet (con, "SELECT "+idfield+" FROM "+table+" "+home.getSubnodeRelation());
} else { } else {
String q = "SELECT "+idfield+" FROM "+table; String q = "SELECT "+idfield+" FROM "+table;
if (subrel.direction == Relation.BACKWARD) { q += rel.buildQuery (home, home.getNonVirtualParent (), null);
String homeid = home.getNonVirtualHomeID ();
q += " WHERE "+subrel.getRemoteField()+" = '"+homeid+"'";
if (subrel.filter != null)
q += " AND "+subrel.filter;
if (rel.dogroupby != null)
q += " AND " + rel.dogroupby + " = '" + home.getString ("groupname", false) +"'";
} else if (subrel.filter != null)
q += " WHERE "+subrel.filter;
// set order, if specified and if not using subnode's relation
if (rel.groupby != null)
q += " GROUP BY "+rel.groupby+" ORDER BY "+(rel.groupbyorder == null ? rel.groupby : rel.groupbyorder);
else if (rel.order != null)
q += " ORDER BY "+rel.order;
qds = new QueryDataSet (con, q); qds = new QueryDataSet (con, q);
} }
@ -644,7 +620,7 @@ public final class NodeManager {
String kstr = rec.getValue (1).asString (); String kstr = rec.getValue (1).asString ();
// make the proper key for the object, either a generic DB key or a groupby key // make the proper key for the object, either a generic DB key or a groupby key
Key key = rel.groupby == null ? Key key = rel.groupby == null ?
(Key) new DbKey (rel.other, kstr) : (Key) new DbKey (rel.otherType, kstr) :
(Key) new SyntheticKey (k, kstr); (Key) new SyntheticKey (k, kstr);
retval.add (new NodeHandle (key)); retval.add (new NodeHandle (key));
// if these are groupby nodes, evict nullNode keys // if these are groupby nodes, evict nullNode keys
@ -679,39 +655,20 @@ public final class NodeManager {
Transactor tx = (Transactor) Thread.currentThread (); Transactor tx = (Transactor) Thread.currentThread ();
// tx.timer.beginEvent ("getNodes "+home); // tx.timer.beginEvent ("getNodes "+home);
if (rel == null || rel.other == null || !rel.other.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.countNodes called for non-relational node "+home); throw new RuntimeException ("NodeMgr.countNodes called for non-relational node "+home);
} else { } else {
List retval = new ArrayList (); List retval = new ArrayList ();
DbMapping dbm = rel.other; DbMapping dbm = rel.otherType;
TableDataSet tds = new TableDataSet (dbm.getConnection (), dbm.getSchema (), dbm.getKeyDef ()); TableDataSet tds = new TableDataSet (dbm.getConnection (), dbm.getSchema (), dbm.getKeyDef ());
try { try {
Relation subrel = rel;
if (subrel.getSubnodeRelation () != null)
subrel = subrel.getSubnodeRelation ();
if (home.getSubnodeRelation() != null) {
// HACK: subnodeRelation includes a "where", but we need it without
tds.where (home.getSubnodeRelation().trim().substring(5));
} else if (subrel.direction == Relation.BACKWARD) {
String homeid = home.getNonVirtualHomeID ();
if (rel.filter != null)
tds.where (subrel.getRemoteField()+" = '"+homeid+"' AND "+subrel.filter);
else
tds.where (subrel.getRemoteField()+" = '"+homeid+"'");
// set order if specified
if (rel.order != null)
tds.order (rel.order);
} else {
// don't set where clause except for static filter, but set order.
if (subrel.filter != null)
tds.where (subrel.filter);
if (rel.order != null)
tds.order (rel.order);
}
tds.where (rel.buildWhere (home, home.getNonVirtualParent (), null));
if (rel.order != null)
tds.order (rel.order);
if (logSql) if (logSql)
app.logEvent ("### getNodes: "+tds.getSelectString()); app.logEvent ("### getNodes: "+tds.getSelectString());
@ -719,7 +676,7 @@ public final class NodeManager {
for (int i=0; i<tds.size (); i++) { for (int i=0; i<tds.size (); i++) {
// create new Nodes. // create new Nodes.
Record rec = tds.getRecord (i); Record rec = tds.getRecord (i);
Node node = new Node (rel.other, rec, safe); Node node = new Node (rel.otherType, rec, safe);
Key primKey = node.getKey (); Key primKey = node.getKey ();
retval.add (new NodeHandle (primKey)); retval.add (new NodeHandle (primKey));
// do we need to synchronize on primKey here? // do we need to synchronize on primKey here?
@ -747,39 +704,22 @@ public final class NodeManager {
Transactor tx = (Transactor) Thread.currentThread (); Transactor tx = (Transactor) Thread.currentThread ();
// tx.timer.beginEvent ("countNodes "+home); // tx.timer.beginEvent ("countNodes "+home);
if (rel == null || rel.other == null || !rel.other.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.countNodes called for non-relational node "+home); throw new RuntimeException ("NodeMgr.countNodes called for non-relational node "+home);
} else { } else {
int retval = 0; int retval = 0;
Connection con = rel.other.getConnection (); Connection con = rel.otherType.getConnection ();
String table = rel.other.getTableName (); String table = rel.otherType.getTableName ();
QueryDataSet qds = null; QueryDataSet qds = null;
try { try {
Relation subrel = rel; String qstr = "SELECT count(*) FROM "+table+rel.buildQuery (home, home.getNonVirtualParent (), null);
if (subrel.getSubnodeRelation () != null)
subrel = subrel.getSubnodeRelation ();
if (home.getSubnodeRelation() != null) {
qds = new QueryDataSet (con, "SELECT count(*) FROM "+table+" "+home.getSubnodeRelation());
} else if (subrel.direction == Relation.BACKWARD) {
String homeid = home.getNonVirtualHomeID ();
String qstr = "SELECT count(*) FROM "+table+" WHERE "+subrel.getRemoteField()+" = '"+homeid+"'";
if (subrel.filter != null)
qstr += " AND "+subrel.filter;
if (rel.dogroupby != null)
qstr += " AND " + rel.dogroupby + " = '" + home.getString ("groupname", false) +"'";
qds = new QueryDataSet (con, qstr);
} else {
String qstr = "SELECT count(*) FROM "+table;
if (subrel.filter != null)
qstr += " WHERE "+subrel.filter;
qds = new QueryDataSet (con, qstr);
}
if (logSql) if (logSql)
app.logEvent ("### countNodes: "+qds.getSelectString()); app.logEvent ("### countNodes: "+qstr);
qds = new QueryDataSet (con, qstr);
qds.fetchRecords (); qds.fetchRecords ();
if (qds.size () == 0) if (qds.size () == 0)
@ -805,16 +745,16 @@ public final class NodeManager {
Transactor tx = (Transactor) Thread.currentThread (); Transactor tx = (Transactor) Thread.currentThread ();
// tx.timer.beginEvent ("getNodeIDs "+home); // tx.timer.beginEvent ("getNodeIDs "+home);
if (rel == null || rel.other == null || !rel.other.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.getPropertyNames called for non-relational node "+home); throw new RuntimeException ("NodeMgr.getPropertyNames called for non-relational node "+home);
} else { } else {
Vector retval = new Vector (); Vector retval = new Vector ();
// 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 namefield = rel.getRemoteField (); String namefield = rel.accessor;
Connection con = rel.other.getConnection (); Connection con = rel.otherType.getConnection ();
String table = rel.other.getTableName (); String table = rel.otherType.getTableName ();
QueryDataSet qds = null; QueryDataSet qds = null;
@ -860,9 +800,7 @@ public final class NodeManager {
if (node != null && dbm != null) if (node != null && dbm != null)
node.setDbMapping (dbm); node.setDbMapping (dbm);
} else { } else {
String idfield = key.getIDField (); String idfield =dbm.getIDField ();
if (idfield == null)
idfield =dbm.getIDField ();
TableDataSet tds = null; TableDataSet tds = null;
try { try {
@ -906,62 +844,27 @@ public final class NodeManager {
} else if (rel != null && rel.groupby != null) { } else if (rel != null && rel.groupby != null) {
node = home.getGroupbySubnode (kstr, false); node = home.getGroupbySubnode (kstr, false);
if (node == null && (rel.other == null || !rel.other.isRelational ())) { if (node == null && (rel.otherType == null || !rel.otherType.isRelational ())) {
node = db.getNode (txn, kstr); node = db.getNode (txn, kstr);
node.nmgr = safe; node.nmgr = safe;
} }
return node; return node;
} else if (rel == null || rel.other == null || !rel.other.isRelational ()) { } else if (rel == null || rel.otherType == null || !rel.otherType.isRelational ()) {
node = db.getNode (txn, kstr); node = db.getNode (txn, kstr);
node.nmgr = safe; node.nmgr = safe;
node.setDbMapping (rel.other); node.setDbMapping (rel.otherType);
return node; return node;
} else { } else {
System.err.println ("GETNODEBYRELATION "+rel);
TableDataSet tds = null; TableDataSet tds = null;
try { try {
DbMapping dbm = rel.other; DbMapping dbm = rel.otherType;
tds = new TableDataSet (dbm.getConnection (), dbm.getSchema (), dbm.getKeyDef ()); tds = new TableDataSet (dbm.getConnection (), dbm.getSchema (), dbm.getKeyDef ());
StringBuffer where = new StringBuffer (); String where = rel.buildWhere (home, home.getNonVirtualParent (), kstr);
where.append (rel.getRemoteField ()); tds.where (where);
where.append (" = '");
where.append (escape(kstr));
where.append ("'");
// Additionally filter properties through subnode relation?
if (rel.subnodesAreProperties) {
String homeid = home.getNonVirtualHomeID ();
// first check for dynamic subrel from node
String nodesubrel = home.getSubnodeRelation();
if (nodesubrel != null && nodesubrel.trim().length() > 5) {
where.append (" and ");
where.append (nodesubrel.trim().substring(5).trim());
} else {
Relation subrel = home.getDbMapping().getSubnodeRelation ();
if (subrel != null) {
if (subrel.getSubnodeRelation () != null)
subrel = subrel.getSubnodeRelation ();
if (subrel != null && subrel.direction == Relation.BACKWARD) {
where.append (" and ");
where.append (subrel.getRemoteField());
where.append (" = '");
where.append (homeid);
where.append ("'");
}
if (rel.dogroupby != null) {
where.append (" and ");
where.append (rel.dogroupby);
where.append (" = '");
where.append (home.getString ("groupname", false));
where.append ("'");
}
}
}
}
tds.where (where.toString ());
if (logSql) if (logSql)
app.logEvent ("### getNodeByRelation: "+tds.getSelectString()); app.logEvent ("### getNodeByRelation: "+tds.getSelectString());
@ -973,7 +876,7 @@ public final class NodeManager {
if (tds.size () > 1) if (tds.size () > 1)
throw new RuntimeException ("More than one value returned by query."); throw new RuntimeException ("More than one value returned by query.");
Record rec = tds.getRecord (0); Record rec = tds.getRecord (0);
node = new Node (rel.other, rec, safe); node = new Node (rel.otherType, rec, safe);
// Check if node is already cached with primary Key. // Check if node is already cached with primary Key.
if (!rel.usesPrimaryKey()) { if (!rel.usesPrimaryKey()) {