Search in sources :

Example 1 with SqlExecutionInterruptor

use of io.questdb.griffin.SqlExecutionInterruptor in project questdb by bluestreak01.

the class SampleByInterpolateRecordCursorFactory method getCursor.

@Override
public RecordCursor getCursor(SqlExecutionContext executionContext) throws SqlException {
    recordKeyMap.clear();
    dataMap.clear();
    final RecordCursor baseCursor = base.getCursor(executionContext);
    final Record baseRecord = baseCursor.getRecord();
    final SqlExecutionInterruptor interruptor = executionContext.getSqlExecutionInterruptor();
    try {
        // init all record function for this cursor, in case functions require metadata and/or symbol tables
        Function.init(recordFunctions, baseCursor, executionContext);
        // At the same time check if cursor has data
        while (baseCursor.hasNext()) {
            interruptor.checkInterrupted();
            final MapKey key = recordKeyMap.withKey();
            mapSink.copy(baseRecord, key);
            key.createValue();
        }
        // no data, nothing to do
        if (recordKeyMap.size() == 0) {
            baseCursor.close();
            return EmptyTableRandomRecordCursor.INSTANCE;
        }
        // topTop() is guaranteeing that we get
        // the same data as previous while() loop
        // there is no data
        baseCursor.toTop();
        // Evaluate group-by functions.
        // On every change of timestamp sample value we
        // check group for gaps and fill them with placeholder
        // entries. Values for these entries will be interpolated later
        // we have data in cursor, so we can grab first value
        final boolean good = baseCursor.hasNext();
        assert good;
        long timestamp = baseRecord.getTimestamp(timestampIndex);
        sampler.setStart(timestamp);
        long prevSample = sampler.round(timestamp);
        // the lowest timestamp value
        long loSample = prevSample;
        long hiSample;
        do {
            // this seems inefficient, but we only double-sample
            // very first record and nothing else
            long sample = sampler.round(baseRecord.getTimestamp(timestampIndex));
            if (sample != prevSample) {
                // before we continue with next interval
                // we need to fill gaps in current interval
                // we will go over unique keys and attempt to
                // find them in data map with current timestamp
                fillGaps(prevSample, sample);
                prevSample = sample;
                GroupByUtils.toTop(groupByFunctions);
            }
            // same data group - evaluate group-by functions
            MapKey key = dataMap.withKey();
            mapSink.copy(baseRecord, key);
            key.putLong(sample);
            MapValue value = key.createValue();
            if (value.isNew()) {
                // not a gap
                value.putByte(0, (byte) 0);
                for (int i = 0; i < groupByFunctionCount; i++) {
                    groupByFunctions.getQuick(i).computeFirst(value, baseRecord);
                }
            } else {
                for (int i = 0; i < groupByFunctionCount; i++) {
                    groupByFunctions.getQuick(i).computeNext(value, baseRecord);
                }
            }
            if (!baseCursor.hasNext()) {
                hiSample = sampler.nextTimestamp(prevSample);
                break;
            }
            interruptor.checkInterrupted();
        } while (true);
        // fill gaps if any at end of base cursor
        fillGaps(prevSample, hiSample);
        if (groupByTwoPointFunctionCount > 0) {
            final RecordCursor mapCursor = recordKeyMap.getCursor();
            final Record mapRecord = mapCursor.getRecord();
            while (mapCursor.hasNext()) {
                MapValue value = findDataMapValue(mapRecord, loSample);
                if (value.getByte(0) == 0) {
                    // we have at least 1 data point
                    long x1 = loSample;
                    long x2 = x1;
                    while (true) {
                        // to timestamp after 'sample' to begin with
                        x2 = sampler.nextTimestamp(x2);
                        if (x2 < hiSample) {
                            value = findDataMapValue(mapRecord, x2);
                            if (value.getByte(0) == 0) {
                                interpolateBoundaryRange(x1, x2, mapRecord);
                                x1 = x2;
                            }
                        } else {
                            break;
                        }
                    }
                }
            }
        }
        // find gaps by checking each of the unique keys against every sample
        long sample;
        for (sample = prevSample = loSample; sample < hiSample; prevSample = sample, sample = sampler.nextTimestamp(sample)) {
            final RecordCursor mapCursor = recordKeyMap.getCursor();
            final Record mapRecord = mapCursor.getRecord();
            while (mapCursor.hasNext()) {
                // locate first gap
                MapValue value = findDataMapValue(mapRecord, sample);
                if (value.getByte(0) == 1) {
                    // gap is at 'sample', so potential X-value is at 'prevSample'
                    // now we need to find Y-value
                    long current = sample;
                    while (true) {
                        // to timestamp after 'sample' to begin with
                        long x2 = sampler.nextTimestamp(current);
                        // is this timestamp within range?
                        if (x2 < hiSample) {
                            value = findDataMapValue(mapRecord, x2);
                            if (value.getByte(0) == 1) {
                                // gap
                                current = x2;
                            } else {
                                // do we really have X-value?
                                if (sample == loSample) {
                                    // prevSample does not exist
                                    // find first valid value from 'x2+1' onwards
                                    long x1 = x2;
                                    while (true) {
                                        x2 = sampler.nextTimestamp(x2);
                                        if (x2 < hiSample) {
                                            final MapValue x2value = findDataMapValue(mapRecord, x2);
                                            if (x2value.getByte(0) == 0) {
                                                // non-gap
                                                // found value at 'x2' - this is our Y-value
                                                // the X-value it at 'x1'
                                                // compute slope and go back down all the way to start
                                                // computing values in records
                                                // this has to be a loop that would store y1 and y2 values for each
                                                // group-by function
                                                // use current 'value' for record
                                                MapValue x1Value = findDataMapValue2(mapRecord, x1);
                                                interpolate(loSample, x1, mapRecord, x1, x2, x1Value, x2value);
                                                break;
                                            }
                                        } else {
                                            // we only have a single value at 'x1' - cannot interpolate
                                            // make all values before and after 'x1' NULL
                                            nullifyRange(loSample, x1, mapRecord);
                                            nullifyRange(sampler.nextTimestamp(x1), hiSample, mapRecord);
                                            break;
                                        }
                                    }
                                } else {
                                    // calculate slope between 'preSample' and 'x2'
                                    // yep, that's right, and go all the way back down
                                    // to 'sample' calculating interpolated values
                                    MapValue x1Value = findDataMapValue2(mapRecord, prevSample);
                                    interpolate(sampler.nextTimestamp(prevSample), x2, mapRecord, prevSample, x2, x1Value, value);
                                }
                                break;
                            }
                        } else {
                            // try using first two values
                            // we had X-value at 'prevSample'
                            // it will become Y-value and X is at 'prevSample-1'
                            // and calculate interpolated value all the way to 'hiSample'
                            long x1 = sampler.previousTimestamp(prevSample);
                            if (x1 < loSample) {
                                // not enough data points
                                // fill all data points from 'sample' down with null
                                nullifyRange(sample, hiSample, mapRecord);
                            } else {
                                MapValue x1Value = findDataMapValue2(mapRecord, x1);
                                MapValue x2value = findDataMapValue(mapRecord, prevSample);
                                interpolate(sampler.nextTimestamp(prevSample), hiSample, mapRecord, x1, prevSample, x1Value, x2value);
                            }
                            break;
                        }
                    }
                }
            }
        }
        cursor.of(baseCursor, dataMap.getCursor());
        return cursor;
    } catch (Throwable e) {
        baseCursor.close();
        throw e;
    }
}
Also used : EmptyTableRandomRecordCursor(io.questdb.griffin.engine.EmptyTableRandomRecordCursor) MapKey(io.questdb.cairo.map.MapKey) SqlExecutionInterruptor(io.questdb.griffin.SqlExecutionInterruptor) MapValue(io.questdb.cairo.map.MapValue)

