/**
   * @return <code>false</code> if sub-expression represented the specified ParseNode definitely
   *     cannot appear on either side of the range (':') operator
   */
  private static boolean isValidRangeOperand(ParseNode a) {
    Ptg tkn = a.getToken();
    // Note - order is important for these instance-of checks
    if (tkn instanceof OperandPtg) {
      // notably cell refs and area refs
      return true;
    }

    // next 2 are special cases of OperationPtg
    if (tkn instanceof AbstractFunctionPtg) {
      AbstractFunctionPtg afp = (AbstractFunctionPtg) tkn;
      byte returnClass = afp.getDefaultOperandClass();
      return Ptg.CLASS_REF == returnClass;
    }
    if (tkn instanceof ValueOperatorPtg) {
      return false;
    }
    if (tkn instanceof OperationPtg) {
      return true;
    }

    // one special case of ControlPtg
    if (tkn instanceof ParenthesisPtg) {
      // parenthesis Ptg should have only one child
      return isValidRangeOperand(a.getChildren()[0]);
    }

    // one special case of ScalarConstantPtg
    if (tkn == ErrPtg.REF_INVALID) {
      return true;
    }

    // All other ControlPtgs and ScalarConstantPtgs cannot be used with ':'
    return false;
  }
  private ParseNode parseUnary(boolean isPlus) {

    boolean numberFollows = IsDigit(look) || look == '.';
    ParseNode factor = powerFactor();

    if (numberFollows) {
      // + or - directly next to a number is parsed with the number

      Ptg token = factor.getToken();
      if (token instanceof NumberPtg) {
        if (isPlus) {
          return factor;
        }
        token = new NumberPtg(-((NumberPtg) token).getValue());
        return new ParseNode(token);
      }
      if (token instanceof IntPtg) {
        if (isPlus) {
          return factor;
        }
        int intVal = ((IntPtg) token).getValue();
        // note - cannot use IntPtg for negatives
        token = new NumberPtg(-intVal);
        return new ParseNode(token);
      }
    }
    return new ParseNode(isPlus ? UnaryPlusPtg.instance : UnaryMinusPtg.instance, factor);
  }
  /**
   * From OOO doc: "Whenever one operand of the reference subexpression is a function, a defined
   * name, a 3D reference, or an external reference (and no error occurs), a tMemFunc token is used"
   */
  private static boolean needsMemFunc(ParseNode root) {
    Ptg token = root.getToken();
    if (token instanceof AbstractFunctionPtg) {
      return true;
    }
    if (token instanceof ExternSheetReferenceToken) { // 3D refs
      return true;
    }
    if (token instanceof NamePtg || token instanceof NameXPtg) { // 3D refs
      return true;
    }

    if (token instanceof OperationPtg || token instanceof ParenthesisPtg) {
      // expect RangePtg, but perhaps also UnionPtg, IntersectionPtg etc
      for (ParseNode child : root.getChildren()) {
        if (needsMemFunc(child)) {
          return true;
        }
      }
      return false;
    }
    if (token instanceof OperandPtg) {
      return false;
    }
    if (token instanceof OperationPtg) {
      return true;
    }

    return false;
  }
  /**
   * @param callerForceArrayFlag <code>true</code> if one of the current node's parents is a
   *     function Ptg which has been changed from default 'V' to 'A' type (due to requirements on
   *     the function return value).
   */
  private void transformNode(
      ParseNode node, byte desiredOperandClass, boolean callerForceArrayFlag) {
    Ptg token = node.getToken();
    ParseNode[] children = node.getChildren();
    boolean isSimpleValueFunc = isSimpleValueFunction(token);

    if (isSimpleValueFunc) {
      boolean localForceArray = desiredOperandClass == Ptg.CLASS_ARRAY;
      for (int i = 0; i < children.length; i++) {
        transformNode(children[i], desiredOperandClass, localForceArray);
      }
      setSimpleValueFuncClass(
          (AbstractFunctionPtg) token, desiredOperandClass, callerForceArrayFlag);
      return;
    }

    if (isSingleArgSum(token)) {
      // Need to process the argument of SUM with transformFunctionNode below
      // so make a dummy FuncVarPtg for that call.
      token = FuncVarPtg.SUM;
      // Note - the tAttrSum token (node.getToken()) is a base
      // token so does not need to have its operand class set
    }
    if (token instanceof ValueOperatorPtg
        || token instanceof ControlPtg
        || token instanceof MemFuncPtg
        || token instanceof MemAreaPtg
        || token instanceof UnionPtg) {
      // Value Operator Ptgs and Control are base tokens, so token will be unchanged
      // but any child nodes are processed according to desiredOperandClass and callerForceArrayFlag

      // As per OOO documentation Sec 3.2.4 "Token Class Transformation", "Step 1"
      // All direct operands of value operators that are initially 'R' type will
      // be converted to 'V' type.
      byte localDesiredOperandClass =
          desiredOperandClass == Ptg.CLASS_REF ? Ptg.CLASS_VALUE : desiredOperandClass;
      for (int i = 0; i < children.length; i++) {
        transformNode(children[i], localDesiredOperandClass, callerForceArrayFlag);
      }
      return;
    }
    if (token instanceof AbstractFunctionPtg) {
      transformFunctionNode(
          (AbstractFunctionPtg) token, children, desiredOperandClass, callerForceArrayFlag);
      return;
    }
    if (children.length > 0) {
      if (token == RangePtg.instance) {
        // TODO is any token transformation required under the various ref operators?
        return;
      }
      throw new IllegalStateException("Node should not have any children");
    }

    if (token.isBaseToken()) {
      // nothing to do
      return;
    }
    token.setClass(transformClass(token.getPtgClass(), desiredOperandClass, callerForceArrayFlag));
  }
