Package com.foundationdb.sql.optimizer.rule

Source Code of com.foundationdb.sql.optimizer.rule.PlanGenerator

/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.foundationdb.sql.optimizer.rule;

import static com.foundationdb.util.Strings.join;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.foundationdb.ais.model.AbstractVisitor;
import com.foundationdb.ais.model.Column;
import com.foundationdb.ais.model.Sequence;
import com.foundationdb.qp.operator.QueryContext;
import com.foundationdb.qp.rowtype.TableRowType;
import com.foundationdb.server.types.TCast;
import com.foundationdb.server.types.TExecutionContext;
import com.foundationdb.server.types.TInstance;
import com.foundationdb.server.types.TPreptimeValue;
import com.foundationdb.server.types.common.types.TypesTranslator;
import com.foundationdb.server.types.service.OverloadResolver;
import com.foundationdb.server.types.service.TypesRegistryService;
import com.foundationdb.server.types.texpressions.TCastExpression;
import com.foundationdb.server.types.texpressions.TPreparedFunction;
import com.foundationdb.server.types.texpressions.TPreparedLiteral;
import com.foundationdb.server.types.texpressions.TSequenceNextValueExpression;
import com.foundationdb.server.types.texpressions.TValidatedScalar;
import com.foundationdb.server.types.value.Value;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.foundationdb.ais.model.AkibanInformationSchema;
import com.foundationdb.ais.model.PrimaryKey;
import com.foundationdb.ais.model.Table;
import com.foundationdb.qp.expression.IndexBound;
import com.foundationdb.qp.expression.IndexKeyRange;
import com.foundationdb.qp.expression.RowBasedUnboundExpressions;
import com.foundationdb.qp.operator.API;
import com.foundationdb.qp.operator.Operator;
import com.foundationdb.qp.operator.API.Ordering;
import com.foundationdb.qp.rowtype.IndexRowType;
import com.foundationdb.qp.rowtype.RowType;
import com.foundationdb.qp.rowtype.Schema;
import com.foundationdb.qp.util.SchemaCache;
import com.foundationdb.server.api.dml.ColumnSelector;
import com.foundationdb.server.explain.ExplainContext;
import com.foundationdb.server.explain.format.DefaultFormatter;
import com.foundationdb.server.types.texpressions.TPreparedExpression;
import com.foundationdb.server.types.texpressions.TPreparedField;
import com.foundationdb.server.types.texpressions.TPreparedParameter;

/**
* Generate one of a static set of internally used operator plans.
* @author tjoneslo
*
*/
public class PlanGenerator {

    private static final Logger logger = LoggerFactory.getLogger(PlanGenerator.class);

   
    /**
     * Scan a group table and pull back all the rows from the group, with their children
     * Group table equivelent of a full table scan.
     *
     * Generates a plan
     * Filter_default
     *   GroupScan (table group)
     *  
     *  
     */
    public static Operator generateScanPlan (AkibanInformationSchema ais, Table table) {
        final Schema schema = SchemaCache.globalSchema(ais);
        Operator plan = API.groupScan_Default(table.getGroup());
        final List<RowType> keepTypes = new ArrayList<>();
        table.visit(new AbstractVisitor() {
            @Override
            public void visit(Table table) {
                keepTypes.add(schema.tableRowType(table));
            }
        });
        plan = API.filter_Default(plan, keepTypes);

        if (logger.isDebugEnabled()) {
            DefaultFormatter formatter = new DefaultFormatter(table.getName().getSchemaName());
            logger.debug("Scan Plan for {}:\n{}", table, join(formatter.format(plan.getExplainer(new ExplainContext()))));

        }

        return plan;
       
    }
   
    /**
     * Scan a group starting with Primary Key of a table,
     * then get all of the children (if any). Primary key
     * is set as parameters to the query context.
     * 
     * Generates a plan:
     * Branch Lookup
     *   Index Scan (table, pk-> ?[, ?...])
     */
    public static Operator generateBranchPlan (AkibanInformationSchema ais, Table table) {
        final Operator indexScan = generateIndexScan(ais, table);
        final Schema schema = SchemaCache.globalSchema(ais);
        PrimaryKey pkey = table.getPrimaryKeyIncludingInternal();
        IndexRowType indexType = schema.indexRowType(pkey.getIndex());
        return generateBranchPlan(table, indexScan, indexType);
    }

    public static Operator generateBranchPlan (Table table, Operator scan, RowType scanType) {
        final Schema schema = (Schema)scanType.schema();
        final TableRowType tableType = schema.tableRowType(table);
        final List<TableRowType> tableTypes = new ArrayList<>();
        tableTypes.add(tableType);
        for (RowType rowType : Schema.descendentTypes(tableType, schema.userTableTypes())) {
            tableTypes.add((TableRowType)rowType);
        }
        Operator plan = API.groupLookup_Default(scan, table.getGroup(),
                                                scanType, tableTypes,
                                                API.InputPreservationOption.DISCARD_INPUT, 1);
                                       
        if (logger.isDebugEnabled()) {
            DefaultFormatter formatter = new DefaultFormatter(table.getName().getSchemaName());
            logger.debug("Branch Plan for {}:\n{}", table,
                         join(formatter.format(plan.getExplainer(new ExplainContext()))));
        }
        return plan;
    }

