http://git-wip-us.apache.org/repos/asf/phoenix/blob/15a54d55/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java 
b/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
index 9b744e1..b5945d0 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
@@ -36,15 +36,19 @@ import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.INDEX_DISABLE_TIME
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.INDEX_STATE;
 import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.IS_VIEW_REFERENCED;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.KEY_SEQ;
+import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.LAST_STATS_UPDATE_TIME;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.LINK_TYPE;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.MULTI_TENANT;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.NULLABLE;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.ORDINAL_POSITION;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PHYSICAL_NAME;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PK_NAME;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.REGION_NAME;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SALT_BUCKETS;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SORT_ORDER;
 import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CATALOG_SCHEMA;
 import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CATALOG_TABLE;
+import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_STATS_TABLE;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_NAME;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_SCHEM;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_SEQ_NUM;
@@ -59,8 +63,10 @@ import static 
org.apache.phoenix.query.QueryServicesOptions.DEFAULT_DROP_METADAT
 import static org.apache.phoenix.schema.PDataType.VARCHAR;
 
 import java.io.IOException;
+import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.PreparedStatement;
+import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
 import java.sql.SQLFeatureNotSupportedException;
@@ -113,6 +119,8 @@ import org.apache.phoenix.parse.NamedTableNode;
 import org.apache.phoenix.parse.ParseNodeFactory;
 import org.apache.phoenix.parse.PrimaryKeyConstraint;
 import org.apache.phoenix.parse.TableName;
+import org.apache.phoenix.parse.UpdateStatisticsStatement;
+import org.apache.phoenix.query.KeyRange;
 import org.apache.phoenix.query.QueryConstants;
 import org.apache.phoenix.query.QueryServices;
 import org.apache.phoenix.query.QueryServicesOptions;
@@ -122,6 +130,7 @@ import org.apache.phoenix.util.ByteUtil;
 import org.apache.phoenix.util.IndexUtil;
 import org.apache.phoenix.util.MetaDataUtil;
 import org.apache.phoenix.util.PhoenixRuntime;
+import org.apache.phoenix.util.ScanUtil;
 import org.apache.phoenix.util.SchemaUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -450,6 +459,55 @@ public class MetaDataClient {
         return connection.getQueryServices().updateData(plan);
     }
 
