package com.tesora.dve.sql.util;
/*
* #%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.HashSet;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import com.tesora.dve.common.catalog.FKMode;
import com.tesora.dve.common.catalog.MultitenantMode;
import com.tesora.dve.exceptions.PEException;
import com.tesora.dve.resultset.ResultColumn;
import com.tesora.dve.resultset.ResultRow;
import com.tesora.dve.sql.parser.ParserInvoker.LineTag;
import com.tesora.dve.sql.parser.ParserInvoker.TaggedLineInfo;
public class PEDDL extends ProjectDDL {
private List<StorageGroupDDL> persGroups;
private boolean tenant = false;
private boolean throwDropRangeInUseException = true;
private List<String> templateDeclarations = new ArrayList<String>();
public PEDDL() {
super();
persGroups = new ArrayList<StorageGroupDDL>();
}
public PEDDL(PEDDL other) {
super(other);
persGroups = other.persGroups;
this.templateDeclarations = new ArrayList<String>(other.templateDeclarations);
}
@Override
public StorageGroupDDL getPersistentGroup() {
return persGroups.get(0);
}
public PEDDL withStorageGroup(StorageGroupDDL sgddl) {
persGroups.add(sgddl);
return this;
}
@Override
public List<String> getCreateStatements() throws Exception {
ArrayList<String> buf = new ArrayList<String>();
if (!tenant) {
for(StorageGroupDDL sgddl : persGroups) {
buf.addAll(sgddl.getCreateStatements());
}
buf.addAll(templateDeclarations);
for(DatabaseDDL dbddl : getDatabases()) {
buf.addAll(dbddl.getCreateStatements());
}
setCreated();
}
buf.add("use " + getDatabases().get(0).getDatabaseName());
return buf;
}
// our destroy is now slightly more complicated - in addition to dropping the db
// we also have to drop ranges, persistent groups
@Override
public void destroy(ConnectionResource mr) throws Throwable {
if(mr == null)
return;
TaggedLineInfo tli = new TaggedLineInfo(-1,null,-1,LineTag.DDL);
// drop all the dbs
for(DatabaseDDL dbddl : getDatabases())
mr.execute(tli, dbddl.getDropStatement());
HashSet<String> pgnames = new HashSet<String>();
for(StorageGroupDDL sgddl : persGroups)
pgnames.add(sgddl.getName());
ResourceResponse rr = mr.fetch("show containers");
List<ResultRow> results = rr.getResults();
for(ResultRow row : results) {
ResultColumn rc = row.getResultColumn(1);
String contName = (String) rc.getColumnValue();
mr.execute(tli,"drop container " + contName);
}
// now we have to find ranges that use our persistent group
rr = mr.fetch("show ranges");
results = rr.getResults();
for(ResultRow row : results) {
ResultColumn rangeNameColumn = row.getResultColumn(1);
ResultColumn storageGroupColumn = row.getResultColumn(2);
String rangeName = rangeNameColumn.getColumnValue().getClass().isArray() ?
new String((byte[])rangeNameColumn.getColumnValue()) : (String)rangeNameColumn.getColumnValue();
String groupName = storageGroupColumn.getColumnValue().getClass().isArray() ?
new String((byte[])storageGroupColumn.getColumnValue()) : (String ) storageGroupColumn.getColumnValue();
if (pgnames.contains(groupName.trim())) {
try {
mr.execute(tli,"drop range " + rangeName + " persistent group " + groupName.trim());
} catch (PEException e) {
if (!throwDropRangeInUseException && (StringUtils.containsIgnoreCase(e.getMessage(), "Unable to drop range") &&
StringUtils.containsIgnoreCase(e.getMessage(), "because used by table"))) {
// eat the exception
} else {
throw e;
}
}
}
}
// now we can drop the persistent group, which apparently also drops the persistent sites
for(StorageGroupDDL sgddl : persGroups) {
sgddl.destroy(mr);
}
}
@Override
public List<String> getSetupDrops() {
ArrayList<String> buf = new ArrayList<String>();
ArrayList<String> nativeDrops = new ArrayList<String>();
for(DatabaseDDL dbddl : getDatabases()) {
buf.addAll(dbddl.getSetupDrops());
for(StorageGroupDDL sgddl : persGroups) {
nativeDrops.addAll(sgddl.getSetupDrops(dbddl.getDatabaseName()));
}
}
buf.addAll(nativeDrops);
return buf;
}
// for mt support - the database name of the tenant is different than the database name of the landlord
@Override
public PEDDL buildTenantDDL(String tenantName) {
PEDDL copy = new PEDDL(this);
if (getDatabases().size() > 1)
throw new IllegalStateException("Cannot build tenant ddl: more than one database");
getDatabases().get(0).dbn = tenantName;
copy.created = true; // tenants never create
copy.tenant = true;
return copy;
}
@Override
public List<String> getDestroyStatements() throws Exception {
throw new IllegalStateException("PEDDL does not use destroy statements");
}
// these are all compatibility constructors and functions
public PEDDL(String dbname, StorageGroupDDL persGroup, String dbtag) {
this(dbname,persGroup,dbtag,null,null);
}
public PEDDL(String dbname, StorageGroupDDL persGroup, String dbtag, String charset, String collation) {
super();
persGroups = new ArrayList<StorageGroupDDL>();
withStorageGroup(persGroup);
withDatabase(new PEDatabaseDDL(dbname,dbtag,charset,collation).withStorageGroup(persGroup));
}
public PEDDL withTemplate(String temp, boolean strict) {
getSinglePEDB().withTemplate(temp, strict);
return this;
}
public PEDDL withMTMode(MultitenantMode mm) {
getSinglePEDB().withMTMode(mm);
return this;
}
public PEDDL withFKMode(FKMode fkm) {
getSinglePEDB().withFKMode(fkm);
return this;
}
public PEDDL withTemplateDeclarations(String...decls) {
for(String s : decls) {
templateDeclarations.add(s);
}
if (templateDeclarations.size() > 0) {
for(DatabaseDDL db : getDatabases()) {
PEDatabaseDDL pedb = (PEDatabaseDDL) db;
pedb.withLoadTemplate(false);
}
}
return this;
}
public MultitenantMode getMultitenantMode() {
return getSinglePEDB().getMultitenantMode();
}
public FKMode getForeignKeyMode() {
return getSinglePEDB().getForeignKeyMode();
}
protected PEDatabaseDDL getSinglePEDB() {
return (PEDatabaseDDL) super.getSingleDB();
}
@Override
public void clearCreated() {
super.clearCreated();
// also do the same on persistent groups
for(StorageGroupDDL sgddl : persGroups)
sgddl.clearCreated();
}
public PEDDL setThrowDropRangeInUseException(boolean value) {
this.throwDropRangeInUseException = value;
return this;
}
}