示例#1
0
    public TupleSource registerRequest(
        CommandContext context,
        Command command,
        String modelName,
        RegisterRequestParameter parameterObject)
        throws TeiidComponentException, TeiidProcessingException {
      callCount++;

      int batchSize = 1;

      // ensure that we have the right kind of insert, and that the data for this row is valid
      if (command instanceof Insert) {
        Insert insert = (Insert) command;
        if (isBulk(insert)) {
          List batch = getBulkRows(insert, insert.getVariables());
          batchSize = batch.size();
          assertEquals(
              "Unexpected batch on call " + callCount, expectedBatchSize, batchSize); // $NON-NLS-1$

          for (int i = 0; i < batchSize; i++) {
            ensureValue2((List) batch.get(i), 2, ((callCount - 1) * batchSize) + i + 1);
          }
        } else if (insert.getTupleSource() != null) {
          TupleSource ts = insert.getTupleSource();
          List tuple = null;
          int i = 0;
          while ((tuple = ts.nextTuple()) != null) {
            ensureValue2(tuple, 2, ++i);
          }
          batchSize = i;
        } else {
          ensureValue(insert, 2, callCount);
        }
      } else if (command instanceof BatchedUpdateCommand) {
        BatchedUpdateCommand bu = (BatchedUpdateCommand) command;
        List<Command> batch = bu.getUpdateCommands();

        batchSize = batch.size();
        assertEquals(
            "Unexpected batch on call " + callCount, expectedBatchSize, batchSize); // $NON-NLS-1$
      } else {
        fail("Unexpected command type"); // $NON-NLS-1$
      }
      if (batchSize > 1) {
        return CollectionTupleSource.createUpdateCountArrayTupleSource(batchSize);
      }
      List counts = Arrays.asList(new Object[] {new Integer(batchSize)});
      FakeTupleSource fakeTupleSource = new FakeTupleSource(null, new List[] {counts});
      return fakeTupleSource;
    }
