/**
* 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.pg;
import com.foundationdb.ais.model.*;
import com.foundationdb.server.store.statistics.IndexStatisticsService;
import com.foundationdb.server.store.statistics.IndexStatisticsYamlTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import java.sql.*;
import java.util.*;
import java.io.File;
public class IndexStatisticsLifecycleIT extends PostgresServerFilesITBase
{
public static final File RESOURCE_DIR = new File(PostgresServerITBase.RESOURCE_DIR, "stats");
@Before
public void loadDatabase() throws Exception {
loadDatabase(RESOURCE_DIR);
}
protected Statement executeStatement;
protected Statement checkStatement;
protected final String CHECK_SQL = "SELECT header.table_id, header.index_id, COUNT(detail.column_count) AS ndetail FROM "+
IndexStatisticsService.INDEX_STATISTICS_TABLE_NAME.getDescription() + " header LEFT JOIN " +
IndexStatisticsService.INDEX_STATISTICS_ENTRY_TABLE_NAME.getDescription() + " detail USING (table_id, index_id) GROUP BY header.table_id, header.index_id";
@Before
public void prepareStatements() throws Exception {
executeStatement = getConnection().createStatement();
checkStatement = getConnection().createStatement();
}
@After
public void closeStatements() throws Exception {
checkStatement.close();
executeStatement.close();
}
// Check what stats are in the database. Do this using the
// information_schema instead of any IndexStatistics API so
// as to detect problems with the loader / caches, etc.
protected Map<Index,Integer> check() throws Exception {
Map<Index,Integer> result = new HashMap<>();
AkibanInformationSchema ais = ddl().getAIS(session());
ResultSet rs = checkStatement.executeQuery(CHECK_SQL);
while (rs.next()) {
int tableId = rs.getInt(1);
int indexId = rs.getInt(2);
int count = rs.getInt(3);
Table table = null;
Index index = null;
Table aTable = ais.getTable(tableId);
if (aTable != null) {
table = aTable;
for (TableIndex tindex : aTable.getIndexesIncludingInternal()) {
if (tindex.getIndexId() == indexId) {
index = tindex;
break;
}
}
if (index == null) {
for (GroupIndex gindex : aTable.getGroupIndexes()) {
if (gindex.getIndexId() == indexId) {
index = gindex;
break;
}
}
}
}
assertNotNull("Table id refers to table", table);
assertNotNull("Index id refers to index", index);
assertTrue("Stats have some entries", (count > 0));
if (table.getName().getSchemaName().equals(SCHEMA_NAME))
result.put(index, count);
}
return result;
}
@Test
public void test() throws Exception {
Map<Index,Integer> entries;
entries = check();
assertTrue("No stats before analyze", entries.isEmpty());
executeStatement.executeUpdate("ALTER TABLE parent ALL UPDATE STATISTICS");
executeStatement.executeUpdate("ALTER TABLE child ALL UPDATE STATISTICS");
entries = check();
assertTrue("Some stats before analyze", !entries.isEmpty());
AkibanInformationSchema ais = ddl().getAIS(session());
TableIndex parentPK = ais.getTable(SCHEMA_NAME, "parent").getIndex("PRIMARY");
Integer parentPKCount = entries.get(parentPK);
assertNotNull("parent PK was analyzed", parentPKCount);
assertEquals("parent PK two entries", 2, parentPKCount.intValue());
TableIndex parentName = ais.getTable(SCHEMA_NAME, "parent").getIndex("name");
Integer parentNameCount = entries.get(parentName);
assertNotNull("parent name was analyzed", parentNameCount);
assertEquals("parent name two entries", 2, parentNameCount.intValue());
GroupIndex bothValue = ais.getGroup(new TableName(SCHEMA_NAME, "parent")).getIndex("value");
Integer bothValueCount = entries.get(bothValue);
assertNotNull("group index was analyzed", bothValueCount);
assertEquals("group index two entries", 6, bothValueCount.intValue());
executeStatement.executeUpdate("DROP INDEX parent.name");
entries = check();
ais = ddl().getAIS(session());
parentPK = ais.getTable(SCHEMA_NAME, "parent").getIndex("PRIMARY");
bothValue = ais.getGroup(new TableName(SCHEMA_NAME , "parent")).getIndex("value");
parentPKCount = entries.get(parentPK);
bothValueCount = entries.get(bothValue);
assertEquals("parent PK intact after name drop", 2, parentPKCount.intValue());
assertEquals("group index intact after name drop", 6, bothValueCount.intValue());
executeStatement.executeUpdate("DROP INDEX value");
entries = check();
ais = ddl().getAIS(session());
parentPK = ais.getTable(SCHEMA_NAME, "parent").getIndex("PRIMARY");
parentPKCount = entries.get(parentPK);
assertEquals("parent PK intact after group indx drop", 2, parentPKCount.intValue());
executeStatement.executeUpdate("DROP TABLE child");
entries = check();
ais = ddl().getAIS(session());
parentPK = ais.getTable(SCHEMA_NAME, "parent").getIndex("PRIMARY");
parentPKCount = entries.get(parentPK);
assertEquals("parent PK intact after child drop", 2, parentPKCount.intValue());
executeStatement.executeUpdate("DROP TABLE parent");
entries = check();
assertTrue("No stats after drop group", entries.isEmpty());
}
}