package org.xenei.jdbc4sparql.sparql; import java.sql.SQLDataException; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xenei.jdbc4sparql.iface.Column; import org.xenei.jdbc4sparql.iface.Table; import org.xenei.jdbc4sparql.iface.name.ColumnName; import org.xenei.jdbc4sparql.iface.name.ItemName; import org.xenei.jdbc4sparql.iface.name.NameSegments; import org.xenei.jdbc4sparql.iface.name.TableName; import org.xenei.jdbc4sparql.sparql.items.QueryColumnInfo; import org.xenei.jdbc4sparql.sparql.items.QueryItemCollection; import org.xenei.jdbc4sparql.sparql.items.QueryItemInfo; import org.xenei.jdbc4sparql.sparql.items.QueryTableInfo; import com.hp.hpl.jena.util.iterator.ExtendedIterator; /** * A collection of all tables and columns in the query. The column names are * index by full aliased table name based names (no short names) */ public class QueryInfoSet { // the list of tables in the query indexed by SQL name. private final QueryItemCollection<QueryTableInfo, Table, TableName> tablesInQuery; // the list of columns in the query indexed by SQL name. private final QueryItemCollection<QueryColumnInfo, Column, ColumnName> columnsInQuery; private static final Logger LOG = LoggerFactory .getLogger(QueryInfoSet.class); // private final Set<String> schemasInQuery; /** * The segments to display. Will be reset by setMinimumColumnSegments. */ private NameSegments segments; private boolean guidFlg; public QueryInfoSet() { this.tablesInQuery = new QueryItemCollection<QueryTableInfo, Table, TableName>(); this.columnsInQuery = new QueryItemCollection<QueryColumnInfo, Column, ColumnName>(); this.segments = NameSegments.ALL; } public boolean addColumn(final QueryColumnInfo columnInfo) { columnInfo.getName().setUseGUID(guidFlg); columnInfo.setSegments(segments); if (LOG.isDebugEnabled()) { QueryInfoSet.LOG.debug("adding column: {}", columnInfo); } return columnsInQuery.add(columnInfo); } public boolean setUseGUID(final boolean state) { boolean retval = this.guidFlg; if (this.guidFlg != state) { this.guidFlg = state; for (final QueryItemInfo<Column, ColumnName> columnInfo : columnsInQuery) { columnInfo.getName().setUseGUID(state); } for (final QueryItemInfo<Table, TableName> tableInfo : tablesInQuery) { tableInfo.getName().setUseGUID(state); } } return retval; } public boolean useGUID() { return guidFlg; } public void addDefinedColumns(final List<String> columnsInUsing) throws SQLDataException { if (tablesInQuery.isEmpty()) { throw new IllegalArgumentException("Must have at least one table"); } for (final QueryItemInfo<Table, TableName> tableInfo : tablesInQuery) { ((QueryTableInfo) tableInfo).addDefinedColumns(columnsInUsing); } } public void addTable(final QueryTableInfo tbl) { if (!tablesInQuery.contains(tbl)) { tbl.getName().setUseGUID(guidFlg); if (LOG.isDebugEnabled()) { QueryInfoSet.LOG.debug("adding table: {}", tbl); } tablesInQuery.add(tbl); tbl.setSegments(NameSegments.ALL); } } /** * Returns true if the name matches any of the column names. * * @see {QueryItemName.findMatch()} * @param name * The name to match * @return true if the name matches is found. */ public boolean containsColumn(final ItemName name) { return columnsInQuery.contains(name); } /** * Find the column in the query. Returns null if not found. * * @param name * The column Name to search for. * @return columnInfo for column or null if not found. */ public QueryColumnInfo findColumn(final ColumnName name) { return columnsInQuery.get(name); } // /** // * Find the column in the query by its GUID. returns null if not found // * // * @param name // * The column name defining the GUID // * @return the QueryColumnInfo or null. // */ // public QueryColumnInfo findColumnByGUID(final ColumnName name) { // return (QueryColumnInfo) columnsInQuery.findGUID(name); // } // /** * Find the column in the query by its GUID. returns null if not found * * @param name * The column name defining the GUID * @return the QueryColumnInfo or null. */ public QueryColumnInfo findColumnByGUIDVar(final String guid) { return columnsInQuery.findGUIDVar(guid); } /** * Force this infoset to use short names for columns. */ public void setMinimumColumnSegments() { segments = NameSegments.WILD; if (tablesInQuery.size() == 0) { throw new IllegalArgumentException( "There must be at lease 1 table in the query."); } if (tablesInQuery.size() == 1) { segments = NameSegments.getInstance(false, false, false, true); } else { boolean duplicateTable = false; boolean duplicateColumn = false; final Set<String> names = new HashSet<String>(); // if there are duplicate table names and multiple schemas then we // have to specify schema for (final QueryItemInfo<Table, TableName> qti : tablesInQuery) { final TableName sn = qti.getName().clone( NameSegments.getInstance(false, true, true, true)); duplicateTable |= names.contains(sn.getTable()); names.add(sn.getTable()); } names.clear(); for (final QueryColumnInfo qci : columnsInQuery) { final ColumnName sn = qci.getName().clone( NameSegments.getInstance(false, true, true, true)); duplicateColumn |= names.contains(sn.getTable()); names.add(sn.getTable()); } segments = NameSegments.getInstance(false, duplicateTable, duplicateTable | duplicateColumn, true); } if (LOG.isDebugEnabled()) { LOG.debug(String.format("Setting default segments to %s", segments)); } for (final QueryItemInfo<Table, TableName> qti : tablesInQuery) { ((QueryTableInfo) qti).setSegments(segments); } } /** * Retrieves the column form the list of query columns. * * Uses the match algorithm. * * @param name * The name to retrieve * @return The column info for the named column * @throws IllegalArgumentException * if the column is not found */ public QueryColumnInfo getColumn(final ColumnName name) { final QueryColumnInfo retval = columnsInQuery.get(name); if (retval == null) { throw new IllegalArgumentException(String.format( SparqlQueryBuilder.NOT_FOUND_IN_QUERY, name)); } return retval; } /** * Get the index of the column in the column name list. * * @param name * @return the index (0 based) or -1 if not present */ public int getColumnIndex(final ColumnName name) { return columnsInQuery.indexOf(name); } /** * Get the list of columns. * * @return the list of columns */ public QueryItemCollection<QueryColumnInfo, Column, ColumnName> getColumns() { return new QueryItemCollection<QueryColumnInfo, Column, ColumnName>( columnsInQuery.iterator().toList()); } /** * Get the table info from the tables in the query * * @param name * The table name to find. * @return The query table info for the name or null if none found * @throws IllegalArgumentException * if more than one object matches. */ public QueryTableInfo getTable(final TableName name) { return tablesInQuery.get(name); } public QueryItemCollection<QueryTableInfo, Table, TableName> getTables() { return new QueryItemCollection<QueryTableInfo, Table, TableName>( tablesInQuery.iterator().toList()); } /** * List the columns that match the name. * * @param name * The Column name to match * @return The list o */ public List<QueryColumnInfo> listColumns(final ItemName name) { return columnsInQuery.match(name).toList(); } public Set<Column> uniqueColumns() { return columnsInQuery.getNamedObjectSet(); } public ExtendedIterator<QueryColumnInfo> iterateColumns(final ItemName name) { return columnsInQuery.match(name); } public Collection<QueryTableInfo> listTables(final ItemName name) { if (name.getUsedSegments().isColumn()) { final TableName searchName = new TableName(name); final NameSegments segs = name.getUsedSegments(); final NameSegments newSegs = NameSegments.getInstance( segs.isCatalog(), segs.isSchema(), segs.isTable(), false); searchName.setUsedSegments(newSegs); return tablesInQuery.match(searchName).toList(); } else { return tablesInQuery.match(name).toList(); } } public NameSegments getSegments() { return segments; } /** * find the first QueryColumnInfo that references the Column * * @param column * The column to find. * @return The first matching QueryColumnInfo or null if not found. */ public QueryColumnInfo findColumn(final Column column) { final Iterator<QueryColumnInfo> iter = columnsInQuery .findBaseObject(column); return iter.hasNext() ? iter.next() : null; } /** * Returns the column from the query if it exists. Otherwise scan across the * tables in the query looking for the column. If found add it to the query * and return it. otherwise return null. * * @param name * @return */ public QueryColumnInfo scanTablesForColumn(final ColumnName cName) { // check exact match QueryColumnInfo retval = findColumn(cName); if (retval == null) { // get the table and see if column is in it final TableName tName = cName.getTableName(); QueryTableInfo tableInfo = null; // table name may be wild so use list. for (final QueryTableInfo testTableInfo : listTables(tName)) { if (testTableInfo.getColumn(cName) != null) { if (tableInfo != null) { QueryInfoSet.LOG.info(String.format( SparqlQueryBuilder.FOUND_IN_MULTIPLE_, cName, "tables")); return null; } tableInfo = testTableInfo; } } if (tableInfo != null) { retval = tableInfo.getColumn(cName); } } return retval; } }