示例#2
0
  /**
   * Process the procedure, using the stack of Programs supplied by the ProcessorEnvironment. With
   * each pass through the loop, the current Program is gotten off the top of the stack, and the
   * current instruction is gotten from that program; each call to an instruction's process method
   * may alter the Program Stack and/or the current instruction pointer of a Program, so it's
   * important that this method's loop refer to the call stack of the ProcessorEnvironment each
   * time, and not cache things in local variables. If the current Program's current instruction is
   * null, then it's time to pop that Program off the stack.
   *
   * @return List a single tuple containing one Integer: the update count resulting from the
   *     procedure execution.
   */
  private TupleSource processProcedure()
      throws TeiidComponentException, TeiidProcessingException, BlockedException {

    // execute plan
    ProgramInstruction inst = null;

    while (!this.programs.empty()) {
      Program program = peek();
      inst = program.getCurrentInstruction();
      if (inst == null) {
        LogManager.logTrace(
            org.teiid.logging.LogConstants.CTX_DQP, "Finished program", program); // $NON-NLS-1$
        // look ahead to see if we need to process in place
        VariableContext vc = this.cursorStates.getParentContext();
        CursorState last = (CursorState) this.cursorStates.getValue(null);
        if (last != null) {
          if (last.resultsBuffer == null && (last.usesLocalTemp || !txnTupleSources.isEmpty())) {
            last.resultsBuffer =
                bufferMgr.createTupleBuffer(
                    last.processor.getOutputElements(),
                    getContext().getConnectionId(),
                    TupleSourceType.PROCESSOR);
            last.returning = true;
          }
          if (last.returning) {
            while (last.ts.hasNext()) {
              List<?> tuple = last.ts.nextTuple();
              last.resultsBuffer.addTuple(tuple);
            }
            last.resultsBuffer.close();
            last.ts = last.resultsBuffer.createIndexedTupleSource(true);
            last.returning = false;
          }
        }
        this.pop(true);
        continue;
      }
      try {
        if (inst instanceof RepeatedInstruction) {
          LogManager.logTrace(
              org.teiid.logging.LogConstants.CTX_DQP,
              "Executing repeated instruction",
              inst); //$NON-NLS-1$
          RepeatedInstruction loop = (RepeatedInstruction) inst;
          if (loop.testCondition(this)) {
            LogManager.logTrace(
                org.teiid.logging.LogConstants.CTX_DQP,
                "Passed condition, executing program " + loop.getNestedProgram()); // $NON-NLS-1$
            inst.process(this);
            this.push(loop.getNestedProgram());
            continue;
          }
          LogManager.logTrace(
              org.teiid.logging.LogConstants.CTX_DQP,
              "Exiting repeated instruction",
              inst); //$NON-NLS-1$
          loop.postInstruction(this);
        } else {
          LogManager.logTrace(
              org.teiid.logging.LogConstants.CTX_DQP, "Executing instruction", inst); // $NON-NLS-1$
          inst.process(this);
          this.evaluator.close();
        }
      } catch (RuntimeException e) {
        throw e;
      } catch (TeiidComponentException e) {
        throw e;
      } catch (Exception e) {
        // processing or teiidsqlexception
        boolean atomic = program.isAtomic();
        while (program.getExceptionGroup() == null) {
          this.pop(false);
          if (this.programs.empty()) {
            // reached the top without a handler, so throw
            if (e instanceof TeiidProcessingException) {
              throw (TeiidProcessingException) e;
            }
            throw new ProcedureErrorInstructionException(QueryPlugin.Event.TEIID30167, e);
          }
          program = peek();
          atomic |= program.isAtomic();
        }
        this.pop(false); // allow the current program to go out of scope
        if (atomic) {
          TransactionContext tc = this.getContext().getTransactionContext();
          if (tc != null && tc.getTransactionType() != Scope.NONE) {
            // a non-completing atomic block under a higher level transaction

            // this will not work correctly until we support
            // checkpoints/subtransactions
            try {
              tc.getTransaction().setRollbackOnly();
            } catch (IllegalStateException e1) {
              throw new TeiidComponentException(e1);
            } catch (SystemException e1) {
              throw new TeiidComponentException(e1);
            }
          }
        }
        if (program.getExceptionProgram() == null) {
          continue;
        }
        Program exceptionProgram = program.getExceptionProgram();
        this.push(exceptionProgram);
        TeiidSQLException tse = TeiidSQLException.create(e);
        GroupSymbol gs = new GroupSymbol(program.getExceptionGroup());
        this.currentVarContext.setValue(exceptionSymbol(gs, 0), tse.getSQLState());
        this.currentVarContext.setValue(exceptionSymbol(gs, 1), tse.getErrorCode());
        this.currentVarContext.setValue(exceptionSymbol(gs, 2), tse.getTeiidCode());
        this.currentVarContext.setValue(exceptionSymbol(gs, 3), tse);
        this.currentVarContext.setValue(exceptionSymbol(gs, 4), tse.getCause());
        continue;
      }
      program.incrementProgramCounter();
    }
    CursorState last = (CursorState) this.cursorStates.getValue(null);
    if (last == null) {
      return CollectionTupleSource.createNullTupleSource();
    }
    return last.ts;
  }
