All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.questdb.query.ResultSet Maven / Gradle / Ivy

There is a newer version: 3.3.3
Show newest version
/*******************************************************************************
 *    ___                  _   ____  ____
 *   / _ \ _   _  ___  ___| |_|  _ \| __ )
 *  | | | | | | |/ _ \/ __| __| | | |  _ \
 *  | |_| | |_| |  __/\__ \ |_| |_| | |_) |
 *   \__\_\\__,_|\___||___/\__|____/|____/
 *
 * Copyright (C) 2014-2016 Appsicle
 *
 * 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 .
 *
 ******************************************************************************/

package com.questdb.query;

import com.questdb.Journal;
import com.questdb.Partition;
import com.questdb.ex.JournalException;
import com.questdb.factory.configuration.ColumnMetadata;
import com.questdb.misc.Rnd;
import com.questdb.misc.Rows;
import com.questdb.query.iterator.ResultSetBufferedIterator;
import com.questdb.query.iterator.ResultSetIterator;
import com.questdb.std.LongList;
import com.questdb.store.ColumnType;
import com.questdb.store.SymbolTable;

import java.util.Iterator;

public class ResultSet implements Iterable {
    private final Journal journal;
    private final LongList rowIDs;

    ResultSet(Journal journal, LongList rowIDs) {
        this.journal = journal;
        this.rowIDs = rowIDs;
    }

    public ResultSetBufferedIterator bufferedIterator() {
        return new ResultSetBufferedIterator<>(this);
    }

    public double getDouble(int rsIndex, int columnIndex) throws JournalException {
        long rowID = rowIDs.get(rsIndex);
        return journal.getPartition(Rows.toPartitionIndex(rowID), true).getDouble(Rows.toLocalRowID(rowID), columnIndex);
    }

    public long getInt(int rsIndex, int columnIndex) throws JournalException {
        long rowID = rowIDs.get(rsIndex);
        return journal.getPartition(Rows.toPartitionIndex(rowID), true).getInt(Rows.toLocalRowID(rowID), columnIndex);
    }

    public Journal getJournal() {
        return journal;
    }

    public long getLong(int rsIndex, int columnIndex) throws JournalException {
        long rowID = rowIDs.get(rsIndex);
        return journal.getPartition(Rows.toPartitionIndex(rowID), true).getLong(Rows.toLocalRowID(rowID), columnIndex);
    }

    public long getRowID(int index) {
        return rowIDs.get(index);
    }

    public String getString(int rsIndex, int columnIndex) throws JournalException {
        long rowID = rowIDs.get(rsIndex);
        return journal.getPartition(Rows.toPartitionIndex(rowID), true).getStr(Rows.toLocalRowID(rowID), columnIndex);
    }

    public String getSymbol(int rsIndex, int columnIndex) throws JournalException {
        long rowID = rowIDs.get(rsIndex);
        return journal.getPartition(Rows.toPartitionIndex(rowID), true).getSym(Rows.toLocalRowID(rowID), columnIndex);
    }

    @Override
    public Iterator iterator() {
        return new ResultSetIterator<>(this);
    }

    public T[] read() throws JournalException {
        return journal.read(rowIDs);
    }

    public void read(int index, T obj) throws JournalException {
        journal.read(rowIDs.get(index), obj);
    }

    public T read(int rsIndex) throws JournalException {
        return journal.read(rowIDs.get(rsIndex));
    }

    public T readFirst() throws JournalException {
        return size() > 0 ? read(0) : null;
    }

    public T readLast() throws JournalException {
        int size = size();
        return size > 0 ? read(size - 1) : null;
    }

    public long[] readTimestamps() throws JournalException {
        int timestampColIndex = journal.getMetadata().getTimestampIndex();
        long[] result = new long[size()];

        for (int i = 0, rowIDsLength = rowIDs.size(); i < rowIDsLength; i++) {
            result[i] = getLong(i, timestampColIndex);
        }
        return result;
    }

    public ResultSet shuffle(Rnd rnd) {
        LongList rows = new LongList(this.rowIDs);
        rows.shuffle(rnd);
        return new ResultSet<>(journal, rows);
    }

    public int size() {
        return rowIDs.size();
    }

    public ResultSet sort(String... columnNames) throws JournalException {
        return sort(Order.ASC, getColumnIndexes(columnNames));
    }

    public ResultSet sort(Order order, String... columnNames) throws JournalException {
        return sort(order, getColumnIndexes(columnNames));
    }

    public ResultSet sort() {
        rowIDs.sort();
        return this;
    }

    /**
     * Creates subset of ResultSet by result set row numbers.
     *
     * @param lo low end point of result set (inclusive)
     * @param hi high end point of result set (exclusive)
     * @return a subset of result set from lo (inclusive) to hi (exclusive)
     */
    public ResultSet subset(int lo, int hi) {
        return new ResultSet<>(journal, this.rowIDs.subset(lo, hi));
    }