Example 2 with SqlExecutionInterruptor

use of io.questdb.griffin.SqlExecutionInterruptor in project questdb by bluestreak01.

the class AbstractSampleByFillRecordCursorFactory method getCursor.

@Override
public RecordCursor getCursor(SqlExecutionContext executionContext) throws SqlException {
    final RecordCursor baseCursor = base.getCursor(executionContext);
    final SqlExecutionInterruptor interruptor = executionContext.getSqlExecutionInterruptor();
    try {
        map.clear();
        // This factory fills gaps in data. To do that we
        // have to know all possible key values. Essentially, every time
        // we sample we return same set of key values with different
        // aggregation results and timestamp
        int n = groupByFunctions.size();
        final Record baseCursorRecord = baseCursor.getRecord();
        while (baseCursor.hasNext()) {
            interruptor.checkInterrupted();
            MapKey key = map.withKey();
            mapSink.copy(baseCursorRecord, key);
            MapValue value = key.createValue();
            if (value.isNew()) {
                // timestamp is always stored in value field 0
                value.putLong(0, Numbers.LONG_NaN);
                // this would set values for when keys are not found right away
                for (int i = 0; i < n; i++) {
                    groupByFunctions.getQuick(i).setNull(value);
                }
            }
        }
        // empty map? this means that base cursor was empty
        if (map.size() == 0) {
            baseCursor.close();
            return EmptyTableNoSizeRecordCursor.INSTANCE;
        }
        // because we pass base cursor twice we have to go back to top
        // for the second run
        baseCursor.toTop();
        boolean next = baseCursor.hasNext();
        // we know base cursor has value
        assert next;
        return initFunctionsAndCursor(executionContext, baseCursor);
    } catch (Throwable ex) {
        baseCursor.close();
        throw ex;
    }
}
Also used : EmptyTableNoSizeRecordCursor(io.questdb.griffin.engine.EmptyTableNoSizeRecordCursor) MapKey(io.questdb.cairo.map.MapKey) SqlExecutionInterruptor(io.questdb.griffin.SqlExecutionInterruptor) MapValue(io.questdb.cairo.map.MapValue)