示例#3
0
  private TupleSource handleSystemProcedures(final CommandContext context, StoredProcedure proc)
      throws TeiidComponentException, QueryMetadataException, QueryProcessingException,
          QueryResolverException, QueryValidatorException, TeiidProcessingException,
          ExpressionEvaluationException {
    final QueryMetadataInterface metadata = context.getMetadata();
    if (StringUtil.endsWithIgnoreCase(proc.getProcedureCallableName(), REFRESHMATVIEW)) {
      Object groupID =
          validateMatView(
              metadata, (String) ((Constant) proc.getParameter(2).getExpression()).getValue());
      TempMetadataID matTableId =
          context.getGlobalTableStore().getGlobalTempTableMetadataId(groupID);
      final GlobalTableStore globalStore = getGlobalStore(context, matTableId);
      String matViewName = metadata.getFullName(groupID);
      String matTableName = metadata.getFullName(matTableId);
      LogManager.logDetail(
          LogConstants.CTX_MATVIEWS, "processing refreshmatview for", matViewName); // $NON-NLS-1$
      boolean invalidate =
          Boolean.TRUE.equals(((Constant) proc.getParameter(3).getExpression()).getValue());
      boolean needsLoading =
          globalStore.needsLoading(matTableName, globalStore.getAddress(), true, true, invalidate);
      if (!needsLoading) {
        return CollectionTupleSource.createUpdateCountTupleSource(-1);
      }
      GroupSymbol matTable = new GroupSymbol(matTableName);
      matTable.setMetadataID(matTableId);
      return loadGlobalTable(context, matTable, matTableName, globalStore);
    } else if (StringUtil.endsWithIgnoreCase(proc.getProcedureCallableName(), REFRESHMATVIEWROW)) {
      final Object groupID =
          validateMatView(
              metadata, (String) ((Constant) proc.getParameter(2).getExpression()).getValue());
      TempMetadataID matTableId =
          context.getGlobalTableStore().getGlobalTempTableMetadataId(groupID);
      final GlobalTableStore globalStore = getGlobalStore(context, matTableId);
      Object pk = metadata.getPrimaryKey(groupID);
      String matViewName = metadata.getFullName(groupID);
      if (pk == null) {
        throw new QueryProcessingException(
            QueryPlugin.Event.TEIID30230,
            QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30230, matViewName));
      }
      List<?> ids = metadata.getElementIDsInKey(pk);
      Constant key = (Constant) proc.getParameter(3).getExpression();
      Object initialValue = key.getValue();
      SPParameter keyOther = proc.getParameter(4);
      Object[] otherCols = null;
      int length = 1;
      if (keyOther != null) {
        otherCols = ((ArrayImpl) ((Constant) keyOther.getExpression()).getValue()).getValues();
        if (otherCols != null) {
          length += otherCols.length;
        }
      }
      if (ids.size() != length) {
        throw new QueryProcessingException(
            QueryPlugin.Event.TEIID30231,
            QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30231, matViewName, ids.size(), length));
      }
      final String matTableName = RelationalPlanner.MAT_PREFIX + matViewName.toUpperCase();
      MatTableInfo info = globalStore.getMatTableInfo(matTableName);
      if (!info.isValid()) {
        return CollectionTupleSource.createUpdateCountTupleSource(-1);
      }
      TempTable tempTable = globalStore.getTempTable(matTableName);
      if (!tempTable.isUpdatable()) {
        throw new QueryProcessingException(
            QueryPlugin.Event.TEIID30232,
            QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30232, matViewName));
      }
      Iterator<?> iter = ids.iterator();
      final Object[] params = new Object[length];
      StringBuilder criteria = new StringBuilder();
      for (int i = 0; i < length; i++) {
        Object id = iter.next();
        String targetTypeName = metadata.getElementType(id);
        Object value = i == 0 ? initialValue : otherCols[i - 1];
        value =
            DataTypeManager.transformValue(value, DataTypeManager.getDataTypeClass(targetTypeName));
        params[i] = value;
        if (i != 0) {
          criteria.append(" AND "); // $NON-NLS-1$
        }
        criteria.append(metadata.getFullName(id)).append(" = ?"); // $NON-NLS-1$
      }
      LogManager.logInfo(
          LogConstants.CTX_MATVIEWS,
          QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30012, matViewName, Arrays.toString(params)));

      String queryString =
          Reserved.SELECT
              + " * "
              + Reserved.FROM
              + ' '
              + matViewName
              + ' '
              + Reserved.WHERE
              + ' '
              + //$NON-NLS-1$
              criteria.toString()
              + ' '
              + Reserved.OPTION
              + ' '
              + Reserved.NOCACHE;
      final QueryProcessor qp =
          context
              .getQueryProcessorFactory()
              .createQueryProcessor(queryString, matViewName.toUpperCase(), context, params);
      final TupleSource ts = new BatchCollector.BatchProducerTupleSource(qp);
      return new ProxyTupleSource() {

        @Override
        protected TupleSource createTupleSource()
            throws TeiidComponentException, TeiidProcessingException {
          List<?> tuple = ts.nextTuple();
          boolean delete = false;
          if (tuple == null) {
            delete = true;
            tuple = Arrays.asList(params);
          } else {
            tuple = new ArrayList<Object>(tuple); // ensure the list is serializable
          }
          List<?> result = globalStore.updateMatViewRow(matTableName, tuple, delete);
          if (eventDistributor != null) {
            eventDistributor.updateMatViewRow(
                context.getVdbName(),
                context.getVdbVersion(),
                metadata.getName(metadata.getModelID(groupID)),
                metadata.getName(groupID),
                tuple,
                delete);
          }
          return CollectionTupleSource.createUpdateCountTupleSource(result != null ? 1 : 0);
        }

        @Override
        public void closeSource() {
          super.closeSource();
          qp.closeProcessing();
        }
      };
    }
    return null;
  }
示例#4
0
  TupleSource registerRequest(final CommandContext context, String modelName, final Command command)
      throws TeiidComponentException, TeiidProcessingException {
    final TempTableStore contextStore = context.getTempTableStore();
    if (command instanceof Query) {
      Query query = (Query) command;
      if (modelName != null && !modelName.equals(TempMetadataAdapter.TEMP_MODEL.getID())) {
        return null;
      }
      return registerQuery(context, contextStore, query);
    }
    if (command instanceof ProcedureContainer) {
      if (command instanceof StoredProcedure) {
        StoredProcedure proc = (StoredProcedure) command;
        if (CoreConstants.SYSTEM_ADMIN_MODEL.equals(modelName)) {
          TupleSource result = handleSystemProcedures(context, proc);
          if (result != null) {
            return result;
          }
        } else if (proc.getGroup().isGlobalTable()) {
          return handleCachedProcedure(context, proc);
        }
        return null; // it's not a stored procedure we want to handle
      }

      final GroupSymbol group = ((ProcedureContainer) command).getGroup();
      if (!modelName.equals(TempMetadataAdapter.TEMP_MODEL.getID()) || !group.isTempGroupSymbol()) {
        return null;
      }
      return new ProxyTupleSource() {

        @Override
        protected TupleSource createTupleSource()
            throws TeiidComponentException, TeiidProcessingException {
          final String groupKey = group.getNonCorrelationName();
          final TempTable table =
              contextStore.getOrCreateTempTable(
                  groupKey, command, bufferManager, true, true, context, group);
          if (command instanceof Insert) {
            Insert insert = (Insert) command;
            TupleSource ts = insert.getTupleSource();
            if (ts == null) {
              Evaluator eval =
                  new Evaluator(Collections.emptyMap(), TempTableDataManager.this, context);
              List<Object> values = new ArrayList<Object>(insert.getValues().size());
              for (Expression expr : (List<Expression>) insert.getValues()) {
                values.add(eval.evaluate(expr, null));
              }
              ts = new CollectionTupleSource(Arrays.asList(values).iterator());
            }
            return table.insert(ts, insert.getVariables(), true, context);
          }
          if (command instanceof Update) {
            final Update update = (Update) command;
            final Criteria crit = update.getCriteria();
            return table.update(crit, update.getChangeList());
          }
          if (command instanceof Delete) {
            final Delete delete = (Delete) command;
            final Criteria crit = delete.getCriteria();
            if (crit == null) {
              // TODO: we'll add a real truncate later
              int rows = table.truncate(false);
              return CollectionTupleSource.createUpdateCountTupleSource(rows);
            }
            return table.delete(crit);
          }
          throw new AssertionError("unknown command " + command); // $NON-NLS-1$
        }
      };
    }
    if (command instanceof Create) {
      Create create = (Create) command;
      String tempTableName = create.getTable().getName();
      if (contextStore.hasTempTable(tempTableName)) {
        throw new QueryProcessingException(
            QueryPlugin.Event.TEIID30229,
            QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30229, tempTableName));
      }
      if (create.getTableMetadata() != null) {
        contextStore.addForeignTempTable(tempTableName, create);
      } else {
        contextStore.addTempTable(tempTableName, create, bufferManager, true, context);
      }
      return CollectionTupleSource.createUpdateCountTupleSource(0);
    }
    if (command instanceof Drop) {
      String tempTableName = ((Drop) command).getTable().getName();
      contextStore.removeTempTableByName(tempTableName, context);
      return CollectionTupleSource.createUpdateCountTupleSource(0);
    }
    if (command instanceof AlterTempTable) {
      AlterTempTable att = (AlterTempTable) command;
      TempTable tt = contextStore.getTempTable(att.getTempTable());
      Assertion.isNotNull(tt, "Table doesn't exist"); // $NON-NLS-1$
      tt.setUpdatable(false);
      if (att.getIndexColumns() != null && tt.getRowCount() > 2 * tt.getTree().getPageSize(true)) {
        for (List<ElementSymbol> cols : att.getIndexColumns()) {
          tt.addIndex(cols, false);
        }
      }
      return CollectionTupleSource.createUpdateCountTupleSource(0);
    }
    return null;
  }
