/* * 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.apache.jena.sdb.store; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.jena.sdb.SDB ; import org.apache.jena.sdb.compiler.SqlBuilder ; import org.apache.jena.sdb.core.AliasesSql ; import org.apache.jena.sdb.core.Annotation1 ; import org.apache.jena.sdb.core.SDBRequest ; import org.apache.jena.sdb.core.sqlexpr.SqlColumn ; import org.apache.jena.sdb.core.sqlnode.ColAlias ; import org.apache.jena.sdb.core.sqlnode.SqlNode ; import org.apache.jena.sdb.shared.SDBInternalError ; import org.apache.jena.sdb.sql.RS ; import org.apache.jena.sdb.sql.ResultSetJDBC ; import org.apache.jena.sdb.sql.SDBExceptionSQL ; import org.apache.jena.sparql.core.Var ; import org.apache.jena.sparql.engine.ExecutionContext ; import org.apache.jena.sparql.engine.QueryIterator ; import org.apache.jena.sparql.engine.binding.Binding ; import org.apache.jena.sparql.engine.iterator.QueryIter ; import org.apache.jena.sparql.engine.iterator.QueryIterPlainWrapper ; /** Convert from whatever results a particular layout returns into * an ARQ QueryIterator of Bindings. An SQLBridge object * is allocated for each query execution. */ public abstract class SQLBridgeBase implements SQLBridge { // Always need to allocate a label for a column // because can't access by table.column private Map<Var, String>varLabels = new HashMap<Var, String>() ; private Annotation1 annotation = new Annotation1() ; private Collection<Var> projectVars = null ; private SqlNode sqlNodeOriginal = null ; private SqlNode sqlNode = null ; // Subclass can mutate protected final SDBRequest request ; protected SQLBridgeBase(SDBRequest request, SqlNode sqlNode, Collection<Var> projectVars) { this.request = request ; this.sqlNodeOriginal = sqlNode ; this.projectVars = projectVars ; this.sqlNode = sqlNode ; } @Override public final void build() { buildValues() ; buildProject() ; } protected abstract void buildValues() ; protected abstract void buildProject() ; // Build next row from the JDBC ResultSet protected abstract Binding assembleBinding(ResultSetJDBC rs, Binding binding) ; @Override final public QueryIterator assembleResults(ResultSetJDBC rs, Binding binding, ExecutionContext execCxt) { if ( execCxt == null || execCxt.getContext().isTrueOrUndef(SDB.jdbcStream) ) { // Stream return new QueryIterSQL(rs, binding, execCxt) ; } // Debugging or problems with unreleasing JDBC ResultSets - read all in now. QueryIterator qIter = new QueryIterSQL(rs, binding, execCxt) ; List<Binding> results = new ArrayList<Binding>() ; for ( ; qIter.hasNext() ; ) results.add(qIter.nextBinding()) ; qIter.close() ; return new QueryIterPlainWrapper(results.iterator(), execCxt) ; } private void setProjectVars(Collection<Var> projectVars) { if ( this.projectVars != null ) throw new SDBInternalError("SQLBridgeBase: Project vars already set") ; this.projectVars = projectVars ; } protected SqlNode getSqlExprNode() { return sqlNodeOriginal ; } @Override public SqlNode getSqlNode() { return sqlNode ; } protected void setSqlNode(SqlNode sqlNode2) { sqlNode = sqlNode2 ; } protected Collection<Var> getProject() { return projectVars ; } // ---- value support // ---- project support protected void addProject(SqlColumn col, String colOutName) { sqlNode = SqlBuilder.project(request, sqlNode, new ColAlias(col, new SqlColumn(null, colOutName))) ; } protected void addAnnotation(String string) { annotation.addAnnotation(string) ; } protected void setAnnotation() { annotation.setAnnotation(sqlNode) ; } // ---- Var allocation protected String allocSqlName(Var v) { String sqlVarName = varLabels.get(v) ; if ( sqlVarName == null ) { sqlVarName = request.genId(AliasesSql.VarBase) ; varLabels.put(v, sqlVarName) ; } return sqlVarName ; } protected String getSqlName(Var v) { return varLabels.get(v) ; } private class QueryIterSQL extends QueryIter { boolean ready = false ; boolean hasNext = false ; private ResultSetJDBC jdbcResultSet ; private Binding parent ; QueryIterSQL(ResultSetJDBC rs, Binding binding, ExecutionContext execCxt) { super(execCxt) ; this.jdbcResultSet = rs ; this.parent = binding ; } @Override protected void closeIterator() { RS.close(jdbcResultSet) ; jdbcResultSet = null ; } @Override protected boolean hasNextBinding() { if (!ready) { try { hasNext = jdbcResultSet.get().next() ; } catch (SQLException ex) { closeIterator() ; throw new SDBExceptionSQL(ex) ; } ready = true ; } return hasNext ; } @Override protected Binding moveToNextBinding() { // if ( ! hasNextBinding() ) // return null ; ready = false ; // Must set the state to 'unknown'. return assembleBinding(jdbcResultSet, parent) ; } // Asynchronous request to cancel. ARQ 2.8.8 and later. @Override protected void requestCancel() {} } }