Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.xenei.jdbc4sparql.sparql; import java.lang.reflect.Field; import java.sql.SQLDataException; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xenei.jdbc4sparql.iface.Catalog; import org.xenei.jdbc4sparql.iface.Column; import org.xenei.jdbc4sparql.iface.Key; import org.xenei.jdbc4sparql.iface.KeySegment; import org.xenei.jdbc4sparql.iface.Schema; 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.SearchName; import org.xenei.jdbc4sparql.iface.name.TableName; import org.xenei.jdbc4sparql.impl.NameUtils; import org.xenei.jdbc4sparql.impl.virtual.VirtualCatalog; import org.xenei.jdbc4sparql.impl.virtual.VirtualSchema; import org.xenei.jdbc4sparql.impl.virtual.VirtualTable; import org.xenei.jdbc4sparql.sparql.items.QueryColumnInfo; import org.xenei.jdbc4sparql.sparql.items.QueryItemCollection; import org.xenei.jdbc4sparql.sparql.items.QueryTableInfo; import org.xenei.jdbc4sparql.sparql.parser.SparqlParser; import org.xenei.jdbc4sparql.sparql.parser.jsqlparser.functions.FunctionColumn; import com.hp.hpl.jena.query.Query; import com.hp.hpl.jena.sparql.core.Var; import com.hp.hpl.jena.sparql.core.VarExprList; import com.hp.hpl.jena.sparql.expr.E_Equals; import com.hp.hpl.jena.sparql.expr.E_Function; import com.hp.hpl.jena.sparql.expr.E_LogicalAnd; import com.hp.hpl.jena.sparql.expr.Expr; import com.hp.hpl.jena.sparql.expr.ExprAggregator; import com.hp.hpl.jena.sparql.expr.ExprVar; import com.hp.hpl.jena.sparql.expr.NodeValue; import com.hp.hpl.jena.sparql.expr.aggregate.Aggregator; import com.hp.hpl.jena.sparql.syntax.Element; import com.hp.hpl.jena.sparql.syntax.ElementBind; import com.hp.hpl.jena.sparql.syntax.ElementFilter; import com.hp.hpl.jena.sparql.syntax.ElementGroup; import com.hp.hpl.jena.sparql.syntax.ElementService; import com.hp.hpl.jena.sparql.syntax.ElementSubQuery; import com.hp.hpl.jena.sparql.syntax.ElementUnion; import com.hp.hpl.jena.util.iterator.Filter; /** * Creates a SparqlQuery while tracking naming changes between nomenclatures. */ public class SparqlQueryBuilder { private static ElementGroup getElementGroup(final Query query) { ElementGroup retval; final Element e = query.getQueryPattern(); if (e == null) { retval = new ElementGroup(); query.setQueryPattern(retval); } else if (e instanceof ElementGroup) { retval = (ElementGroup) e; } else { retval = new ElementGroup(); retval.addElement(e); } return retval; } // a set of error messages. static final String NOT_FOUND_IN_QUERY = "%s not found in SPARQL query"; public static final String FOUND_IN_MULTIPLE_ = "%s was found in multiple %s"; static final String NOT_FOUND_IN_ANY_ = "%s was not found in any %s"; public static final String NOT_FOUND_IN_ = "%s was not found in %s"; public static final boolean OPTIONAL = true; public static final boolean REQUIRED = false; private final SparqlParser parser; private final Map<String, Catalog> catalogs; private final QueryInfoSet infoSet; // the query we are building. private Query query; // query was built flag; private boolean isBuilt; // sparql catalog we are running against. private final Catalog catalog; // sparql schema for default tables private final Schema schema; // the count of aliases used in this query. private int aliasCount; // the list of columns not to be included in the "all columns" result. // perhaps this should store column so that tables may be checked in case // tables are added to the query later. But I don't think so. private final List<String> columnsInUsing; // columns indexed by var. // private final List<Column> columnsInResult; private static Logger LOG = LoggerFactory.getLogger(SparqlQueryBuilder.class); /** * Create a query builder for a catalog and schema * * @param catalog * The catalog to build the query for. * @param schema * The schema to build the query for. * @throws IllegalArgumentException * if catalog is null. */ public SparqlQueryBuilder(final Map<String, Catalog> catalogs, final SparqlParser parser, final Catalog catalog, final Schema schema) { if (catalogs == null) { throw new IllegalArgumentException("Catalogs may not be null"); } if (catalog == null) { throw new IllegalArgumentException("Catalog may not be null"); } if (!catalogs.containsKey(catalog.getShortName())) { catalogs.put(catalog.getShortName(), catalog); } if (parser == null) { throw new IllegalArgumentException("SparqlParser may not be null"); } this.aliasCount = 0; this.catalogs = catalogs; this.parser = parser; this.catalog = catalog; this.schema = schema; this.query = new Query(); this.isBuilt = false; this.infoSet = new QueryInfoSet(); this.columnsInUsing = new ArrayList<String>(); this.infoSet.setUseGUID(catalog.isService()); query.setQuerySelectType(); } /** * Create a sub query builder * * @param parent * The QueryBuilder that this is a sub query for. */ public SparqlQueryBuilder(final SparqlQueryBuilder parent) { this(parent.catalogs, parent.parser, parent.catalog, parent.schema); this.infoSet.setUseGUID(parent.infoSet.useGUID()); } /** * Set the use GUID flag; * * @param state * @return the last state. */ public boolean setUseGUID(final boolean state) { return this.infoSet.setUseGUID(state); } public QueryColumnInfo addAlias(final ColumnName orig, final ColumnName alias) throws SQLDataException { final QueryTableInfo tableInfo = infoSet.getTable(orig.getTableName()); if (tableInfo == null) { throw new IllegalArgumentException( String.format(SparqlQueryBuilder.NOT_FOUND_IN_QUERY, orig.getTableName())); } // find the column will check infoset for existing column first. QueryColumnInfo columnInfo = tableInfo.getColumn(orig); if (columnInfo == null) { // ok now we have to look for column with the proper name. final Column column = tableInfo.getTable().getColumn(orig.getShortName()); if (column == null) { throw new IllegalArgumentException(String.format(SparqlQueryBuilder.NOT_FOUND_IN_QUERY, orig)); } columnInfo = tableInfo.addColumnToQuery(column); } // tableInfo.addDataFilter(columnInfo); // infoSet.addColumn(columnInfo); final QueryColumnInfo aliasInfo = columnInfo.createAlias(alias); tableInfo.addDataFilter(aliasInfo); infoSet.addColumn(aliasInfo); return aliasInfo; } public int getAliasCount() { return aliasCount++; } /** * Add the column to the query. Column must be in a table that has already * been added to the query. * * @param cName * The column name. * @param optional * True if the column is optional. * @return The QueryColumnInfo for the column * @throws SQLException */ public QueryColumnInfo addColumn(final ColumnName cName, final boolean optional) throws SQLException { if (SparqlQueryBuilder.LOG.isDebugEnabled()) { SparqlQueryBuilder.LOG.debug("Adding Column {}", cName); } checkBuilt(); final QueryColumnInfo columnInfo = infoSet.scanTablesForColumn(cName); if (columnInfo == null) { final TableName tName = cName.getTableName(); if (tName.isWild()) { throw new SQLException(String.format(SparqlQueryBuilder.NOT_FOUND_IN_ANY_, cName, "table")); } else { throw new SQLException(String.format(SparqlQueryBuilder.NOT_FOUND_IN_, cName, tName)); } } return columnInfo; } /** * Add a filter to the query. * * @param filter * The filter to add. */ public void addFilter(final Expr filter) { if (LOG.isDebugEnabled()) { SparqlQueryBuilder.LOG.debug("adding Filter: {}", filter); } checkBuilt(); final ElementFilter el = new ElementFilter(filter); SparqlQueryBuilder.getElementGroup(query).addElementFilter(el); } public QueryColumnInfo addColumnToQuery(final ColumnName cName, final boolean optional) { cName.setUsedSegments(getSegments()); final QueryColumnInfo columnInfo = infoSet.scanTablesForColumn(cName); if (columnInfo == null) { throw new IllegalArgumentException(String.format(SparqlQueryBuilder.NOT_FOUND_IN_QUERY, cName)); } return columnInfo; } public void addGroupBy(final Expr expr) { query.addGroupBy(expr); } /** * Add an order by to the query. * * @param expr * The expression to order by. * @param ascending * true of order should be ascending, false = descending. */ public void addOrderBy(final Expr expr, final boolean ascending) { if (LOG.isDebugEnabled()) { SparqlQueryBuilder.LOG.debug("Adding order by {} {}", expr, ascending ? "Ascending" : "Descending"); } checkBuilt(); query.addOrderBy(expr, ascending ? Query.ORDER_ASCENDING : Query.ORDER_DESCENDING); } public void addDefinedColumns() throws SQLDataException { infoSet.addDefinedColumns(columnsInUsing); } public QueryTableInfo addTable(final Table table, final TableName name, final boolean optional) { if (SparqlQueryBuilder.LOG.isDebugEnabled()) { SparqlQueryBuilder.LOG.debug("Adding table {} as {}", table.getSQLName(), name); } // make sure the table is in the query. QueryTableInfo tableInfo = infoSet.getTable(name); if (tableInfo == null) { tableInfo = new QueryTableInfo(infoSet, getElementGroup(), table, name, optional); infoSet.addTable(tableInfo); } return tableInfo; } /** * Add a table to the query. * * @param name * The table name * @param asName * The name of the table as referenced in the query. * @param optional * if true table is optional. * @return The node that represents the table. * @throws SQLException * if the table is in multiple schemas or not found. */ public QueryTableInfo addTable(final TableName name, final TableName asName, final boolean optional) throws SQLException { if (SparqlQueryBuilder.LOG.isDebugEnabled()) { SparqlQueryBuilder.LOG.debug( String.format("Adding %s table %s as %s", optional ? "optional" : "required", name, asName)); } checkBuilt(); final Collection<Table> tables = findTables(name); if (tables.size() > 1) { throw new SQLException(String.format(SparqlQueryBuilder.FOUND_IN_MULTIPLE_ + " of catalog '%s'", name, "schemas", catalog.getName())); } if (tables.isEmpty()) { throw new SQLException(String.format(SparqlQueryBuilder.NOT_FOUND_IN_ANY_ + " of catalog '%s'", name, "schema", catalog.getName())); } return addTable(tables.iterator().next(), asName, optional); } public void addTableColumns(final QueryTableInfo tableInfo) { tableInfo.addTableColumns(query, columnsInUsing); } public void addUnion(final List<SparqlQueryBuilder> unionBuilders) throws SQLDataException { final ElementUnion unionElement = new ElementUnion(); for (final SparqlQueryBuilder sqb : unionBuilders) { unionElement.addElement(new ElementSubQuery(sqb.build())); } getElementGroup().addElement(unionElement); } public void addUsing(final String columnName) { if (LOG.isDebugEnabled()) { SparqlQueryBuilder.LOG.debug("adding Using {}", columnName); } final Collection<QueryTableInfo> tables = infoSet.getTables(); if (tables.size() < 2) { throw new IllegalArgumentException("There must be at least 2 tables in the query"); } final Iterator<QueryTableInfo> iter = tables.iterator(); final QueryTableInfo tableInfo = iter.next(); ColumnName cName = tableInfo.getName().getColumnName(columnName); final QueryColumnInfo columnInfo = tableInfo.getColumn(cName, false); if (columnInfo == null) { throw new IllegalArgumentException( String.format("column %s not found in %s", columnName, tableInfo.getSQLName())); } columnsInUsing.add(columnName); while (iter.hasNext()) { final QueryTableInfo tableInfo2 = iter.next(); cName = tableInfo2.getName().getColumnName(columnName); final QueryColumnInfo columnInfo2 = tableInfo2.getColumn(cName, false); if (columnInfo2 == null) { throw new IllegalArgumentException( String.format("column %s not found in %s", columnInfo2, tableInfo2.getSQLName())); } } } /** * Adds the the expression as a variable to the query. As a variable the * result will be returned from the query. * * @param expr * The expression that defines the variable * @param name * the alias for the expression, if null no alias is used. */ public void addVar(final Expr expr, final String name) { if (LOG.isDebugEnabled()) { SparqlQueryBuilder.LOG.debug("Adding Var {} as {}", expr, name); } checkBuilt(); final NodeValue nv = expr.getConstant(); if ((name != null) || (nv == null) || !nv.asNode().isVariable()) { final String s = StringUtils.defaultString(expr.getVarName()); if (StringUtils.isNotEmpty(s) && s.equals(StringUtils.defaultIfBlank(name, s))) { query.addResultVar(s); } else { if (name != null) { query.addResultVar(name, expr); } else { query.addResultVar(nv.asNode()); } } } else { query.addResultVar(nv.asNode()); } query.getResultVars(); } /** * Adds the the expression as a variable to the query. As a variable the * result will be returned from the query. * * @param expr * The expression that defines the variable * @param name * the alias for the expression. */ public void addVar(final Expr expr, final ColumnName name) { checkBuilt(); final QueryColumnInfo columnInfo = infoSet.getColumn(name); if (!query.getProjectVars().contains(columnInfo.getVar())) { if (LOG.isDebugEnabled()) { SparqlQueryBuilder.LOG.debug("Adding {} as {}", expr, name); } query.addResultVar(columnInfo.getVar(), expr); query.getResultVars(); } } /** * Adds the the expression as a variable to the query. As a variable the * result will be returned from the query. * * @param columnName * The column to add. * @throws SQLException */ public void addVar(final ColumnName columnName) throws SQLException { if (LOG.isDebugEnabled()) { SparqlQueryBuilder.LOG.debug("Adding Var {}", columnName); } checkBuilt(); final QueryColumnInfo columnInfo = addColumn(columnName, false); getTable(columnName.getTableName()).addDataFilter(columnInfo); query.addResultVar(columnInfo.getVar()); query.getResultVars(); } /** * Get the SPARQL query. * * @return The constructed SPARQL query. * @throws SQLDataException */ public Query build() throws SQLDataException { if (!isBuilt) { if (!catalog.isService()) { // apply the type filters to each subpart. for (final QueryTableInfo tableInfo : infoSet.getTables()) { try { tableInfo.addQueryFilters(infoSet); } catch (final SQLDataException e1) { throw new IllegalStateException(e1.getMessage(), e1); } } } // renumber the Bnodes. final Element e = new BnodeRenumber().renumber(query.getQueryPattern()); query.setQueryPattern(e); if (catalog.isService()) { // create a copy of the query so that we can verify that it is // good. final Query serviceCall = query.cloneQuery(); final VarExprList vars = serviceCall.getProject(); // reset the serviceCall select vars // protected VarExprList projectVars = new VarExprList() ; try { Field f = Query.class.getDeclaredField("projectVars"); f.setAccessible(true); f.set(serviceCall, new VarExprList()); } catch (NoSuchFieldException e2) { throw new IllegalStateException(e2.getMessage(), e2); } catch (SecurityException e2) { throw new IllegalStateException(e2.getMessage(), e2); } catch (IllegalAccessException e2) { throw new IllegalStateException(e2.getMessage(), e2); } final ElementService service = new ElementService(catalog.getServiceNode(), new ElementSubQuery(serviceCall), false); final Query newResult = new Query(); newResult.setQuerySelectType(); final ElementGroup filterGroup = SparqlQueryBuilder.getElementGroup(newResult); filterGroup.addElement(service); final ElementGroup typeGroup = new ElementGroup(); typeGroup.addElement(filterGroup); infoSet.setUseGUID(false); // we are now building complete set. // create the service call // make sure we project all vars for the filters. final Collection<QueryColumnInfo> typeFilters = new HashSet<QueryColumnInfo>(); final Collection<QueryColumnInfo> dataFilters = new HashSet<QueryColumnInfo>(); final Collection<QueryColumnInfo> columnsInQuery = new ArrayList<QueryColumnInfo>(); for (final Var v : vars.getVars()) { final QueryColumnInfo colInfo = infoSet.findColumnByGUIDVar(v.getName()); if (colInfo == null) { // may be a variable associated with a function if (vars.getExpr(v) != null) { newResult.addResultVar(v, vars.getExpr(v)); } else { throw new IllegalStateException(String.format("can not find column %s", v)); } } else { columnsInQuery.add(colInfo); newResult.addResultVar(colInfo.getVar()); } } // add the columns to the query. // the columns are named by GUID in the query. boolean firstTable = true; for (final QueryTableInfo tableInfo : infoSet.getTables()) { // add the data type filters for (final Column tblCol : tableInfo.getTable().getColumnList()) { QueryColumnInfo columnInfo = new QueryColumnInfo(tblCol); typeFilters.add(columnInfo); serviceCall.addResultVar(columnInfo.getGUIDVar()); } // add the binds for (QueryColumnInfo colInfo : columnsInQuery) { if (colInfo.getBaseColumnInfo().getName().getTableName().equals(tableInfo.getName())) { if (firstTable || !this.columnsInUsing.contains(colInfo.getName().getShortName())) { dataFilters.add(colInfo); } } } try { QueryTableInfo.addTypeFilters(infoSet, typeFilters, dataFilters, tableInfo.getJoinElements(), filterGroup, typeGroup); } catch (final SQLDataException e1) { throw new IllegalStateException(e1.getMessage(), e1); } dataFilters.clear(); typeFilters.clear(); firstTable = false; } // add equality check into service Call for (final String columnName : columnsInUsing) { QueryColumnInfo first = null; Expr expr = null; for (final QueryColumnInfo columnInfo : infoSet .listColumns(new SearchName(null, null, null, columnName))) { if (first == null) { first = columnInfo; } else { final E_Equals eq = new E_Equals(new ExprVar(first.getGUIDVar()), new ExprVar(columnInfo.getGUIDVar())); if (expr == null) { expr = eq; } else { expr = new E_LogicalAnd(expr, eq); } } } if (expr != null) { if (LOG.isDebugEnabled()) { LOG.debug("Adding filter: {}", expr); } ((ElementGroup) serviceCall.getQueryPattern()).addElementFilter(new ElementFilter(expr)); } } newResult.setQueryPattern(typeGroup); query = newResult; } isBuilt = true; if (LOG.isDebugEnabled()) { SparqlQueryBuilder.LOG.debug("Query parsed as {}", query); } } return query; } private void checkBuilt() { if (isBuilt) { throw new IllegalStateException("Query was already built"); } } private Collection<Table> findTables(final ItemName name) { if (SparqlQueryBuilder.LOG.isDebugEnabled()) { SparqlQueryBuilder.LOG.debug(String.format("Looking for Table %s.%s in '%s' catalog", name.getSchema(), name.getTable(), catalog.getName())); } final List<Table> tables = new ArrayList<Table>(); for (final Schema schema : catalog.findSchemas(name.getSchema())) { for (final Table table : schema.findTables(name.getTable())) { tables.add(table); } } return tables; } /** * Get the catalog this builder is working with. * * @return a Catalog. */ public Catalog getCatalog() { return catalog; } public String getCatalogName() { return catalog.getShortName(); } public Catalog getCatalog(final String catalog) { return catalogs.get(catalog); } public QueryColumnInfo getColumn(final ColumnName cName) { return infoSet.getColumn(cName); } public QueryColumnInfo getColumn(final int i) { if (!isBuilt) { throw new IllegalStateException( "Columns may not be retrieved from a builder until after query is built"); } final Var v = query.getProjectVars().get(i); return getColumn(v); } public int getColumnCount() { if (!isBuilt) { throw new IllegalStateException( "Column count may not be retrieved from a builder until after query is built"); } return query.getProjectVars().size(); } public int getColumnIndex(final String columnName) { final ColumnName cName = ColumnName.getNameInstance(catalog.getShortName(), schema.getName().getShortName(), null, columnName); return infoSet.getColumnIndex(cName); } private ElementGroup getElementGroup() { return SparqlQueryBuilder.getElementGroup(query); } private ColumnName createColumnName(final Var v) { final int segs = v.getName().split(NameUtils.SPARQL_DOT).length; if (segs > 4) { throw new IllegalArgumentException("Name may not have more than 4 segments"); } final ColumnName cName = ColumnName.getNameInstance("", "", "", v.getName()); cName.setUsedSegments(NameSegments.getInstance(segs == 4, segs >= 3, segs >= 2, true)); return cName; } public QueryColumnInfo getColumn(final Var v) { return infoSet.getColumn(createColumnName(v)); } public QueryTableInfo getTable(final Var v) { checkBuilt(); final int segs = v.getName().split(NameUtils.SPARQL_DOT).length; if (segs > 3) { throw new IllegalArgumentException("Name may not have more than 3 segments"); } final TableName tName = TableName.getNameInstance("", "", v.getName()); tName.setUsedSegments(NameSegments.getInstance(segs == 3, segs >= 2, true, false)); return infoSet.getTable(tName); } public List<QueryColumnInfo> getResultColumns() { final List<QueryColumnInfo> retval = new ArrayList<QueryColumnInfo>(); for (final Var v : query.getProjectVars()) { retval.add(getColumn(v)); } return retval; } /** * Get a table from the query. * * @param name * The table name. * @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 infoSet.getTable(name); } public ExprAggregator register(final Aggregator agg, final int type, final String alias) throws SQLException { final ExprAggregator expr = (ExprAggregator) query.allocAggregate(agg); final ColumnName columnName = ColumnName.getNameInstance(VirtualCatalog.NAME, VirtualSchema.NAME, VirtualTable.NAME, alias); if (infoSet.findColumn(columnName) == null) { registerFunctionColumn(columnName, type); } return expr; } public QueryColumnInfo registerFunction(final ColumnName funcName, final int type) throws SQLException { QueryColumnInfo retval = infoSet.findColumn(funcName); if (retval == null) { retval = registerFunctionColumn(funcName, type); } return retval; } public QueryColumnInfo registerFunctionColumn(final ColumnName columnNameArg, final int type) { final ColumnName columnName = new ColumnName( StringUtils.defaultString(columnNameArg.getCatalog(), VirtualCatalog.NAME), StringUtils.defaultString(columnNameArg.getSchema(), VirtualSchema.NAME), StringUtils.defaultString(columnNameArg.getTable(), VirtualTable.NAME), columnNameArg.getShortName()); QueryTableInfo tableInfo = infoSet.getTable(columnName.getTableName()); Column column = null; if (tableInfo == null) { final Catalog cat = getCatalog(VirtualCatalog.NAME); Schema schema = cat.getSchema(columnName.getSchema()); if (schema == null) { schema = new VirtualSchema(cat, columnName.getSchema()); } Table table = schema.getTable(columnName.getTable()); if (table == null) { table = new VirtualTable(schema, columnName.getTable()); } column = new FunctionColumn(table, columnName.getShortName(), type); // new QueryTableInfo adds table to infoSet tableInfo = new QueryTableInfo(infoSet, null, table, columnName.getTableName(), false); infoSet.addTable(tableInfo); } else { column = new FunctionColumn(tableInfo.getTable(), columnName.getShortName(), type); } final QueryColumnInfo columnInfo = new QueryColumnInfo(column, columnName, false); infoSet.addColumn(columnInfo); return columnInfo; } /** * Sets all the columns for all the tables currently defined. This method * should be called after all tables have been added to the querybuilder. * * @throws SQLException */ public void setAllColumns() throws SQLException { if (LOG.isDebugEnabled()) { SparqlQueryBuilder.LOG.debug("Setting All Columns"); } checkBuilt(); final Collection<QueryTableInfo> tableInfos = infoSet.getTables(); if (tableInfos.size() == 0) { throw new IllegalArgumentException("There must be a least one table"); } final QueryItemCollection<QueryColumnInfo, Column, ColumnName> colInfoList = new QueryItemCollection<QueryColumnInfo, Column, ColumnName>(); for (final QueryTableInfo tableInfo : tableInfos) { final Iterator<Column> iter = tableInfo.getTable().getColumns(); while (iter.hasNext()) { final Column col = iter.next(); final ColumnName cName = tableInfo.getName().getColumnName(col.getName().getShortName()); final QueryColumnInfo columnInfo = tableInfo.getColumn(cName, col.isOptional()); colInfoList.add(columnInfo); tableInfo.addDataFilter(columnInfo); } } // find shortest name without name collision. skipping columns in using. NameSegments segs = NameSegments.getInstance(false, false, false, true); for (final QueryColumnInfo columnInfo : colInfoList) { if (!columnsInUsing.contains(columnInfo.getName().getShortName())) { SearchName sn = new SearchName(columnInfo.getName(), segs); while ((colInfoList.count(sn) > 1) && !sn.getUsedSegments().isCatalog()) { if (segs.isSchema()) { segs = NameSegments.getInstance(true, true, true, true); } else if (segs.isTable()) { segs = NameSegments.getInstance(false, true, true, true); } else { segs = NameSegments.getInstance(false, false, true, true); } sn = new SearchName(columnInfo.getName(), segs); } } } // remove the variables for (final Var v : query.getProjectVars()) { for (final QueryColumnInfo columnInfo : colInfoList.match(createColumnName(v)).toList()) { colInfoList.remove(columnInfo); } } // anything left needs to be added for (final QueryColumnInfo columnInfo : colInfoList) { query.addResultVar(columnInfo.getVar()); } } /** * Sets the distinct flag for the SPARQL query. */ public void setDistinct() { if (LOG.isDebugEnabled()) { SparqlQueryBuilder.LOG.debug("Setting Distinct"); } checkBuilt(); query.setDistinct(true); } public void setHaving(final Expr expr) { query.addHavingCondition(expr); } public SparqlQueryBuilder setKey(final Key<?> key) { if (LOG.isDebugEnabled()) { SparqlQueryBuilder.LOG.debug("Setting key {}", key); } if (key != null) { setOrderBy(key); if (key.isUnique()) { setDistinct(); } } return this; } /** * Sets the limit for the SPARQL query. * * @param limit * The number of records to return */ public void setLimit(final Long limit) { if (LOG.isDebugEnabled()) { SparqlQueryBuilder.LOG.debug("Setting limit {}", limit); } checkBuilt(); query.setLimit(limit); } /** * Set the offset for the SPARQL query. * * @param offset * The number of rows to skip over. */ public void setOffset(final Long offset) { if (LOG.isDebugEnabled()) { SparqlQueryBuilder.LOG.debug("Setting Offset {}", offset); } checkBuilt(); query.setOffset(offset); } public void setOrderBy(final Key<?> key) { if (LOG.isDebugEnabled()) { SparqlQueryBuilder.LOG.debug("Setting orderBy {}", key); } final List<Var> vars = query.getProjectVars(); for (final KeySegment seg : key.getSegments()) { query.addOrderBy(vars.get(seg.getIdx()), seg.isAscending() ? Query.ORDER_ASCENDING : Query.ORDER_DESCENDING); } } /** * Return the SPARQL query as the string value for the builder. */ @Override public String toString() { return String.format("QueryBuilder%s[%s]", (isBuilt ? "(builtargs)" : ""), query.toString()); } public Schema getDefaultSchema() { return schema; } public String getDefaultSchemaName() { return schema.getName().getShortName(); } /** * Returns the table name if only one exists in the query. If multiple * tables exist or no table has been added return null. * * @return The default table name. */ public String getDefaultTableName() { final Iterator<QueryTableInfo> iter = infoSet.getTables().iterator(); if (!iter.hasNext()) { return null; } final QueryTableInfo table = iter.next(); if (iter.hasNext()) { return null; } return table.getName().getShortName(); } public void setSegmentCount() { infoSet.setMinimumColumnSegments(); for (final String columnName : columnsInUsing) { final SearchName sn = new SearchName(null, null, null, columnName); for (final QueryColumnInfo columnInfo : infoSet.listColumns(sn)) { columnInfo.setSegments(sn.getUsedSegments()); } } } public NameSegments getSegments() { return infoSet.getSegments(); } }