예제 #1
0
  private static void generateProcessColumnarMethod(
      ClassDefinition classDefinition,
      List<RowExpression> projections,
      List<MethodDefinition> projectColumnarMethods) {
    Parameter session = arg("session", ConnectorSession.class);
    Parameter page = arg("page", Page.class);
    Parameter types = arg("types", List.class);
    MethodDefinition method =
        classDefinition.declareMethod(
            a(PUBLIC), "processColumnar", type(Page.class), session, page, types);

    Scope scope = method.getScope();
    BytecodeBlock body = method.getBody();
    Variable thisVariable = method.getThis();

    Variable selectedPositions =
        scope.declareVariable(
            "selectedPositions",
            body,
            thisVariable.invoke("filterPage", int[].class, session, page));
    Variable cardinality = scope.declareVariable("cardinality", body, selectedPositions.length());

    body.comment("if no rows selected return null")
        .append(
            new IfStatement()
                .condition(equal(cardinality, constantInt(0)))
                .ifTrue(constantNull(Page.class).ret()));

    if (projections.isEmpty()) {
      // if no projections, return new page with selected rows
      body.append(newInstance(Page.class, cardinality, newArray(type(Block[].class), 0)).ret());
      return;
    }

    Variable pageBuilder =
        scope.declareVariable(
            "pageBuilder", body, newInstance(PageBuilder.class, cardinality, types));
    Variable outputBlocks =
        scope.declareVariable(
            "outputBlocks", body, newArray(type(Block[].class), projections.size()));

    for (int projectionIndex = 0; projectionIndex < projections.size(); projectionIndex++) {
      List<BytecodeExpression> params =
          ImmutableList.<BytecodeExpression>builder()
              .add(session)
              .add(page)
              .add(selectedPositions)
              .add(pageBuilder)
              .add(constantInt(projectionIndex))
              .build();
      body.append(
          outputBlocks.setElement(
              projectionIndex,
              thisVariable.invoke(projectColumnarMethods.get(projectionIndex), params)));
    }

    // create new page from outputBlocks
    body.append(newInstance(Page.class, cardinality, outputBlocks).ret());
  }
예제 #2
0
 private static BytecodeNode invokeProject(
     Variable objRef,
     Variable session,
     List<? extends Variable> blockVariables,
     BytecodeExpression position,
     Variable pageBuilder,
     BytecodeExpression projectionIndex,
     MethodDefinition projectionMethod) {
   BytecodeExpression blockBuilder =
       pageBuilder.invoke("getBlockBuilder", BlockBuilder.class, projectionIndex);
   List<BytecodeExpression> params =
       ImmutableList.<BytecodeExpression>builder()
           .add(session)
           .addAll(blockVariables)
           .add(position)
           .add(blockBuilder)
           .build();
   return new BytecodeBlock().append(objRef.invoke(projectionMethod, params));
 }
예제 #3
0
  private static MethodDefinition generateProjectDictionaryMethod(
      ClassDefinition classDefinition,
      String methodName,
      RowExpression projection,
      MethodDefinition project,
      MethodDefinition projectColumnar) {
    Parameter session = arg("session", ConnectorSession.class);
    Parameter page = arg("page", Page.class);
    Parameter selectedPositions = arg("selectedPositions", int[].class);
    Parameter pageBuilder = arg("pageBuilder", PageBuilder.class);
    Parameter projectionIndex = arg("projectionIndex", int.class);

    List<Parameter> params =
        ImmutableList.<Parameter>builder()
            .add(session)
            .add(page)
            .add(selectedPositions)
            .add(pageBuilder)
            .add(projectionIndex)
            .build();

    MethodDefinition method =
        classDefinition.declareMethod(a(PRIVATE), methodName, type(Block.class), params);
    BytecodeBlock body = method.getBody();
    Scope scope = method.getScope();
    Variable thisVariable = method.getThis();

    List<Integer> inputChannels = getInputChannels(projection);

    if (inputChannels.size() != 1) {
      body.append(thisVariable.invoke(projectColumnar, params).ret());
      return method;
    }

    Variable inputBlock =
        scope.declareVariable(
            "inputBlock",
            body,
            page.invoke(
                "getBlock", Block.class, constantInt(Iterables.getOnlyElement(inputChannels))));
    IfStatement ifStatement =
        new IfStatement()
            .condition(inputBlock.instanceOf(DictionaryBlock.class))
            .ifFalse(thisVariable.invoke(projectColumnar, params).ret());
    body.append(ifStatement);

    Variable blockBuilder =
        scope.declareVariable(
            "blockBuilder",
            body,
            pageBuilder.invoke("getBlockBuilder", BlockBuilder.class, projectionIndex));
    Variable cardinality = scope.declareVariable("cardinality", body, selectedPositions.length());

    Variable dictionary = scope.declareVariable(Block.class, "dictionary");
    Variable ids = scope.declareVariable(Slice.class, "ids");
    Variable dictionaryCount = scope.declareVariable(int.class, "dictionaryCount");

    Variable outputDictionary = scope.declareVariable(Block.class, "outputDictionary");
    Variable outputIds = scope.declareVariable(int[].class, "outputIds");

    BytecodeExpression inputDictionaries =
        thisVariable.getField("inputDictionaries", Block[].class);
    BytecodeExpression outputDictionaries =
        thisVariable.getField("outputDictionaries", Block[].class);

    Variable position = scope.declareVariable("position", body, constantInt(0));

    body.comment("Extract dictionary and ids")
        .append(
            dictionary.set(
                inputBlock.cast(DictionaryBlock.class).invoke("getDictionary", Block.class)))
        .append(ids.set(inputBlock.cast(DictionaryBlock.class).invoke("getIds", Slice.class)))
        .append(dictionaryCount.set(dictionary.invoke("getPositionCount", int.class)));

    BytecodeBlock projectDictionary =
        new BytecodeBlock()
            .comment("Project dictionary")
            .append(
                new ForLoop()
                    .initialize(position.set(constantInt(0)))
                    .condition(lessThan(position, dictionaryCount))
                    .update(position.increment())
                    .body(
                        invokeProject(
                            thisVariable,
                            session,
                            ImmutableList.of(dictionary),
                            position,
                            pageBuilder,
                            projectionIndex,
                            project)))
            .append(outputDictionary.set(blockBuilder.invoke("build", Block.class)))
            .append(inputDictionaries.setElement(projectionIndex, dictionary))
            .append(outputDictionaries.setElement(projectionIndex, outputDictionary));

    body.comment("Use processed dictionary, if available, else project it")
        .append(
            new IfStatement()
                .condition(equal(inputDictionaries.getElement(projectionIndex), dictionary))
                .ifTrue(outputDictionary.set(outputDictionaries.getElement(projectionIndex)))
                .ifFalse(projectDictionary));

    body.comment("Filter ids")
        .append(outputIds.set(newArray(type(int[].class), cardinality)))
        .append(
            new ForLoop()
                .initialize(position.set(constantInt(0)))
                .condition(lessThan(position, cardinality))
                .update(position.increment())
                .body(
                    outputIds.setElement(
                        position,
                        ids.invoke(
                            "getInt",
                            int.class,
                            multiply(
                                selectedPositions.getElement(position),
                                constantInt(SIZE_OF_INT))))));

    body.append(
        newInstance(
                DictionaryBlock.class,
                cardinality,
                outputDictionary,
                invokeStatic(Slices.class, "wrappedIntArray", Slice.class, outputIds))
            .cast(Block.class)
            .ret());
    return method;
  }
