Sql4DCompiler/src/main/java/com/yahoo/sql4d/delete/DeleteMeta.java
public class DeleteMeta extends CrudStatementMeta {

    public String id;// UUid
    public Interval interval = null;
    public List<Interval> segmentsToDelete = null;// This will be determined at runtime.
    public List<String> dimensions = new ArrayList<>();// This will be determined at runtime.
    public List<String> metrics = new ArrayList<>();// This will be determined at runtime.

    public DeleteMeta() {
    }

    public DeleteMeta(String dataSource, Interval interval) {
        super(dataSource);
        this.interval = interval;
    }

    @Override
    public String toString() {
        return getJson().toString(2);
    }

    @Override
    public JSONObject getJson() {
        return new JSONObject(getDataMap());
    }
    /**
     * Retain segments only overlapping with the range.
     * @param allSegments 
     */
    public void filterSegments(List<Interval> allSegments) {
        segmentsToDelete = Lists.newArrayList(Iterables.filter(allSegments, new Predicate<Interval>() {
            @Override
            public boolean apply(Interval i) {
                return i.fallsIn(interval);
            }
        }));
    }

    @Override
    public Map<String, Object> getDataMap() {
        // For each instance of data generation generate a new id.
        id = String.format("kill_%s_%s_%s_%s", dataSource, interval.getStartTime(), interval.getEndTime(), new DateTime().toString());
        Map<String, Object> map = super.getDataMap();
        map.put("type", "kill");
        map.put("dataSource", dataSource);
        map.put("interval", interval.toString());
        map.put("id", id);
        return map;
    }


    public <T> void postProcess(T anyContext) {

    }
}
Sql4DCompiler/src/main/java/com/yahoo/sql4d/CrudProgram.java
public abstract class CrudProgram<T extends CrudStatementMeta> extends Program<T>{
    public boolean waitForCompletion = true;
}
Sql4DCompiler/src/main/java/com/yahoo/sql4d/query/RequestType.java
public enum RequestType {
    GROUPBY, TIMESERIES, TOPN, SEARCH, SELECT, TIMEBOUNDARY, UNKNOWN;

    public String getName() {
        if (this == TIMEBOUNDARY) {
            return "timeBoundary";
        }
        return this.name().toLowerCase();
    }
}
Sql4DCompiler/src/main/java/com/yahoo/sql4d/DropProgram.java
public class DropProgram extends CrudProgram<DropMeta>{
    public DropProgram() {
        this.type = Type.DROP;
    }
    
    @Override
    public String toString() {
        StringBuilder buffer = new StringBuilder();
        for (DropMeta dMeta: getAllStmnts()) {
            System.out.println(dMeta.toString());
        }
        return buffer.toString();
    }
    
    /**
     * TODO: Do all semantic checks here. 1st field should be timestamp.
     * @throws java.lang.Exception
     */
    @Override
    public void isValid() throws Exception {
    }

}
Sql4DCompiler/src/main/java/com/yahoo/sql4d/query/select/SelectQueryMeta.java
public class SelectQueryMeta  extends PlainDimQueryMeta {

    public final PagingSpec pagingSpec = new PagingSpec(null, 5);
    public List<String> fetchMetrics = new ArrayList<>();
    
    
    private static final JSONObject EMPTY_JSON = new JSONObject();
    
    public SelectQueryMeta() {
        queryType = RequestType.SELECT;
    }

    public SelectQueryMeta(QueryMeta q) {
        super(q);
        queryType = RequestType.SELECT;
    }

    @Override
    public String toString() {
        return getJson().toString(2);
    }
    
    @Override
    public JSONObject getJson() {
        return new JSONObject(getDataMap());
    }
    
    @Override
    public Map<String, Object> getDataMap() {
        Map<String, Object> map = super.getDataMap();
        Map<String, Object> pagingSpecMap = new LinkedHashMap<>();
        if (pagingSpec != null) {
            if (pagingSpec.pagingIdentifiers == null) {
                pagingSpecMap.put("pagingIdentifiers", EMPTY_JSON);
            } else {
                pagingSpecMap.put("pagingIdentifiers", pagingSpec.pagingIdentifiers);
            }
            pagingSpecMap.put("threshold", pagingSpec.threshold);
        }
        map.put("pagingSpec", pagingSpecMap);
        if (fetchMetrics != null) {
            map.put("metrics", new JSONArray(fetchMetrics));
        }
        return map;
    }
    
    /**
     * This method must be called prior to calling {@link SelectQueryMeta#getDataMap() }.
     * Essentially splits columns into Dimensions and Metrics.
     * @param <T>
     * @param anyContext
     */
    @Override
    public <T> void postProcess(T anyContext) {
        Tuple2<List<String>, List<String>> dimsAndMetrics = (Tuple2<List<String>, List<String>>)anyContext;
        List<String> dims = dimsAndMetrics._1();
        List<String> metrics = dimsAndMetrics._2();
        Iterator<Map.Entry<String, String>> colIter = fetchDimensions.entrySet().iterator();
        while (colIter.hasNext()) {
            Map.Entry<String, String> entry = colIter.next();
            if (dims.contains(entry.getKey())) {
                //No action.
            } else if (metrics.contains(entry.getKey())) {
                fetchMetrics.add(entry.getKey());
                colIter.remove();
            } else {//TODO: Handle error
                
            }
        }
    }
    
