* From Manfred's last patch for bug 468:
- Factor out repetitive SQL query building tasks into DbMapping.appendCondition() - Implement automatic extended prototype filter for collections - add prototype ids, but with simplified implementation (be agnostic about numeric ids vs. prototype names) * Rewrite relational node insertion code * Make better use of DbColumn class wherever possible * Minor code improvements throughout the place
This commit is contained in:
parent
37f26241c4
commit
56f83cb75b
4 changed files with 297 additions and 275 deletions
|
@ -16,10 +16,11 @@
|
|||
|
||||
package helma.objectmodel.db;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* A class that encapsulates the Column name and data type of a
|
||||
* column in a relational table.
|
||||
* A class that encapsulates the Column name and data type of a column in a
|
||||
* relational table.
|
||||
*/
|
||||
public final class DbColumn {
|
||||
private final String name;
|
||||
|
@ -30,8 +31,6 @@ public final class DbColumn {
|
|||
private final boolean isPrototype;
|
||||
private final boolean isName;
|
||||
|
||||
private final boolean isMapped;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
|
@ -47,8 +46,6 @@ public final class DbColumn {
|
|||
isId = name.equalsIgnoreCase(dbmap.getIDField());
|
||||
isPrototype = name.equalsIgnoreCase(dbmap.getPrototypeField());
|
||||
isName = name.equalsIgnoreCase(dbmap.getNameField());
|
||||
|
||||
isMapped = relation != null || isId || isPrototype || isName;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,7 +94,33 @@ public final class DbColumn {
|
|||
* Returns true if this field is mapped by the prototype's db mapping.
|
||||
*/
|
||||
public boolean isMapped() {
|
||||
return isMapped;
|
||||
// Note: not sure if check for primitive or reference relation is really
|
||||
// needed, but we did it before, so we leave it in for safety.
|
||||
return isId || isPrototype || isName ||
|
||||
(relation != null && (relation.isPrimitive() || relation.isReference()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether values for this column need to be quoted in insert/update
|
||||
* stmts
|
||||
*
|
||||
* @return true if values need to be wrapped in quotes
|
||||
*/
|
||||
public boolean needsQuotes() {
|
||||
switch (type) {
|
||||
case Types.CHAR:
|
||||
case Types.VARCHAR:
|
||||
case Types.LONGVARCHAR:
|
||||
case Types.BINARY:
|
||||
case Types.VARBINARY:
|
||||
case Types.LONGVARBINARY:
|
||||
case Types.DATE:
|
||||
case Types.TIME:
|
||||
case Types.TIMESTAMP:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -89,8 +89,13 @@ public final class DbMapping {
|
|||
// db field used to identify name of prototype to use for object instantiation
|
||||
private String protoField;
|
||||
|
||||
// name of parent prototype, if any
|
||||
private String extendsProto;
|
||||
// Used to map prototype ids to prototype names for
|
||||
// prototypes which extend the prototype represented by
|
||||
// this DbMapping.
|
||||
private ResourceProperties extensionMap;
|
||||
|
||||
// a numeric or literal id used to represent this type in db
|
||||
private String extensionId;
|
||||
|
||||
// dbmapping of parent prototype, if any
|
||||
private DbMapping parentMapping;
|
||||
|
@ -221,7 +226,7 @@ public final class DbMapping {
|
|||
lastTypeChange = props.lastModified();
|
||||
|
||||
// see if this prototype extends (inherits from) any other prototype
|
||||
extendsProto = props.getProperty("_extends");
|
||||
String extendsProto = props.getProperty("_extends");
|
||||
|
||||
if (extendsProto != null) {
|
||||
parentMapping = app.getDbMapping(extendsProto);
|
||||
|
@ -245,6 +250,10 @@ public final class DbMapping {
|
|||
parentMapping = null;
|
||||
}
|
||||
|
||||
// check if there is an extension-id specified inside the type.properties
|
||||
extensionId = props.getProperty("_extensionId", typename);
|
||||
registerExtension(extensionId, typename);
|
||||
|
||||
// set the parent prototype in the corresponding Prototype object!
|
||||
// this was previously done by TypeManager, but we need to do it
|
||||
// ourself because DbMapping.update() may be called by other code than
|
||||
|
@ -361,6 +370,57 @@ public final class DbMapping {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given extensionId and the coresponding prototypename
|
||||
* to extensionMap for later lookup.
|
||||
* @param extID the id mapping to the prototypename recogniced by helma
|
||||
* @param extName the name of the extending prototype
|
||||
*/
|
||||
private void registerExtension(String extID, String extName) {
|
||||
// lazy initialization of extensionMap
|
||||
if (extensionMap == null) {
|
||||
extensionMap = new ResourceProperties();
|
||||
extensionMap.setIgnoreCase(true);
|
||||
} else if (extensionMap.containsValue(extName)) {
|
||||
// remove any preexisting mapping for the given childmapping
|
||||
extensionMap.values().remove(extName);
|
||||
}
|
||||
extensionMap.setProperty(extID, extName);
|
||||
if (inheritsStorage()) {
|
||||
parentMapping.registerExtension(extID, extName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Set of Prototypes extending this prototype
|
||||
* @return the Set of Prototypes extending this prototype
|
||||
*/
|
||||
public String[] getExtensions() {
|
||||
return extensionMap == null
|
||||
? new String[] { extensionId }
|
||||
: (String[]) extensionMap.keySet().toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the prototype-name identified by the given integer value
|
||||
* @param id the id specified for the prototype
|
||||
* @return the name of the extending prototype
|
||||
*/
|
||||
public String getPrototypeName(String id) {
|
||||
if (inheritsStorage()) {
|
||||
return parentMapping.getPrototypeName(id);
|
||||
}
|
||||
// fallback to base-prototype if the proto isn't recogniced
|
||||
return extensionMap.getProperty(id, typename);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the id-value of this extension
|
||||
*/
|
||||
public String getExtensionId() {
|
||||
return extensionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method in interface Updatable.
|
||||
*/
|
||||
|
@ -459,7 +519,7 @@ public final class DbMapping {
|
|||
* Get the name of this type's parent type, if any.
|
||||
*/
|
||||
public String getExtends() {
|
||||
return extendsProto;
|
||||
return parentMapping == null ? null : parentMapping.getTypeName();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -937,27 +997,20 @@ public final class DbMapping {
|
|||
*/
|
||||
public DbColumn getColumn(String columnName)
|
||||
throws ClassNotFoundException, SQLException {
|
||||
|
||||
DbColumn col = (DbColumn) columnMap.get(columnName);
|
||||
|
||||
if (col == null) {
|
||||
DbColumn[] cols = columns;
|
||||
|
||||
if (cols == null) {
|
||||
cols = getColumns();
|
||||
}
|
||||
|
||||
for (int i = 0; i < cols.length; i++) {
|
||||
if (columnName.equalsIgnoreCase(cols[i].getName())) {
|
||||
col = cols[i];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
columnMap.put(columnName, col);
|
||||
}
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
|
@ -1057,24 +1110,22 @@ public final class DbMapping {
|
|||
}
|
||||
|
||||
StringBuffer b1 = new StringBuffer("INSERT INTO ");
|
||||
StringBuffer b2 = new StringBuffer(" ) VALUES ( ");
|
||||
b1.append(getTableName());
|
||||
b1.append(" ( ");
|
||||
b1.append(getIDField());
|
||||
|
||||
StringBuffer b2 = new StringBuffer(" ) VALUES ( ?");
|
||||
|
||||
DbColumn[] cols = getColumns();
|
||||
boolean needsComma = false;
|
||||
|
||||
for (int i = 0; i < cols.length; i++) {
|
||||
Relation rel = cols[i].getRelation();
|
||||
String name = cols[i].getName();
|
||||
|
||||
if (((rel != null) && (rel.isPrimitive() ||
|
||||
rel.isReference())) ||
|
||||
name.equalsIgnoreCase(getNameField()) ||
|
||||
name.equalsIgnoreCase(getPrototypeField())) {
|
||||
b1.append(", ").append(cols[i].getName());
|
||||
b2.append(", ?");
|
||||
if (cols[i].isMapped()) {
|
||||
if (needsComma) {
|
||||
b1.append(", ");
|
||||
b2.append(", ");
|
||||
}
|
||||
b1.append(cols[i].getName());
|
||||
b2.append("?");
|
||||
needsComma = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1115,36 +1166,16 @@ public final class DbMapping {
|
|||
* 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 {
|
||||
public boolean needsQuotes(String columnName) throws SQLException, ClassNotFoundException {
|
||||
if ((tableName == null) && (parentMapping != null)) {
|
||||
return parentMapping.needsQuotes(columnName);
|
||||
}
|
||||
|
||||
try {
|
||||
DbColumn col = getColumn(columnName);
|
||||
|
||||
// This is not a mapped column. In case of doubt, add quotes.
|
||||
if (col == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (col.getType()) {
|
||||
case Types.CHAR:
|
||||
case Types.VARCHAR:
|
||||
case Types.LONGVARCHAR:
|
||||
case Types.BINARY:
|
||||
case Types.VARBINARY:
|
||||
case Types.LONGVARBINARY:
|
||||
case Types.DATE:
|
||||
case Types.TIME:
|
||||
case Types.TIMESTAMP:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} catch (Exception x) {
|
||||
throw new SQLException(x.getMessage());
|
||||
} else {
|
||||
return col.needsQuotes();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1367,10 +1398,7 @@ public final class DbMapping {
|
|||
// note: tableName and dbSourceName are nulled out in update() if they
|
||||
// are inherited from the parent mapping. This way we know that
|
||||
// storage is not inherited if either of them is not null.
|
||||
if (parentMapping == null || tableName != null || dbSourceName != null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return parentMapping != null && tableName == null && dbSourceName == null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1451,4 +1479,90 @@ public final class DbMapping {
|
|||
protected void addDependency(DbMapping dbmap) {
|
||||
this.dependentMappings.add(dbmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a sql-condition for the given column which must have
|
||||
* one of the values contained inside the given Set to the given
|
||||
* StringBuffer.
|
||||
* @param q the StringBuffer to append to
|
||||
* @param column the column which must match one of the values
|
||||
* @param values the list of values
|
||||
* @throws SQLException
|
||||
*/
|
||||
protected void appendCondition(StringBuffer q, String column, String[] values)
|
||||
throws SQLException, ClassNotFoundException {
|
||||
if (values.length == 1) {
|
||||
appendCondition(q, column, values[0]);
|
||||
return;
|
||||
}
|
||||
if (column.indexOf('(') == -1 && column.indexOf('.') == -1) {
|
||||
q.append(getTableName()).append(".");
|
||||
}
|
||||
q.append(column).append(" in (");
|
||||
|
||||
if (needsQuotes(column)) {
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (i > 0)
|
||||
q.append(", ");
|
||||
q.append("'").append(escape(values[i])).append("'");
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (i > 0)
|
||||
q.append(", ");
|
||||
q.append(values[i]);
|
||||
}
|
||||
}
|
||||
q.append(")");
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a sql-condition for the given column which must have
|
||||
* the value given to the given StringBuffer.
|
||||
* @param q the StringBuffer to append to
|
||||
* @param column the column which must match one of the values
|
||||
* @param val the value
|
||||
* @throws SQLException
|
||||
*/
|
||||
protected void appendCondition(StringBuffer q, String column, String val)
|
||||
throws SQLException, ClassNotFoundException {
|
||||
if (column.indexOf('(') == -1 && column.indexOf('.') == -1) {
|
||||
q.append(getTableName()).append(".");
|
||||
}
|
||||
q.append(column).append(" = ");
|
||||
|
||||
if (needsQuotes(column)) {
|
||||
q.append("'").append(escape(val)).append("'");
|
||||
} else {
|
||||
q.append(val);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* a utility method to escape single quotes used for inserting
|
||||
* string-values into relational databases.
|
||||
* Searches for "'" characters and escapes them by duplicating them (= "''")
|
||||
* @param str the string to escape
|
||||
* @return the escaped string
|
||||
*/
|
||||
static String escape(String str) {
|
||||
if (str == null) {
|
||||
return null;
|
||||
} else if (str.indexOf("'") < 0) {
|
||||
return str;
|
||||
}
|
||||
|
||||
int l = str.length();
|
||||
StringBuffer sbuf = new StringBuffer(l + 10);
|
||||
|
||||
for (int i = 0; i < l; i++) {
|
||||
char c = str.charAt(i);
|
||||
|
||||
if (c == '\'') {
|
||||
sbuf.append('\'');
|
||||
}
|
||||
sbuf.append(c);
|
||||
}
|
||||
return sbuf.toString();
|
||||
}
|
||||
}
|
|
@ -475,50 +475,36 @@ public final class NodeManager {
|
|||
String insertString = dbm.getInsert();
|
||||
PreparedStatement stmt = con.prepareStatement(insertString);
|
||||
|
||||
// app.logEvent ("inserting relational node: "+node.getID ());
|
||||
// app.logEvent ("inserting relational node: " + node.getID ());
|
||||
DbColumn[] columns = dbm.getColumns();
|
||||
|
||||
String nameField = dbm.getNameField();
|
||||
String prototypeField = dbm.getPrototypeField();
|
||||
|
||||
long logTimeStart = logSql ? System.currentTimeMillis() : 0;
|
||||
|
||||
try {
|
||||
int stmtNumber = 1;
|
||||
|
||||
// first column of insert statement is always the primary key
|
||||
stmt.setString(stmtNumber, node.getID());
|
||||
|
||||
Hashtable propMap = node.getPropMap();
|
||||
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
Relation rel = columns[i].getRelation();
|
||||
Property p = null;
|
||||
|
||||
if (rel != null && propMap != null && (rel.isPrimitive() || rel.isReference())) {
|
||||
p = (Property) propMap.get(rel.getPropName());
|
||||
}
|
||||
|
||||
String name = columns[i].getName();
|
||||
|
||||
if (!((rel != null) && (rel.isPrimitive() || rel.isReference())) &&
|
||||
!name.equalsIgnoreCase(nameField) &&
|
||||
!name.equalsIgnoreCase(prototypeField)) {
|
||||
DbColumn col = columns[i];
|
||||
if (!col.isMapped())
|
||||
continue;
|
||||
}
|
||||
|
||||
stmtNumber++;
|
||||
if (p!=null) {
|
||||
this.setStatementValues (stmt, stmtNumber, p, columns[i].getType());
|
||||
} else if (name.equalsIgnoreCase(nameField)) {
|
||||
stmt.setString(stmtNumber, node.getName());
|
||||
} else if (name.equalsIgnoreCase(prototypeField)) {
|
||||
stmt.setString(stmtNumber, node.getPrototype());
|
||||
if (col.isIdField()) {
|
||||
setStatementValue(stmt, stmtNumber, node.getID(), col);
|
||||
} else if (col.isPrototypeField()) {
|
||||
setStatementValue(stmt, stmtNumber, dbm.getExtensionId(), col);
|
||||
} else {
|
||||
stmt.setNull(stmtNumber, columns[i].getType());
|
||||
}
|
||||
}
|
||||
Relation rel = col.getRelation();
|
||||
Property p = rel == null ? null : node.getProperty(rel.getPropName());
|
||||
|
||||
if (p != null) {
|
||||
setStatementValue(stmt, stmtNumber, p, col.getType());
|
||||
} else if (col.isNameField()) {
|
||||
stmt.setString(stmtNumber, node.getName());
|
||||
} else {
|
||||
stmt.setNull(stmtNumber, col.getType());
|
||||
}
|
||||
}
|
||||
stmtNumber += 1;
|
||||
}
|
||||
stmt.executeUpdate();
|
||||
|
||||
} finally {
|
||||
|
@ -533,7 +519,6 @@ public final class NodeManager {
|
|||
} catch (Exception ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -607,16 +592,7 @@ public final class NodeManager {
|
|||
}
|
||||
|
||||
b.append(" WHERE ");
|
||||
b.append(dbm.getIDField());
|
||||
b.append(" = ");
|
||||
|
||||
if (dbm.needsQuotes(dbm.getIDField())) {
|
||||
b.append("'");
|
||||
b.append(escape(node.getID()));
|
||||
b.append("'");
|
||||
} else {
|
||||
b.append(node.getID());
|
||||
}
|
||||
dbm.appendCondition(b, dbm.getIDField(), node.getID());
|
||||
|
||||
Connection con = dbm.getConnection();
|
||||
// set connection to write mode
|
||||
|
@ -637,7 +613,7 @@ public final class NodeManager {
|
|||
Relation rel = dbm.propertyToRelation(p.getName());
|
||||
|
||||
stmtNumber++;
|
||||
this.setStatementValues (stmt, stmtNumber, p, rel.getColumnType());
|
||||
setStatementValue(stmt, stmtNumber, p, rel.getColumnType());
|
||||
|
||||
p.dirty = false;
|
||||
|
||||
|
@ -1233,10 +1209,8 @@ public final class NodeManager {
|
|||
throws Exception {
|
||||
DbMapping dbm = rel.otherType;
|
||||
|
||||
if ((dbm == null) || !dbm.isRelational()) {
|
||||
// this does nothing for objects in the embedded database
|
||||
return;
|
||||
} else {
|
||||
if (dbm != null && dbm.isRelational()) {
|
||||
int missing = cache.containsKeys(keys);
|
||||
|
||||
if (missing > 0) {
|
||||
|
@ -1251,39 +1225,17 @@ public final class NodeManager {
|
|||
long logTimeStart = logSql ? System.currentTimeMillis() : 0;
|
||||
|
||||
try {
|
||||
StringBuffer b = dbm.getSelect(null);
|
||||
|
||||
StringBuffer b = dbm.getSelect(null).append(" WHERE ");
|
||||
String idfield = (rel.groupby != null) ? rel.groupby : dbm.getIDField();
|
||||
boolean needsQuotes = dbm.needsQuotes(idfield);
|
||||
|
||||
b.append(" WHERE ");
|
||||
b.append(dbm.getTableName());
|
||||
b.append(".");
|
||||
b.append(idfield);
|
||||
b.append(" IN (");
|
||||
|
||||
boolean first = true;
|
||||
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
if (keys[i] != null) {
|
||||
if (!first) {
|
||||
b.append(',');
|
||||
} else {
|
||||
first = false;
|
||||
String[] ids = new String[missing];
|
||||
int j = 0;
|
||||
for (int k = 0; k < keys.length; k++) {
|
||||
if (keys[k] != null)
|
||||
ids[j++] = keys[k].getID();
|
||||
}
|
||||
|
||||
if (needsQuotes) {
|
||||
b.append("'");
|
||||
b.append(escape(keys[i].getID()));
|
||||
b.append("'");
|
||||
} else {
|
||||
b.append(keys[i].getID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
b.append(") ");
|
||||
|
||||
dbm.appendCondition(b, idfield, ids);
|
||||
dbm.addJoinConstraints(b, " AND ");
|
||||
|
||||
if (rel.groupby != null) {
|
||||
|
@ -1388,7 +1340,7 @@ public final class NodeManager {
|
|||
}
|
||||
}
|
||||
} catch (Exception x) {
|
||||
System.err.println ("Error in prefetchNodes(): "+x);
|
||||
app.logError("Error in prefetchNodes()", x);
|
||||
} finally {
|
||||
if (logSql) {
|
||||
long logTimeStop = System.currentTimeMillis();
|
||||
|
@ -1591,22 +1543,10 @@ public final class NodeManager {
|
|||
|
||||
DbColumn[] columns = dbm.getColumns();
|
||||
Relation[] joins = dbm.getJoins();
|
||||
StringBuffer b = dbm.getSelect(null).append("WHERE ")
|
||||
.append(dbm.getTableName())
|
||||
.append(".")
|
||||
.append(idfield)
|
||||
.append(" = ");
|
||||
|
||||
if (dbm.needsQuotes(idfield)) {
|
||||
b.append("'");
|
||||
b.append(escape(kstr));
|
||||
b.append("'");
|
||||
} else {
|
||||
b.append(kstr);
|
||||
}
|
||||
|
||||
StringBuffer b = dbm.getSelect(null).append("WHERE ");
|
||||
dbm.appendCondition(b, idfield, kstr);
|
||||
dbm.addJoinConstraints(b, " AND ");
|
||||
|
||||
query = b.toString();
|
||||
|
||||
ResultSet rs = stmt.executeQuery(query);
|
||||
|
@ -1689,14 +1629,7 @@ public final class NodeManager {
|
|||
if (home.getSubnodeRelation() != null && !rel.isComplexReference()) {
|
||||
// combine our key with the constraints in the manually set subnode relation
|
||||
b.append(" WHERE ");
|
||||
if (rel.accessName.indexOf('(') == -1 && rel.accessName.indexOf('.') == -1) {
|
||||
b.append(dbm.getTableName());
|
||||
b.append(".");
|
||||
}
|
||||
b.append(rel.accessName);
|
||||
b.append(" = '");
|
||||
b.append(escape(kstr));
|
||||
b.append("'");
|
||||
dbm.appendCondition(b, rel.accessName, kstr);
|
||||
// add join contraints in case this is an old oracle style join
|
||||
dbm.addJoinConstraints(b, " AND ");
|
||||
// add potential constraints from manually set subnodeRelation
|
||||
|
@ -1778,7 +1711,8 @@ public final class NodeManager {
|
|||
|
||||
// set prototype?
|
||||
if (columns[i].isPrototypeField()) {
|
||||
protoName = rs.getString(i+1+offset);
|
||||
String protoId = rs.getString(i + 1 + offset);
|
||||
protoName = dbm.getPrototypeName(protoId);
|
||||
|
||||
if (protoName != null) {
|
||||
dbmap = getDbMapping(protoName);
|
||||
|
@ -1795,7 +1729,7 @@ public final class NodeManager {
|
|||
|
||||
// set id?
|
||||
if (columns[i].isIdField()) {
|
||||
id = rs.getString(i+1+offset);
|
||||
id = rs.getString(i + 1 + offset);
|
||||
// if id == null, the object doesn't actually exist - return null
|
||||
if (id == null) {
|
||||
return null;
|
||||
|
@ -1804,14 +1738,14 @@ public final class NodeManager {
|
|||
|
||||
// set name?
|
||||
if (columns[i].isNameField()) {
|
||||
name = rs.getString(i+1+offset);
|
||||
name = rs.getString(i + 1 + offset);
|
||||
}
|
||||
|
||||
Property newprop = new Property(node);
|
||||
|
||||
switch (columns[i].getType()) {
|
||||
case Types.BIT:
|
||||
newprop.setBooleanValue(rs.getBoolean(i+1+offset));
|
||||
newprop.setBooleanValue(rs.getBoolean(i + 1 + offset));
|
||||
|
||||
break;
|
||||
|
||||
|
@ -1819,21 +1753,21 @@ public final class NodeManager {
|
|||
case Types.BIGINT:
|
||||
case Types.SMALLINT:
|
||||
case Types.INTEGER:
|
||||
newprop.setIntegerValue(rs.getLong(i+1+offset));
|
||||
newprop.setIntegerValue(rs.getLong(i + 1 + offset));
|
||||
|
||||
break;
|
||||
|
||||
case Types.REAL:
|
||||
case Types.FLOAT:
|
||||
case Types.DOUBLE:
|
||||
newprop.setFloatValue(rs.getDouble(i+1+offset));
|
||||
newprop.setFloatValue(rs.getDouble(i + 1 + offset));
|
||||
|
||||
break;
|
||||
|
||||
case Types.DECIMAL:
|
||||
case Types.NUMERIC:
|
||||
|
||||
BigDecimal num = rs.getBigDecimal(i+1+offset);
|
||||
BigDecimal num = rs.getBigDecimal(i + 1 + offset);
|
||||
|
||||
if (num == null) {
|
||||
break;
|
||||
|
@ -1849,16 +1783,16 @@ public final class NodeManager {
|
|||
|
||||
case Types.VARBINARY:
|
||||
case Types.BINARY:
|
||||
newprop.setStringValue(rs.getString(i+1+offset));
|
||||
newprop.setStringValue(rs.getString(i + 1 + offset));
|
||||
|
||||
break;
|
||||
|
||||
case Types.LONGVARBINARY:
|
||||
case Types.LONGVARCHAR:
|
||||
try {
|
||||
newprop.setStringValue(rs.getString(i+1+offset));
|
||||
newprop.setStringValue(rs.getString(i + 1 + offset));
|
||||
} catch (SQLException x) {
|
||||
Reader in = rs.getCharacterStream(i+1+offset);
|
||||
Reader in = rs.getCharacterStream(i + 1 + offset);
|
||||
char[] buffer = new char[2048];
|
||||
int read = 0;
|
||||
int r;
|
||||
|
@ -1883,14 +1817,14 @@ public final class NodeManager {
|
|||
case Types.CHAR:
|
||||
case Types.VARCHAR:
|
||||
case Types.OTHER:
|
||||
newprop.setStringValue(rs.getString(i+1+offset));
|
||||
newprop.setStringValue(rs.getString(i + 1 + offset));
|
||||
|
||||
break;
|
||||
|
||||
case Types.DATE:
|
||||
case Types.TIME:
|
||||
case Types.TIMESTAMP:
|
||||
newprop.setDateValue(rs.getTimestamp(i+1+offset));
|
||||
newprop.setDateValue(rs.getTimestamp(i + 1 + offset));
|
||||
|
||||
break;
|
||||
|
||||
|
@ -1912,7 +1846,7 @@ public final class NodeManager {
|
|||
break;
|
||||
|
||||
default:
|
||||
newprop.setStringValue(rs.getString(i+1+offset));
|
||||
newprop.setStringValue(rs.getString(i + 1 + offset));
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1996,32 +1930,6 @@ public final class NodeManager {
|
|||
return app.getDbMapping(protoname);
|
||||
}
|
||||
|
||||
// a utility method to escape single quotes
|
||||
private String escape(String str) {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (str.indexOf("'") < 0) {
|
||||
return str;
|
||||
}
|
||||
|
||||
int l = str.length();
|
||||
StringBuffer sbuf = new StringBuffer(l + 10);
|
||||
|
||||
for (int i = 0; i < l; i++) {
|
||||
char c = str.charAt(i);
|
||||
|
||||
if (c == '\'') {
|
||||
sbuf.append('\'');
|
||||
}
|
||||
|
||||
sbuf.append(c);
|
||||
}
|
||||
|
||||
return sbuf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of the the keys currently held in the object cache
|
||||
*/
|
||||
|
@ -2144,7 +2052,19 @@ public final class NodeManager {
|
|||
}
|
||||
}
|
||||
|
||||
private void setStatementValues (PreparedStatement stmt, int stmtNumber, Property p, int columnType) throws SQLException {
|
||||
private void setStatementValue(PreparedStatement stmt, int stmtNumber, String value, DbColumn col)
|
||||
throws SQLException {
|
||||
if (value == null) {
|
||||
stmt.setNull(stmtNumber, col.getType());
|
||||
} else if (col.needsQuotes()) {
|
||||
stmt.setString(stmtNumber, value);
|
||||
} else {
|
||||
stmt.setLong(stmtNumber, Long.parseLong(value));
|
||||
}
|
||||
}
|
||||
|
||||
private void setStatementValue(PreparedStatement stmt, int stmtNumber, Property p, int columnType)
|
||||
throws SQLException {
|
||||
if (p.getValue() == null) {
|
||||
stmt.setNull(stmtNumber, columnType);
|
||||
} else {
|
||||
|
|
|
@ -813,30 +813,17 @@ public final class Relation {
|
|||
* and a local object.
|
||||
*/
|
||||
public String buildQuery(INode home, INode nonvirtual, String kstr, String pre,
|
||||
boolean useOrder) throws SQLException {
|
||||
boolean useOrder)
|
||||
throws SQLException, ClassNotFoundException {
|
||||
StringBuffer q = new StringBuffer();
|
||||
String prefix = pre;
|
||||
|
||||
if (kstr != null && !isComplexReference()) {
|
||||
q.append(prefix);
|
||||
|
||||
String accessColumn = (accessName == null) ? otherType.getIDField() : accessName;
|
||||
|
||||
if (accessColumn.indexOf('(') == -1 && accessColumn.indexOf('.') == -1) {
|
||||
q.append(otherType.getTableName());
|
||||
q.append(".");
|
||||
}
|
||||
q.append(accessColumn);
|
||||
q.append(" = ");
|
||||
|
||||
// check if column is string type and value needs to be quoted
|
||||
if (otherType.needsQuotes(accessColumn)) {
|
||||
q.append("'");
|
||||
q.append(escape(kstr));
|
||||
q.append("'");
|
||||
} else {
|
||||
q.append(escape(kstr));
|
||||
}
|
||||
String accessColumn = (accessName == null) ?
|
||||
otherType.getIDField() : accessName;
|
||||
otherType.appendCondition(q, accessColumn, kstr);
|
||||
|
||||
prefix = " AND ";
|
||||
}
|
||||
|
@ -906,7 +893,7 @@ public final class Relation {
|
|||
}
|
||||
// end column version
|
||||
if (value != null) {
|
||||
q.append(escape(value.toString()));
|
||||
q.append(DbMapping.escape(value.toString()));
|
||||
} else {
|
||||
q.append("NULL");
|
||||
}
|
||||
|
@ -930,7 +917,7 @@ public final class Relation {
|
|||
*/
|
||||
public void renderConstraints(StringBuffer q, INode home,
|
||||
INode nonvirtual, String prefix)
|
||||
throws SQLException {
|
||||
throws SQLException, ClassNotFoundException {
|
||||
|
||||
if (constraints.length > 1 && logicalOperator != AND) {
|
||||
q.append(prefix);
|
||||
|
@ -949,6 +936,23 @@ public final class Relation {
|
|||
prefix = " AND ";
|
||||
}
|
||||
|
||||
// also take the prototype into consideration if someone
|
||||
// specifies an extension of an prototype inside the brakets of
|
||||
// a type.properties's collection, only nodes having this proto
|
||||
// sould appear inside the collection
|
||||
if (otherType.inheritsStorage()) {
|
||||
String protoField = otherType.getPrototypeField();
|
||||
String[] extensions = otherType.getExtensions();
|
||||
|
||||
// extensions should never be null for extension- and
|
||||
// extended prototypes. nevertheless we check it here
|
||||
if (extensions != null) {
|
||||
q.append(prefix);
|
||||
otherType.appendCondition(q, protoField, extensions);
|
||||
prefix = " AND ";
|
||||
}
|
||||
}
|
||||
|
||||
if (filter != null) {
|
||||
appendFilter(q, nonvirtual, prefix);
|
||||
}
|
||||
|
@ -1214,32 +1218,6 @@ public final class Relation {
|
|||
return map;
|
||||
}
|
||||
|
||||
// a utility method to escape single quotes
|
||||
String escape(String str) {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (str.indexOf("'") < 0) {
|
||||
return str;
|
||||
}
|
||||
|
||||
int l = str.length();
|
||||
StringBuffer sbuf = new StringBuffer(l + 10);
|
||||
|
||||
for (int i = 0; i < l; i++) {
|
||||
char c = str.charAt(i);
|
||||
|
||||
if (c == '\'') {
|
||||
sbuf.append('\'');
|
||||
}
|
||||
|
||||
sbuf.append(c);
|
||||
}
|
||||
|
||||
return sbuf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
|
@ -1279,7 +1257,7 @@ public final class Relation {
|
|||
}
|
||||
|
||||
public void addToQuery(StringBuffer q, INode home, INode nonvirtual)
|
||||
throws SQLException {
|
||||
throws SQLException, ClassNotFoundException {
|
||||
String local = null;
|
||||
INode ref = isGroupby ? home : nonvirtual;
|
||||
|
||||
|
@ -1292,20 +1270,7 @@ public final class Relation {
|
|||
local = ref.getString(homeprop);
|
||||
}
|
||||
|
||||
if (foreignName.indexOf('(') == -1 && foreignName.indexOf('.') == -1) {
|
||||
q.append(otherType.getTableName());
|
||||
q.append(".");
|
||||
}
|
||||
q.append(foreignName);
|
||||
q.append(" = ");
|
||||
|
||||
if (otherType.needsQuotes(foreignName)) {
|
||||
q.append("'");
|
||||
q.append(escape(local));
|
||||
q.append("'");
|
||||
} else {
|
||||
q.append(escape(local));
|
||||
}
|
||||
otherType.appendCondition(q, foreignName, local);
|
||||
}
|
||||
|
||||
public boolean foreignKeyIsPrimary() {
|
||||
|
|
Loading…
Add table
Reference in a new issue