+    public MutationState updateStatistics(UpdateStatisticsStatement 
updateStatisticsStmt) throws SQLException {
+        // Check before updating the stats if we have reached the configured 
time to reupdate the stats once again
+        long minTimeForStatsUpdate = connection.getQueryServices().getProps()
+                .getLong(QueryServices.STATS_UPDATE_FREQ_MS_ATTRIB, 
QueryServicesOptions.DEFAULT_STATS_UPDATE_FREQ_MS);
+        ColumnResolver resolver = 
FromCompiler.getResolver(updateStatisticsStmt, connection);
+        PTable table = resolver.getTables().get(0).getTable();
+        PName physicalName = table.getPhysicalName();
+        byte[] tenantIdBytes = ByteUtil.EMPTY_BYTE_ARRAY;
+        KeyRange analyzeRange = KeyRange.EVERYTHING_RANGE;
+        if (connection.getTenantId() != null && table.isMultiTenant()) {
+            tenantIdBytes = connection.getTenantId().getBytes();
+            //  TODO remove this inner if once PHOENIX-1259 is fixed.
+            if (table.getBucketNum() == null) {
+                List<List<KeyRange>> tenantIdKeyRanges = 
Collections.singletonList(Collections.singletonList(KeyRange
+                        .getKeyRange(tenantIdBytes)));
+                byte[] lowerRange = 
ScanUtil.getMinKey(table.getRowKeySchema(), tenantIdKeyRanges,
+                        ScanUtil.SINGLE_COLUMN_SLOT_SPAN);
+                byte[] upperRange = 
ScanUtil.getMaxKey(table.getRowKeySchema(), tenantIdKeyRanges,
+                        ScanUtil.SINGLE_COLUMN_SLOT_SPAN);
+                analyzeRange = KeyRange.getKeyRange(lowerRange, upperRange);
+            }
+        }
+        Long scn = connection.getSCN();
+        // Always invalidate the cache
+        long clientTS = connection.getSCN() == null ? 
HConstants.LATEST_TIMESTAMP : scn;
+        connection.getQueryServices().clearCacheForTable(tenantIdBytes, 
table.getSchemaName().getBytes(),
+                table.getTableName().getBytes(), clientTS);
+        // Clear the cache also. So that for cases like major compaction also 
we would be able to use the stats
+        updateCache(table.getSchemaName().getString(), 
table.getTableName().getString(), true);
+        String query = "SELECT CURRENT_DATE(),"+ LAST_STATS_UPDATE_TIME + " 
FROM " + SYSTEM_CATALOG_SCHEMA
+                + "." + SYSTEM_STATS_TABLE + " WHERE " + PHYSICAL_NAME + "='" 
+ physicalName.getString() + "' AND " + COLUMN_FAMILY
+                + " IS NULL AND " + REGION_NAME + " IS NULL";
+        ResultSet rs = connection.createStatement().executeQuery(query);
+        long lastUpdatedTime = 0;
+        if (rs.next() && rs.getDate(2) != null) {
+            lastUpdatedTime = rs.getDate(1).getTime() - 
rs.getDate(2).getTime();
+        }
+        if (minTimeForStatsUpdate  > lastUpdatedTime) {
+            // We need to update the stats table
+            connection.getQueryServices().updateStatistics(analyzeRange, 
physicalName.getBytes());
+            connection.getQueryServices().clearCacheForTable(tenantIdBytes, 
table.getSchemaName().getBytes(),
+                    table.getTableName().getBytes(), clientTS);
+            updateCache(table.getSchemaName().getString(), 
table.getTableName().getString(), true);
+            return new MutationState(1, connection);
+        } else {
+            return new MutationState(0, connection);
+        }
+    }
+
     private MutationState buildIndexAtTimeStamp(PTable index, NamedTableNode 
dataTableNode) throws SQLException {
         // If our connection is at a fixed point-in-time, we need to open a new
         // connection so that our new index table is visible.
@@ -1320,7 +1378,8 @@ public class MetaDataClient {
         return dropTable(schemaName, tableName, parentTableName, 
PTableType.INDEX, statement.ifExists(), false);
     }
 
-    private MutationState dropTable(String schemaName, String tableName, 
String parentTableName, PTableType tableType, boolean ifExists, boolean 
cascade) throws SQLException {
+    private MutationState dropTable(String schemaName, String tableName, 
String parentTableName, PTableType tableType,
+            boolean ifExists, boolean cascade) throws SQLException {
         connection.rollback();
         boolean wasAutoCommit = connection.getAutoCommit();
         try {
@@ -1385,6 +1444,7 @@ public class MetaDataClient {
                             for (PTable index: table.getIndexes()) {
                                 tableRefs.add(new TableRef(null, index, ts, 
false));
                             }
+                            deleteFromStatsTable(tableRefs, ts);
                             MutationPlan plan = new 
PostDDLCompiler(connection).compile(tableRefs, null, null, 
Collections.<PColumn>emptyList(), ts);
                             return 
connection.getQueryServices().updateData(plan);
                         }
@@ -1396,6 +1456,41 @@ public class MetaDataClient {
             connection.setAutoCommit(wasAutoCommit);
         }
     }
+    
+    private void deleteFromStatsTable(List<TableRef> tableRefs, long ts) 
throws SQLException {
+        Properties props = new Properties(connection.getClientInfo());
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, 
Long.toString(ts));
+        Connection conn = DriverManager.getConnection(connection.getURL(), 
props);
+        conn.setAutoCommit(true);
+        boolean success = false;
+        SQLException sqlException = null;
+        try {
+            StringBuilder buf = new StringBuilder("DELETE FROM SYSTEM.STATS 
WHERE PHYSICAL_NAME IN (");
+            for (TableRef ref : tableRefs) {
+                buf.append("'" + ref.getTable().getName().getString() + "',");
+            }
+            buf.setCharAt(buf.length() - 1, ')');
+            conn.createStatement().execute(buf.toString());
+            success = true;
+        } catch (SQLException e) {
+            sqlException = e;
+        } finally {
+            try {
+                conn.close();
+            } catch (SQLException e) {
+                if (sqlException == null) {
+                    // If we're not in the middle of throwing another exception
+                    // then throw the exception we got on close.
+                    if (success) {
+                        sqlException = e;
+                    }
+                } else {
+                    sqlException.setNextException(e);
+                }
+            }
+            if (sqlException != null) { throw sqlException; }
+        }
+    }
 
     private MutationCode processMutationResult(String schemaName, String 
tableName, MetaDataMutationResult result) throws SQLException {
         final MutationCode mutationCode = result.getMutationCode();

Reply via email to