    public static SelectQueryMeta promote(QueryMeta qMeta) {
        return new SelectQueryMeta(qMeta);
    }
    
}
Sql4DCompiler/src/main/java/com/yahoo/sql4d/InsertProgram.java
public class InsertProgram extends CrudProgram<InsertMeta>{
    public static InsertProgram getInsertInstance() {
        return new InsertProgram(Type.INSERT);
    } 
    
    public static InsertProgram getInsertHadoopInstance() {
        return new InsertProgram(Type.INSERT_HADOOP);
    } 

    public static InsertProgram getInsertRTInstance() {
        return new InsertProgram(Type.INSERT_REALTIME);
    } 

    private InsertProgram(Type type) {
        this.type = type;
    }
    
    @Override
    public String toString() {
        StringBuilder buffer = new StringBuilder();
        for (InsertMeta iMeta: getAllStmnts()) {
            System.out.println(iMeta.toString());
        }
        return buffer.toString();
    }
    
    /**
     * TODO: Do all semantic checks here. 1st field should be timestamp.
     * @throws java.lang.Exception
     */
    @Override
    public void isValid() throws Exception {
    }

}
Sql4DCompiler/src/main/java/com/yahoo/sql4d/DeleteProgram.java
public class DeleteProgram extends CrudProgram<DeleteMeta>{
    public DeleteProgram() {
        this.type = Type.DELETE;
    }
    
    @Override
    public String toString() {
        StringBuilder buffer = new StringBuilder();
        for (DeleteMeta dMeta: getAllStmnts()) {
            System.out.println(dMeta.toString());
        }
        return buffer.toString();
    }
    
    /**
     * TODO: Do all semantic checks here. 1st field should be timestamp.
     * @throws java.lang.Exception
     */
    @Override
    public void isValid() throws Exception {
    }

}
Sql4DCompiler/src/main/java/com/yahoo/sql4d/insert/InsertMeta.java
public abstract class InsertMeta extends CrudStatementMeta {

    public String dataFormat = "tsv";//
    public String delimiter = ",";
    public String listDelimiter = "\n";
    public List<AggItem> aggregations = new ArrayList<>();
    public Map<String, String> fetchDimensions = new LinkedHashMap<>();
    public Set<String> orderedColumns = new LinkedHashSet<>();//For maintaining the insert order of data columns.

    public GranularitySpec granularitySpec = new GranularitySpec("day");

    public InsertMeta() {
    }

    public InsertMeta(String dataSource) {
        super(dataSource);
    }

    // Could be a dimension or metric.
    public void addColumnInOrder(String column) {
        orderedColumns.add(column);
    }
        
    @Override
    public String toString() {
        return getJson().toString(2);
    }

    @Override
    public JSONObject getJson() {
        return new JSONObject(getDataMap());
    }

    @Override
    public Map<String, Object> getDataMap() {
        Map<String, Object> map = super.getDataMap();
        map.put("dataSource", dataSource);
        return map;
    }

    //TODO: IOConfig should be called before dataSchema to ensure proper format values etc are filled in.
    // See getFirehose() method to see what dependencies are being filled in. This dependency should 
    // be removed in future.
    public Map<String, Object> getSpec() {
        return ImmutableMap.<String, Object>of(
                "ioConfig", getIoConfig(),
                "dataSchema", getDataSchema(),
                "tuningConfig", getTuningConfig());
    }

    public Map<String, Object> getDimensionSpec() {
        List<String> dims = getDimensions(fetchDimensions);
        return ImmutableMap.<String, Object>of(
                "dimensions", dims.subList(1, dims.size()),
                "dimensionExclusions", ImmutableList.<String>of(),
                "spatialDimensions", ImmutableList.<String>of());
    }
    
    public List<JSONObject> getMetricsSpec() {
        ImmutableList.Builder<JSONObject> builder = ImmutableList.<JSONObject>builder();
        for (AggItem item : aggregations) {
            builder.add(item.getJson());
        }
        return builder.build();
    }

    public Map<String, Object> getParser() {
        return ImmutableMap.<String, Object>of(
                "type", "string",
                "parseSpec", getParseSpec());
    }

    public Map<String, Object> getParseSpec() {
        ImmutableMap.Builder builder = ImmutableMap.<String, Object>builder();
        builder.put("format", dataFormat).
                put("timestampSpec", getTimestampSpec()).
                put("dimensionsSpec", getDimensionSpec());
        if (delimiter != null) {
            builder.put("delimiter", delimiter);
        }
        if (listDelimiter != null) {
            builder.put("listDelimiter", listDelimiter);
        }
        builder.put("columns", orderedColumns);
        return builder.build();
    }
    
    public Map<String, Object> getDataSchema() {
        return ImmutableMap.<String, Object>of(
                "dataSource", dataSource,
                "parser", getParser(),
                "metricsSpec", getMetricsSpec(),
                "granularitySpec", granularitySpec.getJson()
                );
    }
    
    public abstract Map<String, Object> getTimestampSpec();
    public abstract Map<String, Object> getIoConfig();
    public abstract Map<String, Object> getTuningConfig();

    public <T> void postProcess(T anyContext) {

    }
}
Sql4DCompiler/src/main/java/com/yahoo/sql4d/QueryProgram.java
public class QueryProgram extends Program<QueryMeta>{
    public final List<String> primaryJoinableHooks = new ArrayList<>();// Has 'N-1' items
    public final List<String> joinTypes = new ArrayList<>();// Has 'N-1' items

    public QueryProgram() {
        this.type = Type.QUERY;
    }
        
    
    public void addJoinHook(String hook) {
        primaryJoinableHooks.add(hook);
    }
    
