/** * Returns all {@link InsertRow}s that reference a column in this <code>InsertRow</code>. The rows * may well be from other tables. * * @return all InsertRows that reference a column in this InsertRow */ Collection<InsertRow> getReferencingRows() { Set<InsertRow> referencingRows = new HashSet<InsertRow>(); Iterator<InsertField> iter = this.columnMap.values().iterator(); while (iter.hasNext()) { InsertField field = iter.next(); referencingRows.addAll(field.getReferencingRows()); } return referencingRows; }
/** * Returns all {@link InsertField} that reference a column in this <code>InsertRow</code>. The * fields may well be from other tables. * * @return all InsertFields that reference a column in this InsertRow */ public List<InsertField> getReferencingFields() { List<InsertField> referencingFields = new ArrayList<InsertField>(); Iterator<InsertField> iter = this.columnMap.values().iterator(); while (iter.hasNext()) { InsertField field = iter.next(); referencingFields.addAll(field.getReferencingFields()); } return referencingFields; }
/** * Returns the {@link InsertField} for the primary key column. * * @return the InsertField for the primary key column */ public InsertField getPKColumn() { InsertField pkField = null; for (InsertField field : this.columnMap.values()) { if (field.isPK()) { pkField = field; break; } } return pkField; }
/** * Returns all {@link InsertRow}s that are referenced by a field from this <code>InsertRow</code>. * The rows may well be from other tables. * * @return all InsertRows that are referenced by a field from this InsertRow */ private Collection<InsertRow> getReferencedRows() { Set<InsertRow> referencedRows = new HashSet<InsertRow>(); Iterator<InsertField> iter = this.columnMap.values().iterator(); while (iter.hasNext()) { InsertField field = iter.next(); InsertRow referencedRow = field.getReferencedRow(); if (referencedRow != null) { referencedRows.add(referencedRow); } } return referencedRows; }
/** * Returns all {@link InsertField}s that are referenced by a field from this <code>InsertRow * </code>. The fields may well be from other tables. * * @return all InsertField that are referenced by a field from this InsertRow */ List<InsertField> getReferencedFields() { List<InsertField> referencedFields = new ArrayList<InsertField>(); Iterator<InsertField> iter = this.columnMap.values().iterator(); while (iter.hasNext()) { InsertField field = iter.next(); InsertField referencedField = field.getReferencedField(); if (referencedField != null) { referencedFields.add(referencedField); } } return referencedFields; }
/** * Sets the value to be inserted in the given table column - the column references the given * {@link InsertField} and thus must have the same value as the referenced column. * * <p>In complex + erroneous mappings (or feature instances), it may happen that different * property values (mapped to the same column) imply different values. This is checked for and in * case an {@link TransactionException} is thrown. * * @param column * @param referencedField * @throws TransactionException if the value for the column clashes */ public void linkColumn(String column, InsertField referencedField) throws TransactionException { if (referencedField.getValue() == null) { LOG.logError("linkColumn (): referencedField is null"); throw new TransactionException("linkColumn (): referenced field is null!"); } InsertField presentField = this.columnMap.get(column); if (presentField != null && (!presentField.getValue().toString().equals(referencedField.getValue().toString()))) { Object[] params = new Object[] { column, this.table, presentField.getValue().toString(), referencedField.getValue().toString() }; String msg = Messages.getMessage("DATASTORE_AMBIGOUS_COLUMN_VALUES", params); throw new TransactionException(msg); } InsertField field = presentField; if (presentField != null) { presentField.relinkField(referencedField); } else { field = new InsertField(this, column, referencedField); this.columnMap.put(column, field); } referencedField.addReferencingField(field); }
/** * Sets the value to be inserted in the given table column. * * <p>In complex + erroneous mappings (or feature instances), it may happen that different * property values (mapped to the same column) imply different values. This is checked for and in * case an {@link TransactionException} is thrown. * * @param column * @param value * @param sqlType * @param isPK * @return column + value to be set * @throws TransactionException if the value for the column clashes */ public InsertField setColumn(String column, Object value, int sqlType, boolean isPK) throws TransactionException { InsertField field = new InsertField(this, column, sqlType, value, isPK); InsertField presentField = columnMap.get(column); if (presentField != null && (!presentField.getValue().toString().equals(value.toString()))) { Object[] params = new Object[] {column, this.table, presentField.getValue().toString(), value.toString()}; String msg = Messages.getMessage("DATASTORE_AMBIGOUS_COLUMN_VALUES", params); throw new TransactionException(msg); } if (presentField == null) { this.columnMap.put(column, field); } // TODO type check return field; }
/** * Sorts the given <code>InsertRow</code>s topologically (respecting the foreign key constraints), * so they can be inserted in the resulting order without causing foreign key violations. * * <p>Number of precedessors (pre): number of fields that *are referenced by* this row Number of * successors (post) : number of fields that *reference* this row * * @param inserts insert rows to sort * @return the nodes of the graph in topological order if no cycle is present, else in arbitrary * order */ public static List<InsertRow> getInsertOrder(List<InsertRow> inserts) { List<InsertRow> result = new ArrayList<InsertRow>(); // key: inserts, value: number of fields that are referenced by this row Map<InsertRow, Integer> preMap = new HashMap<InsertRow, Integer>(); // key: inserts with no foreign key constraints List<InsertRow> noPre = new ArrayList<InsertRow>(); // build map Iterator<InsertRow> insertIter = inserts.iterator(); while (insertIter.hasNext()) { InsertRow insertRow = insertIter.next(); int pre = insertRow.getReferencedFields().size(); LOG.logDebug("Adding row to preMap: " + insertRow); preMap.put(insertRow, pre); if (pre == 0) { noPre.add(insertRow); } } while (!noPre.isEmpty()) { // select an insert row that has no open fk constraints InsertRow insertRow = noPre.get(0); noPre.remove(0); result.add(insertRow); // decrease the number of pending fk constraints for all insert rows that // reference the currently processed insert row Collection<InsertField> postList = insertRow.getReferencingFields(); Iterator<InsertField> iter = postList.iterator(); while (iter.hasNext()) { InsertField postField = iter.next(); if (preMap.get(postField.getRow()) == null) { LOG.logDebug("No pre info for: " + postField.getRow()); } int pre = preMap.get(postField.getRow()); preMap.put(postField.getRow(), --pre); if (pre == 0) { noPre.add(postField.getRow()); } } } if (result.size() != inserts.size()) { Collection<InsertRow> cycle = InsertRow.findCycle(inserts); Iterator<InsertRow> cycleIter = cycle.iterator(); StringBuffer sb = new StringBuffer(); while (cycleIter.hasNext()) { sb.append(cycleIter.next()); if (cycle.iterator().hasNext()) { sb.append(" -> "); } } String msg = Messages.getMessage("DATASTORE_FK_CYCLE", sb.toString()); LOG.logWarning(msg); result.clear(); result.addAll(inserts); } return result; }