Example 3 with SqlExecutionInterruptor

use of io.questdb.griffin.SqlExecutionInterruptor in project questdb by bluestreak01.

the class SortedLightRecordCursor method of.

@Override
public void of(RecordCursor base, SqlExecutionContext executionContext) {
    this.base = base;
    this.baseRecord = base.getRecord();
    final Record placeHolderRecord = base.getRecordB();
    SqlExecutionInterruptor interruptor = executionContext.getSqlExecutionInterruptor();
    chain.clear();
    while (base.hasNext()) {
        interruptor.checkInterrupted();
        // Tree chain is liable to re-position record to
        // other rows to do record comparison. We must use our
        // own record instance in case base cursor keeps
        // state in the record it returns.
        chain.put(baseRecord, base, placeHolderRecord, comparator);
    }
    chainCursor.toTop();
}
Also used : SqlExecutionInterruptor(io.questdb.griffin.SqlExecutionInterruptor) Record(io.questdb.cairo.sql.Record)

Example 4 with SqlExecutionInterruptor

use of io.questdb.griffin.SqlExecutionInterruptor in project questdb by bluestreak01.

the class SortedRecordCursor method of.

@Override
public void of(RecordCursor base, SqlExecutionContext executionContext) {
    try {
        this.chainCursor = chain.getCursor(base);
        final Record record = base.getRecord();
        SqlExecutionInterruptor interruptor = executionContext.getSqlExecutionInterruptor();
        chain.clear();
        while (base.hasNext()) {
            interruptor.checkInterrupted();
            // Tree chain is liable to re-position record to
            // other rows to do record comparison. We must use our
            // own record instance in case base cursor keeps
            // state in the record it returns.
            chain.put(record);
        }
        chainCursor.toTop();
    } catch (Throwable ex) {
        base.close();
        throw ex;
    }
}
Also used : SqlExecutionInterruptor(io.questdb.griffin.SqlExecutionInterruptor) Record(io.questdb.cairo.sql.Record)

Aggregations

SqlExecutionInterruptor (io.questdb.griffin.SqlExecutionInterruptor)4 MapKey (io.questdb.cairo.map.MapKey)2 MapValue (io.questdb.cairo.map.MapValue)2 Record (io.questdb.cairo.sql.Record)2 EmptyTableNoSizeRecordCursor (io.questdb.griffin.engine.EmptyTableNoSizeRecordCursor)1 EmptyTableRandomRecordCursor (io.questdb.griffin.engine.EmptyTableRandomRecordCursor)1