示例#5
0
  private TupleSource updateMatviewRows(
      final CommandContext context,
      final QueryMetadataInterface metadata,
      final Object groupID,
      final GlobalTableStore globalStore,
      final String matViewName,
      List<?> ids,
      Object[][] params)
      throws QueryProcessingException, TeiidComponentException, QueryMetadataException,
          TransformationException {
    final String matTableName = RelationalPlanner.MAT_PREFIX + matViewName.toUpperCase();
    MatTableInfo info = globalStore.getMatTableInfo(matTableName);
    if (!info.isValid()) {
      return CollectionTupleSource.createUpdateCountTupleSource(-1);
    }
    TempTable tempTable = globalStore.getTempTable(matTableName);
    if (!tempTable.isUpdatable()) {
      throw new QueryProcessingException(
          QueryPlugin.Event.TEIID30232,
          QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30232, matViewName));
    }

    List<Object[]> converted = new ArrayList<Object[]>();
    for (Object[] param : params) {
      if (param == null || ids.size() != param.length) {
        throw new QueryProcessingException(
            QueryPlugin.Event.TEIID30231,
            QueryPlugin.Util.gs(
                QueryPlugin.Event.TEIID30231,
                matViewName,
                ids.size(),
                param == null ? 0 : param.length));
      }
      final Object[] vals = new Object[param.length];
      for (int i = 0; i < ids.size(); i++) {
        Object value = param[i];
        String targetTypeName = metadata.getElementType(ids.get(i));
        value =
            DataTypeManager.transformValue(value, DataTypeManager.getDataTypeClass(targetTypeName));
        vals[i] = value;
      }
      converted.add(vals);
    }
    final Iterator<Object[]> paramIter = converted.iterator();

    Iterator<?> iter = ids.iterator();
    StringBuilder criteria = new StringBuilder();
    for (int i = 0; i < ids.size(); i++) {
      Object id = iter.next();
      String targetTypeName = metadata.getElementType(id);
      if (i != 0) {
        criteria.append(" AND "); // $NON-NLS-1$
      }
      criteria.append(metadata.getFullName(id)).append(" = ?"); // $NON-NLS-1$
    }

    final String queryString =
        Reserved.SELECT
            + " * "
            + Reserved.FROM
            + ' '
            + matViewName
            + ' '
            + Reserved.WHERE
            + ' '
            + //$NON-NLS-1$
            criteria.toString()
            + ' '
            + Reserved.OPTION
            + ' '
            + Reserved.NOCACHE;

    return new ProxyTupleSource() {
      private QueryProcessor qp;
      private TupleSource ts;
      private Object[] params;
      private int count;

      @Override
      protected TupleSource createTupleSource()
          throws TeiidComponentException, TeiidProcessingException {
        while (true) {
          if (qp == null) {
            params = paramIter.next();
            LogManager.logInfo(
                LogConstants.CTX_MATVIEWS,
                QueryPlugin.Util.gs(
                    QueryPlugin.Event.TEIID30012, matViewName, Arrays.toString(params)));
            qp =
                context
                    .getQueryProcessorFactory()
                    .createQueryProcessor(queryString, matViewName.toUpperCase(), context, params);
            ts = new BatchCollector.BatchProducerTupleSource(qp);
          }

          List<?> tuple = ts.nextTuple();
          boolean delete = false;
          if (tuple == null) {
            delete = true;
            tuple = Arrays.asList(params);
          } else {
            tuple = new ArrayList<Object>(tuple); // ensure the list is serializable
          }
          List<?> result = globalStore.updateMatViewRow(matTableName, tuple, delete);

          if (result != null) {
            count++;
          }

          if (eventDistributor != null) {
            eventDistributor.updateMatViewRow(
                context.getVdbName(),
                context.getVdbVersion(),
                metadata.getName(metadata.getModelID(groupID)),
                metadata.getName(groupID),
                tuple,
                delete);
          }

          qp.closeProcessing();
          qp = null;
          ts = null;

          if (!paramIter.hasNext()) {
            break;
          }
        }

        return CollectionTupleSource.createUpdateCountTupleSource(count);
      }

      @Override
      public void closeSource() {
        super.closeSource();
        if (qp != null) {
          qp.closeProcessing();
        }
      }
    };
  }
示例#6
0
  private TupleSource handleSystemProcedures(final CommandContext context, StoredProcedure proc)
      throws TeiidComponentException, QueryMetadataException, QueryProcessingException,
          QueryResolverException, QueryValidatorException, TeiidProcessingException,
          ExpressionEvaluationException {
    final QueryMetadataInterface metadata = context.getMetadata();
    if (StringUtil.endsWithIgnoreCase(proc.getProcedureCallableName(), REFRESHMATVIEW)) {
      Object groupID =
          validateMatView(
              metadata, (String) ((Constant) proc.getParameter(2).getExpression()).getValue());
      TempMetadataID matTableId =
          context.getGlobalTableStore().getGlobalTempTableMetadataId(groupID);
      final GlobalTableStore globalStore = getGlobalStore(context, matTableId);
      String matViewName = metadata.getFullName(groupID);
      String matTableName = metadata.getFullName(matTableId);
      LogManager.logDetail(
          LogConstants.CTX_MATVIEWS, "processing refreshmatview for", matViewName); // $NON-NLS-1$
      boolean invalidate =
          Boolean.TRUE.equals(((Constant) proc.getParameter(3).getExpression()).getValue());
      boolean needsLoading =
          globalStore.needsLoading(matTableName, globalStore.getAddress(), true, true, invalidate);
      if (!needsLoading) {
        return CollectionTupleSource.createUpdateCountTupleSource(-1);
      }
      GroupSymbol matTable = new GroupSymbol(matTableName);
      matTable.setMetadataID(matTableId);
      return loadGlobalTable(context, matTable, matTableName, globalStore);
    } else if (StringUtil.endsWithIgnoreCase(proc.getProcedureCallableName(), REFRESHMATVIEWROWS)) {
      final Object groupID =
          validateMatView(
              metadata, (String) ((Constant) proc.getParameter(2).getExpression()).getValue());
      TempMetadataID matTableId =
          context.getGlobalTableStore().getGlobalTempTableMetadataId(groupID);
      final GlobalTableStore globalStore = getGlobalStore(context, matTableId);
      Object pk = metadata.getPrimaryKey(groupID);
      String matViewName = metadata.getFullName(groupID);
      if (pk == null) {
        throw new QueryProcessingException(
            QueryPlugin.Event.TEIID30230,
            QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30230, matViewName));
      }
      List<?> ids = metadata.getElementIDsInKey(pk);
      Object[][] params =
          (Object[][])
              ((ArrayImpl) ((Constant) proc.getParameter(3).getExpression()).getValue())
                  .getValues();
      return updateMatviewRows(context, metadata, groupID, globalStore, matViewName, ids, params);
    } else if (StringUtil.endsWithIgnoreCase(proc.getProcedureCallableName(), REFRESHMATVIEWROW)) {
      final Object groupID =
          validateMatView(
              metadata, (String) ((Constant) proc.getParameter(2).getExpression()).getValue());
      TempMetadataID matTableId =
          context.getGlobalTableStore().getGlobalTempTableMetadataId(groupID);
      final GlobalTableStore globalStore = getGlobalStore(context, matTableId);
      Object pk = metadata.getPrimaryKey(groupID);
      final String matViewName = metadata.getFullName(groupID);
      if (pk == null) {
        throw new QueryProcessingException(
            QueryPlugin.Event.TEIID30230,
            QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30230, matViewName));
      }
      List<?> ids = metadata.getElementIDsInKey(pk);
      Constant key = (Constant) proc.getParameter(3).getExpression();
      Object initialValue = key.getValue();
      SPParameter keyOther = proc.getParameter(4);
      Object[] param = null;
      if (keyOther != null) {
        Object[] otherCols =
            ((ArrayImpl) ((Constant) keyOther.getExpression()).getValue()).getValues();
        if (otherCols != null) {
          param = new Object[1 + otherCols.length];
          param[0] = initialValue;
          for (int i = 0; i < otherCols.length; i++) {
            param[i + 1] = otherCols[i];
          }
        }
      }
      if (param == null) {
        param = new Object[] {initialValue};
      }

      Object[][] params = new Object[][] {param};

      return updateMatviewRows(context, metadata, groupID, globalStore, matViewName, ids, params);
    }
    return null;
  }