    private static  int compare(Journal journal, int[] columns, long rightRowID, long leftRowID) throws JournalException {
        int result = 0;
        long leftLocalRowID = Rows.toLocalRowID(leftRowID);
        long rightLocalRowID = Rows.toLocalRowID(rightRowID);

        Partition leftPart = journal.getPartition(Rows.toPartitionIndex(leftRowID), true);
        Partition rightPart = journal.getPartition(Rows.toPartitionIndex(rightRowID), true);

        for (int column : columns) {
            ColumnMetadata meta = journal.getMetadata().getColumnQuick(column);

            String leftStr;
            String rightStr;

            switch (meta.type) {
                case ColumnType.STRING:
                    leftStr = leftPart.getStr(leftLocalRowID, column);
                    rightStr = rightPart.getStr(rightLocalRowID, column);

                    if (leftStr == null && rightStr == null) {
                        result = 0;
                    } else if (leftStr == null) {
                        result = 1;
                    } else if (rightStr == null) {
                        result = -1;
                    } else {
                        result = rightStr.compareTo(leftStr);
                    }
                    break;
                default:
                    switch (meta.type) {
                        case ColumnType.INT:
                            result = compare(rightPart.getInt(rightLocalRowID, column), leftPart.getInt(leftLocalRowID, column));
                            break;
                        case ColumnType.LONG:
                        case ColumnType.DATE:
                            result = compare(rightPart.getLong(rightLocalRowID, column), leftPart.getLong(leftLocalRowID, column));
                            break;
                        case ColumnType.DOUBLE:
                            result = compare(rightPart.getDouble(rightLocalRowID, column), leftPart.getDouble(leftLocalRowID, column));
                            break;
                        case ColumnType.FLOAT:
                            result = compare(rightPart.getFloat(rightLocalRowID, column), leftPart.getFloat(leftLocalRowID, column));
                            break;
                        case ColumnType.SYMBOL:
                            int leftSymIndex = leftPart.getInt(leftLocalRowID, column);
                            int rightSymIndex = rightPart.getInt(rightLocalRowID, column);

                            if (leftSymIndex == SymbolTable.VALUE_IS_NULL && rightSymIndex == SymbolTable.VALUE_IS_NULL) {
                                result = 0;
                            } else if (leftSymIndex == SymbolTable.VALUE_IS_NULL) {
                                result = 1;
                            } else if (rightSymIndex == SymbolTable.VALUE_IS_NULL) {
                                result = -1;
                            } else {
                                leftStr = meta.symbolTable.value(leftSymIndex);
                                rightStr = meta.symbolTable.value(rightSymIndex);

                                if (leftStr == null || rightStr == null) {
                                    throw new JournalException("Corrupt column [%s] !", meta);
                                }

                                result = rightStr.compareTo(leftStr);
                            }
                            break;
                        default:
                            throw new JournalException("Unsupported type: " + meta.type);
                    }
            }


            if (result != 0) {
                break;
            }
        }
        return result;
    }

    private static int compare(long a, long b) {
        if (a == b) {
            return 0;
        } else if (a > b) {
            return 1;
        } else {
            return -1;
        }
    }

    private static int compare(int a, int b) {
        if (a == b) {
            return 0;
        } else if (a > b) {
            return 1;
        } else {
            return -1;
        }
    }

    private static int compare(double a, double b) {
        if (a == b) {
            return 0;
        } else if (a > b) {
            return 1;
        } else {
            return -1;
        }
    }

    private static int compare(float a, float b) {
        if (a == b) {
            return 0;
        } else if (a > b) {
            return 1;
        } else {
            return -1;
        }
    }

    private int[] getColumnIndexes(String... columnNames) {
        int columnIndices[] = new int[columnNames.length];
        for (int i = 0, columnNamesLength = columnNames.length; i < columnNamesLength; i++) {
            columnIndices[i] = journal.getMetadata().getColumnIndex(columnNames[i]);
        }
        return columnIndices;
    }

    private void quickSort(Order order, int lo, int hi, int... columnIndices) throws JournalException {

        if (lo >= hi) {
            return;
        }

        int pIndex = lo + (hi - lo) / 2;
        long pivot = rowIDs.get(pIndex);

        int multiplier = 1;

        if (order == Order.DESC) {
            multiplier = -1;
        }

        int i = lo;
        int j = hi;

        while (i <= j) {

            while (multiplier * compare(journal, columnIndices, rowIDs.get(i), pivot) < 0) {
                i++;
            }

            while (multiplier * compare(journal, columnIndices, pivot, rowIDs.get(j)) < 0) {
                j--;
            }

            if (i <= j) {
                long temp = rowIDs.get(i);
                rowIDs.set(i, rowIDs.get(j));
                rowIDs.set(j, temp);
                i++;
                j--;
            }
        }
        quickSort(order, lo, j, columnIndices);
        quickSort(order, i, hi, columnIndices);
    }

    private ResultSet sort(Order order, int... columnIndices) throws JournalException {
        int size = size();
        if (size > 0) {
            quickSort(order, 0, size - 1, columnIndices);
        }
        return this;
    }

    public enum Order {
        ASC, DESC
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy