/** * Converts nested ColumnFilter.f values from a column ID to the corresponding SQL field name. * * @param filters * @param entities * @return A copy of filters with field names in place of the column IDs. * @see ColumnFilter#f */ private static NestedColumnFilters convertColumnIdsToFieldNames( NestedColumnFilters filters, Map<Integer, DataEntity> entities) { if (filters == null) return null; NestedColumnFilters result = new NestedColumnFilters(); if (filters.cond != null) { result.cond = new ColumnFilter(); result.cond.v = filters.cond.v; result.cond.r = filters.cond.r; result.cond.f = entities .get(((Number) filters.cond.f).intValue()) .privateMetadata .get(PrivateMetadata.SQLCOLUMN); } else { NestedColumnFilters[] in = (filters.and != null ? filters.and : filters.or); NestedColumnFilters[] out = new NestedColumnFilters[in.length]; for (int i = 0; i < in.length; i++) out[i] = convertColumnIdsToFieldNames(in[i], entities); if (filters.and == in) result.and = out; else result.or = out; } return result; }
@SuppressWarnings("unchecked") public static WeaveRecordList getFilteredRows( int[] columns, NestedColumnFilters filters, String[] keysArray) throws RemoteException { if (columns == null || columns.length == 0) throw new RemoteException("At least one column must be specified."); if (filters != null) filters.assertValid(); DataConfig dataConfig = getDataConfig(); WeaveRecordList result = new WeaveRecordList(); Map<Integer, DataEntity> entityLookup = new HashMap<Integer, DataEntity>(); { // get all column IDs whether or not they are to be selected. Set<Integer> allColumnIds = new HashSet<Integer>(); if (filters != null) allColumnIds.addAll(getReferencedColumnIds(filters)); for (int id : columns) allColumnIds.add(id); // get all corresponding entities for (DataEntity entity : dataConfig.getEntities(allColumnIds, true)) entityLookup.put(entity.id, entity); // check for missing columns for (int id : allColumnIds) if (entityLookup.get(id) == null) throw new RemoteException("No column with ID=" + id); // provide public metadata in the same order as the selected columns result.attributeColumnMetadata = new Map[columns.length]; for (int i = 0; i < columns.length; i++) result.attributeColumnMetadata[i] = entityLookup.get(columns[i]).publicMetadata; } String keyType = result.attributeColumnMetadata[0].get(PublicMetadata.KEYTYPE); // make sure all columns have same keyType for (int i = 1; i < columns.length; i++) if (!Strings.equal(keyType, result.attributeColumnMetadata[i].get(PublicMetadata.KEYTYPE))) throw new RemoteException("Specified columns must all have same keyType."); if (keysArray == null) { boolean canGenerateSQL = true; // check to see if all the columns are from the same SQL table. String connection = null; String sqlSchema = null; String sqlTable = null; for (DataEntity entity : entityLookup.values()) { String c = entity.privateMetadata.get(PrivateMetadata.CONNECTION); String s = entity.privateMetadata.get(PrivateMetadata.SQLSCHEMA); String t = entity.privateMetadata.get(PrivateMetadata.SQLTABLE); if (connection == null) connection = c; if (sqlSchema == null) sqlSchema = s; if (sqlTable == null) sqlTable = t; if (!Strings.equal(connection, c) || !Strings.equal(sqlSchema, s) || !Strings.equal(sqlTable, t)) { canGenerateSQL = false; break; } } if (canGenerateSQL) { Connection conn = getColumnConnectionInfo(entityLookup.get(columns[0])).getStaticReadOnlyConnection(); try { result.recordData = getFilteredRowsFromSQL(conn, sqlSchema, sqlTable, columns, filters, entityLookup) .rows; } catch (SQLException e) { throw new RemoteException("getFilteredRows() failed.", e); } } } if (result.recordData == null) { throw new Error("Selecting across tables is not supported yet."); /* HashMap<String,Object[]> data = new HashMap<String,Object[]>(); if (keysArray != null) for (String key : keysArray) data.put(key, new Object[entities.length]); for (int colIndex = 0; colIndex < entities.length; colIndex++) { Object[] filters = fcrs[colIndex].filters; DataEntity info = entities[colIndex]; String sqlQuery = info.privateMetadata.get(PrivateMetadata.SQLQUERY); String sqlParams = info.privateMetadata.get(PrivateMetadata.SQLPARAMS); //if (dataWithKeysQuery.length() == 0) // throw new RemoteException(String.format("No SQL query is associated with column \"%s\" in dataTable \"%s\"", attributeColumnName, dataTableName)); String dataType = info.publicMetadata.get(PublicMetadata.DATATYPE); // use config min,max or param min,max to filter the data String infoMinStr = info.publicMetadata.get(PublicMetadata.MIN); String infoMaxStr = info.publicMetadata.get(PublicMetadata.MAX); double minValue = Double.NEGATIVE_INFINITY; double maxValue = Double.POSITIVE_INFINITY; // first try parsing config min,max values try { minValue = Double.parseDouble(infoMinStr); } catch (Exception e) { } try { maxValue = Double.parseDouble(infoMaxStr); } catch (Exception e) { } // override config min,max with param values if given // * columnInfoArray = config.getDataEntity(params); // * for each info in columnInfoArray // * get sql data // * for each row in sql data // * if key is in keys array, // * add this value to the result // * return result try { //timer.start(); boolean errorReported = false; Connection conn = getColumnConnectionInfo(info).getStaticReadOnlyConnection(); String[] sqlParamsArray = null; if (sqlParams != null && sqlParams.length() > 0) sqlParamsArray = CSVParser.defaultParser.parseCSV(sqlParams, true)[0]; SQLResult sqlResult = SQLUtils.getResultFromQuery(conn, sqlQuery, sqlParamsArray, false); //timer.lap("get row set"); // if dataType is defined in the config file, use that value. // otherwise, derive it from the sql result. if (Strings.isEmpty(dataType)) dataType = DataType.fromSQLType(sqlResult.columnTypes[1]); boolean isNumeric = dataType != null && dataType.equalsIgnoreCase(DataType.NUMBER); Object keyObj, dataObj; for (int iRow = 0; iRow < sqlResult.rows.length; iRow++) { keyObj = sqlResult.rows[iRow][0]; dataObj = sqlResult.rows[iRow][1]; if (keyObj == null || dataObj == null) continue; keyObj = keyObj.toString(); if (data.containsKey(keyObj)) { // if row has been set to null, skip if (data.get(keyObj) == null) continue; } else { // if keys are specified and row is not present, skip if (keysArray != null) continue; } try { boolean passedFilters = true; // convert the data to the appropriate type, then filter by value if (isNumeric) { if (dataObj instanceof Number) // TEMPORARY SOLUTION - FIX ME { double doubleValue = ((Number)dataObj).doubleValue(); // filter the data based on the min,max values if (minValue <= doubleValue && doubleValue <= maxValue) { // filter the value if (filters != null) { passedFilters = false; for (Object range : filters) { Number min = (Number)((Object[])range)[0]; Number max = (Number)((Object[])range)[1]; if (min.doubleValue() <= doubleValue && doubleValue <= max.doubleValue()) { passedFilters = true; break; } } } } else passedFilters = false; } else passedFilters = false; } else { String stringValue = dataObj.toString(); dataObj = stringValue; // filter the value if (filters != null) { passedFilters = false; for (Object filter : filters) { if (filter.equals(stringValue)) { passedFilters = true; break; } } } } Object[] row = data.get(keyObj); if (passedFilters) { // add existing row if it has not been added yet if (!data.containsKey(keyObj)) { for (int i = 0; i < colIndex; i++) { Object[] prevFilters = fcrs[i].filters; if (prevFilters != null) { passedFilters = false; break; } } if (passedFilters) row = new Object[entities.length]; data.put((String)keyObj, row); } if (row != null) row[colIndex] = dataObj; } else { // remove existing row if value did not pass filters if (row != null || !data.containsKey(keyObj)) data.put((String)keyObj, null); } } catch (Exception e) { if (!errorReported) { errorReported = true; e.printStackTrace(); } } } } catch (SQLException e) { e.printStackTrace(); } catch (NullPointerException e) { e.printStackTrace(); throw new RemoteException(e.getMessage()); } } if (keysArray == null) { List<String> keys = new LinkedList<String>(); for (Entry<String,Object[]> entry : data.entrySet()) if (entry.getValue() != null) keys.add(entry.getKey()); keysArray = keys.toArray(new String[keys.size()]); } Object[][] rows = new Object[keysArray.length][]; for (int iKey = 0; iKey < keysArray.length; iKey++) rows[iKey] = data.get(keysArray[iKey]); result.recordData = rows; */ } result.keyType = keyType; result.recordKeys = keysArray; return result; }