Example #5
0
  private void elaborate(ParseNode newRoot) {
    (root = newRoot).doParent();
    if (root.badFlag) return;

    variables = new Hashtable<Object, Hashtable>();
    legalVariables = new Hashtable<String, Integer>();
    knowns = new Hashtable<String, Double>();
    knowns.put("pi", new Double(Math.PI));
    knowns.put("Pi", new Double(Math.PI));
    knowns.put("PI", new Double(Math.PI));
    parameters = new Hashtable<String, Double>();
    make_legalVariables();
    fixImpliedMultiplication(root);
    if (find_variables(root) == null) {
      theValue = null;
      variables = null;
      legalVariables = null;
      knowns = null;
      parameters = null;
      root = null;
      return;
    } // end if

    Hashtable h = (Hashtable) (variables.get(root));
    Enumeration k = h.keys();
    while (k.hasMoreElements()) {
      String var = (String) k.nextElement();
      // System.out.println(var);
      Double t = (Double) knowns.get(var);
      // System.out.println(t);

      if (t == null) continue;

      Vector v = (Vector) h.get(var);
      Enumeration e = v.elements();
      while (e.hasMoreElements()) {
        ParseNode pn = (ParseNode) e.nextElement();
        pn.value = t;
      } // end while
    } // end while

    for (Enumeration e = variables.keys(); e.hasMoreElements(); ) {
      Object r;
      h = (Hashtable) (variables.get(r = e.nextElement()));

      for (k = knowns.keys(); k.hasMoreElements(); ) h.remove(k.nextElement());

      variables.put(r, h);
    } // end for

    condenseConstants(root);

    if ((theValue = root.value) != null) {
      valueString = MathUtil.trimDouble(theValue.doubleValue(), 12);
    } // end if
    else valueString = null;

    varStrings = new SortedKeyStrings((Hashtable) (variables.get(root))).theKeys;
  } // end elaborate
 private static ParseNode augmentWithMemPtg(ParseNode root) {
   Ptg memPtg;
   if (needsMemFunc(root)) {
     memPtg = new MemFuncPtg(root.getEncodedSize());
   } else {
     memPtg = new MemAreaPtg(root.getEncodedSize());
   }
   return new ParseNode(memPtg, root);
 }
  public SClassParseNode(
      ISourcePosition position, ParseNode recvNode, StaticScope scope, ParseNode bodyNode) {
    super(position, recvNode.containsVariableAssignment() || bodyNode.containsVariableAssignment());

    assert scope != null : "scope is not null";
    assert recvNode != null : "receiverNode is not null";

    this.receiverNode = recvNode;
    this.scope = scope;
    this.bodyNode = bodyNode;
  }
Example #8
0
  private void condenseConstants(ParseNode r) {
    if (r.value != null) return;

    Hashtable h = (Hashtable) variables.get(r);

    if (h.isEmpty()) {
      r.value = new Double(r.eval());
      return;
    } // end if

    if (r.children != null)
      for (int i = 0; i < r.children.length; i++) condenseConstants(r.children[i]);
  } // end condenseConstants
Example #9
0
  private Hashtable<String, Vector> find_variables(ParseNode r) {
    Hashtable<String, Vector> leavesOfR = new Hashtable<String, Vector>();
    // System.out.println("in find_varibles");

    if (r.operator == Action.NO_OP) { // no children
      if (legalVariables.get(r.theString) != null) {
        Vector<ParseNode> v = new Vector<ParseNode>();
        v.addElement(r);
        leavesOfR.put(r.theString, v);
      } // end if
      else
        try {
          r.value = new Double(r.theString);
        } // end try
        catch (NumberFormatException NFE) {
          return null;
        } // end catch
    } // end if operator
    else {
      Hashtable childLeaves;
      for (int i = 0; i < r.children.length; i++) {
        if ((childLeaves = find_variables(r.children[i])) == null) return null;
        combine(childLeaves, leavesOfR);
      } // end for i
    } // end else
    variables.put(r, leavesOfR);
    return leavesOfR;
  } // end find_variables
  public ParseNode not(ParseNode child) {
    if (child instanceof ExistsParseNode) {
      return exists(child.getChildren().get(0), !((ExistsParseNode) child).isNegate());
    }

    return new NotParseNode(child);
  }
 private Ptg[] getRPNPtg(int formulaType) {
   OperandClassTransformer oct = new OperandClassTransformer(formulaType);
   // RVA is for 'operand class': 'reference', 'value', 'array'
   oct.transformFormula(_rootNode);
   return ParseNode.toTokenArray(_rootNode);
 }
  public MutationPlan compile(UpsertStatement upsert, List<Object> binds) throws SQLException {
    final PhoenixConnection connection = statement.getConnection();
    ConnectionQueryServices services = connection.getQueryServices();
    final int maxSize =
        services
            .getProps()
            .getInt(
                QueryServices.MAX_MUTATION_SIZE_ATTRIB,
                QueryServicesOptions.DEFAULT_MAX_MUTATION_SIZE);
    final ColumnResolver resolver = FromCompiler.getResolver(upsert, connection);
    final TableRef tableRef = resolver.getTables().get(0);
    PTable table = tableRef.getTable();
    if (table.getType() == PTableType.VIEW) {
      throw new ReadOnlyTableException("Mutations not allowed for a view (" + tableRef + ")");
    }
    Scan scan = new Scan();
    final StatementContext context =
        new StatementContext(connection, resolver, binds, upsert.getBindCount(), scan);
    // Setup array of column indexes parallel to values that are going to be set
    List<ColumnName> columnNodes = upsert.getColumns();
    List<PColumn> allColumns = table.getColumns();

    int[] columnIndexesToBe;
    int[] pkSlotIndexesToBe;
    PColumn[] targetColumns;
    // Allow full row upsert if no columns or only dynamic one are specified and values count match
    if (columnNodes.isEmpty()
        || columnNodes.size() == upsert.getTable().getDynamicColumns().size()) {
      columnIndexesToBe = new int[allColumns.size()];
      pkSlotIndexesToBe = new int[columnIndexesToBe.length];
      targetColumns = new PColumn[columnIndexesToBe.length];
      int j = table.getBucketNum() == null ? 0 : 1; // Skip over the salting byte.
      for (int i = 0; i < allColumns.size(); i++) {
        columnIndexesToBe[i] = i;
        targetColumns[i] = allColumns.get(i);
        if (SchemaUtil.isPKColumn(allColumns.get(i))) {
          pkSlotIndexesToBe[i] = j++;
        }
      }
    } else {
      columnIndexesToBe = new int[columnNodes.size()];
      pkSlotIndexesToBe = new int[columnIndexesToBe.length];
      targetColumns = new PColumn[columnIndexesToBe.length];
      Arrays.fill(
          columnIndexesToBe,
          -1); // TODO: necessary? So we'll get an AIOB exception if it's not replaced
      Arrays.fill(
          pkSlotIndexesToBe,
          -1); // TODO: necessary? So we'll get an AIOB exception if it's not replaced
      BitSet pkColumnsSet = new BitSet(table.getPKColumns().size());
      for (int i = 0; i < columnNodes.size(); i++) {
        ColumnName colName = columnNodes.get(i);
        ColumnRef ref =
            resolver.resolveColumn(null, colName.getFamilyName(), colName.getColumnName());
        columnIndexesToBe[i] = ref.getColumnPosition();
        targetColumns[i] = ref.getColumn();
        if (SchemaUtil.isPKColumn(ref.getColumn())) {
          pkColumnsSet.set(pkSlotIndexesToBe[i] = ref.getPKSlotPosition());
        }
      }
      int i = table.getBucketNum() == null ? 0 : 1;
      for (; i < table.getPKColumns().size(); i++) {
        PColumn pkCol = table.getPKColumns().get(i);
        if (!pkColumnsSet.get(i)) {
          if (!pkCol.isNullable()) {
            throw new ConstraintViolationException(
                table.getName().getString()
                    + "."
                    + pkCol.getName().getString()
                    + " may not be null");
          }
        }
      }
    }

    List<ParseNode> valueNodes = upsert.getValues();
    QueryPlan plan = null;
    RowProjector projector = null;
    int nValuesToSet;
    boolean runOnServer = false;
    if (valueNodes == null) {
      SelectStatement select = upsert.getSelect();
      assert (select != null);
      TableRef selectTableRef = FromCompiler.getResolver(select, connection).getTables().get(0);
      boolean sameTable = tableRef.equals(selectTableRef);
      // Pass scan through if same table in upsert and select so that projection is computed
      // correctly
      QueryCompiler compiler =
          new QueryCompiler(connection, 0, sameTable ? scan : new Scan(), targetColumns);
      plan = compiler.compile(select, binds);
      projector = plan.getProjector();
      nValuesToSet = projector.getColumnCount();
      // Cannot auto commit if doing aggregation or topN or salted
      // Salted causes problems because the row may end up living on a different region
      runOnServer =
          plan.getGroupBy() == null
              && sameTable
              && select.getOrderBy().isEmpty()
              && table.getBucketNum() == null;
    } else {
      nValuesToSet = valueNodes.size();
    }
    final QueryPlan queryPlan = plan;
    // Resize down to allow a subset of columns to be specifiable
    if (columnNodes.isEmpty()) {
      columnIndexesToBe = Arrays.copyOf(columnIndexesToBe, nValuesToSet);
      pkSlotIndexesToBe = Arrays.copyOf(pkSlotIndexesToBe, nValuesToSet);
    }

    if (nValuesToSet != columnIndexesToBe.length) {
      throw new SQLExceptionInfo.Builder(SQLExceptionCode.UPSERT_COLUMN_NUMBERS_MISMATCH)
          .setMessage(
              "Numbers of columns: "
                  + columnIndexesToBe.length
                  + ". Number of values: "
                  + nValuesToSet)
          .build()
          .buildException();
    }

    final int[] columnIndexes = columnIndexesToBe;
    final int[] pkSlotIndexes = pkSlotIndexesToBe;

    // TODO: break this up into multiple functions
    ////////////////////////////////////////////////////////////////////
    // UPSERT SELECT
    /////////////////////////////////////////////////////////////////////
    if (valueNodes == null) {
      /* We can run the upsert in a coprocessor if:
       * 1) the into table matches from table
       * 2) the select query isn't doing aggregation
       * 3) autoCommit is on
       * 4) not topN
       * Otherwise, run the query to pull the data from the server
       * and populate the MutationState (upto a limit).
       */
      final boolean isAutoCommit = connection.getAutoCommit();
      runOnServer &= isAutoCommit;

      ////////////////////////////////////////////////////////////////////
      // UPSERT SELECT run server-side (maybe)
      /////////////////////////////////////////////////////////////////////
      if (runOnServer) {
        // At most this array will grow bigger by the number of PK columns
        int[] allColumnsIndexes = Arrays.copyOf(columnIndexes, columnIndexes.length + nValuesToSet);
        int[] reverseColumnIndexes = new int[table.getColumns().size()];
        List<Expression> projectedExpressions =
            Lists.newArrayListWithExpectedSize(reverseColumnIndexes.length);
        Arrays.fill(reverseColumnIndexes, -1);
        for (int i = 0; i < nValuesToSet; i++) {
          projectedExpressions.add(projector.getColumnProjector(i).getExpression());
          reverseColumnIndexes[columnIndexes[i]] = i;
        }
        /*
         * Order projected columns and projected expressions with PK columns
         * leading order by slot position
         */
        int offset = table.getBucketNum() == null ? 0 : 1;
        for (int i = 0; i < table.getPKColumns().size() - offset; i++) {
          PColumn column = table.getPKColumns().get(i + offset);
          int pos = reverseColumnIndexes[column.getPosition()];
          if (pos == -1) {
            // Last PK column may be fixed width and nullable
            // We don't want to insert a null expression b/c
            // it's not valid to set a fixed width type to null.
            if (column.getDataType().isFixedWidth()) {
              continue;
            }
            // Add literal null for missing PK columns
            pos = projectedExpressions.size();
            Expression literalNull = LiteralExpression.newConstant(null, column.getDataType());
            projectedExpressions.add(literalNull);
            allColumnsIndexes[pos] = column.getPosition();
          }
          // Swap select expression at pos with i
          Collections.swap(projectedExpressions, i, pos);
          // Swap column indexes and reverse column indexes too
          int tempPos = allColumnsIndexes[i];
          allColumnsIndexes[i] = allColumnsIndexes[pos];
          allColumnsIndexes[pos] = tempPos;
          reverseColumnIndexes[tempPos] = reverseColumnIndexes[i];
          reverseColumnIndexes[i] = i;
        }
        // If any pk slots are changing, be conservative and don't run this server side.
        // If the row ends up living in a different region, we'll get an error otherwise.
        for (int i = 0; i < table.getPKColumns().size(); i++) {
          PColumn column = table.getPKColumns().get(i);
          Expression source = projectedExpressions.get(i);
          if (source == null
              || !source.equals(
                  new ColumnRef(tableRef, column.getPosition()).newColumnExpression())) {
            // TODO: we could check the region boundaries to see if the pk will still be in it.
            runOnServer = false; // bail on running server side, since PK may be changing
            break;
          }
        }

        ////////////////////////////////////////////////////////////////////
        // UPSERT SELECT run server-side
        /////////////////////////////////////////////////////////////////////
        if (runOnServer) {
          // Iterate through columns being projected
          List<PColumn> projectedColumns =
              Lists.newArrayListWithExpectedSize(projectedExpressions.size());
          for (int i = 0; i < projectedExpressions.size(); i++) {
            // Must make new column if position has changed
            PColumn column = allColumns.get(allColumnsIndexes[i]);
            projectedColumns.add(column.getPosition() == i ? column : new PColumnImpl(column, i));
          }
          // Build table from projectedColumns
          PTable projectedTable =
              PTableImpl.makePTable(
                  table.getName(),
                  table.getType(),
                  table.getTimeStamp(),
                  table.getSequenceNumber(),
                  table.getPKName(),
                  table.getBucketNum(),
                  projectedColumns);

          // Remove projection of empty column, since it can lead to problems when building another
          // projection
          // using this same scan. TODO: move projection code to a later stage, like
          // QueryPlan.newScanner to
          // prevent having to do this.
          ScanUtil.removeEmptyColumnFamily(context.getScan(), table);
          List<AliasedNode> select =
              Collections.<AliasedNode>singletonList(
                  NODE_FACTORY.aliasedNode(
                      null,
                      NODE_FACTORY.function(
                          CountAggregateFunction.NORMALIZED_NAME, LiteralParseNode.STAR)));
          // Ignore order by - it has no impact
          final RowProjector aggProjector =
              ProjectionCompiler.getRowProjector(
                  context, select, false, GroupBy.EMPTY_GROUP_BY, OrderBy.EMPTY_ORDER_BY, null);
          /*
           * Transfer over PTable representing subset of columns selected, but all PK columns.
           * Move columns setting PK first in pkSlot order, adding LiteralExpression of null for any missing ones.
           * Transfer over List<Expression> for projection.
           * In region scan, evaluate expressions in order, collecting first n columns for PK and collection non PK in mutation Map
           * Create the PRow and get the mutations, adding them to the batch
           */
          scan.setAttribute(
              UngroupedAggregateRegionObserver.UPSERT_SELECT_TABLE,
              UngroupedAggregateRegionObserver.serialize(projectedTable));
          scan.setAttribute(
              UngroupedAggregateRegionObserver.UPSERT_SELECT_EXPRS,
              UngroupedAggregateRegionObserver.serialize(projectedExpressions));
          final QueryPlan aggPlan =
              new AggregatePlan(
                  context,
                  tableRef,
                  projector,
                  null,
                  GroupBy.EMPTY_GROUP_BY,
                  false,
                  null,
                  OrderBy.EMPTY_ORDER_BY);
          return new MutationPlan() {

            @Override
            public PhoenixConnection getConnection() {
              return connection;
            }

            @Override
            public ParameterMetaData getParameterMetaData() {
              return context.getBindManager().getParameterMetaData();
            }

            @Override
            public MutationState execute() throws SQLException {
              Scanner scanner = aggPlan.getScanner();
              ResultIterator iterator = scanner.iterator();
              try {
                Tuple row = iterator.next();
                ImmutableBytesWritable ptr = context.getTempPtr();
                final long mutationCount =
                    (Long) aggProjector.getColumnProjector(0).getValue(row, PDataType.LONG, ptr);
                return new MutationState(maxSize, connection) {
                  @Override
                  public long getUpdateCount() {
                    return mutationCount;
                  }
                };
              } finally {
                iterator.close();
              }
            }

            @Override
            public ExplainPlan getExplainPlan() throws SQLException {
              List<String> queryPlanSteps = aggPlan.getExplainPlan().getPlanSteps();
              List<String> planSteps =
                  Lists.newArrayListWithExpectedSize(queryPlanSteps.size() + 1);
              planSteps.add("UPSERT ROWS");
              planSteps.addAll(queryPlanSteps);
              return new ExplainPlan(planSteps);
            }
          };
        }
      }

      ////////////////////////////////////////////////////////////////////
      // UPSERT SELECT run client-side
      /////////////////////////////////////////////////////////////////////
      final int batchSize = Math.min(connection.getMutateBatchSize(), maxSize);
      return new MutationPlan() {

        @Override
        public PhoenixConnection getConnection() {
          return connection;
        }

        @Override
        public ParameterMetaData getParameterMetaData() {
          return context.getBindManager().getParameterMetaData();
        }

        @Override
        public MutationState execute() throws SQLException {
          byte[][] values = new byte[columnIndexes.length][];
          Scanner scanner = queryPlan.getScanner();
          int estSize = scanner.getEstimatedSize();
          int rowCount = 0;
          Map<ImmutableBytesPtr, Map<PColumn, byte[]>> mutation =
              Maps.newHashMapWithExpectedSize(estSize);
          ResultSet rs = new PhoenixResultSet(scanner, statement);
          PTable table = tableRef.getTable();
          PColumn column;
          while (rs.next()) {
            for (int i = 0; i < values.length; i++) {
              column = table.getColumns().get(columnIndexes[i]);
              byte[] byteValue = rs.getBytes(i + 1);
              Object value = rs.getObject(i + 1);
              int rsPrecision = rs.getMetaData().getPrecision(i + 1);
              Integer precision = rsPrecision == 0 ? null : rsPrecision;
              int rsScale = rs.getMetaData().getScale(i + 1);
              Integer scale = rsScale == 0 ? null : rsScale;
              // If ColumnModifier from expression in SELECT doesn't match the
              // column being projected into then invert the bits.
              if (column.getColumnModifier() == ColumnModifier.SORT_DESC) {
                byte[] tempByteValue = Arrays.copyOf(byteValue, byteValue.length);
                byteValue =
                    ColumnModifier.SORT_DESC.apply(byteValue, tempByteValue, 0, byteValue.length);
              }
              // We are guaranteed that the two column will have compatible types,
              // as we checked that before.
              if (!column
                  .getDataType()
                  .isSizeCompatible(
                      column.getDataType(),
                      value,
                      byteValue,
                      precision,
                      column.getMaxLength(),
                      scale,
                      column.getScale())) {
                throw new SQLExceptionInfo.Builder(SQLExceptionCode.DATA_INCOMPATIBLE_WITH_TYPE)
                    .setColumnName(column.getName().getString())
                    .build()
                    .buildException();
              }
              values[i] =
                  column
                      .getDataType()
                      .coerceBytes(
                          byteValue,
                          value,
                          column.getDataType(),
                          precision,
                          scale,
                          column.getMaxLength(),
                          column.getScale());
            }
            setValues(values, pkSlotIndexes, columnIndexes, table, mutation);
            rowCount++;
            // Commit a batch if auto commit is true and we're at our batch size
            if (isAutoCommit && rowCount % batchSize == 0) {
              MutationState state = new MutationState(tableRef, mutation, 0, maxSize, connection);
              connection.getMutationState().join(state);
              connection.commit();
              mutation.clear();
            }
          }
          // If auto commit is true, this last batch will be committed upon return
          return new MutationState(
              tableRef, mutation, rowCount / batchSize * batchSize, maxSize, connection);
        }

        @Override
        public ExplainPlan getExplainPlan() throws SQLException {
          List<String> queryPlanSteps = queryPlan.getExplainPlan().getPlanSteps();
          List<String> planSteps = Lists.newArrayListWithExpectedSize(queryPlanSteps.size() + 1);
          planSteps.add("UPSERT SELECT");
          planSteps.addAll(queryPlanSteps);
          return new ExplainPlan(planSteps);
        }
      };
    }

    ////////////////////////////////////////////////////////////////////
    // UPSERT VALUES
    /////////////////////////////////////////////////////////////////////
    int nodeIndex = 0;
    // Allocate array based on size of all columns in table,
    // since some values may not be set (if they're nullable).
    UpsertValuesCompiler expressionBuilder = new UpsertValuesCompiler(context);
    final byte[][] values = new byte[nValuesToSet][];
    for (ParseNode valueNode : valueNodes) {
      if (!valueNode.isConstant()) {
        throw new SQLExceptionInfo.Builder(SQLExceptionCode.VALUE_IN_UPSERT_NOT_CONSTANT)
            .build()
            .buildException();
      }
      PColumn column = allColumns.get(columnIndexes[nodeIndex]);
      expressionBuilder.setColumn(column);
      LiteralExpression literalExpression = (LiteralExpression) valueNode.accept(expressionBuilder);
      byte[] byteValue = literalExpression.getBytes();
      if (literalExpression.getDataType() != null) {
        // If ColumnModifier from expression in SELECT doesn't match the
        // column being projected into then invert the bits.
        if (literalExpression.getColumnModifier() != column.getColumnModifier()) {
          byte[] tempByteValue = Arrays.copyOf(byteValue, byteValue.length);
          byteValue = ColumnModifier.SORT_DESC.apply(byteValue, tempByteValue, 0, byteValue.length);
        }
        if (!literalExpression
            .getDataType()
            .isCoercibleTo(column.getDataType(), literalExpression.getValue())) {
          throw new TypeMismatchException(
              literalExpression.getDataType(),
              column.getDataType(),
              "expression: " + literalExpression.toString() + " in column " + column);
        }
        if (!column
            .getDataType()
            .isSizeCompatible(
                literalExpression.getDataType(),
                literalExpression.getValue(),
                byteValue,
                literalExpression.getMaxLength(),
                column.getMaxLength(),
                literalExpression.getScale(),
                column.getScale())) {
          throw new SQLExceptionInfo.Builder(SQLExceptionCode.DATA_INCOMPATIBLE_WITH_TYPE)
              .setColumnName(column.getName().getString())
              .setMessage("value=" + literalExpression.toString())
              .build()
              .buildException();
        }
      }
      byteValue =
          column
              .getDataType()
              .coerceBytes(
                  byteValue,
                  literalExpression.getValue(),
                  literalExpression.getDataType(),
                  literalExpression.getMaxLength(),
                  literalExpression.getScale(),
                  column.getMaxLength(),
                  column.getScale());
      values[nodeIndex] = byteValue;
      nodeIndex++;
    }
    return new MutationPlan() {

      @Override
      public PhoenixConnection getConnection() {
        return connection;
      }

      @Override
      public ParameterMetaData getParameterMetaData() {
        return context.getBindManager().getParameterMetaData();
      }

      @Override
      public MutationState execute() {
        Map<ImmutableBytesPtr, Map<PColumn, byte[]>> mutation = Maps.newHashMapWithExpectedSize(1);
        setValues(values, pkSlotIndexes, columnIndexes, tableRef.getTable(), mutation);
        return new MutationState(tableRef, mutation, 0, maxSize, connection);
      }

      @Override
      public ExplainPlan getExplainPlan() throws SQLException {
        return new ExplainPlan(Collections.singletonList("PUT SINGLE ROW"));
      }
    };
  }
Example #13
0
 public List<ParseNode> childNodes() {
   return ParseNode.createList(receiverNode, bodyNode);
 }
Example #14
0
  private void fixImpliedMultiplication(ParseNode r) {
    int i;

    if (r.operator == Action.NO_OP) {
      if (legalVariables.get(r.theString) != null) return;

      Vector<String> v = splitIM(r.theString);

      if (v.size() == 1) return;

      r.operator = Action.PRODUCT;
      r.children = new ParseNode[v.size()];
      Enumeration<String> e = v.elements();
      for (i = 0; e.hasMoreElements(); i++) r.children[i] = new ParseNode((String) e.nextElement());
    } // end if
    else if (r.operator == Action.POWER) {
      int n0 = 0, n1 = 1;
      ParseNode r0 = r.children[0], r1 = r.children[1];
      StringBuffer b0 = new StringBuffer(), b1 = new StringBuffer();

      if (r0.operator == Action.NO_OP) {
        Vector<String> v = splitIM(r0.theString);

        if ((n0 = v.size() - 1) < 0) {
          root.badFlag = true;
          return;
        } // end if

        for (i = 0; i < n0; i++) b0.append((String) v.elementAt(i) + "*");

        b0.append((String) v.elementAt(n0) + "^");
      } // end if
      else b0.append(new Expression(r0).toString() + "^");

      switch (r1.operator) {
        case Action.NO_OP:
          {
            Vector<String> v = splitIM(r1.theString);

            if ((n1 = v.size()) < 1) {
              root.badFlag = true;
              return;
            } // end if

            b1.append((String) v.elementAt(0));

            if (n1 > 1) b1.append("*");

            for (i = 1; i < n1; i++) b1.append((String) v.elementAt(i));
            break;
          } // end block

        case Action.PRODUCT:
        case Action.SUM:
          b1.append("(" + new Expression(r1).toString() + ")");
          break;

        default:
          b1.append(new Expression(r1).toString());
      } // end switch

      if (n0 == 0 && n1 == 1) return;

      ParseNode t = new Expression(b0.toString() + b1.toString()).root;

      if (t == null) {
        root.badFlag = true;
        return;
      } // end if

      r.children = t.children;
      r.operator = t.operator;
    } // end if
    else for (i = 0; i < r.children.length; i++) fixImpliedMultiplication(r.children[i]);
  } // end fixImpliedMultiplication