    /**
     * Scan a table starting with the primary key and return the full data row
     * Generates a plan like
     * AncestorScan (Table)
     *   IndexScan (table, pk->?[, ?])
     */
    public static Operator generateAncestorPlan (AkibanInformationSchema ais, Table table) {
        final Schema schema = SchemaCache.globalSchema(ais);
        TableRowType tableType = schema.tableRowType(table);

        List<TableRowType> ancestorType = new ArrayList<>(1);
        ancestorType.add (tableType);

        IndexRowType indexType = schema.indexRowType(table.getPrimaryKeyIncludingInternal().getIndex());
       
        Operator indexScan = generateIndexScan (ais, table);
        Operator lookup = API.groupLookup_Default(indexScan,
                table.getGroup(),
                indexType,
                ancestorType,
                API.InputPreservationOption.DISCARD_INPUT,
                1);
        if (logger.isDebugEnabled()) {
            DefaultFormatter formatter = new DefaultFormatter(table.getName().getSchemaName());
            logger.debug("Ancestor Plan for {}:\n{}", table,
                         join(formatter.format(lookup.getExplainer(new ExplainContext()))));
        }
        return lookup;
    }
   
    /**
     * Generate an index scan of the table based upon the table's primary key
     * Values for the scan are set as parameters in the PK order.
     * @param ais
     * @param table
     * @return Operator plan for the Index scan
     */
    private static Operator generateIndexScan (AkibanInformationSchema ais, Table table) {
        final Schema schema = SchemaCache.globalSchema(ais);
        PrimaryKey pkey = table.getPrimaryKeyIncludingInternal();
        final int nkeys = pkey.getColumns().size();
        IndexRowType indexType = schema.indexRowType(pkey.getIndex());

        List<TPreparedExpression> pexprs = new ArrayList<>(nkeys);
        for (int i = 0; i < nkeys; i++) {
            pexprs.add(new TPreparedParameter(i, indexType.typeAt(i)));
        }
        IndexBound bound =
            new IndexBound(new RowBasedUnboundExpressions(indexType, pexprs),
                           new ColumnSelector() {
                               @Override
                               public boolean includesColumn(int columnPosition) {
                                   return columnPosition < nkeys;
                               }
                           });
        IndexKeyRange indexRange = IndexKeyRange.bounded(indexType,
                                                         bound, true,
                                                         bound, true);

        Ordering ordering = API.ordering();
        for (int i = 0; i < nkeys; i++) {
            ordering.append(new TPreparedField(indexType.typeAt(i), i),
                            false);
        }

        return API.indexScan_Default(indexType, indexRange, ordering);
    }

    /**
     * Generate an expression for a column's default value. {@code expression} may
     * be {@code null} if none was provided (e.g. from user).
     */
    public static TPreparedExpression generateDefaultExpression(Column column,
                                                                TPreparedExpression expression,
                                                                TypesRegistryService typesService,
                                                                TypesTranslator typesTranslator,
                                                                QueryContext queryContext) {
        Sequence sequence = column.getIdentityGenerator();
        if ((sequence != null) && Boolean.FALSE.equals(column.getDefaultIdentity())) {
            // FALSE => ALWAYS, override user value even if present
            expression = new TSequenceNextValueExpression(column.getType(), sequence);
        }
        else if (expression == null) {
            TInstance type = column.getType();
            if (sequence != null) {
                expression = new TSequenceNextValueExpression(type, sequence);
            }
            else if (column.getDefaultFunction() != null) {
                OverloadResolver<TValidatedScalar> resolver = typesService.getScalarsResolver();
                TValidatedScalar overload = resolver.get(column.getDefaultFunction(),
                                                         Collections.<TPreptimeValue>emptyList()).getOverload();
                TInstance dinst = overload.resultStrategy().fixed(false);
                TPreparedExpression defExpr = new TPreparedFunction(overload,
                                                                    dinst,
                                                                    Collections.<TPreparedExpression>emptyList());
                if (!dinst.equals(type)) {
                    TCast tcast = typesService.getCastsResolver().cast(dinst.typeClass(), type.typeClass());
                    defExpr = new TCastExpression(defExpr, tcast, type);
                }
                expression = defExpr;
            }
            else {
                final String defaultValue = column.getDefaultValue();
                final Value defaultValueSource;
                if(defaultValue == null) {
                    defaultValueSource = new Value(type);
                    defaultValueSource.putNull();
                } else {
                    TCast cast = type.typeClass().castFromVarchar();
                    if (cast != null) {
                        defaultValueSource = new Value(type);
                        TInstance valInst = typesTranslator.typeForString(defaultValue);
                        TExecutionContext executionContext = new TExecutionContext(Collections.singletonList(valInst),
                                                                                   type,
                                                                                   queryContext);
                        cast.evaluate(executionContext,
                                      new Value(valInst, defaultValue),
                                      defaultValueSource);
                    } else {
                        defaultValueSource = new Value(type, defaultValue);
                    }
                }
                expression = new TPreparedLiteral(type, defaultValueSource);
            }
        }
        return expression;
    }
}
TOP

Related Classes of com.foundationdb.sql.optimizer.rule.PlanGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.