@Test public void testProcedureBatching() throws Exception { ProcedureExecution exec = new FakeProcedureExecution(2, 1); // this has two result set columns and 1 out parameter int total_columns = 3; StoredProcedure command = (StoredProcedure) helpGetCommand("{call pm2.spTest8(?)}", EXAMPLE_BQT); // $NON-NLS-1$ command.getInputParameters().get(0).setExpression(new Constant(1)); Call proc = new LanguageBridgeFactory(EXAMPLE_BQT).translate(command); ProcedureBatchHandler pbh = new ProcedureBatchHandler(proc, exec); assertEquals(total_columns, pbh.padRow(Arrays.asList(null, null)).size()); List params = pbh.getParameterRow(); assertEquals(total_columns, params.size()); // check the parameter value assertEquals(Integer.valueOf(0), params.get(2)); try { pbh.padRow(Arrays.asList(1)); fail("Expected exception from resultset mismatch"); // $NON-NLS-1$ } catch (TranslatorException err) { assertEquals( "TEIID30479 Could not process stored procedure results for EXEC spTest8(1). Expected 2 result set columns, but was 1. Please update your models to allow for stored procedure results batching.", err.getMessage()); // $NON-NLS-1$ } }
private TupleSource handleCachedProcedure(final CommandContext context, StoredProcedure proc) throws TeiidComponentException, QueryMetadataException, TeiidProcessingException { String fullName = context.getMetadata().getFullName(proc.getProcedureID()); LogManager.logDetail( LogConstants.CTX_DQP, "processing cached procedure request for", fullName); // $NON-NLS-1$ LinkedList<Object> vals = new LinkedList<Object>(); for (SPParameter param : proc.getInputParameters()) { vals.add(((Constant) param.getExpression()).getValue()); } // collapse the hash to single byte for the key to restrict the possible results to 256 int hash = vals.hashCode(); hash |= (hash >>> 16); hash |= (hash >>> 8); hash &= 0x000000ff; final CacheID cid = new CacheID( new ParseInfo(), fullName + hash, context.getVdbName(), context.getVdbVersion(), context.getConnectionId(), context.getUserName()); cid.setParameters(vals); CachedResults results = cache.get(cid); if (results != null) { TupleBuffer buffer = results.getResults(); return buffer.createIndexedTupleSource(); } // construct a query with a no cache hint final CacheHint hint = proc.getCacheHint(); proc.setCacheHint(null); Option option = new Option(); option.setNoCache(true); option.addNoCacheGroup(fullName); proc.setOption(option); StoredProcedure cloneProc = (StoredProcedure) proc.clone(); int i = 0; for (SPParameter param : cloneProc.getInputParameters()) { param.setExpression(new Reference(i++)); } final QueryProcessor qp = context .getQueryProcessorFactory() .createQueryProcessor( cloneProc.toString(), fullName.toUpperCase(), context, vals.toArray()); final BatchCollector bc = qp.createBatchCollector(); return new ProxyTupleSource() { boolean success = false; @Override protected TupleSource createTupleSource() throws TeiidComponentException, TeiidProcessingException { TupleBuffer tb = bc.collectTuples(); CachedResults cr = new CachedResults(); cr.setResults(tb, qp.getProcessorPlan()); Determinism determinismLevel = qp.getContext().getDeterminismLevel(); if (hint != null && hint.getDeterminism() != null) { LogManager.logTrace( LogConstants.CTX_DQP, new Object[] { "Cache hint modified the query determinism from ", determinismLevel, " to ", hint.getDeterminism() }); //$NON-NLS-1$ //$NON-NLS-2$ determinismLevel = hint.getDeterminism(); } cache.put(cid, determinismLevel, cr, hint != null ? hint.getTtl() : null); context.setDeterminismLevel(determinismLevel); success = true; return tb.createIndexedTupleSource(); } @Override public void closeSource() { super.closeSource(); qp.closeProcessing(); if (!success && bc.getTupleBuffer() != null) { bc.getTupleBuffer().remove(); } } }; }