    public void addJoinType(String type) {
        joinTypes.add(type);
    }
    @Override
    public String toString() {
        StringBuilder buffer = new StringBuilder();
        int i = 0;
        for (QueryMeta qMeta: getAllStmnts()) {
            buffer.append(qMeta.toString());
            buffer.append("\n");
            if (i == numStmnts() - 1) {
                break;
            }
            if (numStmnts() > 1) {
                buffer.append(" joined with ");
                buffer.append(primaryJoinableHooks.get(i++));
                buffer.append("\n");
            }
            
        }
        return buffer.toString();
    }
    
    /**
     * TODO: This method should be a full blown functional but right now address 
     * only partial semantics.
     * Do all semantic checks here.
     * @throws java.lang.Exception
     */
    @Override
    public void isValid() throws Exception {
        if (numStmnts() >= 2) {
            if (primaryJoinableHooks.size() > 0) {
                for (String joinField:primaryJoinableHooks) {
                    if (joinField.equals("timestamp")) {// timestamp is implicitly present in the result.
                        continue;
                    }
                    for (QueryMeta query: getAllStmnts()) {
                        boolean isPresent = false;
                        if (query instanceof BaseAggQueryMeta) {// Since BaseAggQueryMeta is also a PlainDimQueryMeta we go with former first.
                            for (AggItem item:((BaseAggQueryMeta)query).aggregations) {
                                if (joinField.equals(item.fieldName) || (item.asName != null && joinField.equals(item.asName))) {
                                    isPresent = true;
                                }
                            }
                        }
                        if (query instanceof PlainDimQueryMeta) {
                            Map<String, String> dims = ((PlainDimQueryMeta)query).fetchDimensions;
                            for (Map.Entry<String, String> entry :dims.entrySet()) {
                                if (joinField.equals(entry.getKey()) || (entry.getValue() != null && joinField.equals(entry.getValue()))) {
                                    isPresent = true;
                                }
                            }
                        }
                        if (!isPresent) {
                            String error = joinField + " mentioned in the composite key should appear in all the data sources being queried and joined.";
                            throw new Exception(error);
                        }
                    }
                }
            } else {
                String error = "Need atleast one field to join on";
                throw new Exception(error);
            }
        }
    }
}
Sql4DCompiler/src/main/java/com/yahoo/sql4d/CrudStatementMeta.java
public abstract class CrudStatementMeta extends BaseStatementMeta {
    public CrudStatementMeta() {
    }

    public CrudStatementMeta(String dataSource) {
        this.dataSource = dataSource;
    }
}
Sql4DCompiler/src/main/java/com/yahoo/sql4d/query/nodes/Interval.java
public class Interval {
    public String startTime;
    public String endTime;
    public int days;// Includes partial days as well.
    
    public Interval(String startTime, String endTime) {
        this.startTime = startTime.replaceAll("'", "");
        this.endTime = endTime.replaceAll("'", "");
        days = Days.daysBetween(getStartTime().withTimeAtStartOfDay() , getEndTime().withTimeAtStartOfDay() ).getDays() + 1;
    }

    /**
     * Interval should be of form 2014-10-31T00:00:00.000-07:00/2014-11-01T00:00:00.000-07:00
     * @param interval 
     */
    public Interval(String interval) {
        String[] dates = interval.split("/");
        Preconditions.checkArgument(dates.length == 2);
        this.startTime = dates[0].replaceAll("'", "");
        this.endTime = dates[1].replaceAll("'", "");
        days = Days.daysBetween(getStartTime().withTimeAtStartOfDay() , getEndTime().withTimeAtStartOfDay() ).getDays() + 1;
    }

    public DateTime getStartTime() {
        return TimeUtils.getDateTime(startTime);
    }

    public DateTime getEndTime() {
        return TimeUtils.getDateTime(endTime);
    }

    public int getDays() {
        return days;
    }
    
    public Interval getInterval(int daysOffset, int startHourOffset, int endHourOffset) {
        DateTime baseDateTime = getStartTime().withTime(0, 0, 0, 0).plusDays(daysOffset);
        return new Interval(baseDateTime.plusHours(startHourOffset).toString(), 
                baseDateTime.plusHours(endHourOffset).minusSeconds(1).toString());
    }

    public Interval expandIntervalByDay(int days) {
        return new Interval(getStartTime().minusDays(days).toString(), 
                getEndTime().plusDays(days).toString());
    }

    public Interval expandEndTimeByDay(int days) {
        return new Interval(getStartTime().toString(), 
                getEndTime().plusDays(days).toString());
    }

    public Interval expandIntervalBySec(int secs) {
        return new Interval(getStartTime().minusSeconds(secs).toString(), 
                getEndTime().plusSeconds(secs).toString());
    }

    @Override
    public String toString() {
        return String.format("%s/%s", startTime, endTime);
    }
    
    public boolean fallsIn(Interval range) {
        return range.getStartTime().isBefore(getStartTime()) && range.getEndTime().isAfter(getEndTime());
    }

}
Sql4Ddriver/src/main/java/com/yahoo/sql4d/sql4ddriver/sql/MysqlAccessor.java
public class MysqlAccessor extends BasePoolableObjectFactory<Tuple2<DataSource, Connection>> {

    private final String connectorUrl = "jdbc:mysql://%s:%d/%s?autoReconnectForPools=true";
    private String host = "localhost";
    private int port = 3306;
    private String id = "druid";//druid by default.
    private String password = "diurd";//diurd by default.
    private String db = "druid";//druid by default
    private ObjectPool<Tuple2<DataSource, Connection>> pool = null ;

    static {
        try {
            Class.forName("com.mysql.jdbc.Driver").newInstance();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
            Logger.getLogger(MysqlAccessor.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    public MysqlAccessor() {
        this("localhost", 3306, "druid", "diurd", "druid");
    }

    public MysqlAccessor(String host, int port) {
        this(host, port, "druid", "diurd", "druid");
    }

    public MysqlAccessor(String host, int port, String id, String passwd) {
        this(host, port, id, passwd, "druid");
    }

    public MysqlAccessor(String host, int port, String id, String passwd, String db) {
        this.host = host;
        this.port = port;
        this.id = id;
        this.password = passwd;
        this.db = db;
        init();
    }
    
    private void init() {
        GenericObjectPool.Config config = new GenericObjectPool.Config();
        config.maxActive = 2;//TODO: Make this configurable.
        config.testOnBorrow = true;
        config.testWhileIdle = true;
        config.timeBetweenEvictionRunsMillis = 10000;
        config.minEvictableIdleTimeMillis = 60000;
        GenericObjectPoolFactory genericObjectPoolFactory = new GenericObjectPoolFactory(this, config);
        pool = genericObjectPoolFactory.createPool();
    }
    
    @Override
    public Tuple2<DataSource, Connection> makeObject() throws Exception {
        DataSource ds = new DriverManagerDataSource(format(connectorUrl, host, port, db), id, password);
        return new Tuple2<>(ds, ds.getConnection());
    }

    @Override
    public void destroyObject(Tuple2<DataSource, Connection> connTuple) throws Exception {
        connTuple._2().close();
    }

    @Override
    public boolean validateObject(Tuple2<DataSource, Connection> conn) {
        try {
            return conn._2().isValid(0);
        } catch (SQLException ex) {
            Logger.getLogger(MysqlAccessor.class.getName()).log(Level.SEVERE, null, ex);
            try {//Could be due to stale connection. Invalidate the object.
                pool.invalidateObject(conn);
            } catch (Exception ex1) {//TODO: Something serious with DB.
                Logger.getLogger(MysqlAccessor.class.getName()).log(Level.SEVERE, null, ex1);
            }
        }
        return false;
    }
    
    public Tuple2<DataSource, Connection> getConnection() {
        try {
            return pool.borrowObject();
        } catch (Exception ex) {
            Logger.getLogger(MysqlAccessor.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public void returnConnection(Tuple2<DataSource, Connection> con) {
        try {
            if (con != null) {
                pool.returnObject(con);
            }
        } catch (Exception ex) {
            Logger.getLogger(MysqlAccessor.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void shutdown() {
        try {
            pool.clear();
            pool.close();
        } catch (Exception ex) {
            Logger.getLogger(MysqlAccessor.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public List<Map<String, Object>> query(Map<String, String> params, String query) {
        List<Map<String, Object>> result = null;
        Tuple2<DataSource, Connection> conn = null;
        try {
            conn = getConnection();
            NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(conn._1());
            result = jdbcTemplate.queryForList(query, params);
        } catch (Exception ex) {
            Logger.getLogger(MysqlAccessor.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            returnConnection(conn);
        }
        return result;
    }

    /**
     * Suitable for CRUD operations where no result set is expected.
     * @param params
     * @param query 
     * @return  
     */
    public boolean execute(Map<String, String> params, String query) {
        final AtomicBoolean result = new AtomicBoolean(false);
        Tuple2<DataSource, Connection> conn = null;
        try {
            conn = getConnection();
            NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(conn._1());
            jdbcTemplate.execute(query, params, new PreparedStatementCallback<Void>() {
                @Override
                public Void doInPreparedStatement(PreparedStatement ps) {
                    try {
                        result.set(ps.execute());
                    } catch(SQLException e) {
                        result.set(false);
                    }
                    return null;
                }
            });
        } catch (Exception ex) {
            Logger.getLogger(MysqlAccessor.class.getName()).log(Level.SEVERE, null, ex);
            result.set(false);
        } finally {
            returnConnection(conn);
        }
        return result.get();
    }
    
    public List<Map<String, Object>> segmentsInRange(String table, Interval interval) {
        return query(ImmutableMap.of("dataSource", table,
                "iStart", interval.startTime,
                "iEnd", interval.endTime), DAODictionary.SEGMENTS_IN_RANGE);
    }

    public List<Map<String, Object>> usedSegmentsInRange(String table, Interval interval) {
        return query(ImmutableMap.of("dataSource", table,
                "iStart", interval.startTime,
                "iEnd", interval.endTime,
                "used", "1"), DAODictionary.USED_SEGMENTS_IN_RANGE);
    }

    public boolean disableSegmentsInRange(String table, Interval interval) {
        return execute(ImmutableMap.of("dataSource", table,
                "iStart", interval.startTime,
                "iEnd", interval.endTime), DAODictionary.DISABLE_SEGMENTS_IN_RANGE);
    }

    public boolean disableAllSegments(String table) {
        return execute(ImmutableMap.of("dataSource", table), DAODictionary.DISABLE_ALL_SEGMENTS);
    }

    public static void main(String[] args) {
        MysqlAccessor accessor = new MysqlAccessor();
        System.out.println(accessor.usedSegmentsInRange("abf2", new Interval("2014-10-31/2014-11-01")));
        accessor.shutdown();
    }
}
Sql4DCompiler/src/main/java/com/yahoo/sql4d/query/QueryMeta.java
public class QueryMeta extends BaseStatementMeta {
    public Granularity granularity = new Granularity("all");
    public Filter filter;
    public List<Interval> intervals = new ArrayList<>(); 
    public List<Pair<Integer, Integer>> microIntervals = new ArrayList<>(); // If empty or if intervals list size > 1 then this is not used.
    public RequestType queryType;
    
    public QueryMeta() {
    }

    public QueryMeta(QueryMeta q) {
        super(q);
        this.granularity = q.granularity;
        this.filter = q.filter;
        this.intervals = q.intervals;
        this.microIntervals = q.microIntervals;
    }
    
    public QueryMeta(String dataSource, Granularity granularity, Filter filter, List<Interval> intervals, List<Pair<Integer, Integer>> microIntervals) {
        super(dataSource);
        this.granularity = granularity;
        this.filter = filter;
        this.intervals = intervals;
        this.microIntervals = microIntervals;
    }

    
    @Override
    public String toString() {
        return getJson().toString(2);
    }
    
    @Override
    public JSONObject getJson() {
        return new JSONObject(getDataMap());
    }
    @Override
    public Map<String, Object> getDataMap() {
        Map<String, Object> map = super.getDataMap();
        map.put("queryType", queryType.getName());
        if (queryType == RequestType.TIMEBOUNDARY) {
            return map;
        }
        if (granularity != null) {
            if (granularity.gComplex != null) {
                map.put("granularity", granularity.getJson());
            } else {
                map.put("granularity", granularity.gSimple);
            }
        }
        if (filter != null) {
            map.put("filter", filter.getJson());
        }

        JSONArray intervalsArray = new JSONArray();
        if (!intervals.isEmpty()) {
            if (intervals.size() == 1 && !microIntervals.isEmpty()) {
                Interval grandInterval = intervals.get(0);
                // Break the single interval into micro intervals.
                for (int i = 0; i < grandInterval.getDays();i++) {
                    for (Pair<Integer, Integer> pair:microIntervals) {
                        Interval microInterval = grandInterval.getInterval(i, pair.a, pair.a + pair.b);// a = start hour of day, b = number of hours from there of.
                        intervalsArray.put(microInterval.toString());
                    }
                }
            } else {
                for (Interval interval:intervals) {
                    intervalsArray.put(interval.toString());
                }
            }
            JSONObject finalIntervalJson = new JSONObject();
            finalIntervalJson.put("type", "intervals");
            finalIntervalJson.put("intervals", intervalsArray);
            map.put("intervals", finalIntervalJson);
        }
        return map;
    }
    
}
Sql4Ddriver/src/main/java/com/yahoo/sql4d/sql4ddriver/rowmapper/DruidBaseBean.java
public class DruidBaseBean<T extends DruidBaseBean> extends Serializer<T> {
    private static final DateTimeFormatter dateOnlyFormat = DateTimeFormat.forPattern("yyyy-MM-dd");
    private static final DateTimeFormatter dateTimeFormat = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss");
    private static final DateTimeFormatter dateTimeWithSubSecFormat = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
    private static final DateTimeFormatter dateTimeAndTZFormat = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ssZZ");
    private static final DateTimeFormatter dateTimeWithSubSecAndTZFormat = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZZ");

    public static void main(String[] args) {
        System.out.println(dateTimeFormat.parseDateTime("2014-05-25T16:45:49"));
        System.out.println(dateTimeAndTZFormat.parseDateTime("2014-05-25T16:45:49+00:00"));
        System.out.println(dateTimeAndTZFormat.parseDateTime("2014-05-25T16:45:49Z"));
        System.out.println(dateTimeWithSubSecFormat.parseDateTime("2014-05-25T16:45:49.100"));
        System.out.println(dateTimeWithSubSecAndTZFormat.parseDateTime("2014-05-25T16:45:49.000Z"));
    }

    public String timestamp;// TODO: Crazy,though getDeclaredMethods can be used to access private fields, it is not possible on subclasses.

    public void setTimestamp(String timestamp) {
        this.timestamp = timestamp;
    }

    public String getTimestamp() {
        return timestamp;
    }
    
    public Map<String, Object> toMap() {
        Map<String, Object> map = new ObjectMapper().convertValue(this, Map.class);
        // The following 2 comes from Serializer.
        map.remove("acceptsNull");
        map.remove("immutable");
        return map;        
    }

    @Override
    public String toString() {
        return toMap().toString();
    }

    @Override
    public void write(Kryo kryo, Output output, T t) {
        Map<String, Object> map = toMap();
        for (String key:map.keySet()) {
            Object value = map.get(key);
            kryo.writeClass(output, value.getClass());
            kryo.writeObjectOrNull(output, key, String.class);
            kryo.writeObjectOrNull(output, value, value.getClass());
        }
    }

    @Override
    public T read(Kryo kryo, Input input, Class<T> type) {
        T retValue = null;
        try {
            retValue = type.newInstance();
            Registration reg = kryo.readClass(input);
            String key = kryo.readObjectOrNull(input, String.class);
            Object value = kryo.readObjectOrNull(input, reg.getType());
            Util.applyKVToBean(retValue, key, value);
        } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | IllegalArgumentException | InvocationTargetException ex) {
            Logger.getLogger(DruidBaseBean.class.getName()).log(Level.SEVERE, null, ex);
        }
        return retValue;
    }
    
}
Sql4DCompiler/src/main/java/com/yahoo/sql4d/DCompiler.java
public class DCompiler {
    /**
     * To avoid instantiation.
     */
    private DCompiler() {
    }
    /**
     * Sql->Json.
     * @param query
     * @return 
     */
    public static Program compileSql(String query) {
        try {
            ANTLRStringStream in = new ANTLRStringStream(query);
            druidGLexer lexer = new druidGLexer(in);
            CommonTokenStream tokens = new CommonTokenStream(lexer);
            druidGParser parser = new druidGParser(tokens);
            Program pgm = parser.program();
            return pgm;
        } catch (RecognitionException ex) {
            System.out.println(ex);
            Logger.getLogger(DCompiler.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }
    
    public static void main(String[] args) {
        //Program p = compileSql("select UNIQUE(referer) AS refe, referer FROM miab_hourly_v2 WHERE interval BETWEEN 2014-11-05T08:18:00.000Z AND 2014-11-05T08:20:00.000Z  BREAK BY 'day' GROUP BY referer;");
        Program p = compileSql("INSERT INTO abf (timestamp , provider , title, uuid, DOUBLE_SUM(click) AS click)  VALUES ('2014-10-31 00:00:00','sri','SE','fsd-sdf-dfgdf','2') WHERE interval BETWEEN '2013-08-31' AND '2023-09-01'  BREAK BY 'day';");
        System.out.println(p);
    }
}
Sql4Ddriver/src/main/java/com/yahoo/sql4d/sql4ddriver/Util.java
public class Util {
    public static final void newLine() {
        System.out.println();
    }
    
    public static final void print(char c) {
        System.out.print(c);
        System.out.flush();
    }

    public static final void print(String message) {
        System.out.print(message);
        System.out.flush();
    }

    public static final void println(String message) {
        System.out.println(message);
        System.out.flush();
    }

    public static final void printf(String format, Object ...args) {
        System.out.printf(format, args);
        System.out.flush();
    }

    public static final String repeat(String item, int n) {
        StringBuilder buff = new StringBuilder();
        for (int i = 0;i < n;i++) {
            buff.append(item);
        }
        return buff.toString();
    }

    public static void printTable(JSONArray jsonArray) {
        if (jsonArray.length() == 0) {
            return;
        }
        JSONObject sample = jsonArray.getJSONObject(0);
        if (sample.has("event")) {// GroupBy
            for (int i = 0;i < jsonArray.length();i++) {
                JSONObject jsonItem = jsonArray.getJSONObject(i);
                JSONObject event = jsonItem.getJSONObject("event");
                
                // Print headers.
                if (i == 0) {
                    printf("%-10s  |", "timestamp");
                    for (Object key: event.keySet()) {
                        printf("%-10s  |", key);
                    }
                    newLine();
                }
                println(repeat("-", (event.keySet().size() + 1) * 10));
                // Print data.
                printf("%-10s  |", jsonItem.getString("timestamp"));
                for (Object key: event.keySet()) {
                    printf("%-10s  |", event.get(key.toString()));
                }
                newLine();
            }
        } else if (sample.has("result")) {// Could be timeseries/topN
            if (sample.optJSONObject("result") != null) {// Timeseries
                JSONObject sampleResult = sample.optJSONObject("result");
                // Print headers.
                printf("%-10s  |", "timestamp");
                for (Object key: sampleResult.keySet()) {
                    printf("%-10s  |", key);
                }
                newLine();
                println(repeat("-", (sampleResult.keySet().size() + 1) * 10));
                // Print data.
                for (int i = 0;i < jsonArray.length();i++) {
                    JSONObject jsonItem = jsonArray.getJSONObject(i);
                    printf("%-10s  |", jsonItem.getString("timestamp"));
                    JSONObject result = jsonItem.getJSONObject("result");
                    for (Object key: result.keySet()) {
                        printf("%-10s  |", result.get(key.toString()));
                    }
                    newLine();
                }
            } else if (sample.optJSONArray("result") != null) {// TopN
                // There should be only 1 item in here.
                JSONObject jsonItem = jsonArray.getJSONObject(0);
                
                JSONArray result = jsonItem.getJSONArray("result");
                // Print headers.
                printf("%-10s  |", "timestamp");
                if (result.length() == 0) {// Nothing to be printed
                    return;
                }
                for (Object key: result.getJSONObject(0).keySet()) {
                    printf("%-10s  |", key);
                }
                newLine();
                println(repeat("-", (result.getJSONObject(0).keySet().size() + 1) * 10));
                for (int j = 0;j < result.length();j++) {
                    printf("%-10s  |", jsonItem.getString("timestamp"));
                    JSONObject deepItem = result.getJSONObject(j);
                    for (Object key: deepItem.keySet()) {
                        printf("%-10s  |", deepItem.get(key.toString()));
                    }
                    newLine();
                }
                newLine();
            }
        } 
    }
    
    public static void printTable(List<String> baseFieldNames, Map<Object, List<Object>> baseAllRows) {
        for(String header:baseFieldNames) {
            printf("%-10s  |", header);
        }
        newLine();
        for(List<Object> row:baseAllRows.values()) {
            for (Object rowColValue:row) {
                printf("%-10s  |", rowColValue);
            }
            newLine();
        }
    }

    public static void printTable(List<String> baseFieldNames, List<List<Object>> baseAllRows) {
        for(String header:baseFieldNames) {
            printf("%-10s  |", header);
        }
        newLine();
        for(List<Object> row:baseAllRows) {
            for (Object rowColValue:row) {
                printf("%-10s  |", rowColValue);
            }
            newLine();
        }
    }

    public static <T extends DruidBaseBean> void printTable(List<T> baseAllRows) {
        if (baseAllRows == null || baseAllRows.isEmpty()) {
            return;
        }
        List<Method> setters = getAllSetters(baseAllRows.get(0).getClass());
        for(Method setter:setters) {
            printf("%-10s  |", setter.getName().substring(3));
        }
        newLine();
        List<Method> getters = getAllGetters(baseAllRows.get(0).getClass());
        for(T row:baseAllRows) {
            for(Method getter:getters) {
                try {
                    printf("%-10s  |", getter.invoke(row));
                } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
                    Logger.getLogger(Util.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            newLine();
        }
    }
    
    public static List<Method> getAllSetters(Class<?> clazz) {
        Method[] allMethods = clazz.getMethods();
        List<Method> setters = new ArrayList<>();
        for(Method method : allMethods) {
            if(method.getName().startsWith("set")) {
                setters.add(method);
            }
        }    
        return setters;
    }

    public static List<Method> getAllGetters(Class<?> clazz) {
        Method[] allMethods = clazz.getMethods();
        List<Method> getters = new ArrayList<>();
        for(Method method : allMethods) {
            if(method.getName().startsWith("get") && !method.getName().equals("getClass")) {
                getters.add(method);
            }
        }    
        return getters;
    }
    
    public static String getterMethodName(String key) {
        return "get" + capitalize(key);
    }

    public static String setterMethodName(String key) {
        return "set" + capitalize(key);
    }

    public static String capitalize(String word) {
        StringBuilder buff = new StringBuilder(word);
        if (word.charAt(0) != '_') {
            buff.setCharAt(0, Character.toUpperCase(word.charAt(0)));
        }
        for (int i = 1; i < buff.length(); i++) {
            if (buff.charAt(i - 1) == '_') {
                buff.setCharAt(i, Character.toUpperCase(word.charAt(i)));
            }
        }
        return buff.toString().replace("_", "");
    }

    public static Either<JSONArray, JSONObject> asJsonType(String str) throws JSONException {
        JSONArray possibleResArray = null;
        try {
            possibleResArray = new JSONArray(str);
            return new Left<>(possibleResArray);
        } catch (JSONException je) {
            JSONObject possibleResObj = new JSONObject(str);
            return new Right<>(possibleResObj);
        }
    }    
    
    /**
     * More granular(sets the property of a bean based on a key value).
     *
     * @param bean
     * @param key
     * @param value
     * @throws NoSuchMethodException
     * @throws IllegalAccessException
     * @throws IllegalArgumentException
     * @throws InvocationTargetException
     */
    public static void applyKVToBean(Object bean, String key, Object value) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Method getterMethod = bean.getClass().getMethod(Util.getterMethodName(key));
        Method setterMethod = bean.getClass().getMethod(Util.setterMethodName(key), getterMethod.getReturnType());
        setterMethod.invoke(bean, value);
    }
    
}
Sql4DCompiler/src/main/java/com/yahoo/sql4d/drop/DropMeta.java
public class DropMeta extends CrudStatementMeta {

    public String id;// UUid
    public Interval interval = null;// This should be filled with time boundary at runtime.
    public List<String> dimensions = new ArrayList<>();// This will be determined at runtime.
    public List<String> metrics = new ArrayList<>();// This will be determined at runtime.

    public DropMeta() {
    }

    public DropMeta(String dataSource, Interval interval) {
        super(dataSource);
        this.interval = interval;
    }

    @Override
    public String toString() {
        return getJson().toString(2);
    }

    @Override
    public JSONObject getJson() {
        return new JSONObject(getDataMap());
    }

    @Override
    public Map<String, Object> getDataMap() {
        // For each instance of data generation generate a new id.
        id = String.format("kill_%s_%s_%s_%s", dataSource, interval.getStartTime(), interval.getEndTime(), new DateTime().toString());
        Map<String, Object> map = super.getDataMap();
        map.put("type", "kill");
        map.put("dataSource", dataSource);
        map.put("interval", interval.toString());
        map.put("id", id);
        return map;
    }


    public <T> void postProcess(T anyContext) {

    }
}


Question: import com.yahoo.sql4d.BaseStatementMeta;
import com.yahoo.sql4d.CrudProgram;
import com.yahoo.sql4d.CrudStatementMeta;
import com.yahoo.sql4d.query.RequestType;
import static com.yahoo.sql4d.sql4ddriver.Util.*;
import com.yahoo.sql4d.DCompiler;
import com.yahoo.sql4d.DeleteProgram;
import com.yahoo.sql4d.DropProgram;
import com.yahoo.sql4d.InsertProgram;
import com.yahoo.sql4d.Program;
import com.yahoo.sql4d.QueryProgram;
import com.yahoo.sql4d.delete.DeleteMeta;
import com.yahoo.sql4d.drop.DropMeta;
import com.yahoo.sql4d.insert.InsertMeta;
import com.yahoo.sql4d.query.QueryMeta;
import com.yahoo.sql4d.query.nodes.Interval;
import com.yahoo.sql4d.query.select.SelectQueryMeta;
import com.yahoo.sql4d.sql4ddriver.rowmapper.DruidBaseBean;
import com.yahoo.sql4d.sql4ddriver.sql.MysqlAccessor;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.joda.time.DateTime;
import org.json.JSONArray;
import scala.util.Either;
import scala.util.Left;
import scala.util.Right;
import scala.Tuple2;
/**
 * Copyright 2014 Yahoo! Inc. Licensed under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License. See accompanying
 * LICENSE file.
 */
package com.yahoo.sql4d.sql4ddriver;



/**
 * TODO: Use logger. Database driver for druid. Does not conform
 * to javax.sql.DataSource. 
 * 
 * Possible druid responses :
 *
 * For groupBy the response is as follows. [ { "version" : "v1", "timestamp" :
 * "2013-07-12T04:00:00.000Z", "event" : { ... } }, { "version" : "v1",
 * "timestamp" : "2013-07-12T04:00:00.000Z", "event" : { ... } },... ] 
 * 
 * For timeseries the response is as follows [ { "timestamp":
 * "2012-01-01T00:00:00.000Z", "result": { "sample_name1": <some_value>,
 * "sample_name2": <some_value>, "sample_divide": <some_value> } }, {
 * "timestamp": "2012-01-02T00:00:00.000Z", "result": { "sample_name1":
 * <some_value>, "sample_name2": <some_value>, "sample_divide": <some_value> } }
 * ]
 * 
 * For TopN query the response is as follows [ { "timestamp":
 * "2013-08-31T00:00:00.000Z", "result": [ { "dim1": "dim1_val", "count": 111,
 * "some_metrics": 10669, "average": 96.11711711711712 }, {.... } ] } ]
 *
 * @author srikalyan
 */
public class DDataSource {

    private BrokerAccessor broker; 
    private CoordinatorAccessor coordinator; 
    private OverlordAccessor overlord; 
    
    private MysqlAccessor dbAccessor;
    
    private static int MAX_CONNS_IN_POOL = 150;
    private static int MAX_BROKER_CONNS = 100;
    private static int MAX_COORD_CONNS = 50;
    private static int MAX_OVERLORD_CONNS = 50;

    public DDataSource(String bHost, int bPort) {
        this(bHost, bPort, null, 0);
    }

    public DDataSource(String bHost, int bPort, String cHost, int cPort) {
        this(bHost, bPort, cHost, cPort, null, 0);
    }

    public DDataSource(String bHost, int bPort, String cHost, int cPort, String oHost, int oPort) {
        this(bHost, bPort, cHost, cPort, oHost, oPort, "localhost", 3306, "druid", "diurd", "druid");
    }

    public DDataSource(String bHost, int bPort, String cHost, int cPort, String oHost, int oPort, String sqlHost, int sqlPort, String sqlId, String sqlPasswd, String dbName) {
        broker = new BrokerAccessor(bHost, bPort, MAX_BROKER_CONNS);
        coordinator = new CoordinatorAccessor(cHost, cPort, MAX_COORD_CONNS);
        overlord = new OverlordAccessor(oHost, oPort, MAX_OVERLORD_CONNS);
        dbAccessor = new MysqlAccessor(sqlHost, sqlPort, sqlId, sqlPasswd, dbName);
    }

    /**
     * Call if a custom pool size, and fine grained control on connections per route.
     * NOTE: This must be called prior to instantiating DDataSource for the settings
     * to be effective.
     * @param maxConnsInPool
     * @param maxBrokerConns
     * @param maxCoordConns
     * @param maxOverlordConns 
     */
    public static void adjustPoolSettings(int maxConnsInPool, int maxBrokerConns, int maxCoordConns, int maxOverlordConns) {
        MAX_CONNS_IN_POOL = maxConnsInPool;
        MAX_BROKER_CONNS = maxBrokerConns;
        MAX_COORD_CONNS = maxCoordConns;
        MAX_OVERLORD_CONNS = maxOverlordConns;
        DruidNodeAccessor.setMaxConnections(MAX_CONNS_IN_POOL);
    }
    
    /**
     * NOTE: This must be called prior to instantiating DDataSource for the settings
     * to be effective.
     * @param pHost
     * @param pPort 
     */
    public static void setProxy(String pHost, int pPort) {
        DruidNodeAccessor.setProxy(pHost, pPort);
    }
    
    private String preprocessSqlQuery(String sqlQuery, NamedParameters namedParams) {
        if (namedParams != null) {
            return namedParams.deParameterize(sqlQuery);
        }
        return sqlQuery;
    }

    /**
     * Get an in memory representation of broken SQL query. This may require 
     * contacting druid for resolving dimensions Vs metrics for SELECT queries
     * hence it also optionally accepts HTTP request headers to be sent out.
     *
     * @param sqlQuery
     * @param namedParams
     * @param reqHeaders
     * @return
     * @throws java.lang.Exception
     */
    public Program<BaseStatementMeta> getCompiledAST(String sqlQuery, NamedParameters namedParams, Map<String, String> reqHeaders) throws Exception {
        Program<BaseStatementMeta> pgm = DCompiler.compileSql(preprocessSqlQuery(sqlQuery, namedParams));
        for (BaseStatementMeta stmnt : pgm.getAllStmnts()) {
            if (stmnt instanceof QueryMeta) {
                QueryMeta query = (QueryMeta) stmnt;
                if (query.queryType == RequestType.SELECT) {//classifyColumnsToDimAndMetrics
                    Either<String, Tuple2<List<String>, List<String>>> dataSourceDescRes = coordinator.aboutDataSource(stmnt.dataSource, reqHeaders);
                    if (dataSourceDescRes.isLeft()) {
                        throw new Exception("Datasource info either not available (or)could not be loaded ." + dataSourceDescRes.left().get());
                    } else {
                        ((SelectQueryMeta) query).postProcess(dataSourceDescRes.right().get());
                    }
                }
Answer:             } else if (stmnt instanceof InsertMeta) {//TODO: Handle this.