/** * Process the traversal start event for a query {@link org.plasma.query.model.Property property} * within an {@link org.plasma.query.model.Expression expression} just traversing the property * path if exists and capturing context information for the current {@link * org.plasma.query.model.Expression expression}. * * @see org.plasma.query.visitor.DefaultQueryVisitor#start(org.plasma.query.model.Property) */ @Override public void start(Property property) { org.plasma.query.model.FunctionValues function = property.getFunction(); if (function != null) throw new GraphFilterException( "aggregate functions only supported in subqueries not primary queries"); Path path = property.getPath(); PlasmaType targetType = (PlasmaType) this.rootType; if (path != null) { for (int i = 0; i < path.getPathNodes().size(); i++) { AbstractPathElement pathElem = path.getPathNodes().get(i).getPathElement(); if (pathElem instanceof WildcardPathElement) throw new DataAccessException( "wildcard path elements applicable for 'Select' clause paths only, not 'Where' clause paths"); String elem = ((PathElement) pathElem).getValue(); PlasmaProperty prop = (PlasmaProperty) targetType.getProperty(elem); targetType = (PlasmaType) prop.getType(); // traverse } } PlasmaProperty endpointProp = (PlasmaProperty) targetType.getProperty(property.getName()); this.contextProperty = endpointProp; this.contextType = targetType; this.contextPropertyPath = property.asPathString(); super.start(property); }
/** * Assembles a data object of the given target type by first forming a query using the given * key/property pairs. If an existing data object is mapped for the given key pairs, the existing * data object is linked. * * @param targetType the type for the data object to be assembled * @param source the source data object * @param sourceProperty the source property * @param childKeyPairs the key pairs for the data object to be assembled */ protected void assemble( PlasmaType targetType, PlasmaDataObject source, PlasmaProperty sourceProperty, List<PropertyPair> childKeyPairs, int level) { Set<Property> props = this.collector.getProperties(targetType, level); if (props == null) props = EMPTY_PROPERTY_SET; if (log.isDebugEnabled()) log.debug( String.valueOf(level) + ":assemble: " + source.getType().getName() + "." + sourceProperty.getName() + "->" + targetType.getName() + ": " + props); List<List<PropertyPair>> result = this.getPredicateResult(targetType, sourceProperty, props, childKeyPairs); if (log.isDebugEnabled()) log.debug(String.valueOf(level) + ":results: " + result.size()); Map<PlasmaDataObject, List<PropertyPair>> resultMap = this.collectResults(targetType, source, sourceProperty, result); // now traverse Iterator<PlasmaDataObject> iter = resultMap.keySet().iterator(); while (iter.hasNext()) { PlasmaDataObject target = iter.next(); List<PropertyPair> row = resultMap.get(target); // traverse singular results props for (PropertyPair pair : row) { if (pair.getProp().isMany() || pair.getProp().getType().isDataType()) continue; // only singular reference props if (!pair.isQueryProperty()) continue; // property is a key or other property not explicitly cited in the source query, // don't traverse it List<PropertyPair> nextKeyPairs = this.getNextKeyPairs(target, pair, level); if (log.isDebugEnabled()) log.debug( String.valueOf(level) + ":traverse: (" + pair.getProp().isMany() + ") " + pair.getProp().toString() + ":" + String.valueOf(pair.getValue())); assemble( (PlasmaType) pair.getProp().getType(), target, pair.getProp(), nextKeyPairs, level + 1); } // traverse multi props based, not on the results // row, but on keys within this data object for (Property p : props) { PlasmaProperty prop = (PlasmaProperty) p; if (!prop.isMany() || prop.getType().isDataType()) continue; // only many reference props List<PropertyPair> childKeyProps = this.getChildKeyProps(target, targetType, prop); if (log.isDebugEnabled()) log.debug( String.valueOf(level) + ":traverse: (" + prop.isMany() + ") " + prop.toString() + " - " + childKeyProps.toArray().toString()); assemble((PlasmaType) prop.getType(), target, prop, childKeyProps, level + 1); } } }
private List<List<PropertyPair>> findResults( Query query, PropertySelectionCollector collector, PlasmaType type, Connection con) { Object[] params = new Object[0]; JDBCDataConverter converter = JDBCDataConverter.INSTANCE; if (log.isDebugEnabled()) { log(query); } AliasMap aliasMap = new AliasMap(type); Map<Type, List<String>> selectMap = collector.getResult(); // construct a filter adding to alias map JDBCFilterAssembler filterAssembler = null; Where where = query.findWhereClause(); if (where != null) { filterAssembler = new JDBCFilterAssembler(where, type, aliasMap); params = filterAssembler.getParams(); } JDBCOrderingDeclarationAssembler orderingDeclAssembler = null; OrderBy orderby = query.findOrderByClause(); if (orderby != null) orderingDeclAssembler = new JDBCOrderingDeclarationAssembler(orderby, type, aliasMap); JDBCGroupingDeclarationAssembler groupingDeclAssembler = null; GroupBy groupby = query.findGroupByClause(); if (groupby != null) groupingDeclAssembler = new JDBCGroupingDeclarationAssembler(groupby, type, aliasMap); String rootAlias = aliasMap.getAlias(type); StringBuilder sqlQuery = new StringBuilder(); sqlQuery.append("SELECT "); int i = 0; List<String> names = selectMap.get(type); for (String name : names) { PlasmaProperty prop = (PlasmaProperty) type.getProperty(name); if (prop.isMany() && !prop.getType().isDataType()) continue; if (i > 0) sqlQuery.append(", "); sqlQuery.append(rootAlias); sqlQuery.append("."); sqlQuery.append(prop.getPhysicalName()); i++; } // construct a FROM clause from alias map sqlQuery.append(" FROM "); Iterator<PlasmaType> it = aliasMap.getTypes(); int count = 0; while (it.hasNext()) { PlasmaType aliasType = it.next(); String alias = aliasMap.getAlias(aliasType); if (count > 0) sqlQuery.append(", "); sqlQuery.append(aliasType.getPhysicalName()); sqlQuery.append(" "); sqlQuery.append(alias); count++; } // append WHERE filter if (filterAssembler != null) { sqlQuery.append(" "); sqlQuery.append(filterAssembler.getFilter()); } // set the result range // FIXME: Oracle specific if (query.getStartRange() != null && query.getEndRange() != null) { if (where == null) sqlQuery.append(" WHERE "); else sqlQuery.append(" AND "); sqlQuery.append("ROWNUM >= "); sqlQuery.append(String.valueOf(query.getStartRange())); sqlQuery.append(" AND ROWNUM <= "); sqlQuery.append(String.valueOf(query.getEndRange())); } if (orderingDeclAssembler != null) { sqlQuery.append(" "); sqlQuery.append(orderingDeclAssembler.getOrderingDeclaration()); } if (groupingDeclAssembler != null) { sqlQuery.append(" "); sqlQuery.append(groupingDeclAssembler.getGroupingDeclaration()); } List<List<PropertyPair>> rows = new ArrayList<List<PropertyPair>>(); PreparedStatement statement = null; ResultSet rs = null; try { statement = con.prepareStatement( sqlQuery.toString(), ResultSet.TYPE_FORWARD_ONLY, /*ResultSet.TYPE_SCROLL_INSENSITIVE,*/ ResultSet.CONCUR_READ_ONLY); // set params // note params are pre-converted // to string in filter assembly // FIXME: are parameters relevant in SQL in this context? if (filterAssembler != null) { params = filterAssembler.getParams(); if (params != null) for (i = 0; i < params.length; i++) statement.setString(i + 1, String.valueOf(params[i])); } if (log.isDebugEnabled()) { if (params == null || params.length == 0) { log.debug("executing: " + sqlQuery.toString()); } else { StringBuilder paramBuf = new StringBuilder(); paramBuf.append(" ["); for (int p = 0; p < params.length; p++) { if (p > 0) paramBuf.append(", "); paramBuf.append(String.valueOf(params[p])); } paramBuf.append("]"); log.debug("executing: " + sqlQuery.toString() + " " + paramBuf.toString()); } } statement.execute(); rs = statement.getResultSet(); int numcols = rs.getMetaData().getColumnCount(); ResultSetMetaData rsMeta = rs.getMetaData(); List<PropertyPair> row = null; PropertyPair pair = null; while (rs.next()) { row = new ArrayList<PropertyPair>(); rows.add(row); for (i = 1; i <= numcols; i++) { String columnName = rsMeta.getColumnName(i); int columnType = rsMeta.getColumnType(i); PlasmaProperty prop = (PlasmaProperty) type.getProperty(columnName); Object value = converter.fromJDBCDataType(rs, i, columnType, prop); pair = new PropertyPair(prop, value); pair.setColumn(i); row.add(pair); } } } catch (Throwable t) { StringBuffer buf = this.generateErrorDetail(t, sqlQuery.toString(), filterAssembler); log.error(buf.toString()); throw new DataAccessException(t); } finally { try { if (rs != null) rs.close(); if (statement != null) statement.close(); } catch (SQLException e) { log.error(e.getMessage(), e); } } return rows; }
private int countResults(Connection con, Query query, PlasmaType type) { int result = 0; Object[] params = new Object[0]; JDBCFilterAssembler filterAssembler = null; StringBuilder sqlQuery = new StringBuilder(); AliasMap aliasMap = new AliasMap(type); sqlQuery.append("SELECT COUNT(*)"); sqlQuery.append(aliasMap.getAlias(type)); Statement statement = null; ResultSet rs = null; try { Where where = query.findWhereClause(); if (where != null) { filterAssembler = new JDBCFilterAssembler(where, type, aliasMap); sqlQuery.append(" "); sqlQuery.append(filterAssembler.getFilter()); params = filterAssembler.getParams(); if (log.isDebugEnabled()) { log.debug("filter: " + filterAssembler.getFilter()); } } else { sqlQuery.append(" FROM "); sqlQuery.append(type.getPhysicalName()); sqlQuery.append(" "); sqlQuery.append(aliasMap.getAlias(type)); } if (query.getStartRange() != null && query.getEndRange() != null) log.warn( "query range (start: " + query.getStartRange() + ", end: " + query.getEndRange() + ") ignored for count operation"); if (log.isDebugEnabled()) { log.debug("queryString: " + sqlQuery.toString()); log.debug("executing..."); } statement = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); statement.execute(sqlQuery.toString()); rs = statement.getResultSet(); rs.first(); result = rs.getInt(1); } catch (Throwable t) { StringBuffer buf = this.generateErrorDetail(t, sqlQuery.toString(), filterAssembler); log.error(buf.toString()); throw new DataAccessException(t); } finally { try { if (rs != null) rs.close(); if (statement != null) statement.close(); } catch (SQLException e) { log.error(e.getMessage(), e); } } return result; }