diff --git a/src/helma/objectmodel/db/DbMapping.java b/src/helma/objectmodel/db/DbMapping.java index 0d541aea..d2500fa5 100644 --- a/src/helma/objectmodel/db/DbMapping.java +++ b/src/helma/objectmodel/db/DbMapping.java @@ -921,6 +921,7 @@ public final class DbMapping implements Updatable { // assign to local variable first so we are thread safe // (selectString may be reset by other threads) String sel = selectString; + boolean isOracle = isOracle(); if (rel == null && sel != null) { return new StringBuffer(sel); @@ -962,13 +963,24 @@ public final class DbMapping implements Updatable { if (!joins[i].otherType.isRelational()) { continue; } - s.append("LEFT OUTER JOIN "); - s.append(joins[i].otherType.getTableName()); - s.append(" AS "); - s.append(Relation.JOIN_PREFIX); - s.append(joins[i].propName); - s.append(" ON "); - joins[i].renderJoinConstraints(s); + if (isOracle) { + // generate an old-style oracle left join - see + // http://www.praetoriate.com/oracle_tips_outer_joins.htm + s.append(", "); + s.append(joins[i].otherType.getTableName()); + s.append(" "); + s.append(Relation.JOIN_PREFIX); + s.append(joins[i].propName); + s.append(" "); + } else { + s.append("LEFT OUTER JOIN "); + s.append(joins[i].otherType.getTableName()); + s.append(" "); + s.append(Relation.JOIN_PREFIX); + s.append(joins[i].propName); + s.append(" ON "); + joins[i].renderJoinConstraints(s, isOracle); + } } // cache rendered string for later calls, but only if it wasn't @@ -1064,6 +1076,37 @@ public final class DbMapping implements Updatable { } } + /** + * Add constraints to select query string to join object references + */ + public void addJoinConstraints(StringBuffer s, String pre) { + boolean isOracle = isOracle(); + String prefix = pre; + + if (!isOracle) { + // constraints have already been rendered by getSelect() + return; + } + + for (int i = 0; i < joins.length; i++) { + if (!joins[i].otherType.isRelational()) { + continue; + } + s.append(prefix); + joins[i].renderJoinConstraints(s, isOracle); + prefix = " AND "; + } + } + + /** + * Is the database behind this an Oracle db? + * + * @return true if the dbsource is using an oracle JDBC driver + */ + public boolean isOracle() { + return dbSource != null && dbSource.isOracle(); + } + /** * * diff --git a/src/helma/objectmodel/db/DbSource.java b/src/helma/objectmodel/db/DbSource.java index 4c92948f..c8939525 100644 --- a/src/helma/objectmodel/db/DbSource.java +++ b/src/helma/objectmodel/db/DbSource.java @@ -33,6 +33,7 @@ public class DbSource { private String driver; protected String user; private String password; + private boolean isOracle; private long lastRead = 0L; /** @@ -87,6 +88,7 @@ public class DbSource { defaultProps.lastModified()); url = props.getProperty(name + ".url"); driver = props.getProperty(name + ".driver"); + isOracle = driver != null && driver.startsWith("oracle.jdbc.driver"); Class.forName(driver); user = props.getProperty(name + ".user"); password = props.getProperty(name + ".password"); @@ -118,4 +120,13 @@ public class DbSource { public static void setDefaultProps(SystemProperties props) { defaultProps = props; } + + /** + * Is this an Oracle database? + * + * @return true if we're using an oracle JDBC driver + */ + public boolean isOracle() { + return isOracle; + } } diff --git a/src/helma/objectmodel/db/NodeManager.java b/src/helma/objectmodel/db/NodeManager.java index 1b055e9e..ab55f523 100644 --- a/src/helma/objectmodel/db/NodeManager.java +++ b/src/helma/objectmodel/db/NodeManager.java @@ -1201,6 +1201,8 @@ public final class NodeManager { q.append(") "); + dbm.addJoinConstraints(q, " AND "); + if (rel.groupby != null) { q.append(rel.renderConstraints(home, home.getNonVirtualParent())); @@ -1504,6 +1506,8 @@ public final class NodeManager { q.append(kstr); } + dbm.addJoinConstraints(q, " AND "); + if (logSql) { app.logEvent("### getNodeByKey: " + q.toString()); } diff --git a/src/helma/objectmodel/db/Relation.java b/src/helma/objectmodel/db/Relation.java index af93fc5e..09ae034b 100644 --- a/src/helma/objectmodel/db/Relation.java +++ b/src/helma/objectmodel/db/Relation.java @@ -800,6 +800,8 @@ public final class Relation { appendFilter(q, nonvirtual, prefix); } + ownType.addJoinConstraints(q, prefix); + if (groupby != null) { q.append(" GROUP BY " + groupby); @@ -912,8 +914,11 @@ public final class Relation { /** * Render the constraints for this relation for use within * a left outer join select statement for the base object. + * + * @param select the string buffer to write to + * @param isOracle create Oracle pre-9 style left outer join */ - public void renderJoinConstraints(StringBuffer select) { + public void renderJoinConstraints(StringBuffer select, boolean isOracle) { for (int i = 0; i < constraints.length; i++) { select.append(ownType.getTableName()); select.append("."); @@ -923,6 +928,11 @@ public final class Relation { select.append(propName); select.append("."); select.append(constraints[i].foreignName); + if (isOracle) { + // create old oracle style join - see + // http://www.praetoriate.com/oracle_tips_outer_joins.htm + select.append("(+)"); + } if (i == constraints.length-1) { select.append(" "); } else { @@ -1062,6 +1072,7 @@ public final class Relation { */ public void unsetConstraints(Node parent, INode child) { Node home = parent.getNonVirtualParent(); + for (int i = 0; i < constraints.length; i++) { // don't set groupby constraints since we don't know if the // parent node is the base node or a group node