All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.trino.sql.gen.DereferenceCodeGenerator Maven / Gradle / Ivy

/*
 * Licensed 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 io.trino.sql.gen;

import io.airlift.bytecode.BytecodeBlock;
import io.airlift.bytecode.BytecodeNode;
import io.airlift.bytecode.Variable;
import io.airlift.bytecode.control.IfStatement;
import io.airlift.bytecode.expression.BytecodeExpression;
import io.airlift.bytecode.instruction.LabelNode;
import io.trino.spi.block.Block;
import io.trino.spi.block.SqlRow;
import io.trino.spi.type.Type;
import io.trino.sql.relational.ConstantExpression;
import io.trino.sql.relational.RowExpression;
import io.trino.sql.relational.SpecialForm;

import static com.google.common.base.Preconditions.checkArgument;
import static io.airlift.bytecode.expression.BytecodeExpressions.constantInt;
import static io.trino.sql.gen.SqlTypeBytecodeExpression.constantType;
import static java.lang.Math.toIntExact;
import static java.util.Objects.requireNonNull;

public class DereferenceCodeGenerator
        implements BytecodeGenerator
{
    private final Type returnType;
    private final RowExpression base;
    private final int index;

    public DereferenceCodeGenerator(SpecialForm specialForm)
    {
        requireNonNull(specialForm, "specialForm is null");
        returnType = specialForm.type();
        checkArgument(specialForm.arguments().size() == 2);
        base = specialForm.arguments().get(0);
        index = toIntExact((long) ((ConstantExpression) specialForm.arguments().get(1)).value());
    }

    @Override
    public BytecodeNode generateExpression(BytecodeGeneratorContext generator)
    {
        CallSiteBinder callSiteBinder = generator.getCallSiteBinder();

        BytecodeBlock block = new BytecodeBlock().comment("DEREFERENCE").setDescription("DEREFERENCE");
        Variable wasNull = generator.wasNull();
        Variable row = generator.getScope().getOrCreateTempVariable(SqlRow.class);

        // clear the wasNull flag before evaluating the row value
        block.putVariable(wasNull, false);
        block.append(generator.generate(base)).putVariable(row);

        IfStatement ifRowBlockIsNull = new IfStatement("if row block is null...")
                .condition(wasNull);

        Class javaType = returnType.getJavaType();
        LabelNode end = new LabelNode("end");
        ifRowBlockIsNull.ifTrue()
                .comment("if row block is null, push null to the stack and goto 'end' label (return)")
                .putVariable(wasNull, true)
                .pushJavaDefault(javaType)
                .gotoLabel(end);

        block.append(ifRowBlockIsNull);

        IfStatement ifFieldIsNull = new IfStatement("if row field is null...");
        ifFieldIsNull.condition(row.invoke("getRawFieldBlock", Block.class, constantInt(index)).invoke("isNull", boolean.class, row.invoke("getRawIndex", int.class)));

        ifFieldIsNull.ifTrue()
                .comment("if the field is null, push null to stack")
                .putVariable(wasNull, true)
                .pushJavaDefault(javaType);

        BytecodeExpression value = constantType(callSiteBinder, returnType).getValue(row.invoke("getRawFieldBlock", Block.class, constantInt(index)), row.invoke("getRawIndex", int.class));

        ifFieldIsNull.ifFalse()
                .comment("otherwise call type.getTYPE(row, index)")
                .append(value)
                .putVariable(wasNull, false);

        generator.getScope().releaseTempVariableForReuse(row);

        block.append(ifFieldIsNull)
                .visitLabel(end);

        return block;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy