package com.tesora.dve.sql.schema;
/*
* #%L
* Tesora Inc.
* Database Virtualization Engine
* %%
* Copyright (C) 2011 - 2014 Tesora Inc.
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* 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/>.
* #L%
*/
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.tesora.dve.common.PEStringUtils;
import com.tesora.dve.common.catalog.PersistentTable;
import com.tesora.dve.common.catalog.TableState;
import com.tesora.dve.common.catalog.UserTable;
import com.tesora.dve.exceptions.PEException;
import com.tesora.dve.resultset.ResultRow;
import com.tesora.dve.sql.schema.modifiers.TableModifier;
import com.tesora.dve.sql.util.Functional;
import com.tesora.dve.sql.util.IsInstance;
import com.tesora.dve.sql.util.ListSet;
import com.tesora.dve.sql.util.UnaryPredicate;
// specifically for handling tables created via create table as select and
// userland temporary tables. we use a separate class so that we can compose both
// behaviors.
public class ComplexPETable extends PETable implements AutoIncrement {
// for a temporary table I think we want to use a qualified name here maybe
public ComplexPETable(SchemaContext pc, Name name,
List<TableComponent<?>> fieldsAndKeys, DistributionVector dv,
List<TableModifier> modifier, PEPersistentGroup defStorage,
PEDatabase db, TableState theState) {
super(pc, name, fieldsAndKeys, dv, modifier, defStorage, db, theState);
// TODO Auto-generated constructor stub
}
private ListSet<ComplexTableType> types = new ListSet<ComplexTableType>();
public ComplexPETable withTemporaryTable(SchemaContext sc) {
TemporaryTableType ttt = new TemporaryTableType();
ttt.setDatabaseName(super.getDatabaseName(sc));
if (hasAutoInc())
ttt.setHasAutoIncrement(0);
types.add(ttt);
return this;
}
public ComplexPETable withCTA() {
types.add(new CTATableType());
return this;
}
@Override
public Name getDatabaseName(SchemaContext sc) {
for(ComplexTableType ctt : types) {
Name n = ctt.getDatabaseName();
if (n != null)
return n;
}
return super.getDatabaseName(sc);
}
public void setDatabaseName(Name n) {
for(ComplexTableType ctt : types) {
ctt.setDatabaseName(n);
}
}
@Override
public boolean mustBeCreated() {
return Functional.any(types, ComplexTableType.created);
}
@Override
public PersistentTable getPersistentTable(SchemaContext sc) {
if (cached == null) {
if (Functional.any(types,ComplexTableType.persistentTable)) {
cached = new CachedPETable(sc,this);
}
}
return cached;
}
@Override
public UserTable persistTree(SchemaContext sc, boolean forRefresh) throws PEException {
TemporaryTableType ttt = getTemporaryTableType();
if (ttt != null && !ttt.isPersisted())
return null;
return super.persistTree(sc, forRefresh);
}
public UserTable buildUserTableForRedist(SchemaContext sc) throws PEException {
TemporaryTableType ttt = getTemporaryTableType();
Boolean mutWas = sc.getMutableSourceOverride();
try {
if (ttt != null) {
sc.setMutableSourceOverride(true);
ttt.setPersisted();
}
return super.persistTree(sc, false);
} finally {
sc.setMutableSourceOverride(mutWas);
if (ttt != null)
ttt.clearPersisted();
}
}
@Override
public PETable recreate(SchemaContext sc, String decl, LockInfo li) {
PETable recreated = super.recreate(sc,decl, li).asTable();
if (isUserlandTemporaryTable()) {
// copy over the autoinc value
ComplexPETable pettab = (ComplexPETable) recreated;
TemporaryTableType mtt = getTemporaryTableType();
TemporaryTableType ytt = pettab.getTemporaryTableType();
if (mtt.hasAutoIncrement()) {
ytt.setHasAutoIncrement(mtt.readAutoIncrBlock(null));
}
}
return recreated;
}
private TemporaryTableType getTemporaryTableType() {
List<ComplexTableType> any = Functional.select(types, isTemporaryTable);
if (any.isEmpty())
return null;
return (TemporaryTableType) any.get(0);
}
private static final IsInstance<ComplexTableType> isTemporaryTable =
new IsInstance<ComplexTableType>(TemporaryTableType.class);
@Override
public boolean isUserlandTemporaryTable() {
return Functional.any(types, isTemporaryTable);
}
public static abstract class ComplexTableType {
public abstract boolean hasPersistentTable();
public abstract boolean mustBeCreated();
public void setDatabaseName(Name n) {
// default does nothing
}
public Name getDatabaseName() {
return null;
}
public static final UnaryPredicate<ComplexTableType> persistentTable = new UnaryPredicate<ComplexTableType>() {
@Override
public boolean test(ComplexTableType object) {
return object.hasPersistentTable();
}
};
public static final UnaryPredicate<ComplexTableType> created = new UnaryPredicate<ComplexTableType>() {
@Override
public boolean test(ComplexTableType object) {
return object.mustBeCreated();
}
};
}
public static class CTATableType extends ComplexTableType {
@Override
public boolean hasPersistentTable() {
return true;
}
@Override
public boolean mustBeCreated() {
return true;
}
}
public static class TemporaryTableType extends ComplexTableType implements AutoIncrement {
private Name dbName;
private long autoincValue = -1; // unused
private boolean persist = false;
@Override
public boolean hasPersistentTable() {
return true;
}
@Override
public boolean mustBeCreated() {
return false;
}
@Override
public void setDatabaseName(Name n) {
dbName = n;
}
@Override
public Name getDatabaseName() {
return dbName;
}
@Override
public long getNextAutoIncrBlock(SchemaContext sc, long blockSize) {
long current = autoincValue;
autoincValue += blockSize;
return current;
}
@Override
public long readAutoIncrBlock(SchemaContext sc) {
return autoincValue;
}
@Override
public void removeValue(SchemaContext sc, long value) {
if (value > autoincValue) {
autoincValue = value+1;
}
}
public void setHasAutoIncrement(long v) {
autoincValue = v;
}
public boolean hasAutoIncrement() {
return autoincValue > -1;
}
void setPersisted() {
persist = true;
}
void clearPersisted() {
persist = false;
}
boolean isPersisted() {
return persist;
}
}
@Override
public long getNextAutoIncrBlock(SchemaContext sc, long blockSize) {
TemporaryTableType ttt = getTemporaryTableType();
if (ttt == null) return -1;
return ttt.getNextAutoIncrBlock(sc, blockSize);
}
@Override
public long readAutoIncrBlock(SchemaContext sc) {
TemporaryTableType ttt = getTemporaryTableType();
if (ttt == null) return -1;
return ttt.readAutoIncrBlock(sc);
}
@Override
public void removeValue(SchemaContext sc, long value) {
TemporaryTableType ttt = getTemporaryTableType();
if (ttt == null) return;
ttt.removeValue(sc, value);
}
// to say that this is a leaky vacuum chamber is an understatement.
public List<ResultRow> getShowColumns(final SchemaContext sc, String likeExpr) {
// religious expletive is this vacuum chamber busted
Pattern filtered = null;
if (likeExpr != null)
filtered = PEStringUtils.buildSQLPattern(likeExpr);
ArrayList<ResultRow> out = new ArrayList<ResultRow>();
for(PEColumn pec : getColumns(sc)) {
if (filtered != null) {
String n = pec.getName().getUnquotedName().get();
Matcher m = filtered.matcher(n);
if (!m.matches())
continue;
}
out.add(pec.buildRow(sc));
}
return out;
}
public List<ResultRow> getShowKeys(SchemaContext sc) {
ArrayList<ResultRow> out = new ArrayList<ResultRow>();
for(PEKey pek : getKeys(sc)) {
List<ResultRow> sub = pek.buildRow(sc);
if (sub == null) continue;
out.addAll(sub);
}
return out;
}
}