예제 #4
0
  private static MethodDefinition generateProjectColumnarMethod(
      ClassDefinition classDefinition,
      CallSiteBinder callSiteBinder,
      String methodName,
      RowExpression projection,
      MethodDefinition projectionMethod) {
    Parameter session = arg("session", ConnectorSession.class);
    Parameter page = arg("page", Page.class);
    Parameter selectedPositions = arg("selectedPositions", int[].class);
    Parameter pageBuilder = arg("pageBuilder", PageBuilder.class);
    Parameter projectionIndex = arg("projectionIndex", int.class);

    List<Parameter> params =
        ImmutableList.<Parameter>builder()
            .add(session)
            .add(page)
            .add(selectedPositions)
            .add(pageBuilder)
            .add(projectionIndex)
            .build();
    MethodDefinition method =
        classDefinition.declareMethod(a(PRIVATE), methodName, type(Block.class), params);

    BytecodeBlock body = method.getBody();
    Scope scope = method.getScope();
    Variable thisVariable = method.getThis();

    ImmutableList.Builder<Variable> builder = ImmutableList.<Variable>builder();
    for (int channel : getInputChannels(projection)) {
      Variable blockVariable =
          scope.declareVariable(
              "block_" + channel, body, page.invoke("getBlock", Block.class, constantInt(channel)));
      builder.add(blockVariable);
    }
    List<Variable> inputs = builder.build();

    Variable positionCount =
        scope.declareVariable("positionCount", body, page.invoke("getPositionCount", int.class));
    Variable position = scope.declareVariable("position", body, constantInt(0));
    Variable cardinality = scope.declareVariable("cardinality", body, selectedPositions.length());
    Variable outputBlock = scope.declareVariable(Block.class, "outputBlock");
    Variable blockBuilder =
        scope.declareVariable(
            "blockBuilder",
            body,
            pageBuilder.invoke("getBlockBuilder", BlockBuilder.class, projectionIndex));
    Variable type =
        scope.declareVariable(
            "type", body, pageBuilder.invoke("getType", Type.class, projectionIndex));

    BytecodeBlock projectBlock =
        new BytecodeBlock()
            .append(
                new ForLoop()
                    .initialize(position.set(constantInt(0)))
                    .condition(lessThan(position, cardinality))
                    .update(position.increment())
                    .body(
                        invokeProject(
                            thisVariable,
                            session,
                            inputs,
                            selectedPositions.getElement(position),
                            pageBuilder,
                            projectionIndex,
                            projectionMethod)))
            .append(outputBlock.set(blockBuilder.invoke("build", Block.class)));

    if (isIdentityExpression(projection)) {
      // if nothing is filtered out, copy the entire block, else project it
      body.append(
          new IfStatement()
              .condition(equal(cardinality, positionCount))
              .ifTrue(outputBlock.set(inputs.get(0)))
              .ifFalse(projectBlock));
    } else if (isConstantExpression(projection)) {
      // if projection is a constant, create RLE block of constant expression with cardinality
      // positions
      ConstantExpression constantExpression = (ConstantExpression) projection;
      verify(getInputChannels(projection).isEmpty());
      BytecodeExpression value =
          loadConstant(callSiteBinder, constantExpression.getValue(), Object.class);
      body.append(
          outputBlock.set(
              invokeStatic(
                  RunLengthEncodedBlock.class, "create", Block.class, type, value, cardinality)));
    } else {
      body.append(projectBlock);
    }
    body.append(outputBlock.ret());
    return method;
  }