/**
* 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.server.test.it.dxl;
import com.foundationdb.ais.model.Table;
import com.foundationdb.qp.row.Row;
import com.foundationdb.server.error.InvalidOperationException;
import com.foundationdb.server.test.it.ITBase;
import org.junit.Test;
import java.util.List;
import static org.junit.Assert.*;
public final class TruncateTableIT extends ITBase {
@Test
public void basic() throws InvalidOperationException {
int tableId = createTable("test", "t", "id int not null primary key");
final int rowCount = 5;
for(int i = 1; i <= rowCount; ++i) {
writeRow(tableId, i);
}
expectRowCount(tableId, rowCount);
dml().truncateTable(session(), tableId);
// Check table stats
expectRowCount(tableId, 0);
// Check table scan
List<Row> rows = scanAll(tableId);
assertEquals("Rows scanned", 0, rows.size());
}
/*
* Bug appeared after truncate was implemented as 'scan all rows and delete'.
* Manifested as a corrupt RowData when doing a non-primary index scan after the truncate.
* Store requires all index columns be present in the passed row.
*/
@Test
public void bug687225() throws InvalidOperationException {
int tableId = createTable("test",
"t",
"id int NOT NULL, pid int NOT NULL, PRIMARY KEY(id), UNIQUE(pid)");
writeRows(row(tableId, 1, 1),
row(tableId, 2, 2));
expectRowCount(tableId, 2);
dml().truncateTable(session(), tableId);
int indexId = ddl().getAIS(session()).getTable("test", "t").getIndex("pid").getIndexId();
// Exception originally thrown during dml.doScan: Corrupt RowData at {1,(long)1}
List<Row> rows = scanAll(tableId, indexId);
assertEquals("Rows scanned", 0, rows.size());
}
@Test
public void multipleIndex() throws InvalidOperationException {
int tableId = createTable("test",
"t",
"id int not null primary key, tag int, value decimal(10,2), other char(1), name varchar(32), unique(name)");
createIndex("test", "t", "value", "value");
writeRows(row(tableId, 1, 1234, "10.50", "a", "foo"),
row(tableId, 2, -421, "14.99", "b", "bar"),
row(tableId, 3, 1337, "100.5", "c", "zap"),
row(tableId, 4, -987, "12.95", "d", "dob"),
row(tableId, 5, 3409, "99.00", "e", "eek"));
expectRowCount(tableId, 5);
dml().truncateTable(session(), tableId);
// Check table stats
expectRowCount(tableId, 0);
final Table table = ddl().getTable(session(), tableId);
final int pkeyIndexId = table.getIndex("PRIMARY").getIndexId();
final int valueIndexId = table.getIndex("value").getIndexId();
final int nameIndexId = table.getIndex("name").getIndexId();
// Scan on primary key
List<Row> rows = scanAll(tableId, pkeyIndexId);
assertEquals("Rows scanned", 0, rows.size());
// Scan on index
rows = scanAll(tableId, valueIndexId);
assertEquals("Rows scanned", 0, rows.size());
// Scan on unique index
rows = scanAll(tableId, nameIndexId);
assertEquals("Rows scanned", 0, rows.size());
// Table scan
rows = scanAll(tableId);
assertEquals("Rows scanned", 0, rows.size());
}
@Test
public void truncateParentNoChildRows() throws InvalidOperationException {
int parentId = createTable("test",
"parent",
"id int not null primary key");
int childId = createTable("test",
"child",
"id int not null primary key, pid int, grouping foreign key (pid) references parent(id)");
writeRow(parentId, 1);
expectRowCount(parentId, 1);
dml().truncateTable(session(), parentId);
expectRowCount(parentId, 0);
List<Row> rows = scanAll(parentId);
assertEquals("Rows scanned", 0, rows.size());
}
@Test
public void truncateParentWithChildRows() throws InvalidOperationException {
int parentId = createTable("test",
"parent",
"id int not null primary key");
int childId = createTable("test",
"child",
"id int not null primary key, pid int, grouping foreign key (pid) references parent(id)");
writeRow(parentId, 1);
expectRowCount(parentId, 1);
writeRow(childId, 1, 1);
expectRowCount(childId, 1);
dml().truncateTable(session(), parentId);
expectRowCount(parentId, 0);
List<Row> rows = scanAll(parentId);
assertEquals("Rows scanned", 0, rows.size());
expectRowCount(childId, 1);
rows = scanAll(childId);
assertEquals("Rows scanned", 1, rows.size());
}
@Test
public void tableWithNoPK() throws InvalidOperationException {
int tableId = createTable("test", "t", "c1 CHAR(10) NOT NULL");
writeRows(row(tableId, "a"),
row(tableId, "aaa"),
row(tableId, "b"),
row(tableId, "b"),
row(tableId, "bb"),
row(tableId, "bbb"),
row(tableId, "c"));
expectRowCount(tableId, 7);
dml().truncateTable(session(), tableId);
// Check table stats
expectRowCount(tableId, 0);
// Check table scan
List<Row> rows = scanAll(tableId);
assertEquals("Rows scanned", 0, rows.size());
}
// bug1024501: Truncate table incorrectly deletes entire group
@Test
public void truncateOFromCOIAllWithRows() throws InvalidOperationException {
int cId = createTable("test", "c", "id int not null primary key");
int oId = createTable("test", "o", "id int not null primary key, cid int, grouping foreign key (cid) references c(id)");
int iId = createTable("test", "i", "id int not null primary key, oid int, grouping foreign key (oid) references o(id)");
writeRow(cId, 1);
writeRow(oId, 10, 1);
writeRow(iId, 100, 10);
expectRowCount(cId, 1);
expectRowCount(oId, 1);
expectRowCount(iId, 1);
dml().truncateTable(session(), cId);
expectRowCount(cId, 0);
expectRowCount(oId, 1);
expectRowCount(iId, 1);
dml().truncateTable(session(), oId);
expectRowCount(cId, 0);
expectRowCount(oId, 0);
expectRowCount(iId, 1);
dml().truncateTable(session(), iId);
expectRowCount(cId, 0);
expectRowCount(oId, 0);
expectRowCount(iId, 0);
}
@Test
public void truncateCascade() throws InvalidOperationException {
int cId = createTable("test", "c", "id int not null primary key");
int oId = createTable("test", "o", "id int not null primary key, cid int, grouping foreign key (cid) references c(id)");
int iId = createTable("test", "i", "id int not null primary key, oid int, grouping foreign key (oid) references o(id)");
int aId = createTable("test", "a", "id int not null primary key, cid int, grouping foreign key (cid) references c(id)");
writeRow(cId, 1);
writeRow(oId, 10, 1);
writeRow(iId, 100, 10);
writeRow(aId, 10, 1);
expectRowCount(cId, 1);
expectRowCount(oId, 1);
expectRowCount(iId, 1);
expectRowCount(aId, 1);
dml().truncateTable(session(), cId, true);
expectRowCount(cId, 0);
expectRowCount(oId, 0);
expectRowCount(iId, 0);
expectRowCount(aId, 0);
writeRow(cId, 1);
writeRow(oId, 10, 1);
writeRow(iId, 100, 10);
writeRow(aId, 10, 1);
expectRowCount(cId, 1);
expectRowCount(oId, 1);
expectRowCount(iId, 1);
expectRowCount(aId, 1);
dml().truncateTable(session(), oId, true);
expectRowCount(cId, 1);
expectRowCount(oId, 0);
expectRowCount(iId, 0);
expectRowCount(aId, 1);
dml().truncateTable(session(), cId, true);
expectRowCount(cId, 0);
expectRowCount(oId, 0);
expectRowCount(iId, 0);
expectRowCount(aId, 0);
writeRow(oId, 10, 1);
writeRow(iId, 100, 10);
expectRowCount(cId, 0);
expectRowCount(oId, 1);
expectRowCount(iId, 1);
expectRowCount(aId, 0);
dml().truncateTable(session(), oId, true);
expectRowCount(cId, 0);
expectRowCount(oId, 0);
expectRowCount(iId, 0);
expectRowCount(aId, 0);
}
}