diff --git a/.github/gh_matrix_builder.py b/.github/gh_matrix_builder.py index 6d9a8606a40..2ea58bf5437 100755 --- a/.github/gh_matrix_builder.py +++ b/.github/gh_matrix_builder.py @@ -78,7 +78,7 @@ def build_debug_config(overrides): "ignored_tests": default_ignored_tests, "name": "Debug", "os": "ubuntu-22.04", - "pg_extra_args": "--enable-debug --enable-cassert --with-llvm LLVM_CONFIG=llvm-config-14", + "pg_extra_args": "CFLAGS=-march=native --enable-debug --enable-cassert --with-llvm LLVM_CONFIG=llvm-config-14", "pg_extensions": "postgres_fdw test_decoding pageinspect pgstattuple", "pginstallcheck": True, "tsdb_build_args": "-DWARNINGS_AS_ERRORS=ON -DREQUIRE_ALL_TESTS=ON", diff --git a/.github/workflows/linux-32bit-build-and-test.yaml b/.github/workflows/linux-32bit-build-and-test.yaml index c66d99b9bbf..620f509971d 100644 --- a/.github/workflows/linux-32bit-build-and-test.yaml +++ b/.github/workflows/linux-32bit-build-and-test.yaml @@ -47,7 +47,9 @@ jobs: CC: clang-14 CXX: clang++-14 DEBIAN_FRONTEND: noninteractive - IGNORES: "append-* transparent_decompression-* transparent_decompress_chunk-* pg_dump telemetry bgw_db_scheduler* hypercore_vacuum" + # vectorized_aggregation has different output on i386 because int8 is by + # reference and currently it cannot be used for vectorized hash grouping. + IGNORES: "append-* transparent_decompression-* transparent_decompress_chunk-* pg_dump telemetry bgw_db_scheduler* hypercore_vacuum vectorized_aggregation" SKIPS: chunk_adaptive histogram_test-* EXTENSIONS: "postgres_fdw test_decoding pageinspect pgstattuple" strategy: diff --git a/.unreleased/vectorized-agg-filter b/.unreleased/vectorized-agg-filter new file mode 100644 index 00000000000..79b88afb3db --- /dev/null +++ b/.unreleased/vectorized-agg-filter @@ -0,0 +1 @@ +Implements: #7458 Support vecorized aggregation with aggregate FILTER clauses that are also vectorizable diff --git a/.unreleased/vectorized-grouping-one-fixed b/.unreleased/vectorized-grouping-one-fixed new file mode 100644 index 00000000000..47f74a45210 --- /dev/null +++ b/.unreleased/vectorized-grouping-one-fixed @@ -0,0 +1 @@ +Implements: #7341 Vectorized aggregation with grouping by one fixed-size by-value compressed column (such as arithmetic types). diff --git a/scripts/clang_format_all.sh b/scripts/clang_format_all.sh index ea1bb03e8b8..5828d39b855 100755 --- a/scripts/clang_format_all.sh +++ b/scripts/clang_format_all.sh @@ -5,5 +5,5 @@ SCRIPT_DIR=$(cd "$(dirname $0)" || exit; pwd) BASE_DIR=$(dirname $SCRIPT_DIR) find ${BASE_DIR} \( -path "${BASE_DIR}/src/*" -or -path "${BASE_DIR}/test/*" -or -path "${BASE_DIR}/tsl/*" \) \ - -and -not \( -path "*/.*" -or -path "*CMake*" \) \ + -and -not \( -path "*/.*" -or -path "*CMake*" -or -path "${BASE_DIR}/tsl/src/import/*" \) \ -and \( -name '*.c' -or -name '*.h' \) -print0 | xargs -0 ${SCRIPT_DIR}/clang_format_wrapper.sh -style=file -i diff --git a/tsl/src/compression/arrow_c_data_interface.h b/tsl/src/compression/arrow_c_data_interface.h index 1473e24945b..a1f989c99e2 100644 --- a/tsl/src/compression/arrow_c_data_interface.h +++ b/tsl/src/compression/arrow_c_data_interface.h @@ -184,25 +184,73 @@ arrow_set_row_validity(uint64 *bitmap, size_t row_number, bool value) } /* - * AND two optional arrow validity bitmaps into the given storage. + * Combine the validity bitmaps into the given storage. */ static inline const uint64 * arrow_combine_validity(size_t num_words, uint64 *restrict storage, const uint64 *filter1, - const uint64 *filter2) + const uint64 *filter2, const uint64 *filter3) { + /* + * Any and all of the filters can be null. For simplicity, move the non-null + * filters to the leading positions. + */ + const uint64 *tmp; +#define SWAP(X, Y) \ + tmp = (X); \ + (X) = (Y); \ + (Y) = tmp; + if (filter1 == NULL) { - return filter2; + /* + * We have at least one NULL that goes to the last position. + */ + SWAP(filter1, filter3); + + if (filter1 == NULL) + { + /* + * We have another NULL that goes to the second position. + */ + SWAP(filter1, filter2); + } } + else + { + if (filter2 == NULL) + { + /* + * We have at least one NULL that goes to the last position. + */ + SWAP(filter2, filter3); + } + } +#undef SWAP + + Assert(filter2 == NULL || filter1 != NULL); + Assert(filter3 == NULL || filter2 != NULL); if (filter2 == NULL) { + /* Either have one non-null filter, or all of them are null. */ return filter1; } - for (size_t i = 0; i < num_words; i++) + if (filter3 == NULL) + { + /* Have two non-null filters. */ + for (size_t i = 0; i < num_words; i++) + { + storage[i] = filter1[i] & filter2[i]; + } + } + else { - storage[i] = filter1[i] & filter2[i]; + /* Have three non-null filters. */ + for (size_t i = 0; i < num_words; i++) + { + storage[i] = filter1[i] & filter2[i] & filter3[i]; + } } return storage; diff --git a/tsl/src/import/CMakeLists.txt b/tsl/src/import/CMakeLists.txt index ccac900c3ee..32e5a008652 100644 --- a/tsl/src/import/CMakeLists.txt +++ b/tsl/src/import/CMakeLists.txt @@ -1,2 +1,2 @@ -set(SOURCES "") -target_sources(${PROJECT_NAME} PRIVATE ${SOURCES}) +set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/umash.c) +target_sources(${TSL_LIBRARY_NAME} PRIVATE ${SOURCES}) diff --git a/tsl/src/import/ts_simplehash.h b/tsl/src/import/ts_simplehash.h new file mode 100644 index 00000000000..a2a1451753b --- /dev/null +++ b/tsl/src/import/ts_simplehash.h @@ -0,0 +1,1045 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ + +/* + * This file contains source code that was copied and/or modified from + * the PostgreSQL database, which is licensed under the open-source + * PostgreSQL License. Please see the NOTICE at the top level + * directory for a copy of the PostgreSQL License. + */ + +/* + * simplehash.h + * + * When included this file generates a "templated" (by way of macros) + * open-addressing hash table implementation specialized to user-defined + * types. + * + * It's probably not worthwhile to generate such a specialized implementation + * for hash tables that aren't performance or space sensitive. + * + * Compared to dynahash, simplehash has the following benefits: + * + * - Due to the "templated" code generation has known structure sizes and no + * indirect function calls (which show up substantially in dynahash + * profiles). These features considerably increase speed for small + * entries. + * - Open addressing has better CPU cache behavior than dynahash's chained + * hashtables. + * - The generated interface is type-safe and easier to use than dynahash, + * though at the cost of more complex setup. + * - Allocates memory in a MemoryContext or another allocator with a + * malloc/free style interface (which isn't easily usable in a shared + * memory context) + * - Does not require the overhead of a separate memory context. + * + * Usage notes: + * + * To generate a hash-table and associated functions for a use case several + * macros have to be #define'ed before this file is included. Including + * the file #undef's all those, so a new hash table can be generated + * afterwards. + * The relevant parameters are: + * - SH_PREFIX - prefix for all symbol names generated. A prefix of 'foo' + * will result in hash table type 'foo_hash' and functions like + * 'foo_insert'/'foo_lookup' and so forth. + * - SH_ELEMENT_TYPE - type of the contained elements + * - SH_KEY_TYPE - type of the hashtable's key + * - SH_DECLARE - if defined function prototypes and type declarations are + * generated + * - SH_DEFINE - if defined function definitions are generated + * - SH_SCOPE - in which scope (e.g. extern, static inline) do function + * declarations reside + * - SH_RAW_ALLOCATOR - if defined, memory contexts are not used; instead, + * use this to allocate bytes. The allocator must zero the returned space. + * - SH_USE_NONDEFAULT_ALLOCATOR - if defined no element allocator functions + * are defined, so you can supply your own + * The following parameters are only relevant when SH_DEFINE is defined: + * - SH_KEY - name of the element in SH_ELEMENT_TYPE containing the hash key + * - SH_EQUAL(table, a, b) - compare two table keys + * - SH_HASH_KEY(table, key) - generate hash for the key + * - SH_STORE_HASH - if defined the hash is stored in the elements + * - SH_GET_HASH(tb, a) - return the field to store the hash in + * + * While SH_STORE_HASH (and subsequently SH_GET_HASH) are optional, because + * the hash table implementation needs to compare hashes to move elements + * (particularly when growing the hash), it's preferable, if possible, to + * store the element's hash in the element's data type. If the hash is so + * stored, the hash table will also compare hashes before calling SH_EQUAL + * when comparing two keys. + * + * For convenience the hash table create functions accept a void pointer + * that will be stored in the hash table type's member private_data. This + * allows callbacks to reference caller provided data. + * + * For examples of usage look at tidbitmap.c (file local definition) and + * execnodes.h/execGrouping.c (exposed declaration, file local + * implementation). + * + * Hash table design: + * + * The hash table design chosen is a variant of linear open-addressing. The + * reason for doing so is that linear addressing is CPU cache & pipeline + * friendly. The biggest disadvantage of simple linear addressing schemes + * are highly variable lookup times due to clustering, and deletions + * leaving a lot of tombstones around. To address these issues a variant + * of "robin hood" hashing is employed. Robin hood hashing optimizes + * chaining lengths by moving elements close to their optimal bucket + * ("rich" elements), out of the way if a to-be-inserted element is further + * away from its optimal position (i.e. it's "poor"). While that can make + * insertions slower, the average lookup performance is a lot better, and + * higher fill factors can be used in a still performant manner. To avoid + * tombstones - which normally solve the issue that a deleted node's + * presence is relevant to determine whether a lookup needs to continue + * looking or is done - buckets following a deleted element are shifted + * backwards, unless they're empty or already at their optimal position. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/lib/simplehash.h + */ + +#include "port/pg_bitutils.h" + +/* helpers */ +#define SH_MAKE_PREFIX(a) CppConcat(a, _) +#define SH_MAKE_NAME(name) SH_MAKE_NAME_(SH_MAKE_PREFIX(SH_PREFIX), name) +#define SH_MAKE_NAME_(a, b) CppConcat(a, b) + +/* name macros for: */ + +/* type declarations */ +#define SH_TYPE SH_MAKE_NAME(hash) +#define SH_ITERATOR SH_MAKE_NAME(iterator) + +/* function declarations */ +#define SH_CREATE SH_MAKE_NAME(create) +#define SH_DESTROY SH_MAKE_NAME(destroy) +#define SH_RESET SH_MAKE_NAME(reset) +#define SH_INSERT SH_MAKE_NAME(insert) +#define SH_INSERT_HASH SH_MAKE_NAME(insert_hash) +#define SH_LOOKUP SH_MAKE_NAME(lookup) +#define SH_LOOKUP_HASH SH_MAKE_NAME(lookup_hash) +#define SH_GROW SH_MAKE_NAME(grow) +#define SH_START_ITERATE SH_MAKE_NAME(start_iterate) +#define SH_START_ITERATE_AT SH_MAKE_NAME(start_iterate_at) +#define SH_ITERATE SH_MAKE_NAME(iterate) +#define SH_ALLOCATE SH_MAKE_NAME(allocate) +#define SH_FREE SH_MAKE_NAME(free) +#define SH_STAT SH_MAKE_NAME(stat) + +/* internal helper functions (no externally visible prototypes) */ +#define SH_COMPUTE_PARAMETERS SH_MAKE_NAME(compute_parameters) +#define SH_NEXT SH_MAKE_NAME(next) +#define SH_PREV SH_MAKE_NAME(prev) +#define SH_DISTANCE_FROM_OPTIMAL SH_MAKE_NAME(distance) +#define SH_INITIAL_BUCKET SH_MAKE_NAME(initial_bucket) +#define SH_ENTRY_HASH SH_MAKE_NAME(entry_hash) +#define SH_INSERT_HASH_INTERNAL SH_MAKE_NAME(insert_hash_internal) +#define SH_LOOKUP_HASH_INTERNAL SH_MAKE_NAME(lookup_hash_internal) + +/* generate forward declarations necessary to use the hash table */ +#ifdef SH_DECLARE + +/* type definitions */ +typedef struct SH_TYPE +{ + /* + * Size of data / bucket array, 64 bits to handle UINT32_MAX sized hash + * tables. Note that the maximum number of elements is lower + * (SH_MAX_FILLFACTOR) + */ + uint64 size; + + /* how many elements have valid contents */ + uint32 members; + + /* mask for bucket and size calculations, based on size */ + uint32 sizemask; + + /* boundary after which to grow hashtable */ + uint32 grow_threshold; + + /* hash buckets */ + SH_ELEMENT_TYPE *restrict data; + +#ifndef SH_RAW_ALLOCATOR + /* memory context to use for allocations */ + MemoryContext ctx; +#endif + + /* user defined data, useful for callbacks */ + void *private_data; +} SH_TYPE; + +typedef struct SH_ITERATOR +{ + uint32 cur; /* current element */ + uint32 end; + bool done; /* iterator exhausted? */ +} SH_ITERATOR; + +/* externally visible function prototypes */ +#ifdef SH_RAW_ALLOCATOR +/* _hash _create(uint32 nelements, void *private_data) */ +SH_SCOPE SH_TYPE *SH_CREATE(uint32 nelements, void *private_data); +#else +/* + * _hash _create(MemoryContext ctx, uint32 nelements, + * void *private_data) + */ +SH_SCOPE SH_TYPE *SH_CREATE(MemoryContext ctx, uint32 nelements, void *private_data); +#endif + +/* void _destroy(_hash *tb) */ +SH_SCOPE void SH_DESTROY(SH_TYPE *tb); + +/* void _reset(_hash *tb) */ +SH_SCOPE void SH_RESET(SH_TYPE *tb); + +/* void _grow(_hash *tb, uint64 newsize) */ +SH_SCOPE void SH_GROW(SH_TYPE *tb, uint64 newsize); + +/* *_insert(_hash *tb, key, bool *found) */ +SH_SCOPE SH_ELEMENT_TYPE *SH_INSERT(SH_TYPE *tb, SH_KEY_TYPE key, bool *found); + +/* + * *_insert_hash(_hash *tb, key, uint32 hash, + * bool *found) + */ +SH_SCOPE SH_ELEMENT_TYPE *SH_INSERT_HASH(SH_TYPE *tb, SH_KEY_TYPE key, uint32 hash, bool *found); + +/* *_lookup(_hash *tb, key) */ +SH_SCOPE SH_ELEMENT_TYPE *SH_LOOKUP(SH_TYPE *tb, SH_KEY_TYPE key); + +/* *_lookup_hash(_hash *tb, key, uint32 hash) */ +SH_SCOPE SH_ELEMENT_TYPE *SH_LOOKUP_HASH(SH_TYPE *tb, SH_KEY_TYPE key, uint32 hash); + +/* void _start_iterate(_hash *tb, _iterator *iter) */ +SH_SCOPE void SH_START_ITERATE(SH_TYPE *tb, SH_ITERATOR *iter); + +/* + * void _start_iterate_at(_hash *tb, _iterator *iter, + * uint32 at) + */ +SH_SCOPE void SH_START_ITERATE_AT(SH_TYPE *tb, SH_ITERATOR *iter, uint32 at); + +/* *_iterate(_hash *tb, _iterator *iter) */ +SH_SCOPE SH_ELEMENT_TYPE *SH_ITERATE(SH_TYPE *tb, SH_ITERATOR *iter); + +/* void _stat(_hash *tb */ +SH_SCOPE void SH_STAT(SH_TYPE *tb); + +#endif /* SH_DECLARE */ + +/* generate implementation of the hash table */ +#ifdef SH_DEFINE + +#ifndef SH_RAW_ALLOCATOR +#include "utils/memutils.h" +#endif + +/* max data array size,we allow up to PG_UINT32_MAX buckets, including 0 */ +#define SH_MAX_SIZE (((uint64) PG_UINT32_MAX) + 1) + +/* normal fillfactor, unless already close to maximum */ +#ifndef SH_FILLFACTOR +#define SH_FILLFACTOR (0.9) +#endif +/* increase fillfactor if we otherwise would error out */ +#define SH_MAX_FILLFACTOR (0.98) +/* grow if actual and optimal location bigger than */ +#ifndef SH_GROW_MAX_DIB +#define SH_GROW_MAX_DIB 25 +#endif +/* grow if more than elements to move when inserting */ +#ifndef SH_GROW_MAX_MOVE +#define SH_GROW_MAX_MOVE 150 +#endif +#ifndef SH_GROW_MIN_FILLFACTOR +/* but do not grow due to SH_GROW_MAX_* if below */ +#define SH_GROW_MIN_FILLFACTOR 0.1 +#endif + +#ifdef SH_STORE_HASH +#define SH_COMPARE_KEYS(tb, ahash, akey, b) \ + (ahash == SH_GET_HASH(tb, b) && SH_EQUAL(tb, b->SH_KEY, akey)) +#else +#define SH_COMPARE_KEYS(tb, ahash, akey, b) (SH_EQUAL(tb, b->SH_KEY, akey)) +#endif + +/* + * Wrap the following definitions in include guards, to avoid multiple + * definition errors if this header is included more than once. The rest of + * the file deliberately has no include guards, because it can be included + * with different parameters to define functions and types with non-colliding + * names. + */ +#ifndef SIMPLEHASH_H +#define SIMPLEHASH_H + +#ifdef FRONTEND +#define sh_error(...) pg_fatal(__VA_ARGS__) +#define sh_log(...) pg_log_info(__VA_ARGS__) +#else +#define sh_error(...) elog(ERROR, __VA_ARGS__) +#define sh_log(...) elog(LOG, __VA_ARGS__) +#endif + +#endif + +/* + * Compute sizing parameters for hashtable. Called when creating and growing + * the hashtable. + */ +static inline void +SH_COMPUTE_PARAMETERS(SH_TYPE *tb, uint64 newsize) +{ + uint64 size; + + /* supporting zero sized hashes would complicate matters */ + size = Max(newsize, 2); + + /* round up size to the next power of 2, that's how bucketing works */ + size = pg_nextpower2_64(size); + Assert(size <= SH_MAX_SIZE); + + /* + * Verify that allocation of ->data is possible on this platform, without + * overflowing Size. + */ + if (unlikely((((uint64) sizeof(SH_ELEMENT_TYPE)) * size) >= SIZE_MAX / 2)) + sh_error("hash table too large"); + + /* now set size */ + tb->size = size; + tb->sizemask = (uint32) (size - 1); + + /* + * Compute the next threshold at which we need to grow the hash table + * again. + */ + if (tb->size == SH_MAX_SIZE) + tb->grow_threshold = ((double) tb->size) * SH_MAX_FILLFACTOR; + else + tb->grow_threshold = ((double) tb->size) * SH_FILLFACTOR; +} + +/* return the optimal bucket for the hash */ +static pg_attribute_always_inline uint32 +SH_INITIAL_BUCKET(SH_TYPE *tb, uint32 hash) +{ + return hash & tb->sizemask; +} + +/* return next bucket after the current, handling wraparound */ +static inline uint32 +SH_NEXT(SH_TYPE *tb, uint32 curelem, uint32 startelem) +{ + curelem = (curelem + 1) & tb->sizemask; + + Assert(curelem != startelem); + + return curelem; +} + +/* return bucket before the current, handling wraparound */ +static inline uint32 +SH_PREV(SH_TYPE *tb, uint32 curelem, uint32 startelem) +{ + curelem = (curelem - 1) & tb->sizemask; + + Assert(curelem != startelem); + + return curelem; +} + +/* return distance between bucket and its optimal position */ +static inline uint32 +SH_DISTANCE_FROM_OPTIMAL(SH_TYPE *tb, uint32 optimal, uint32 bucket) +{ + if (optimal <= bucket) + return bucket - optimal; + else + return (tb->size + bucket) - optimal; +} + +static inline uint32 +SH_ENTRY_HASH(SH_TYPE *tb, SH_ELEMENT_TYPE *entry) +{ +#ifdef SH_STORE_HASH + return SH_GET_HASH(tb, entry); +#else + return SH_HASH_KEY(tb, entry->SH_KEY); +#endif +} + +/* default memory allocator function */ +static inline void *SH_ALLOCATE(SH_TYPE *type, Size size); +static inline void SH_FREE(SH_TYPE *type, void *pointer); + +#ifndef SH_USE_NONDEFAULT_ALLOCATOR + +/* default memory allocator function */ +static inline void * +SH_ALLOCATE(SH_TYPE *type, Size size) +{ +#ifdef SH_RAW_ALLOCATOR + return SH_RAW_ALLOCATOR(size); +#else + return MemoryContextAllocExtended(type->ctx, size, MCXT_ALLOC_HUGE | MCXT_ALLOC_ZERO); +#endif +} + +/* default memory free function */ +static inline void +SH_FREE(SH_TYPE *type, void *pointer) +{ + pfree(pointer); +} + +#endif + +/* + * Create a hash table with enough space for `nelements` distinct members. + * Memory for the hash table is allocated from the passed-in context. If + * desired, the array of elements can be allocated using a passed-in allocator; + * this could be useful in order to place the array of elements in a shared + * memory, or in a context that will outlive the rest of the hash table. + * Memory other than for the array of elements will still be allocated from + * the passed-in context. + */ +#ifdef SH_RAW_ALLOCATOR +SH_SCOPE SH_TYPE * +SH_CREATE(uint32 nelements, void *private_data) +#else +SH_SCOPE SH_TYPE * +SH_CREATE(MemoryContext ctx, uint32 nelements, void *private_data) +#endif +{ + SH_TYPE *tb; + uint64 size; + +#ifdef SH_RAW_ALLOCATOR + tb = (SH_TYPE *) SH_RAW_ALLOCATOR(sizeof(SH_TYPE)); +#else + tb = (SH_TYPE *) MemoryContextAllocZero(ctx, sizeof(SH_TYPE)); + tb->ctx = ctx; +#endif + tb->private_data = private_data; + + /* increase nelements by fillfactor, want to store nelements elements */ + size = Min((double) SH_MAX_SIZE, ((double) nelements) / SH_FILLFACTOR); + + SH_COMPUTE_PARAMETERS(tb, size); + + tb->data = (SH_ELEMENT_TYPE *) SH_ALLOCATE(tb, sizeof(SH_ELEMENT_TYPE) * tb->size); + + return tb; +} + +/* destroy a previously created hash table */ +SH_SCOPE void +SH_DESTROY(SH_TYPE *tb) +{ + SH_FREE(tb, tb->data); + pfree(tb); +} + +/* reset the contents of a previously created hash table */ +SH_SCOPE void +SH_RESET(SH_TYPE *tb) +{ + memset(tb->data, 0, sizeof(SH_ELEMENT_TYPE) * tb->size); + tb->members = 0; +} + +/* + * Grow a hash table to at least `newsize` buckets. + * + * Usually this will automatically be called by insertions/deletions, when + * necessary. But resizing to the exact input size can be advantageous + * performance-wise, when known at some point. + */ +SH_SCOPE void +SH_GROW(SH_TYPE *tb, uint64 newsize) +{ + uint64 oldsize = tb->size; + SH_ELEMENT_TYPE *olddata = tb->data; + SH_ELEMENT_TYPE *newdata; + uint32 i; + uint32 startelem = 0; + uint32 copyelem; + + Assert(oldsize == pg_nextpower2_64(oldsize)); + Assert(oldsize != SH_MAX_SIZE); + Assert(oldsize < newsize); + + /* compute parameters for new table */ + SH_COMPUTE_PARAMETERS(tb, newsize); + + tb->data = (SH_ELEMENT_TYPE *) SH_ALLOCATE(tb, sizeof(SH_ELEMENT_TYPE) * tb->size); + + newdata = tb->data; + + /* + * Copy entries from the old data to newdata. We theoretically could use + * SH_INSERT here, to avoid code duplication, but that's more general than + * we need. We neither want tb->members increased, nor do we need to do + * deal with deleted elements, nor do we need to compare keys. So a + * special-cased implementation is lot faster. As resizing can be time + * consuming and frequent, that's worthwhile to optimize. + * + * To be able to simply move entries over, we have to start not at the + * first bucket (i.e olddata[0]), but find the first bucket that's either + * empty, or is occupied by an entry at its optimal position. Such a + * bucket has to exist in any table with a load factor under 1, as not all + * buckets are occupied, i.e. there always has to be an empty bucket. By + * starting at such a bucket we can move the entries to the larger table, + * without having to deal with conflicts. + */ + + /* search for the first element in the hash that's not wrapped around */ + for (i = 0; i < oldsize; i++) + { + SH_ELEMENT_TYPE *oldentry = &olddata[i]; + uint32 hash; + uint32 optimal; + + if (SH_ENTRY_EMPTY(oldentry)) + { + startelem = i; + break; + } + + hash = SH_ENTRY_HASH(tb, oldentry); + optimal = SH_INITIAL_BUCKET(tb, hash); + + if (optimal == i) + { + startelem = i; + break; + } + } + + /* and copy all elements in the old table */ + copyelem = startelem; + for (i = 0; i < oldsize; i++) + { + SH_ELEMENT_TYPE *oldentry = &olddata[copyelem]; + + if (!SH_ENTRY_EMPTY(oldentry)) + { + uint32 hash; + uint32 startelem; + uint32 curelem; + SH_ELEMENT_TYPE *newentry; + + hash = SH_ENTRY_HASH(tb, oldentry); + startelem = SH_INITIAL_BUCKET(tb, hash); + curelem = startelem; + + /* find empty element to put data into */ + while (true) + { + newentry = &newdata[curelem]; + + if (SH_ENTRY_EMPTY(newentry)) + { + break; + } + + curelem = SH_NEXT(tb, curelem, startelem); + } + + /* copy entry to new slot */ + memcpy(newentry, oldentry, sizeof(SH_ELEMENT_TYPE)); + } + + /* can't use SH_NEXT here, would use new size */ + copyelem++; + if (copyelem >= oldsize) + { + copyelem = 0; + } + } + + SH_FREE(tb, olddata); +} + +/* + * This is a separate static inline function, so it can be reliably be inlined + * into its wrapper functions even if SH_SCOPE is extern. + */ +static pg_attribute_always_inline SH_ELEMENT_TYPE * +SH_INSERT_HASH_INTERNAL(SH_TYPE *restrict tb, SH_KEY_TYPE key, uint32 hash, bool *found) +{ + /* + * We do the grow check even if the key is actually present, to avoid + * doing the check inside the loop. This also lets us avoid having to + * re-find our position in the hashtable after resizing. + * + * Note that this also reached when resizing the table due to + * SH_GROW_MAX_DIB / SH_GROW_MAX_MOVE. + */ + if (unlikely(tb->members >= tb->grow_threshold)) + { + if (unlikely(tb->size == SH_MAX_SIZE)) + sh_error("hash table size exceeded"); + + /* + * When optimizing, it can be very useful to print these out. + */ + /* SH_STAT(tb); */ + SH_GROW(tb, tb->size * 2); + /* SH_STAT(tb); */ + } + + SH_ELEMENT_TYPE *restrict data = tb->data; + + /* perform insert, start bucket search at optimal location */ + const uint32 startelem = SH_INITIAL_BUCKET(tb, hash); + uint32 curelem = startelem; + uint32 insertdist = 0; + while (true) + { + SH_ELEMENT_TYPE *entry = &data[curelem]; + + /* any empty bucket can directly be used */ + if (SH_ENTRY_EMPTY(entry)) + { + tb->members++; + entry->SH_KEY = key; +#ifdef SH_STORE_HASH + SH_GET_HASH(tb, entry) = hash; +#endif + *found = false; + return entry; + } + + /* + * If the bucket is not empty, we either found a match (in which case + * we're done), or we have to decide whether to skip over or move the + * colliding entry. When the colliding element's distance to its + * optimal position is smaller than the to-be-inserted entry's, we + * shift the colliding entry (and its followers) forward by one. + */ + + if (SH_COMPARE_KEYS(tb, hash, key, entry)) + { + Assert(!SH_ENTRY_EMPTY(entry)); + *found = true; + return entry; + } + + const uint32 curhash = SH_ENTRY_HASH(tb, entry); + const uint32 curoptimal = SH_INITIAL_BUCKET(tb, curhash); + const uint32 curdist = SH_DISTANCE_FROM_OPTIMAL(tb, curoptimal, curelem); + + if (insertdist > curdist) + { + /* We're going to insert at this position. */ + break; + } + + curelem = SH_NEXT(tb, curelem, startelem); + insertdist++; + + /* + * To avoid negative consequences from overly imbalanced hashtables, + * grow the hashtable if collisions lead to large runs. The most + * likely cause of such imbalance is filling a (currently) small + * table, from a currently big one, in hash-table order. Don't grow + * if the hashtable would be too empty, to prevent quick space + * explosion for some weird edge cases. + */ + if (unlikely(insertdist > SH_GROW_MAX_DIB) && + ((double) tb->members / tb->size) >= SH_GROW_MIN_FILLFACTOR) + { + SH_GROW(tb, tb->size * 2); + return SH_INSERT_HASH(tb, key, hash, found); + } + } + + /* Actually insert. */ + SH_ELEMENT_TYPE *entry = &data[curelem]; + SH_ELEMENT_TYPE *lastentry = entry; + uint32 emptyelem = curelem; + int32 emptydist = 0; + + /* find next empty bucket */ + while (true) + { + SH_ELEMENT_TYPE *emptyentry; + + emptyelem = SH_NEXT(tb, emptyelem, startelem); + emptyentry = &data[emptyelem]; + + if (SH_ENTRY_EMPTY(emptyentry)) + { + lastentry = emptyentry; + break; + } + + /* + * To avoid negative consequences from overly imbalanced + * hashtables, grow the hashtable if collisions would require + * us to move a lot of entries. The most likely cause of such + * imbalance is filling a (currently) small table, from a + * currently big one, in hash-table order. Don't grow if the + * hashtable would be too empty, to prevent quick space + * explosion for some weird edge cases. + */ + if (unlikely(++emptydist > SH_GROW_MAX_MOVE) && + ((double) tb->members / tb->size) >= SH_GROW_MIN_FILLFACTOR) + { + SH_GROW(tb, tb->size * 2); + return SH_INSERT_HASH(tb, key, hash, found); + } + } + + /* shift forward, starting at last occupied element */ + + /* + * TODO: This could be optimized to be one memcpy in many cases, + * excepting wrapping around at the end of ->data. Hasn't shown up + * in profiles so far though. + */ + uint32 moveelem = emptyelem; + while (moveelem != curelem) + { + SH_ELEMENT_TYPE *moveentry; + + moveelem = SH_PREV(tb, moveelem, startelem); + moveentry = &data[moveelem]; + + memcpy(lastentry, moveentry, sizeof(SH_ELEMENT_TYPE)); + lastentry = moveentry; + } + + /* and fill the now empty spot */ + tb->members++; + + entry->SH_KEY = key; +#ifdef SH_STORE_HASH + SH_GET_HASH(tb, entry) = hash; +#endif + *found = false; + return entry; +} + +/* + * Insert the key key into the hash-table, set *found to true if the key + * already exists, false otherwise. Returns the hash-table entry in either + * case. + */ +static pg_attribute_always_inline SH_ELEMENT_TYPE * +SH_INSERT(SH_TYPE *tb, SH_KEY_TYPE key, bool *found) +{ + uint32 hash = SH_HASH_KEY(tb, key); + + return SH_INSERT_HASH_INTERNAL(tb, key, hash, found); +} + +/* + * Insert the key key into the hash-table using an already-calculated + * hash. Set *found to true if the key already exists, false + * otherwise. Returns the hash-table entry in either case. + */ +SH_SCOPE SH_ELEMENT_TYPE * +SH_INSERT_HASH(SH_TYPE *tb, SH_KEY_TYPE key, uint32 hash, bool *found) +{ + return SH_INSERT_HASH_INTERNAL(tb, key, hash, found); +} + +/* + * This is a separate static inline function, so it can be reliably be inlined + * into its wrapper functions even if SH_SCOPE is extern. + */ +static inline SH_ELEMENT_TYPE * +SH_LOOKUP_HASH_INTERNAL(SH_TYPE *tb, SH_KEY_TYPE key, uint32 hash) +{ + const uint32 startelem = SH_INITIAL_BUCKET(tb, hash); + uint32 curelem = startelem; + + while (true) + { + SH_ELEMENT_TYPE *entry = &tb->data[curelem]; + + if (SH_ENTRY_EMPTY(entry)) + { + return NULL; + } + + Assert(!SH_ENTRY_EMPTY(entry)); + + if (SH_COMPARE_KEYS(tb, hash, key, entry)) + return entry; + + /* + * TODO: we could stop search based on distance. If the current + * buckets's distance-from-optimal is smaller than what we've skipped + * already, the entry doesn't exist. Probably only do so if + * SH_STORE_HASH is defined, to avoid re-computing hashes? + */ + + curelem = SH_NEXT(tb, curelem, startelem); + } +} + +/* + * Lookup up entry in hash table. Returns NULL if key not present. + */ +SH_SCOPE SH_ELEMENT_TYPE * +SH_LOOKUP(SH_TYPE *tb, SH_KEY_TYPE key) +{ + uint32 hash = SH_HASH_KEY(tb, key); + + return SH_LOOKUP_HASH_INTERNAL(tb, key, hash); +} + +/* + * Lookup up entry in hash table using an already-calculated hash. + * + * Returns NULL if key not present. + */ +SH_SCOPE SH_ELEMENT_TYPE * +SH_LOOKUP_HASH(SH_TYPE *tb, SH_KEY_TYPE key, uint32 hash) +{ + return SH_LOOKUP_HASH_INTERNAL(tb, key, hash); +} + +/* + * Initialize iterator. + */ +SH_SCOPE void +SH_START_ITERATE(SH_TYPE *tb, SH_ITERATOR *iter) +{ + uint64 startelem = PG_UINT64_MAX; + + /* + * Search for the first empty element. As deletions during iterations are + * supported, we want to start/end at an element that cannot be affected + * by elements being shifted. + */ + for (uint32 i = 0; i < tb->size; i++) + { + SH_ELEMENT_TYPE *entry = &tb->data[i]; + + if (SH_ENTRY_EMPTY(entry)) + { + startelem = i; + break; + } + } + + /* we should have found an empty element */ + Assert(startelem < SH_MAX_SIZE); + + /* + * Iterate backwards, that allows the current element to be deleted, even + * if there are backward shifts + */ + iter->cur = startelem; + iter->end = iter->cur; + iter->done = false; +} + +/* + * Initialize iterator to a specific bucket. That's really only useful for + * cases where callers are partially iterating over the hashspace, and that + * iteration deletes and inserts elements based on visited entries. Doing that + * repeatedly could lead to an unbalanced keyspace when always starting at the + * same position. + */ +SH_SCOPE void +SH_START_ITERATE_AT(SH_TYPE *tb, SH_ITERATOR *iter, uint32 at) +{ + /* + * Iterate backwards, that allows the current element to be deleted, even + * if there are backward shifts. + */ + iter->cur = at & tb->sizemask; /* ensure at is within a valid range */ + iter->end = iter->cur; + iter->done = false; +} + +/* + * Iterate over all entries in the hash-table. Return the next occupied entry, + * or NULL if done. + * + * During iteration the current entry in the hash table may be deleted, + * without leading to elements being skipped or returned twice. Additionally + * the rest of the table may be modified (i.e. there can be insertions or + * deletions), but if so, there's neither a guarantee that all nodes are + * visited at least once, nor a guarantee that a node is visited at most once. + */ +SH_SCOPE SH_ELEMENT_TYPE * +SH_ITERATE(SH_TYPE *tb, SH_ITERATOR *iter) +{ + while (!iter->done) + { + SH_ELEMENT_TYPE *elem; + + elem = &tb->data[iter->cur]; + + /* next element in backward direction */ + iter->cur = (iter->cur - 1) & tb->sizemask; + + if ((iter->cur & tb->sizemask) == (iter->end & tb->sizemask)) + iter->done = true; + if (!SH_ENTRY_EMPTY(elem)) + { + return elem; + } + } + + return NULL; +} + +/* + * Report some statistics about the state of the hashtable. For + * debugging/profiling purposes only. + */ +SH_SCOPE void +SH_STAT(SH_TYPE *tb) +{ + uint32 max_chain_length = 0; + uint32 total_chain_length = 0; + double avg_chain_length; + double fillfactor; + uint32 i; + + uint32 *collisions = (uint32 *) palloc0(tb->size * sizeof(uint32)); + uint32 total_collisions = 0; + uint32 max_collisions = 0; + double avg_collisions; + + for (i = 0; i < tb->size; i++) + { + uint32 hash; + uint32 optimal; + uint32 dist; + SH_ELEMENT_TYPE *elem; + + elem = &tb->data[i]; + + if (SH_ENTRY_EMPTY(elem)) + continue; + + hash = SH_ENTRY_HASH(tb, elem); + optimal = SH_INITIAL_BUCKET(tb, hash); + dist = SH_DISTANCE_FROM_OPTIMAL(tb, optimal, i); + + if (dist > max_chain_length) + max_chain_length = dist; + total_chain_length += dist; + + collisions[optimal]++; + } + + for (i = 0; i < tb->size; i++) + { + uint32 curcoll = collisions[i]; + + if (curcoll == 0) + continue; + + /* single contained element is not a collision */ + curcoll--; + total_collisions += curcoll; + if (curcoll > max_collisions) + max_collisions = curcoll; + } + + /* large enough to be worth freeing, even if just used for debugging */ + pfree(collisions); + + if (tb->members > 0) + { + fillfactor = tb->members / ((double) tb->size); + avg_chain_length = ((double) total_chain_length) / tb->members; + avg_collisions = ((double) total_collisions) / tb->members; + } + else + { + fillfactor = 0; + avg_chain_length = 0; + avg_collisions = 0; + } + + sh_log("size: " UINT64_FORMAT + ", members: %u, filled: %f, total chain: %u, max chain: %u, avg chain: %f, " + "total_collisions: %u, max_collisions: %u, avg_collisions: %f", + tb->size, + tb->members, + fillfactor, + total_chain_length, + max_chain_length, + avg_chain_length, + total_collisions, + max_collisions, + avg_collisions); +} + +#endif /* SH_DEFINE */ + +/* undefine external parameters, so next hash table can be defined */ +#undef SH_PREFIX +#undef SH_KEY_TYPE +#undef SH_KEY +#undef SH_ELEMENT_TYPE +#undef SH_HASH_KEY +#undef SH_SCOPE +#undef SH_DECLARE +#undef SH_DEFINE +#undef SH_GET_HASH +#undef SH_STORE_HASH +#undef SH_USE_NONDEFAULT_ALLOCATOR +#undef SH_EQUAL + +/* undefine locally declared macros */ +#undef SH_MAKE_PREFIX +#undef SH_MAKE_NAME +#undef SH_MAKE_NAME_ +#undef SH_FILLFACTOR +#undef SH_MAX_FILLFACTOR +#undef SH_GROW_MAX_DIB +#undef SH_GROW_MAX_MOVE +#undef SH_GROW_MIN_FILLFACTOR +#undef SH_MAX_SIZE + +/* types */ +#undef SH_TYPE +#undef SH_ITERATOR + +/* external function names */ +#undef SH_CREATE +#undef SH_DESTROY +#undef SH_RESET +#undef SH_INSERT +#undef SH_INSERT_HASH +#undef SH_LOOKUP +#undef SH_LOOKUP_HASH +#undef SH_GROW +#undef SH_START_ITERATE +#undef SH_START_ITERATE_AT +#undef SH_ITERATE +#undef SH_ALLOCATE +#undef SH_FREE +#undef SH_STAT + +/* internal function names */ +#undef SH_COMPUTE_PARAMETERS +#undef SH_COMPARE_KEYS +#undef SH_INITIAL_BUCKET +#undef SH_NEXT +#undef SH_PREV +#undef SH_DISTANCE_FROM_OPTIMAL +#undef SH_ENTRY_HASH +#undef SH_INSERT_HASH_INTERNAL +#undef SH_LOOKUP_HASH_INTERNAL diff --git a/tsl/src/import/umash.c b/tsl/src/import/umash.c new file mode 100644 index 00000000000..eebcf8e2ced --- /dev/null +++ b/tsl/src/import/umash.c @@ -0,0 +1,1568 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ + +/* + * This file contains source code that was copied and/or modified from + * the UMASH hash implementation at https://github.com/backtrace-labs/umash. + * + * This is a copy of umash.c, git commit sha + * fc4c5b6ca1f06c308e96c43aa080bd766238e092. + */ + +#include "umash.h" + +/* + * UMASH is distributed under the MIT license. + * + * SPDX-License-Identifier: MIT + * + * Copyright 2020-2022 Backtrace I/O, Inc. + * Copyright 2022 Paul Khuong + * Copyright 2022 Dougall Johnson + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if !defined(UMASH_TEST_ONLY) && !defined(NDEBUG) +#define NDEBUG +#endif + +/** + * -DUMASH_LONG_INPUTS=0 to disable the routine specialised for long + * inputs, and -DUMASH_LONG_INPUTS=1 to enable it. If the variable + * isn't defined, we try to probe for `umash_long.inc`: that's where + * the long input routines are defined. + */ +#ifndef UMASH_LONG_INPUTS +#ifdef __has_include +#if __has_include("umash_long.inc") +#define UMASH_LONG_INPUTS 1 +#endif /* __has_include() */ +#endif /* __has_include */ + +#ifndef UMASH_LONG_INPUTS +#define UMASH_LONG_INPUTS 0 +#endif /* !UMASH_LONG_INPUTS */ +#endif /* !UMASH_LONG_INPUTS */ + +/* + * Default to dynamically dispatching implementations on x86-64 + * (there's nothing to dispatch on aarch64). + */ +#ifndef UMASH_DYNAMIC_DISPATCH +#ifdef __x86_64__ +#define UMASH_DYNAMIC_DISPATCH 1 +#else +#define UMASH_DYNAMIC_DISPATCH 0 +#endif +#endif + +/* + * Enable inline assembly by default when building with recent GCC or + * compatible compilers. It should always be safe to disable this + * option, although there may be a performance cost. + */ +#ifndef UMASH_INLINE_ASM + +#if defined(__clang__) +/* + * We need clang 8+ for output flags, and 10+ for relaxed vector + * constraints. + */ +#if __clang_major__ >= 10 +#define UMASH_INLINE_ASM 1 +#else +#define UMASH_INLINE_ASM 0 +#endif /* __clang_major__ */ + +#elif defined(__GNUC__) +#if __GNUC__ >= 6 +#define UMASH_INLINE_ASM 1 +#else +#define UMASH_INLINE_ASM 0 +#endif /* __GNUC__ */ + +#else +#define UMASH_INLINE_ASM 0 +#endif + +#endif + +#include +#include + +#ifdef __PCLMUL__ +/* If we have access to x86 PCLMUL (and some basic SSE). */ +#include + +/* We only use 128-bit vector, as pairs of 64-bit integers. */ +typedef __m128i v128; + +#define V128_ZERO { 0 }; + +static inline v128 +v128_create(uint64_t lo, uint64_t hi) +{ + return _mm_set_epi64x(hi, lo); +} + +/* Shift each 64-bit lane left by one bit. */ +static inline v128 +v128_shift(v128 x) +{ + return _mm_add_epi64(x, x); +} + +/* Computes the 128-bit carryless product of x and y. */ +static inline v128 +v128_clmul(uint64_t x, uint64_t y) +{ + return _mm_clmulepi64_si128(_mm_cvtsi64_si128(x), _mm_cvtsi64_si128(y), 0); +} + +/* Computes the 128-bit carryless product of the high and low halves of x. */ +static inline v128 +v128_clmul_cross(v128 x) +{ + return _mm_clmulepi64_si128(x, x, 1); +} + +#elif defined(__ARM_FEATURE_CRYPTO) + +#include + +typedef uint64x2_t v128; + +#define V128_ZERO { 0 }; + +static inline v128 +v128_create(uint64_t lo, uint64_t hi) +{ + return vcombine_u64(vcreate_u64(lo), vcreate_u64(hi)); +} + +static inline v128 +v128_shift(v128 x) +{ + return vshlq_n_u64(x, 1); +} + +static inline v128 +v128_clmul(uint64_t x, uint64_t y) +{ + return vreinterpretq_u64_p128(vmull_p64(x, y)); +} + +static inline v128 +v128_clmul_cross(v128 x) +{ + v128 swapped = vextq_u64(x, x, 1); +#if UMASH_INLINE_ASM + /* Keep the result out of GPRs. */ + __asm__("" : "+w"(swapped)); +#endif + + return v128_clmul(vgetq_lane_u64(x, 0), vgetq_lane_u64(swapped, 0)); +} + +#else + +#error \ + "Unsupported platform: umash requires CLMUL (-mpclmul) on x86-64, or crypto (-march=...+crypto) extensions on aarch64." +#endif + +/* + * #define UMASH_STAP_PROBE=1 to insert probe points in public UMASH + * functions. + * + * This functionality depends on Systemtap's SDT header file. + */ +#if defined(UMASH_STAP_PROBE) && UMASH_STAP_PROBE +#include +#else +#define DTRACE_PROBE1(lib, name, a0) +#define DTRACE_PROBE2(lib, name, a0, a1) +#define DTRACE_PROBE3(lib, name, a0, a1, a2) +#define DTRACE_PROBE4(lib, name, a0, a1, a2, a3) +#endif + +/* + * #define UMASH_SECTION="special_section" to emit all UMASH symbols + * in the `special_section` ELF section. + */ +#if defined(UMASH_SECTION) && defined(__GNUC__) +#define FN __attribute__((__section__(UMASH_SECTION))) +#else +#define FN +#endif + +/* + * Defining UMASH_TEST_ONLY switches to a debug build with internal + * symbols exposed. + */ +#ifdef UMASH_TEST_ONLY +#define TEST_DEF FN +#include "t/umash_test_only.h" +#else +#define TEST_DEF static FN +#endif + +#ifdef __GNUC__ +#define LIKELY(X) __builtin_expect(!!(X), 1) +#define UNLIKELY(X) __builtin_expect(!!(X), 0) +#define HOT __attribute__((__hot__)) +#define COLD __attribute__((__cold__)) +#else +#define LIKELY(X) X +#define UNLIKELY(X) X +#define HOT +#define COLD +#endif + +#define ARRAY_SIZE(ARR) (sizeof(ARR) / sizeof(ARR[0])) + +#define BLOCK_SIZE (sizeof(uint64_t) * UMASH_OH_PARAM_COUNT) + +/* + * We derive independent short hashes by offsetting the constant array + * by four u64s. In theory, any positive even number works, but this + * is the constant we used in an earlier incarnation, and it works. + */ +#define OH_SHORT_HASH_SHIFT 4 + +/* Incremental UMASH consumes 16 bytes at a time. */ +#define INCREMENTAL_GRANULARITY 16 + +/** + * Modular arithmetic utilities. + * + * The code below uses GCC extensions. It should be possible to add + * support for other compilers. + */ + +#if !defined(__x86_64__) || !UMASH_INLINE_ASM +static inline void +mul128(uint64_t x, uint64_t y, uint64_t *hi, uint64_t *lo) +{ + __uint128_t product = x; + + product *= y; + *hi = product >> 64; + *lo = product; + return; +} +#else +static inline void +mul128(uint64_t x, uint64_t y, uint64_t *hi, uint64_t *lo) +{ + uint64_t mulhi, mullo; + + __asm__("mul %3" : "=a"(mullo), "=d"(mulhi) : "%a"(x), "r"(y) : "cc"); + *hi = mulhi; + *lo = mullo; + return; +} +#endif + +TEST_DEF inline uint64_t +add_mod_fast(uint64_t x, uint64_t y) +{ + unsigned long long sum; + + /* If `sum` overflows, `sum + 8` does not. */ + return (__builtin_uaddll_overflow(x, y, &sum) ? sum + 8 : sum); +} + +static FN COLD uint64_t +add_mod_slow_slow_path(uint64_t sum, uint64_t fixup) +{ + /* Reduce sum, mod 2**64 - 8. */ + sum = (sum >= (uint64_t)-8) ? sum + 8 : sum; + /* sum < 2**64 - 8, so this doesn't overflow. */ + sum += fixup; + /* Reduce again. */ + sum = (sum >= (uint64_t)-8) ? sum + 8 : sum; + return sum; +} + +TEST_DEF inline uint64_t +add_mod_slow(uint64_t x, uint64_t y) +{ + unsigned long long sum; + uint64_t fixup = 0; + + /* x + y \equiv sum + fixup */ + if (__builtin_uaddll_overflow(x, y, &sum)) + fixup = 8; + + /* + * We must ensure `sum + fixup < 2**64 - 8`. + * + * We want a conditional branch here, but not in the + * overflowing add: overflows happen roughly half the time on + * pseudorandom inputs, but `sum < 2**64 - 16` is almost + * always true, for pseudorandom `sum`. + */ + if (LIKELY(sum < (uint64_t)-16)) + return sum + fixup; + +#ifdef UMASH_INLINE_ASM + /* + * Some compilers like to compile the likely branch above with + * conditional moves or predication. Insert a compiler barrier + * in the slow path here to force a branch. + */ + __asm__("" : "+r"(sum)); +#endif + return add_mod_slow_slow_path(sum, fixup); +} + +TEST_DEF inline uint64_t +mul_mod_fast(uint64_t m, uint64_t x) +{ + uint64_t hi, lo; + + mul128(m, x, &hi, &lo); + return add_mod_fast(lo, 8 * hi); +} + +TEST_DEF inline uint64_t +horner_double_update(uint64_t acc, uint64_t m0, uint64_t m1, uint64_t x, uint64_t y) +{ + + acc = add_mod_fast(acc, x); + return add_mod_slow(mul_mod_fast(m0, acc), mul_mod_fast(m1, y)); +} + +/** + * Salsa20 stream generator, used to derive struct umash_param. + * + * Slightly prettified version of D. J. Bernstein's public domain NaCL + * (version 20110121), without paying any attention to constant time + * execution or any other side-channel. + */ +static inline uint32_t +rotate(uint32_t u, int c) +{ + + return (u << c) | (u >> (32 - c)); +} + +static inline uint32_t +load_littleendian(const void *buf) +{ + uint32_t ret = 0; + uint8_t x[4]; + + memcpy(x, buf, sizeof(x)); + for (size_t i = 0; i < 4; i++) + ret |= (uint32_t)x[i] << (8 * i); + + return ret; +} + +static inline void +store_littleendian(void *dst, uint32_t u) +{ + + for (size_t i = 0; i < 4; i++) { + uint8_t lo = u; + + memcpy(dst, &lo, 1); + u >>= 8; + dst = (char *)dst + 1; + } + + return; +} + +static FN void +core_salsa20(char *out, const uint8_t in[static 16], const uint8_t key[static 32], + const uint8_t constant[16]) +{ + enum { ROUNDS = 20 }; + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + + j0 = x0 = load_littleendian(constant + 0); + j1 = x1 = load_littleendian(key + 0); + j2 = x2 = load_littleendian(key + 4); + j3 = x3 = load_littleendian(key + 8); + j4 = x4 = load_littleendian(key + 12); + j5 = x5 = load_littleendian(constant + 4); + j6 = x6 = load_littleendian(in + 0); + j7 = x7 = load_littleendian(in + 4); + j8 = x8 = load_littleendian(in + 8); + j9 = x9 = load_littleendian(in + 12); + j10 = x10 = load_littleendian(constant + 8); + j11 = x11 = load_littleendian(key + 16); + j12 = x12 = load_littleendian(key + 20); + j13 = x13 = load_littleendian(key + 24); + j14 = x14 = load_littleendian(key + 28); + j15 = x15 = load_littleendian(constant + 12); + + for (size_t i = 0; i < ROUNDS; i += 2) { + x4 ^= rotate(x0 + x12, 7); + x8 ^= rotate(x4 + x0, 9); + x12 ^= rotate(x8 + x4, 13); + x0 ^= rotate(x12 + x8, 18); + x9 ^= rotate(x5 + x1, 7); + x13 ^= rotate(x9 + x5, 9); + x1 ^= rotate(x13 + x9, 13); + x5 ^= rotate(x1 + x13, 18); + x14 ^= rotate(x10 + x6, 7); + x2 ^= rotate(x14 + x10, 9); + x6 ^= rotate(x2 + x14, 13); + x10 ^= rotate(x6 + x2, 18); + x3 ^= rotate(x15 + x11, 7); + x7 ^= rotate(x3 + x15, 9); + x11 ^= rotate(x7 + x3, 13); + x15 ^= rotate(x11 + x7, 18); + x1 ^= rotate(x0 + x3, 7); + x2 ^= rotate(x1 + x0, 9); + x3 ^= rotate(x2 + x1, 13); + x0 ^= rotate(x3 + x2, 18); + x6 ^= rotate(x5 + x4, 7); + x7 ^= rotate(x6 + x5, 9); + x4 ^= rotate(x7 + x6, 13); + x5 ^= rotate(x4 + x7, 18); + x11 ^= rotate(x10 + x9, 7); + x8 ^= rotate(x11 + x10, 9); + x9 ^= rotate(x8 + x11, 13); + x10 ^= rotate(x9 + x8, 18); + x12 ^= rotate(x15 + x14, 7); + x13 ^= rotate(x12 + x15, 9); + x14 ^= rotate(x13 + x12, 13); + x15 ^= rotate(x14 + x13, 18); + } + + x0 += j0; + x1 += j1; + x2 += j2; + x3 += j3; + x4 += j4; + x5 += j5; + x6 += j6; + x7 += j7; + x8 += j8; + x9 += j9; + x10 += j10; + x11 += j11; + x12 += j12; + x13 += j13; + x14 += j14; + x15 += j15; + + store_littleendian(out + 0, x0); + store_littleendian(out + 4, x1); + store_littleendian(out + 8, x2); + store_littleendian(out + 12, x3); + store_littleendian(out + 16, x4); + store_littleendian(out + 20, x5); + store_littleendian(out + 24, x6); + store_littleendian(out + 28, x7); + store_littleendian(out + 32, x8); + store_littleendian(out + 36, x9); + store_littleendian(out + 40, x10); + store_littleendian(out + 44, x11); + store_littleendian(out + 48, x12); + store_littleendian(out + 52, x13); + store_littleendian(out + 56, x14); + store_littleendian(out + 60, x15); + return; +} + +TEST_DEF void +salsa20_stream( + void *dst, size_t len, const uint8_t nonce[static 8], const uint8_t key[static 32]) +{ + static const uint8_t sigma[16] = "expand 32-byte k"; + uint8_t in[16]; + + if (len == 0) + return; + + memcpy(in, nonce, 8); + memset(in + 8, 0, 8); + + while (len >= 64) { + unsigned int u; + + core_salsa20(dst, in, key, sigma); + u = 1; + for (size_t i = 8; i < 16; i++) { + u += in[i]; + in[i] = u; + u >>= 8; + } + + dst = (char *)dst + 64; + len -= 64; + } + + if (len > 0) { + char block[64]; + + core_salsa20(block, in, key, sigma); + memcpy(dst, block, len); + } + + return; +} + +#if defined(UMASH_TEST_ONLY) || UMASH_LONG_INPUTS +#include "umash_long.inc" +#endif + +/** + * OH block compression. + */ +TEST_DEF struct umash_oh +oh_varblock(const uint64_t *params, uint64_t tag, const void *block, size_t n_bytes) +{ + struct umash_oh ret; + v128 acc = V128_ZERO; + + /* The final block processes `remaining > 0` bytes. */ + size_t remaining = 1 + ((n_bytes - 1) % sizeof(v128)); + size_t end_full_pairs = (n_bytes - remaining) / sizeof(uint64_t); + const void *last_ptr = (const char *)block + n_bytes - sizeof(v128); + size_t i; + + for (i = 0; i < end_full_pairs; i += 2) { + v128 x, k; + + memcpy(&x, block, sizeof(x)); + block = (const char *)block + sizeof(x); + + memcpy(&k, ¶ms[i], sizeof(k)); + x ^= k; + acc ^= v128_clmul_cross(x); + } + + memcpy(&ret, &acc, sizeof(ret)); + + /* Compress the final (potentially partial) pair. */ + { + uint64_t x, y, enh_hi, enh_lo; + + memcpy(&x, last_ptr, sizeof(x)); + last_ptr = (const char *)last_ptr + sizeof(x); + memcpy(&y, last_ptr, sizeof(y)); + + x += params[i]; + y += params[i + 1]; + mul128(x, y, &enh_hi, &enh_lo); + enh_hi += tag; + + ret.bits[0] ^= enh_lo; + ret.bits[1] ^= enh_hi ^ enh_lo; + } + + return ret; +} + +TEST_DEF void +oh_varblock_fprint(struct umash_oh dst[static restrict 2], + const uint64_t *restrict params, uint64_t tag, const void *restrict block, + size_t n_bytes) +{ + v128 acc = V128_ZERO; /* Base umash */ + v128 acc_shifted = V128_ZERO; /* Accumulates shifted values */ + v128 lrc; + /* The final block processes `remaining > 0` bytes. */ + size_t remaining = 1 + ((n_bytes - 1) % sizeof(v128)); + size_t end_full_pairs = (n_bytes - remaining) / sizeof(uint64_t); + const void *last_ptr = (const char *)block + n_bytes - sizeof(v128); + size_t i; + + lrc = v128_create(params[UMASH_OH_PARAM_COUNT], params[UMASH_OH_PARAM_COUNT + 1]); + for (i = 0; i < end_full_pairs; i += 2) { + v128 x, k; + + memcpy(&x, block, sizeof(x)); + block = (const char *)block + sizeof(x); + + memcpy(&k, ¶ms[i], sizeof(k)); + + x ^= k; + lrc ^= x; + + x = v128_clmul_cross(x); + + acc ^= x; + if (i + 2 >= end_full_pairs) + break; + + acc_shifted ^= x; + acc_shifted = v128_shift(acc_shifted); + } + + /* + * Update the LRC for the last chunk before treating it + * specially. + */ + { + v128 x, k; + + memcpy(&x, last_ptr, sizeof(x)); + memcpy(&k, ¶ms[end_full_pairs], sizeof(k)); + + lrc ^= x ^ k; + } + + acc_shifted ^= acc; + acc_shifted = v128_shift(acc_shifted); + + acc_shifted ^= v128_clmul_cross(lrc); + + memcpy(&dst[0], &acc, sizeof(dst[0])); + memcpy(&dst[1], &acc_shifted, sizeof(dst[1])); + + { + uint64_t x, y, kx, ky, enh_hi, enh_lo; + + memcpy(&x, last_ptr, sizeof(x)); + last_ptr = (const char *)last_ptr + sizeof(x); + memcpy(&y, last_ptr, sizeof(y)); + + kx = x + params[end_full_pairs]; + ky = y + params[end_full_pairs + 1]; + + mul128(kx, ky, &enh_hi, &enh_lo); + enh_hi += tag; + + enh_hi ^= enh_lo; + dst[0].bits[0] ^= enh_lo; + dst[0].bits[1] ^= enh_hi; + + dst[1].bits[0] ^= enh_lo; + dst[1].bits[1] ^= enh_hi; + } + + return; +} + +/** + * Returns `then` if `cond` is true, `otherwise` if false. + * + * This noise helps compiler emit conditional moves. + */ +static inline const void * +select_ptr(bool cond, const void *then, const void *otherwise) +{ + const char *ret; + +#if UMASH_INLINE_ASM + /* Force strict evaluation of both arguments. */ + __asm__("" ::"r"(then), "r"(otherwise)); +#endif + + ret = (cond) ? then : otherwise; + +#if UMASH_INLINE_ASM + /* And also force the result to be materialised with a blackhole. */ + __asm__("" : "+r"(ret)); +#endif + return ret; +} + +/** + * Short UMASH (<= 8 bytes). + */ +TEST_DEF inline uint64_t +vec_to_u64(const void *data, size_t n_bytes) +{ + const char zeros[2] = { 0 }; + uint32_t hi, lo; + + /* + * If there are at least 4 bytes to read, read the first 4 in + * `lo`, and the last 4 in `hi`. This covers the whole range, + * since `n_bytes` is at most 8. + */ + if (LIKELY(n_bytes >= sizeof(lo))) { + memcpy(&lo, data, sizeof(lo)); + memcpy(&hi, (const char *)data + n_bytes - sizeof(hi), sizeof(hi)); + } else { + /* 0 <= n_bytes < 4. Decode the size in binary. */ + uint16_t word; + uint8_t byte; + + /* + * If the size is odd, load the first byte in `byte`; + * otherwise, load in a zero. + */ + memcpy(&byte, select_ptr(n_bytes & 1, data, zeros), 1); + lo = byte; + + /* + * If the size is 2 or 3, load the last two bytes in `word`; + * otherwise, load in a zero. + */ + memcpy(&word, + select_ptr(n_bytes & 2, (const char *)data + n_bytes - 2, zeros), 2); + /* + * We have now read `bytes[0 ... n_bytes - 1]` + * exactly once without overwriting any data. + */ + hi = word; + } + + /* + * Mix `hi` with the `lo` bits: SplitMix64 seems to have + * trouble with the top 4 bits. + */ + return ((uint64_t)hi << 32) | (lo + hi); +} + +TEST_DEF uint64_t +umash_short(const uint64_t *params, uint64_t seed, const void *data, size_t n_bytes) +{ + uint64_t h; + + seed += params[n_bytes]; + h = vec_to_u64(data, n_bytes); + h ^= h >> 30; + h *= 0xbf58476d1ce4e5b9ULL; + h = (h ^ seed) ^ (h >> 27); + h *= 0x94d049bb133111ebULL; + h ^= h >> 31; + return h; +} + +static FN struct umash_fp +umash_fp_short(const uint64_t *params, uint64_t seed, const void *data, size_t n_bytes) +{ + struct umash_fp ret; + uint64_t h; + + ret.hash[0] = seed + params[n_bytes]; + ret.hash[1] = seed + params[n_bytes + OH_SHORT_HASH_SHIFT]; + + h = vec_to_u64(data, n_bytes); + h ^= h >> 30; + h *= 0xbf58476d1ce4e5b9ULL; + h ^= h >> 27; + +#define TAIL(i) \ + do { \ + ret.hash[i] ^= h; \ + ret.hash[i] *= 0x94d049bb133111ebULL; \ + ret.hash[i] ^= ret.hash[i] >> 31; \ + } while (0) + + TAIL(0); + TAIL(1); +#undef TAIL + + return ret; +} + +/** + * Rotates `x` left by `n` bits. + */ +static inline uint64_t +rotl64(uint64_t x, int n) +{ + + return (x << n) | (x >> (64 - n)); +} + +TEST_DEF inline uint64_t +finalize(uint64_t x) +{ + + return (x ^ rotl64(x, 8)) ^ rotl64(x, 33); +} + +TEST_DEF uint64_t +umash_medium(const uint64_t multipliers[static 2], const uint64_t *oh, uint64_t seed, + const void *data, size_t n_bytes) +{ + uint64_t enh_hi, enh_lo; + + { + uint64_t x, y; + + memcpy(&x, data, sizeof(x)); + memcpy(&y, (const char *)data + n_bytes - sizeof(y), sizeof(y)); + x += oh[0]; + y += oh[1]; + + mul128(x, y, &enh_hi, &enh_lo); + enh_hi += seed ^ n_bytes; + } + + enh_hi ^= enh_lo; + return finalize(horner_double_update( + /*acc=*/0, multipliers[0], multipliers[1], enh_lo, enh_hi)); +} + +static FN struct umash_fp +umash_fp_medium(const uint64_t multipliers[static 2][2], const uint64_t *oh, + uint64_t seed, const void *data, size_t n_bytes) +{ + struct umash_fp ret; + const uint64_t offset = seed ^ n_bytes; + uint64_t enh_hi, enh_lo; + union { + v128 v; + uint64_t u64[2]; + } mixed_lrc; + uint64_t lrc[2] = { oh[UMASH_OH_PARAM_COUNT], oh[UMASH_OH_PARAM_COUNT + 1] }; + uint64_t x, y; + uint64_t a, b; + + /* Expand the 9-16 bytes to 16. */ + memcpy(&x, data, sizeof(x)); + memcpy(&y, (const char *)data + n_bytes - sizeof(y), sizeof(y)); + + a = oh[0]; + b = oh[1]; + + lrc[0] ^= x ^ a; + lrc[1] ^= y ^ b; + mixed_lrc.v = v128_clmul(lrc[0], lrc[1]); + + a += x; + b += y; + + mul128(a, b, &enh_hi, &enh_lo); + enh_hi += offset; + enh_hi ^= enh_lo; + + ret.hash[0] = finalize(horner_double_update( + /*acc=*/0, multipliers[0][0], multipliers[0][1], enh_lo, enh_hi)); + + ret.hash[1] = finalize(horner_double_update(/*acc=*/0, multipliers[1][0], + multipliers[1][1], enh_lo ^ mixed_lrc.u64[0], enh_hi ^ mixed_lrc.u64[1])); + + return ret; +} + +TEST_DEF uint64_t +umash_long(const uint64_t multipliers[static 2], const uint64_t *oh, uint64_t seed, + const void *data, size_t n_bytes) +{ + uint64_t acc = 0; + + /* + * umash_long.inc defines this variable when the long input + * routine is enabled. + */ +#ifdef UMASH_MULTIPLE_BLOCKS_THRESHOLD + if (UNLIKELY(n_bytes >= UMASH_MULTIPLE_BLOCKS_THRESHOLD)) { + size_t n_block = n_bytes / BLOCK_SIZE; + const void *remaining; + + n_bytes %= BLOCK_SIZE; + remaining = (const char *)data + (n_block * BLOCK_SIZE); + acc = umash_multiple_blocks(acc, multipliers, oh, seed, data, n_block); + + data = remaining; + if (n_bytes == 0) + goto finalize; + + goto last_block; + } +#else + /* Avoid warnings about the unused labels. */ + if (0) { + goto last_block; + goto finalize; + } +#endif + + while (n_bytes > BLOCK_SIZE) { + struct umash_oh compressed; + + compressed = oh_varblock(oh, seed, data, BLOCK_SIZE); + data = (const char *)data + BLOCK_SIZE; + n_bytes -= BLOCK_SIZE; + + acc = horner_double_update(acc, multipliers[0], multipliers[1], + compressed.bits[0], compressed.bits[1]); + } + +last_block: + /* Do the final block. */ + { + struct umash_oh compressed; + + seed ^= (uint8_t)n_bytes; + compressed = oh_varblock(oh, seed, data, n_bytes); + acc = horner_double_update(acc, multipliers[0], multipliers[1], + compressed.bits[0], compressed.bits[1]); + } + +finalize: + return finalize(acc); +} + +TEST_DEF struct umash_fp +umash_fp_long(const uint64_t multipliers[static 2][2], const uint64_t *oh, uint64_t seed, + const void *data, size_t n_bytes) +{ + struct umash_oh compressed[2]; + struct umash_fp ret; + uint64_t acc[2] = { 0, 0 }; + +#ifdef UMASH_MULTIPLE_BLOCKS_THRESHOLD + if (UNLIKELY(n_bytes >= UMASH_MULTIPLE_BLOCKS_THRESHOLD)) { + struct umash_fp poly = { .hash = { 0, 0 } }; + size_t n_block = n_bytes / BLOCK_SIZE; + const void *remaining; + + n_bytes %= BLOCK_SIZE; + remaining = (const char *)data + (n_block * BLOCK_SIZE); + poly = umash_fprint_multiple_blocks( + poly, multipliers, oh, seed, data, n_block); + + acc[0] = poly.hash[0]; + acc[1] = poly.hash[1]; + + data = remaining; + if (n_bytes == 0) + goto finalize; + + goto last_block; + } +#else + /* Avoid warnings about the unused labels. */ + if (0) { + goto last_block; + goto finalize; + } +#endif + + while (n_bytes > BLOCK_SIZE) { + oh_varblock_fprint(compressed, oh, seed, data, BLOCK_SIZE); + +#define UPDATE(i) \ + acc[i] = horner_double_update(acc[i], multipliers[i][0], multipliers[i][1], \ + compressed[i].bits[0], compressed[i].bits[1]) + + UPDATE(0); + UPDATE(1); +#undef UPDATE + + data = (const char *)data + BLOCK_SIZE; + n_bytes -= BLOCK_SIZE; + } + +last_block: + oh_varblock_fprint(compressed, oh, seed ^ (uint8_t)n_bytes, data, n_bytes); + +#define FINAL(i) \ + do { \ + acc[i] = horner_double_update(acc[i], multipliers[i][0], \ + multipliers[i][1], compressed[i].bits[0], compressed[i].bits[1]); \ + } while (0) + + FINAL(0); + FINAL(1); +#undef FINAL + +finalize: + ret.hash[0] = finalize(acc[0]); + ret.hash[1] = finalize(acc[1]); + return ret; +} + +static FN bool +value_is_repeated(const uint64_t *values, size_t n, uint64_t needle) +{ + + for (size_t i = 0; i < n; i++) { + if (values[i] == needle) + return true; + } + + return false; +} + +FN bool +umash_params_prepare(struct umash_params *params) +{ + static const uint64_t modulo = (1UL << 61) - 1; + /* + * The polynomial parameters have two redundant fields (for + * the pre-squared multipliers). Use them as our source of + * extra entropy if needed. + */ + uint64_t buf[] = { params->poly[0][0], params->poly[1][0] }; + size_t buf_idx = 0; + +#define GET_RANDOM(DST) \ + do { \ + if (buf_idx >= ARRAY_SIZE(buf)) \ + return false; \ + \ + (DST) = buf[buf_idx++]; \ + } while (0) + + /* Check the polynomial multipliers: we don't want 0s. */ + for (size_t i = 0; i < ARRAY_SIZE(params->poly); i++) { + uint64_t f = params->poly[i][1]; + + while (true) { + /* + * Zero out bits and use rejection sampling to + * guarantee uniformity. + */ + f &= (1UL << 61) - 1; + if (f != 0 && f < modulo) + break; + + GET_RANDOM(f); + } + + /* We can work in 2**64 - 8 and reduce after the fact. */ + params->poly[i][0] = mul_mod_fast(f, f) % modulo; + params->poly[i][1] = f; + } + + /* Avoid repeated OH noise values. */ + for (size_t i = 0; i < ARRAY_SIZE(params->oh); i++) { + while (value_is_repeated(params->oh, i, params->oh[i])) + GET_RANDOM(params->oh[i]); + } + + return true; +} + +FN void +umash_params_derive(struct umash_params *params, uint64_t bits, const void *key) +{ + uint8_t umash_key[32] = "Do not use UMASH VS adversaries."; + + if (key != NULL) + memcpy(umash_key, key, sizeof(umash_key)); + + while (true) { + uint8_t nonce[8]; + + for (size_t i = 0; i < 8; i++) + nonce[i] = bits >> (8 * i); + + salsa20_stream(params, sizeof(*params), nonce, umash_key); + if (umash_params_prepare(params)) + return; + + /* + * This should practically never fail, so really + * shouldn't happen multiple times. If it does, an + * infinite loop is as good as anything else. + */ + bits++; + } +} + +/* + * Updates the polynomial state at the end of a block. + */ +static FN void +sink_update_poly(struct umash_sink *sink) +{ + uint64_t oh0, oh1; + + oh0 = sink->oh_acc.bits[0]; + oh1 = sink->oh_acc.bits[1]; + sink->poly_state[0].acc = horner_double_update(sink->poly_state[0].acc, + sink->poly_state[0].mul[0], sink->poly_state[0].mul[1], oh0, oh1); + + sink->oh_acc = (struct umash_oh) { .bits = { 0 } }; + if (sink->hash_wanted == 0) + return; + + oh0 = sink->oh_twisted.acc.bits[0]; + oh1 = sink->oh_twisted.acc.bits[1]; + sink->poly_state[1].acc = horner_double_update(sink->poly_state[1].acc, + sink->poly_state[1].mul[0], sink->poly_state[1].mul[1], oh0, oh1); + + sink->oh_twisted = + (struct umash_twisted_oh) { .lrc = { sink->oh[UMASH_OH_PARAM_COUNT], + sink->oh[UMASH_OH_PARAM_COUNT + 1] } }; + return; +} + +/* + * Updates the OH state with 16 bytes of data. If `final` is true, we + * are definitely consuming the last chunk in the input. + */ +static FN void +sink_consume_buf( + struct umash_sink *sink, const char buf[static INCREMENTAL_GRANULARITY], bool final) +{ + const size_t buf_begin = sizeof(sink->buf) - INCREMENTAL_GRANULARITY; + const size_t param = sink->oh_iter; + const uint64_t k0 = sink->oh[param]; + const uint64_t k1 = sink->oh[param + 1]; + uint64_t x, y; + + /* Use GPR loads to avoid forwarding stalls. */ + memcpy(&x, buf, sizeof(x)); + memcpy(&y, buf + sizeof(x), sizeof(y)); + + /* All but the last 16-byte chunk of each block goes through PH. */ + if (sink->oh_iter < UMASH_OH_PARAM_COUNT - 2 && !final) { + v128 acc, h, twisted_acc, prev; + uint64_t m0, m1; + + m0 = x ^ k0; + m1 = y ^ k1; + + memcpy(&acc, &sink->oh_acc, sizeof(acc)); + h = v128_clmul(m0, m1); + acc ^= h; + memcpy(&sink->oh_acc, &acc, sizeof(acc)); + + if (sink->hash_wanted == 0) + goto next; + + sink->oh_twisted.lrc[0] ^= m0; + sink->oh_twisted.lrc[1] ^= m1; + + memcpy(&twisted_acc, &sink->oh_twisted.acc, sizeof(twisted_acc)); + memcpy(&prev, sink->oh_twisted.prev, sizeof(prev)); + + twisted_acc ^= prev; + twisted_acc = v128_shift(twisted_acc); + memcpy(&sink->oh_twisted.acc, &twisted_acc, sizeof(twisted_acc)); + memcpy(&sink->oh_twisted.prev, &h, sizeof(h)); + } else { + /* The last chunk is combined with the size tag with ENH. */ + uint64_t tag = sink->seed ^ (uint8_t)(sink->block_size + sink->bufsz); + uint64_t enh_hi, enh_lo; + + mul128(x + k0, y + k1, &enh_hi, &enh_lo); + enh_hi += tag; + enh_hi ^= enh_lo; + + if (sink->hash_wanted != 0) { + union { + v128 vec; + uint64_t h[2]; + } lrc_hash; + uint64_t lrc0, lrc1; + uint64_t oh0, oh1; + uint64_t oh_twisted0, oh_twisted1; + + lrc0 = sink->oh_twisted.lrc[0] ^ x ^ k0; + lrc1 = sink->oh_twisted.lrc[1] ^ y ^ k1; + lrc_hash.vec = v128_clmul(lrc0, lrc1); + + oh_twisted0 = sink->oh_twisted.acc.bits[0]; + oh_twisted1 = sink->oh_twisted.acc.bits[1]; + + oh0 = sink->oh_acc.bits[0]; + oh1 = sink->oh_acc.bits[1]; + oh0 ^= oh_twisted0; + oh0 <<= 1; + oh1 ^= oh_twisted1; + oh1 <<= 1; + + oh0 ^= lrc_hash.h[0]; + oh1 ^= lrc_hash.h[1]; + sink->oh_twisted.acc.bits[0] = oh0 ^ enh_lo; + sink->oh_twisted.acc.bits[1] = oh1 ^ enh_hi; + } + + sink->oh_acc.bits[0] ^= enh_lo; + sink->oh_acc.bits[1] ^= enh_hi; + } + +next: + memmove(&sink->buf, buf, buf_begin); + sink->block_size += sink->bufsz; + sink->bufsz = 0; + sink->oh_iter += 2; + + if (sink->oh_iter == UMASH_OH_PARAM_COUNT || final) { + sink_update_poly(sink); + sink->block_size = 0; + sink->oh_iter = 0; + } + + return; +} + +/** + * Hashes full 256-byte blocks into a sink that just dumped its OH + * state in the toplevel polynomial hash and reset the block state. + */ +static FN size_t +block_sink_update(struct umash_sink *sink, const void *data, size_t n_bytes) +{ + size_t consumed = 0; + + assert(n_bytes >= BLOCK_SIZE); + assert(sink->bufsz == 0); + assert(sink->block_size == 0); + assert(sink->oh_iter == 0); + +#ifdef UMASH_MULTIPLE_BLOCKS_THRESHOLD + if (UNLIKELY(n_bytes > UMASH_MULTIPLE_BLOCKS_THRESHOLD)) { + /* + * We leave the last block (partial or not) for the + * caller: incremental hashing must save some state + * at the end of a block. + */ + size_t n_blocks = (n_bytes - 1) / BLOCK_SIZE; + + if (sink->hash_wanted != 0) { + const uint64_t multipliers[2][2] = { + [0][0] = sink->poly_state[0].mul[0], + [0][1] = sink->poly_state[0].mul[1], + [1][0] = sink->poly_state[1].mul[0], + [1][1] = sink->poly_state[1].mul[1], + }; + struct umash_fp poly = { + .hash[0] = sink->poly_state[0].acc, + .hash[1] = sink->poly_state[1].acc, + }; + + poly = umash_fprint_multiple_blocks( + poly, multipliers, sink->oh, sink->seed, data, n_blocks); + + sink->poly_state[0].acc = poly.hash[0]; + sink->poly_state[1].acc = poly.hash[1]; + } else { + sink->poly_state[0].acc = umash_multiple_blocks( + sink->poly_state[0].acc, sink->poly_state[0].mul, sink->oh, + sink->seed, data, n_blocks); + } + + return n_blocks * BLOCK_SIZE; + } +#endif + + while (n_bytes > BLOCK_SIZE) { + /* + * Is this worth unswitching? Not obviously, given + * the amount of work in one OH block. + */ + if (sink->hash_wanted != 0) { + struct umash_oh hashes[2]; + + oh_varblock_fprint( + hashes, sink->oh, sink->seed, data, BLOCK_SIZE); + sink->oh_acc = hashes[0]; + sink->oh_twisted.acc = hashes[1]; + } else { + sink->oh_acc = + oh_varblock(sink->oh, sink->seed, data, BLOCK_SIZE); + } + + sink_update_poly(sink); + consumed += BLOCK_SIZE; + data = (const char *)data + BLOCK_SIZE; + n_bytes -= BLOCK_SIZE; + } + + return consumed; +} + +FN void +umash_sink_update(struct umash_sink *sink, const void *data, size_t n_bytes) +{ + const size_t buf_begin = sizeof(sink->buf) - INCREMENTAL_GRANULARITY; + size_t remaining = INCREMENTAL_GRANULARITY - sink->bufsz; + + DTRACE_PROBE4(libumash, umash_sink_update, sink, remaining, data, n_bytes); + + if (n_bytes < remaining) { + memcpy(&sink->buf[buf_begin + sink->bufsz], data, n_bytes); + sink->bufsz += n_bytes; + return; + } + + memcpy(&sink->buf[buf_begin + sink->bufsz], data, remaining); + data = (const char *)data + remaining; + n_bytes -= remaining; + /* We know we're hashing at least 16 bytes. */ + sink->large_umash = true; + sink->bufsz = INCREMENTAL_GRANULARITY; + + /* + * We can't compress a 16-byte buffer until we know whether + * data is coming: the last 16-byte chunk goes to `NH` instead + * of `PH`. We could try to detect when the buffer is the + * last chunk in a block and immediately go to `NH`, but it + * seems more robust to always let the stores settle before we + * read them, just in case the combination is bad for forwarding. + */ + if (n_bytes == 0) + return; + + sink_consume_buf(sink, sink->buf + buf_begin, /*final=*/false); + + while (n_bytes > INCREMENTAL_GRANULARITY) { + size_t consumed; + + if (sink->oh_iter == 0 && n_bytes > BLOCK_SIZE) { + consumed = block_sink_update(sink, data, n_bytes); + assert(consumed >= BLOCK_SIZE); + + /* + * Save the tail of the data we just consumed + * in `sink->buf[0 ... buf_begin - 1]`: the + * final digest may need those bytes for its + * redundant read. + */ + memcpy(sink->buf, + (const char *)data + (consumed - INCREMENTAL_GRANULARITY), + buf_begin); + } else { + consumed = INCREMENTAL_GRANULARITY; + sink->bufsz = INCREMENTAL_GRANULARITY; + sink_consume_buf(sink, data, /*final=*/false); + } + + n_bytes -= consumed; + data = (const char *)data + consumed; + } + + memcpy(&sink->buf[buf_begin], data, n_bytes); + sink->bufsz = n_bytes; + return; +} + +FN uint64_t +umash_full(const struct umash_params *params, uint64_t seed, int which, const void *data, + size_t n_bytes) +{ + + DTRACE_PROBE4(libumash, umash_full, params, which, data, n_bytes); + + /* + * We don't (yet) implement code that only evaluates the + * second hash. We don't currently use that logic, and it's + * about to become a bit more complex, so let's just go for a + * full fingerprint and take what we need. + * + * umash_full is also rarely used that way: usually we want + * either the main hash, or the full fingerprint. + */ + if (UNLIKELY(which != 0)) { + struct umash_fp fp; + + fp = umash_fprint(params, seed, data, n_bytes); + return fp.hash[1]; + } + + /* + * It's not that short inputs are necessarily more likely, but + * we want to make sure they fall through correctly to + * minimise latency. + */ + if (LIKELY(n_bytes <= sizeof(v128))) { + if (LIKELY(n_bytes <= sizeof(uint64_t))) + return umash_short(params->oh, seed, data, n_bytes); + + return umash_medium(params->poly[0], params->oh, seed, data, n_bytes); + } + + return umash_long(params->poly[0], params->oh, seed, data, n_bytes); +} + +FN struct umash_fp +umash_fprint( + const struct umash_params *params, uint64_t seed, const void *data, size_t n_bytes) +{ + + DTRACE_PROBE3(libumash, umash_fprint, params, data, n_bytes); + if (LIKELY(n_bytes <= sizeof(v128))) { + if (LIKELY(n_bytes <= sizeof(uint64_t))) + return umash_fp_short(params->oh, seed, data, n_bytes); + + return umash_fp_medium(params->poly, params->oh, seed, data, n_bytes); + } + + return umash_fp_long(params->poly, params->oh, seed, data, n_bytes); +} + +FN void +umash_init(struct umash_state *state, const struct umash_params *params, uint64_t seed, + int which) +{ + + which = (which == 0) ? 0 : 1; + DTRACE_PROBE3(libumash, umash_init, state, params, which); + + state->sink = (struct umash_sink) { + .poly_state[0] = { + .mul = { + params->poly[0][0], + params->poly[0][1], + }, + }, + .poly_state[1]= { + .mul = { + params->poly[1][0], + params->poly[1][1], + }, + }, + .oh = params->oh, + .hash_wanted = which, + .oh_twisted.lrc = { params->oh[UMASH_OH_PARAM_COUNT], + params->oh[UMASH_OH_PARAM_COUNT + 1] }, + .seed = seed, + }; + + return; +} + +FN void +umash_fp_init( + struct umash_fp_state *state, const struct umash_params *params, uint64_t seed) +{ + + DTRACE_PROBE2(libumash, umash_fp_init, state, params); + + state->sink = (struct umash_sink) { + .poly_state[0] = { + .mul = { + params->poly[0][0], + params->poly[0][1], + }, + }, + .poly_state[1]= { + .mul = { + params->poly[1][0], + params->poly[1][1], + }, + }, + .oh = params->oh, + .hash_wanted = 2, + .oh_twisted.lrc = { params->oh[UMASH_OH_PARAM_COUNT], + params->oh[UMASH_OH_PARAM_COUNT + 1] }, + .seed = seed, + }; + + return; +} + +/** + * Pumps any last block out of the incremental state. + */ +static FN void +digest_flush(struct umash_sink *sink) +{ + + if (sink->bufsz > 0) + sink_consume_buf(sink, &sink->buf[sink->bufsz], /*final=*/true); + return; +} + +/** + * Finalizes a digest out of `sink`'s current state. + * + * The `sink` must be `digest_flush`ed if it is a `large_umash`. + * + * @param index 0 to return the first (only, if hashing) value, 1 for the + * second independent value for fingerprinting. + */ +static FN uint64_t +digest(const struct umash_sink *sink, int index) +{ + const size_t buf_begin = sizeof(sink->buf) - INCREMENTAL_GRANULARITY; + const size_t shift = (index == 0) ? 0 : OH_SHORT_HASH_SHIFT; + + if (sink->large_umash) + return finalize(sink->poly_state[index].acc); + + if (sink->bufsz <= sizeof(uint64_t)) + return umash_short( + &sink->oh[shift], sink->seed, &sink->buf[buf_begin], sink->bufsz); + + return umash_medium(sink->poly_state[index].mul, sink->oh, sink->seed, + &sink->buf[buf_begin], sink->bufsz); +} + +static FN struct umash_fp +fp_digest_sink(const struct umash_sink *sink) +{ + struct umash_sink copy; + struct umash_fp ret; + const size_t buf_begin = sizeof(sink->buf) - INCREMENTAL_GRANULARITY; + + if (sink->large_umash) { + copy = *sink; + digest_flush(©); + sink = © + } else if (sink->bufsz <= sizeof(uint64_t)) { + return umash_fp_short( + sink->oh, sink->seed, &sink->buf[buf_begin], sink->bufsz); + } else { + const struct umash_params *params; + + /* + * Back out the params struct from our pointer to its + * `oh` member. + */ + params = (const void *)((const char *)sink->oh - + __builtin_offsetof(struct umash_params, oh)); + return umash_fp_medium(params->poly, sink->oh, sink->seed, + &sink->buf[buf_begin], sink->bufsz); + } + + for (size_t i = 0; i < ARRAY_SIZE(ret.hash); i++) + ret.hash[i] = digest(sink, i); + + return ret; +} + +FN uint64_t +umash_digest(const struct umash_state *state) +{ + struct umash_sink copy; + const struct umash_sink *sink = &state->sink; + + DTRACE_PROBE1(libumash, umash_digest, state); + + if (sink->hash_wanted == 1) { + struct umash_fp fp; + + fp = fp_digest_sink(sink); + return fp.hash[1]; + } + + if (sink->large_umash) { + copy = *sink; + digest_flush(©); + sink = © + } + + return digest(sink, 0); +} + +FN struct umash_fp +umash_fp_digest(const struct umash_fp_state *state) +{ + + DTRACE_PROBE1(libumash, umash_fp_digest, state); + return fp_digest_sink(&state->sink); +} diff --git a/tsl/src/import/umash.h b/tsl/src/import/umash.h new file mode 100644 index 00000000000..f85bd54a49c --- /dev/null +++ b/tsl/src/import/umash.h @@ -0,0 +1,324 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ + +/* + * This file contains source code that was copied and/or modified from + * the UMASH hash implementation at https://github.com/backtrace-labs/umash, + * which is licensed under the MIT License: + * + * Copyright 2020-2022 Backtrace I/O, Inc. + * Copyright 2022 Paul Khuong + * Copyright 2022 Dougall Johnson + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * This is a copy of umash.h, git commit sha + * fc4c5b6ca1f06c308e96c43aa080bd766238e092. + */ + +#ifndef UMASH_H +#define UMASH_H +#include +#include +#include + +/** + * # UMASH: a non-cryptographic hash function with collision bounds + * + * SPDX-License-Identifier: MIT + * Copyright 2020-2022 Backtrace I/O, Inc. + * Copyright 2022 Paul Khuong + * + * UMASH is a fast (9-22 ns latency for inputs of 1-64 bytes and 22 + * GB/s peak throughput, on a 2.5 GHz Intel 8175M) 64-bit hash + * function with mathematically proven collision bounds: it is + * [ceil(s / 4096) * 2^{-55}]-almost-universal for inputs of s or + * fewer bytes. + * + * When that's not enough, UMASH can also generate a pair of 64-bit + * hashes in a single traversal. The resulting fingerprint reduces + * the collision probability to less than [ceil(s / 2^{26})^2 * 2^{-83}]; + * the probability that two distinct inputs receive the same + * fingerprint is less 2^{-83} for inputs up to 64 MB, and less than + * 2^{-70} as long as the inputs are shorter than 5 GB each. This + * expectation is taken over the randomly generated `umash_params`. + * If an attacker can infer the contents of these parameters, the + * bounds do not apply. + * + * ## Initialisation + * + * In order to use `UMASH`, one must first generate a `struct + * umash_params`; each such param defines a distinct `UMASH` function + * (a pair of such functions, in fact). Ideally, one would fill + * a struct with random bytes and call`umash_params_prepare`. + * + * - `umash_params_prepare`: attempts to convert the contents of + * randomly filled `struct umash_params` into a valid UMASH + * parameter struct (key). When the input consists of uniformly + * generated random bytes, the probability of failure is + * astronomically small. + * + * - `umash_params_derive`: deterministically constructs a `struct + * umash_params` from a 64-bit seed and an optional 32-byte secret. + * The seed and secret are expanded into random bytes with Salsa20; + * the resulting `umash_params` should be practically random, as + * long the seed or secret are unknown. + * + * ## Batch hashing and fingerprinting + * + * Once we have a `struct umash_params`, we can use `umash_full` or + * `umash_fprint` like regular hash functions. + * + * - `umash_full` can compute either of the two UMASH functions + * described by a `struct umash_params`. Its `seed` argument will + * change the output, but is not associated with any collision + * bound. + * + * - `umash_fprint` computes both `UMASH` functions described by a + * `struct umash_params`. `umash_fp::hash[0]` corresponds to + * calling `umash_full` with the same arguments and `which = 0`; + * `umash_fp::hash[1]` corresponds to `which = 1`. + * + * ## Incremental hashing and fingerprinting + * + * We can also compute UMASH values by feeding bytes incrementally. + * The result is guaranteed to the same as if we had buffered all the + * bytes and called `umash_full` or `umash_fprint`. + * + * - `umash_init` initialises a `struct umash_state` with the same + * parameters one would pass to `umash_full`. + * + * - `umash_digest` computes the value `umash_full` would return + * were it passed the arguments that were given to `umash_init`, + * and the bytes "fed" into the `umash_state`. + * + * - `umash_fp_init` initialises a `struct umash_fp_state` with the + * same parameters one would pass to `umash_fprint`. + * + * - `umash_fp_digest` computes the value `umash_fprint` would return + * for the bytes "fed" into the `umash_fp_state`. + * + * In both cases, one passes a pointer to `struct umash_state::sink` + * or `struct umash_fp_state::sink` to callees that wish to feed bytes + * into the `umash_state` or `umash_fp_state`. + * + * - `umash_sink_update` feeds a byte range to the `umash_sink` + * initialised by calling `umash_init` or `umash_fp_init`. The sink + * does not take ownership of anything and the input bytes may be + * overwritten or freed as soon as `umash_sink_update` returns. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +enum { UMASH_OH_PARAM_COUNT = 32, UMASH_OH_TWISTING_COUNT = 2 }; + +/** + * A single UMASH params struct stores the parameters for a pair of + * independent `UMASH` functions. + */ +struct umash_params { + /* + * Each uint64_t[2] array consists of {f^2, f}, where f is a + * random multiplier in mod 2**61 - 1. + */ + uint64_t poly[2][2]; + /* + * The second (twisted) OH function uses an additional + * 128-bit constant stored in the last two elements. + */ + uint64_t oh[UMASH_OH_PARAM_COUNT + UMASH_OH_TWISTING_COUNT]; +}; + +/** + * A fingerprint consists of two independent `UMASH` hash values. + */ +struct umash_fp { + uint64_t hash[2]; +}; + +/** + * This struct holds the state for incremental UMASH hashing or + * fingerprinting. + * + * A sink owns no allocation, and simply borrows a pointer to its + * `umash_params`. It can be byte-copied to snapshot its state. + * + * The layout works best with alignment to 64 bytes, but does not + * require it. + */ +struct umash_sink { + /* + * We incrementally maintain two states when fingerprinting. + * When hashing, only the first `poly_state` and `oh_acc` + * entries are active. + */ + struct { + uint64_t mul[2]; /* Multiplier, and multiplier^2. */ + uint64_t acc; /* Current Horner accumulator. */ + } poly_state[2]; + + /* + * We write new bytes to the second half, and keep the previous + * 16 byte chunk in the first half. + * + * We may temporarily have a full 16-byte buffer in the second half: + * we must know if the first 16 byte chunk is the first of many, or + * the whole input. + */ + char buf[2 * 16]; + + /* The next 64 bytes are accessed in the `OH` inner loop. */ + + /* key->oh. */ + const uint64_t *oh; + + /* oh_iter tracks where we are in the inner loop, times 2. */ + uint32_t oh_iter; + uint8_t bufsz; /* Write pointer in `buf + 16`. */ + uint8_t block_size; /* Current OH block size, excluding `bufsz`. */ + bool large_umash; /* True once we definitely have >= 16 bytes. */ + /* + * 0 if we're computing the first umash, 1 for the second, and + * 2 for a fingerprint. + * + * In practice, we treat 1 and 2 the same (always compute a + * full fingerprint), and return only the second half if we + * only want that half. + */ + uint8_t hash_wanted; + + /* Accumulators for the current OH value. */ + struct umash_oh { + uint64_t bits[2]; + } oh_acc; + struct umash_twisted_oh { + uint64_t lrc[2]; + uint64_t prev[2]; + struct umash_oh acc; + } oh_twisted; + + uint64_t seed; +}; + +/** + * The `umash_state` struct wraps a sink in a type-safe interface: we + * don't want to try and extract a fingerprint from a sink configured + * for hashing. + */ +struct umash_state { + struct umash_sink sink; +}; + +/** + * Similarly, the `umash_fp_state` struct wraps a sink from which we + * should extract a fingerprint. + */ +struct umash_fp_state { + struct umash_sink sink; +}; + +/** + * Converts a `umash_params` struct filled with random values into + * something usable by the UMASH functions below. + * + * When it succeeds, this function is idempotent. Failure happens + * with probability < 2**-110 is `params` is filled with uniformly + * distributed random bits. That's an astronomically unlikely event, + * and most likely signals an issue with the caller's (pseudo-)random + * number generator. + * + * @return false on failure, probably because the input was not random. + */ +bool umash_params_prepare(struct umash_params *params); + +/** + * Deterministically derives a `umash_params` struct from `bits` and + * `key`. The `bits` values do not have to be particularly well + * distributed, and can be generated sequentially. + * + * @param key a pointer to exactly 32 secret bytes. NULL will be + * replaced with "Do not use UMASH VS adversaries.", the default + * UMASH secret. + */ +void umash_params_derive(struct umash_params *, uint64_t bits, const void *key); + +/** + * Updates a `umash_sink` to take into account `data[0 ... n_bytes)`. + */ +void umash_sink_update(struct umash_sink *, const void *data, size_t n_bytes); + +/** + * Computes the UMASH hash of `data[0 ... n_bytes)`. + * + * Randomly generated `param` lead to independent UMASH values and + * associated worst-case collision bounds; changing the `seed` comes + * with no guarantee. + * + * @param which 0 to compute the first UMASH defined by `params`, 1 + * for the second. + */ +uint64_t umash_full(const struct umash_params *params, uint64_t seed, int which, + const void *data, size_t n_bytes); + +/** + * Computes the UMASH fingerprint of `data[0 ... n_bytes)`. + * + * Randomly generated `param` lead to independent UMASH values and + * associated worst-case collision bounds; changing the `seed` comes + * with no guarantee. + */ +struct umash_fp umash_fprint( + const struct umash_params *params, uint64_t seed, const void *data, size_t n_bytes); + +/** + * Prepares a `umash_state` for computing the `which`th UMASH function in + * `params`. + */ +void umash_init( + struct umash_state *, const struct umash_params *params, uint64_t seed, int which); + +/** + * Returns the UMASH value for the bytes that have been + * `umash_sink_update`d into the state. + */ +uint64_t umash_digest(const struct umash_state *); + +/** + * Prepares a `umash_fp_state` for computing the UMASH fingerprint in + * `params`. + */ +void umash_fp_init( + struct umash_fp_state *, const struct umash_params *params, uint64_t seed); + +/** + * Returns the UMASH fingerprint for the bytes that have been + * `umash_sink_update`d into the state. + */ +struct umash_fp umash_fp_digest(const struct umash_fp_state *); + +#ifdef __cplusplus +} +#endif +#endif /* !UMASH_H */ diff --git a/tsl/src/nodes/decompress_chunk/compressed_batch.c b/tsl/src/nodes/decompress_chunk/compressed_batch.c index 81ed77fa8e0..582df8cbc1b 100644 --- a/tsl/src/nodes/decompress_chunk/compressed_batch.c +++ b/tsl/src/nodes/decompress_chunk/compressed_batch.c @@ -20,18 +20,6 @@ #include "nodes/decompress_chunk/vector_predicates.h" #include "nodes/decompress_chunk/vector_quals.h" -/* - * VectorQualState for a compressed batch used to pass - * DecompressChunk-specific data to vector qual functions that are shared - * across scan nodes. - */ -typedef struct CompressedBatchVectorQualState -{ - VectorQualState vqstate; - DecompressBatchState *batch_state; - DecompressContext *dcontext; -} CompressedBatchVectorQualState; - /* * Create a single-value ArrowArray of an arithmetic type. This is a specialized * function because arithmetic types have a particular layout of ArrowArrays. @@ -312,7 +300,7 @@ decompress_column(DecompressContext *dcontext, DecompressBatchState *batch_state * VectorQualState->get_arrow_array() function used to interface with the * vector qual code across different scan nodes. */ -static const ArrowArray * +const ArrowArray * compressed_batch_get_arrow_array(VectorQualState *vqstate, Expr *expr, bool *is_default_value) { CompressedBatchVectorQualState *cbvqstate = (CompressedBatchVectorQualState *) vqstate; @@ -360,8 +348,6 @@ compressed_batch_get_arrow_array(VectorQualState *vqstate, Expr *expr, bool *is_ var->varattno); Assert(column_description != NULL); Assert(column_description->typid == var->vartype); - Ensure(column_description->type == COMPRESSED_COLUMN, - "only compressed columns are supported in vectorized quals"); CompressedColumnValues *column_values = &batch_state->compressed_columns[column_index]; diff --git a/tsl/src/nodes/decompress_chunk/compressed_batch.h b/tsl/src/nodes/decompress_chunk/compressed_batch.h index 3131c2c7fd2..dcacc40a8a0 100644 --- a/tsl/src/nodes/decompress_chunk/compressed_batch.h +++ b/tsl/src/nodes/decompress_chunk/compressed_batch.h @@ -7,6 +7,7 @@ #include "compression/compression.h" #include "nodes/decompress_chunk/decompress_context.h" +#include "nodes/decompress_chunk/vector_quals.h" #include typedef struct ArrowArray ArrowArray; @@ -102,7 +103,7 @@ typedef struct DecompressBatchState * row. Indexed same as arrow arrays, w/o accounting for the reverse scan * direction. Initialized to all ones, i.e. all rows pass. */ - uint64 *restrict vector_qual_result; + const uint64 *restrict vector_qual_result; /* * This follows DecompressContext.compressed_chunk_columns, but does not @@ -172,3 +173,18 @@ compressed_batch_current_tuple(DecompressBatchState *batch_state) Assert(batch_state->per_batch_context != NULL); return &batch_state->decompressed_scan_slot_data.base; } + +/* + * VectorQualState for a compressed batch used to pass + * DecompressChunk-specific data to vector qual functions that are shared + * across scan nodes. + */ +typedef struct CompressedBatchVectorQualState +{ + VectorQualState vqstate; + DecompressBatchState *batch_state; + DecompressContext *dcontext; +} CompressedBatchVectorQualState; + +const ArrowArray *compressed_batch_get_arrow_array(VectorQualState *vqstate, Expr *expr, + bool *is_default_value); diff --git a/tsl/src/nodes/decompress_chunk/decompress_context.h b/tsl/src/nodes/decompress_chunk/decompress_context.h index bd12927d77e..6eae55d5467 100644 --- a/tsl/src/nodes/decompress_chunk/decompress_context.h +++ b/tsl/src/nodes/decompress_chunk/decompress_context.h @@ -29,6 +29,7 @@ typedef struct CompressionColumnDescription Oid typid; int16 value_bytes; bool by_value; + char typalign; /* * Attno of the decompressed column in the scan tuple of DecompressChunk node. diff --git a/tsl/src/nodes/decompress_chunk/exec.c b/tsl/src/nodes/decompress_chunk/exec.c index 18d1ec1e54b..a2e04c6492d 100644 --- a/tsl/src/nodes/decompress_chunk/exec.c +++ b/tsl/src/nodes/decompress_chunk/exec.c @@ -297,7 +297,10 @@ decompress_chunk_begin(CustomScanState *node, EState *estate, int eflags) TupleDescAttr(desc, AttrNumberGetAttrOffset(column.custom_scan_attno)); column.typid = attribute->atttypid; - get_typlenbyval(column.typid, &column.value_bytes, &column.by_value); + get_typlenbyvalalign(column.typid, + &column.value_bytes, + &column.by_value, + &column.typalign); if (list_nth_int(chunk_state->is_segmentby_column, compressed_index)) column.type = SEGMENTBY_COLUMN; diff --git a/tsl/src/nodes/decompress_chunk/planner.c b/tsl/src/nodes/decompress_chunk/planner.c index 8048fc2ceac..871da35d929 100644 --- a/tsl/src/nodes/decompress_chunk/planner.c +++ b/tsl/src/nodes/decompress_chunk/planner.c @@ -148,12 +148,6 @@ typedef struct } DecompressionMapContext; -typedef struct VectorQualInfoDecompressChunk -{ - VectorQualInfo vqinfo; - const UncompressedColumnInfo *colinfo; -} VectorQualInfoDecompressChunk; - static bool * build_vector_attrs_array(const UncompressedColumnInfo *colinfo, const CompressionInfo *info) { @@ -816,6 +810,8 @@ vector_qual_make(Node *qual, const VectorQualInfo *vqinfo) if (!vqinfo->vector_attrs[var->varattno]) { /* This column doesn't support bulk decompression. */ + // fprintf(stderr, "doesn't support bulk decompression:\n"); + // my_print(var); return NULL; } diff --git a/tsl/src/nodes/decompress_chunk/vector_predicates.h b/tsl/src/nodes/decompress_chunk/vector_predicates.h index cace90dbc44..204177c07a7 100644 --- a/tsl/src/nodes/decompress_chunk/vector_predicates.h +++ b/tsl/src/nodes/decompress_chunk/vector_predicates.h @@ -26,7 +26,7 @@ typedef enum VectorQualSummary } VectorQualSummary; static pg_attribute_always_inline VectorQualSummary -get_vector_qual_summary(uint64 *restrict qual_result, size_t n_rows) +get_vector_qual_summary(const uint64 *qual_result, size_t n_rows) { bool any_rows_pass = false; bool all_rows_pass = true; diff --git a/tsl/src/nodes/vector_agg/CMakeLists.txt b/tsl/src/nodes/vector_agg/CMakeLists.txt index e621571d5f5..cf69755c077 100644 --- a/tsl/src/nodes/vector_agg/CMakeLists.txt +++ b/tsl/src/nodes/vector_agg/CMakeLists.txt @@ -1,6 +1,8 @@ add_subdirectory(function) +add_subdirectory(hashing) set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/exec.c ${CMAKE_CURRENT_SOURCE_DIR}/grouping_policy_batch.c + ${CMAKE_CURRENT_SOURCE_DIR}/grouping_policy_hash.c ${CMAKE_CURRENT_SOURCE_DIR}/plan.c) target_sources(${TSL_LIBRARY_NAME} PRIVATE ${SOURCES}) diff --git a/tsl/src/nodes/vector_agg/exec.c b/tsl/src/nodes/vector_agg/exec.c index 1d773ce1c4e..1d8d4e86b54 100644 --- a/tsl/src/nodes/vector_agg/exec.c +++ b/tsl/src/nodes/vector_agg/exec.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "nodes/vector_agg/exec.h" @@ -18,6 +19,7 @@ #include "guc.h" #include "nodes/decompress_chunk/compressed_batch.h" #include "nodes/decompress_chunk/exec.h" +#include "nodes/decompress_chunk/vector_quals.h" #include "nodes/vector_agg.h" static int @@ -54,6 +56,25 @@ get_input_offset(DecompressChunkState *decompress_state, Var *var) return index; } +static int +grouping_column_comparator(const void *a_ptr, const void *b_ptr) +{ + const GroupingColumn *a = (GroupingColumn *) a_ptr; + const GroupingColumn *b = (GroupingColumn *) b_ptr; + + if (a->value_bytes == b->value_bytes) + { + return 0; + } + + if (a->value_bytes > b->value_bytes) + { + return -1; + } + + return 1; +} + static void vector_agg_begin(CustomScanState *node, EState *estate, int eflags) { @@ -67,6 +88,17 @@ vector_agg_begin(CustomScanState *node, EState *estate, int eflags) DecompressChunkState *decompress_state = (DecompressChunkState *) linitial(vector_agg_state->custom.custom_ps); + /* + * Set up the helper structures used to evaluate stable expressions in + * vectorized FILTER clauses. + */ + PlannerGlobal glob = { + .boundParams = node->ss.ps.state->es_param_list_info, + }; + PlannerInfo root = { + .glob = &glob, + }; + /* * The aggregated targetlist with Aggrefs is in the custom scan targetlist * of the custom scan node that is performing the vectorized aggregation. @@ -131,6 +163,9 @@ vector_agg_begin(CustomScanState *node, EState *estate, int eflags) Aggref *aggref = castNode(Aggref, tlentry->expr); + // fprintf(stderr, "the aggref at execution is:\n"); + // my_print(aggref); + VectorAggFunctions *func = get_vector_aggregate(aggref->aggfnoid); Assert(func != NULL); def->func = *func; @@ -149,6 +184,12 @@ vector_agg_begin(CustomScanState *node, EState *estate, int eflags) { def->input_offset = -1; } + + if (aggref->aggfilter != NULL) + { + Node *constified = estimate_expression_value(&root, (Node *) aggref->aggfilter); + def->filter_clauses = list_make1(constified); + } } else { @@ -160,17 +201,95 @@ vector_agg_begin(CustomScanState *node, EState *estate, int eflags) Var *var = castNode(Var, tlentry->expr); col->input_offset = get_input_offset(decompress_state, var); + + DecompressContext *dcontext = &decompress_state->decompress_context; + CompressionColumnDescription *desc = + &dcontext->compressed_chunk_columns[col->input_offset]; + + col->typid = desc->typid; + col->value_bytes = desc->value_bytes; + col->by_value = desc->by_value; + if (col->value_bytes == -1) + { + /* + * long varlena requires 4 byte alignment, not sure why text has 'i' + * typalign in pg catalog. + */ + col->alignment_bytes = 4; + } + else + { + switch (desc->typalign) + { + case TYPALIGN_CHAR: + col->alignment_bytes = 1; + break; + case TYPALIGN_SHORT: + col->alignment_bytes = ALIGNOF_SHORT; + break; + case TYPALIGN_INT: + col->alignment_bytes = ALIGNOF_INT; + break; + case TYPALIGN_DOUBLE: + col->alignment_bytes = ALIGNOF_DOUBLE; + break; + default: + Assert(false); + col->alignment_bytes = 1; + } + } } } /* - * Currently the only grouping policy we use is per-batch grouping. + * Sort grouping columns by descending column size, variable size last. This + * helps improve branch predictability and key packing when we use hashed + * serialized multi-column keys. */ - vector_agg_state->grouping = - create_grouping_policy_batch(vector_agg_state->num_agg_defs, - vector_agg_state->agg_defs, - vector_agg_state->num_grouping_columns, - vector_agg_state->grouping_columns); + qsort(vector_agg_state->grouping_columns, + vector_agg_state->num_grouping_columns, + sizeof(GroupingColumn), + grouping_column_comparator); + + /* + * Determine which grouping policy we are going to use. + */ + bool all_segmentby = true; + for (int i = 0; i < vector_agg_state->num_grouping_columns; i++) + { + GroupingColumn *col = &vector_agg_state->grouping_columns[i]; + DecompressContext *dcontext = &decompress_state->decompress_context; + CompressionColumnDescription *desc = &dcontext->compressed_chunk_columns[col->input_offset]; + // if (desc->type == COMPRESSED_COLUMN && desc->by_value && desc->value_bytes > 0 && + // (size_t) desc->value_bytes <= sizeof(Datum)) + if (desc->type != SEGMENTBY_COLUMN) + { + all_segmentby = false; + break; + } + } + if (all_segmentby) + { + /* + * Per-batch grouping. + */ + vector_agg_state->grouping = + create_grouping_policy_batch(vector_agg_state->num_agg_defs, + vector_agg_state->agg_defs, + vector_agg_state->num_grouping_columns, + vector_agg_state->grouping_columns); + } + else + { + /* + * Hash grouping. + */ + vector_agg_state->grouping = + create_grouping_policy_hash(vector_agg_state->num_agg_defs, + vector_agg_state->agg_defs, + vector_agg_state->num_grouping_columns, + vector_agg_state->grouping_columns); + } } static void @@ -293,6 +412,37 @@ vector_agg_exec(CustomScanState *node) dcontext->ps->instrument->tuplecount += not_filtered_rows; } + /* + * Compute the vectorized filters for the aggregate function FILTER + * clauses. + */ + const int naggs = vector_agg_state->num_agg_defs; + for (int i = 0; i < naggs; i++) + { + VectorAggDef *agg_def = &vector_agg_state->agg_defs[i]; + if (agg_def->filter_clauses == NIL) + { + continue; + } + CompressedBatchVectorQualState cbvqstate = { + .vqstate = { + .vectorized_quals_constified = agg_def->filter_clauses, + .num_results = batch_state->total_batch_rows, + .per_vector_mcxt = batch_state->per_batch_context, + .slot = compressed_slot, + .get_arrow_array = compressed_batch_get_arrow_array, + }, + .batch_state = batch_state, + .dcontext = dcontext, + }; + VectorQualState *vqstate = &cbvqstate.vqstate; + vector_qual_compute(vqstate); + agg_def->filter_result = vqstate->vector_qual_result; + } + + /* + * Finally, pass the compressed batch to the grouping policy. + */ grouping->gp_add_batch(grouping, batch_state); } diff --git a/tsl/src/nodes/vector_agg/exec.h b/tsl/src/nodes/vector_agg/exec.h index 26f832b3548..20bbd852395 100644 --- a/tsl/src/nodes/vector_agg/exec.h +++ b/tsl/src/nodes/vector_agg/exec.h @@ -18,12 +18,19 @@ typedef struct VectorAggDef VectorAggFunctions func; int input_offset; int output_offset; + List *filter_clauses; + uint64 *filter_result; } VectorAggDef; typedef struct GroupingColumn { int input_offset; int output_offset; + + Oid typid; + int16 value_bytes; + bool by_value; + int8 alignment_bytes; } GroupingColumn; typedef struct diff --git a/tsl/src/nodes/vector_agg/function/agg_many_vector_helper.c b/tsl/src/nodes/vector_agg/function/agg_many_vector_helper.c new file mode 100644 index 00000000000..192fad35017 --- /dev/null +++ b/tsl/src/nodes/vector_agg/function/agg_many_vector_helper.c @@ -0,0 +1,58 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ + +/* + * A generic implementation of adding the given batch to many aggregate function + * states with given offsets. Used for hash aggregation, and builds on the + * FUNCTION_NAME(one) function, which adds one passing non-null row to the given + * aggregate function state. + */ +static pg_attribute_always_inline void +FUNCTION_NAME(many_vector_impl)(void *restrict agg_states, const uint32 *offsets, + const uint64 *filter, int start_row, int end_row, + const ArrowArray *vector, MemoryContext agg_extra_mctx) +{ + FUNCTION_NAME(state) *restrict states = (FUNCTION_NAME(state) *) agg_states; + const CTYPE *values = vector->buffers[1]; + MemoryContext old = MemoryContextSwitchTo(agg_extra_mctx); + for (int row = start_row; row < end_row; row++) + { + const CTYPE value = values[row]; + FUNCTION_NAME(state) *restrict state = &states[offsets[row]]; + if (arrow_row_is_valid(filter, row)) + { + Assert(offsets[row] != 0); + FUNCTION_NAME(one)(state, value); + } + } + MemoryContextSwitchTo(old); +} + +static pg_noinline void +FUNCTION_NAME(many_vector_all_valid)(void *restrict agg_states, const uint32 *offsets, + int start_row, int end_row, const ArrowArray *vector, + MemoryContext agg_extra_mctx) +{ + FUNCTION_NAME(many_vector_impl) + (agg_states, offsets, NULL, start_row, end_row, vector, agg_extra_mctx); +} + +static void +FUNCTION_NAME(many_vector)(void *restrict agg_states, const uint32 *offsets, const uint64 *filter, + int start_row, int end_row, const ArrowArray *vector, + MemoryContext agg_extra_mctx) +{ + if (filter == NULL) + { + FUNCTION_NAME(many_vector_all_valid) + (agg_states, offsets, start_row, end_row, vector, agg_extra_mctx); + } + else + { + FUNCTION_NAME(many_vector_impl) + (agg_states, offsets, filter, start_row, end_row, vector, agg_extra_mctx); + } +} diff --git a/tsl/src/nodes/vector_agg/function/float48_accum_single.c b/tsl/src/nodes/vector_agg/function/float48_accum_single.c index 0bdcd928593..eba81ee687b 100644 --- a/tsl/src/nodes/vector_agg/function/float48_accum_single.c +++ b/tsl/src/nodes/vector_agg/function/float48_accum_single.c @@ -316,6 +316,7 @@ FUNCTION_NAME(one)(void *restrict agg_state, const CTYPE value) state->Sx = newSx; } +#include "agg_many_vector_helper.c" #include "agg_scalar_helper.c" #include "agg_vector_validity_helper.c" @@ -325,6 +326,7 @@ VectorAggFunctions FUNCTION_NAME(argdef) = { .agg_emit = FUNCTION_NAME(emit), .agg_scalar = FUNCTION_NAME(scalar), .agg_vector = FUNCTION_NAME(vector), + .agg_many_vector = FUNCTION_NAME(many_vector), }; #undef UPDATE #undef COMBINE diff --git a/tsl/src/nodes/vector_agg/function/functions.c b/tsl/src/nodes/vector_agg/function/functions.c index 1cd08e7cd25..bb6ef7cf074 100644 --- a/tsl/src/nodes/vector_agg/function/functions.c +++ b/tsl/src/nodes/vector_agg/function/functions.c @@ -52,11 +52,70 @@ count_star_scalar(void *agg_state, Datum constvalue, bool constisnull, int n, state->count += n; } +static pg_attribute_always_inline void +count_star_many_scalar_impl(void *restrict agg_states, const uint32 *offsets, const uint64 *filter, + int start_row, int end_row, Datum constvalue, bool constisnull, + MemoryContext agg_extra_mctx) +{ + CountState *states = (CountState *) agg_states; + for (int row = start_row; row < end_row; row++) + { + if (arrow_row_is_valid(filter, row)) + { + states[offsets[row]].count++; + } + } +} + +static pg_noinline void +count_star_many_scalar_nofilter(void *restrict agg_states, const uint32 *offsets, int start_row, + int end_row, Datum constvalue, bool constisnull, + MemoryContext agg_extra_mctx) +{ + count_star_many_scalar_impl(agg_states, + offsets, + NULL, + start_row, + end_row, + constvalue, + constisnull, + agg_extra_mctx); +} + +static void +count_star_many_scalar(void *restrict agg_states, const uint32 *offsets, const uint64 *filter, + int start_row, int end_row, Datum constvalue, bool constisnull, + MemoryContext agg_extra_mctx) +{ + if (filter == NULL) + { + count_star_many_scalar_nofilter(agg_states, + offsets, + start_row, + end_row, + constvalue, + constisnull, + agg_extra_mctx); + } + else + { + count_star_many_scalar_impl(agg_states, + offsets, + filter, + start_row, + end_row, + constvalue, + constisnull, + agg_extra_mctx); + } +} + VectorAggFunctions count_star_agg = { .state_bytes = sizeof(CountState), .agg_init = count_init, .agg_scalar = count_star_scalar, .agg_emit = count_emit, + .agg_many_scalar = count_star_many_scalar, }; /* @@ -110,12 +169,28 @@ count_any_vector(void *agg_state, const ArrowArray *vector, const uint64 *filter } } +static void +count_any_many_vector(void *restrict agg_states, const uint32 *offsets, const uint64 *filter, + int start_row, int end_row, const ArrowArray *vector, + MemoryContext agg_extra_mctx) +{ + for (int row = start_row; row < end_row; row++) + { + CountState *state = (offsets[row] + (CountState *) agg_states); + if (arrow_row_is_valid(filter, row)) + { + state->count++; + } + } +} + VectorAggFunctions count_any_agg = { .state_bytes = sizeof(CountState), .agg_init = count_init, .agg_emit = count_emit, .agg_scalar = count_any_scalar, .agg_vector = count_any_vector, + .agg_many_vector = count_any_many_vector, }; /* diff --git a/tsl/src/nodes/vector_agg/function/functions.h b/tsl/src/nodes/vector_agg/function/functions.h index cd05fe4ea5a..5845333d79d 100644 --- a/tsl/src/nodes/vector_agg/function/functions.h +++ b/tsl/src/nodes/vector_agg/function/functions.h @@ -37,6 +37,22 @@ typedef struct void (*agg_scalar)(void *restrict agg_state, Datum constvalue, bool constisnull, int n, MemoryContext agg_extra_mctx); + /* + * Add the rows of the given arrow array to aggregate function states given + * by the respective offsets. + */ + void (*agg_many_vector)(void *restrict agg_states, const uint32 *offsets, const uint64 *filter, + int start_row, int end_row, const ArrowArray *vector, + MemoryContext agg_extra_mctx); + + /* + * Same as above, but for a scalar argument. This is mostly important for + * count(*) and can be NULL. + */ + void (*agg_many_scalar)(void *restrict agg_states, const uint32 *offsets, const uint64 *filter, + int start_row, int end_row, Datum constvalue, bool constisnull, + MemoryContext agg_extra_mctx); + /* Emit a partial aggregation result. */ void (*agg_emit)(void *restrict agg_state, Datum *out_result, bool *out_isnull); } VectorAggFunctions; diff --git a/tsl/src/nodes/vector_agg/function/int128_accum_single.c b/tsl/src/nodes/vector_agg/function/int128_accum_single.c index d94ead56cd3..2e0b9ca25f2 100644 --- a/tsl/src/nodes/vector_agg/function/int128_accum_single.c +++ b/tsl/src/nodes/vector_agg/function/int128_accum_single.c @@ -110,6 +110,7 @@ FUNCTION_NAME(one)(void *restrict agg_state, const CTYPE value) #endif } +#include "agg_many_vector_helper.c" #include "agg_scalar_helper.c" #include "agg_vector_validity_helper.c" @@ -119,6 +120,7 @@ VectorAggFunctions FUNCTION_NAME(argdef) = { .agg_emit = FUNCTION_NAME(emit), .agg_scalar = FUNCTION_NAME(scalar), .agg_vector = FUNCTION_NAME(vector), + .agg_many_vector = FUNCTION_NAME(many_vector), }; #endif diff --git a/tsl/src/nodes/vector_agg/function/int24_avg_accum_single.c b/tsl/src/nodes/vector_agg/function/int24_avg_accum_single.c index 9fbf950330a..fb90f116255 100644 --- a/tsl/src/nodes/vector_agg/function/int24_avg_accum_single.c +++ b/tsl/src/nodes/vector_agg/function/int24_avg_accum_single.c @@ -38,6 +38,7 @@ FUNCTION_NAME(one)(void *restrict agg_state, const CTYPE value) state->sum += value; } +#include "agg_many_vector_helper.c" #include "agg_scalar_helper.c" #include "agg_vector_validity_helper.c" @@ -47,6 +48,7 @@ VectorAggFunctions FUNCTION_NAME(argdef) = { .agg_emit = int24_avg_accum_emit, .agg_scalar = FUNCTION_NAME(scalar), .agg_vector = FUNCTION_NAME(vector), + .agg_many_vector = FUNCTION_NAME(many_vector), }; #endif diff --git a/tsl/src/nodes/vector_agg/function/int24_sum_single.c b/tsl/src/nodes/vector_agg/function/int24_sum_single.c index ccf1e98cbf8..95320240e75 100644 --- a/tsl/src/nodes/vector_agg/function/int24_sum_single.c +++ b/tsl/src/nodes/vector_agg/function/int24_sum_single.c @@ -61,6 +61,7 @@ FUNCTION_NAME(one)(void *restrict agg_state, const CTYPE value) typedef Int24SumState FUNCTION_NAME(state); +#include "agg_many_vector_helper.c" #include "agg_scalar_helper.c" #include "agg_vector_validity_helper.c" @@ -70,6 +71,7 @@ VectorAggFunctions FUNCTION_NAME(argdef) = { .agg_emit = int_sum_emit, .agg_scalar = FUNCTION_NAME(scalar), .agg_vector = FUNCTION_NAME(vector), + .agg_many_vector = FUNCTION_NAME(many_vector), }; #endif diff --git a/tsl/src/nodes/vector_agg/function/minmax_arithmetic_single.c b/tsl/src/nodes/vector_agg/function/minmax_arithmetic_single.c index e21658c4dfe..e64dab8e20c 100644 --- a/tsl/src/nodes/vector_agg/function/minmax_arithmetic_single.c +++ b/tsl/src/nodes/vector_agg/function/minmax_arithmetic_single.c @@ -58,6 +58,7 @@ FUNCTION_NAME(one)(void *restrict agg_state, const CTYPE value) } } +#include "agg_many_vector_helper.c" #include "agg_scalar_helper.c" #include "agg_vector_validity_helper.c" @@ -67,6 +68,7 @@ VectorAggFunctions FUNCTION_NAME(argdef) = { .agg_emit = minmax_emit, .agg_scalar = FUNCTION_NAME(scalar), .agg_vector = FUNCTION_NAME(vector), + .agg_many_vector = FUNCTION_NAME(many_vector), }; #endif diff --git a/tsl/src/nodes/vector_agg/function/sum_float_single.c b/tsl/src/nodes/vector_agg/function/sum_float_single.c index cce0d6f42c2..6f3002fd12f 100644 --- a/tsl/src/nodes/vector_agg/function/sum_float_single.c +++ b/tsl/src/nodes/vector_agg/function/sum_float_single.c @@ -91,6 +91,7 @@ FUNCTION_NAME(one)(void *restrict agg_state, const CTYPE value) state->result += value; } +#include "agg_many_vector_helper.c" #include "agg_scalar_helper.c" #include "agg_vector_validity_helper.c" @@ -100,6 +101,7 @@ VectorAggFunctions FUNCTION_NAME(argdef) = { .agg_emit = FUNCTION_NAME(emit), .agg_scalar = FUNCTION_NAME(scalar), .agg_vector = FUNCTION_NAME(vector), + .agg_many_vector = FUNCTION_NAME(many_vector), }; #endif diff --git a/tsl/src/nodes/vector_agg/grouping_policy.h b/tsl/src/nodes/vector_agg/grouping_policy.h index 98bcbbed315..e7c77073502 100644 --- a/tsl/src/nodes/vector_agg/grouping_policy.h +++ b/tsl/src/nodes/vector_agg/grouping_policy.h @@ -54,3 +54,7 @@ typedef struct GroupingPolicy extern GroupingPolicy *create_grouping_policy_batch(int num_agg_defs, VectorAggDef *agg_defs, int num_grouping_columns, GroupingColumn *grouping_columns); + +extern GroupingPolicy *create_grouping_policy_hash(int num_agg_defs, VectorAggDef *agg_defs, + int num_grouping_columns, + GroupingColumn *grouping_columns); diff --git a/tsl/src/nodes/vector_agg/grouping_policy_batch.c b/tsl/src/nodes/vector_agg/grouping_policy_batch.c index c9fa8f66709..c9b4249c3f4 100644 --- a/tsl/src/nodes/vector_agg/grouping_policy_batch.c +++ b/tsl/src/nodes/vector_agg/grouping_policy_batch.c @@ -151,6 +151,7 @@ compute_single_aggregate(GroupingPolicyBatch *policy, DecompressBatchState *batc const uint64 *filter = arrow_combine_validity(num_words, policy->tmp_filter, batch_state->vector_qual_result, + agg_def->filter_result, arg_validity_bitmap); /* @@ -166,15 +167,16 @@ compute_single_aggregate(GroupingPolicyBatch *policy, DecompressBatchState *batc /* * Scalar argument, or count(*). Have to also count the valid rows in * the batch. - */ - const int n = arrow_num_valid(filter, batch_state->total_batch_rows); - - /* + * * The batches that are fully filtered out by vectorized quals should - * have been skipped by the caller. + * have been skipped by the caller, but we also have to check for the + * case when no rows match the aggregate FILTER clause. */ - Assert(n > 0); - agg_def->func.agg_scalar(agg_state, arg_datum, arg_isnull, n, agg_extra_mctx); + const int n = arrow_num_valid(filter, batch_state->total_batch_rows); + if (n > 0) + { + agg_def->func.agg_scalar(agg_state, arg_datum, arg_isnull, n, agg_extra_mctx); + } } } @@ -185,7 +187,7 @@ gp_batch_add_batch(GroupingPolicy *gp, DecompressBatchState *batch_state) /* * Allocate the temporary filter array for computing the combined results of - * batch filter and column validity. + * batch filter, aggregate filter and column validity. */ const size_t num_words = (batch_state->total_batch_rows + 63) / 64; if (num_words > policy->num_tmp_filter_words) diff --git a/tsl/src/nodes/vector_agg/grouping_policy_hash.c b/tsl/src/nodes/vector_agg/grouping_policy_hash.c new file mode 100644 index 00000000000..3b02a795ec6 --- /dev/null +++ b/tsl/src/nodes/vector_agg/grouping_policy_hash.c @@ -0,0 +1,511 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ + +/* + * This grouping policy groups the rows using a hash table. Currently it only + * supports a single fixed-size by-value compressed column that fits into a Datum. + */ + +#include + +#include +#include + +#include "grouping_policy.h" + +#include "nodes/decompress_chunk/compressed_batch.h" +#include "nodes/vector_agg/exec.h" + +#include "grouping_policy_hash.h" + +#ifdef USE_FLOAT8_BYVAL +#define DEBUG_LOG(MSG, ...) elog(DEBUG3, MSG, __VA_ARGS__) +#else +/* + * On 32-bit platforms we'd have to use the cross-platform int width printf + * specifiers which are really unreadable. + */ +#define DEBUG_LOG(...) +#endif + +extern HashingStrategy single_fixed_2_strategy; +extern HashingStrategy single_fixed_4_strategy; +extern HashingStrategy single_fixed_8_strategy; +extern HashingStrategy single_text_strategy; +extern HashingStrategy serialized_strategy; + +static const GroupingPolicy grouping_policy_hash_functions; + +GroupingPolicy * +create_grouping_policy_hash(int num_agg_defs, VectorAggDef *agg_defs, int num_grouping_columns, + GroupingColumn *grouping_columns) +{ + GroupingPolicyHash *policy = palloc0(sizeof(GroupingPolicyHash)); + policy->funcs = grouping_policy_hash_functions; + + policy->num_grouping_columns = num_grouping_columns; + policy->grouping_columns = grouping_columns; + + policy->agg_extra_mctx = + AllocSetContextCreate(CurrentMemoryContext, "agg extra", ALLOCSET_DEFAULT_SIZES); + policy->num_agg_state_rows = TARGET_COMPRESSED_BATCH_SIZE; + + policy->num_agg_defs = num_agg_defs; + policy->agg_defs = agg_defs; + + policy->per_agg_states = palloc(sizeof(*policy->per_agg_states) * policy->num_agg_defs); + for (int i = 0; i < policy->num_agg_defs; i++) + { + const VectorAggDef *agg_def = &policy->agg_defs[i]; + policy->per_agg_states[i] = palloc(agg_def->func.state_bytes * policy->num_agg_state_rows); + } + + policy->current_batch_grouping_column_values = + palloc(sizeof(CompressedColumnValues) * num_grouping_columns); + + if (num_grouping_columns == 1) + { + const GroupingColumn *g = &policy->grouping_columns[0]; + switch (g->value_bytes) + { + case 8: + policy->hashing = single_fixed_8_strategy; + break; + case 4: + policy->hashing = single_fixed_4_strategy; + break; + case 2: + policy->hashing = single_fixed_2_strategy; + break; + case -1: + Assert(g->typid == TEXTOID); + policy->hashing = single_text_strategy; + break; + default: + Assert(false); + break; + } + } + else + { + policy->hashing = serialized_strategy; + } + + policy->hashing.key_body_mctx = policy->agg_extra_mctx; + + policy->hashing.init(&policy->hashing, policy); + + return &policy->funcs; +} + +static void +gp_hash_reset(GroupingPolicy *obj) +{ + GroupingPolicyHash *policy = (GroupingPolicyHash *) obj; + + MemoryContextReset(policy->agg_extra_mctx); + + policy->returning_results = false; + + policy->hashing.reset(&policy->hashing); + + /* + * Have to reset this because it's in the key body context which is also + * reset here. + */ + policy->tmp_key_storage = NULL; + policy->num_tmp_key_storage_bytes = 0; + + policy->last_used_key_index = 0; + + policy->stat_input_valid_rows = 0; + policy->stat_input_total_rows = 0; + policy->stat_bulk_filtered_rows = 0; + policy->stat_consecutive_keys = 0; +} + +static void +compute_single_aggregate(GroupingPolicyHash *policy, const DecompressBatchState *batch_state, + int start_row, int end_row, const VectorAggDef *agg_def, void *agg_states) +{ + const ArrowArray *arg_arrow = NULL; + const uint64 *arg_validity_bitmap = NULL; + Datum arg_datum = 0; + bool arg_isnull = true; + + const uint32 *offsets = policy->key_index_for_row; + MemoryContext agg_extra_mctx = policy->agg_extra_mctx; + + /* + * We have functions with one argument, and one function with no arguments + * (count(*)). Collect the arguments. + */ + if (agg_def->input_offset >= 0) + { + const CompressedColumnValues *values = + &batch_state->compressed_columns[agg_def->input_offset]; + Assert(values->decompression_type != DT_Invalid); + Assert(values->decompression_type != DT_Iterator); + + if (values->arrow != NULL) + { + arg_arrow = values->arrow; + arg_validity_bitmap = values->buffers[0]; + } + else + { + Assert(values->decompression_type == DT_Scalar); + arg_datum = *values->output_value; + arg_isnull = *values->output_isnull; + } + } + + /* + * Compute the unified validity bitmap. + */ + const size_t num_words = (batch_state->total_batch_rows + 63) / 64; + const uint64 *filter = arrow_combine_validity(num_words, + policy->tmp_filter, + batch_state->vector_qual_result, + agg_def->filter_result, + arg_validity_bitmap); + + /* + * Now call the function. + */ + if (arg_arrow != NULL) + { + /* Arrow argument. */ + agg_def->func.agg_many_vector(agg_states, + offsets, + filter, + start_row, + end_row, + arg_arrow, + agg_extra_mctx); + } + else + { + /* + * Scalar argument, or count(*). The latter has an optimized + * implementation. + */ + if (agg_def->func.agg_many_scalar != NULL) + { + agg_def->func.agg_many_scalar(agg_states, + offsets, + filter, + start_row, + end_row, + arg_datum, + arg_isnull, + agg_extra_mctx); + } + else + { + for (int i = start_row; i < end_row; i++) + { + if (!arrow_row_is_valid(filter, i)) + { + continue; + } + + void *state = (offsets[i] * agg_def->func.state_bytes + (char *) agg_states); + agg_def->func.agg_scalar(state, arg_datum, arg_isnull, 1, agg_extra_mctx); + } + } + } +} + +static void +add_one_range(GroupingPolicyHash *policy, DecompressBatchState *batch_state, const int start_row, + const int end_row) +{ + const int num_fns = policy->num_agg_defs; + + Assert(start_row < end_row); + Assert(end_row <= batch_state->total_batch_rows); + + /* + * Remember which aggregation states have already existed, and which we + * have to initialize. State index zero is invalid. + */ + const uint32 last_initialized_key_index = policy->last_used_key_index; + Assert(last_initialized_key_index <= policy->num_agg_state_rows); + + /* + * Match rows to aggregation states using a hash table. + */ + Assert((size_t) end_row <= policy->num_key_index_for_row); + policy->hashing.fill_offsets(policy, batch_state, start_row, end_row); + + /* + * Process the aggregate function states. + */ + const uint64 new_aggstate_rows = policy->num_agg_state_rows * 2 + 1; + for (int i = 0; i < num_fns; i++) + { + const VectorAggDef *agg_def = &policy->agg_defs[i]; + if (policy->last_used_key_index > last_initialized_key_index) + { + if (policy->last_used_key_index >= policy->num_agg_state_rows) + { + policy->per_agg_states[i] = repalloc(policy->per_agg_states[i], + new_aggstate_rows * agg_def->func.state_bytes); + } + + /* + * Initialize the aggregate function states for the newly added keys. + */ + void *first_uninitialized_state = + agg_def->func.state_bytes * (last_initialized_key_index + 1) + + (char *) policy->per_agg_states[i]; + agg_def->func.agg_init(first_uninitialized_state, + policy->last_used_key_index - last_initialized_key_index); + } + + /* + * Update the aggregate function states. + */ + compute_single_aggregate(policy, + batch_state, + start_row, + end_row, + agg_def, + policy->per_agg_states[i]); + } + + /* + * Record the newly allocated number of rows in case we had to reallocate. + */ + if (policy->last_used_key_index >= policy->num_agg_state_rows) + { + Assert(new_aggstate_rows > policy->num_agg_state_rows); + policy->num_agg_state_rows = new_aggstate_rows; + } +} + +static void +gp_hash_add_batch(GroupingPolicy *gp, DecompressBatchState *batch_state) +{ + GroupingPolicyHash *policy = (GroupingPolicyHash *) gp; + + Assert(!policy->returning_results); + + const int n = batch_state->total_batch_rows; + + /* + * Initialize the array for storing the aggregate state offsets corresponding + * to a given batch row. We don't need the offsets for the previous batch + * that are currently stored there, so we don't need to use repalloc. + */ + if ((size_t) n > policy->num_key_index_for_row) + { + if (policy->key_index_for_row != NULL) + { + pfree(policy->key_index_for_row); + } + policy->num_key_index_for_row = n; + policy->key_index_for_row = + palloc(sizeof(policy->key_index_for_row[0]) * policy->num_key_index_for_row); + } + memset(policy->key_index_for_row, 0, n * sizeof(policy->key_index_for_row[0])); + + /* + * Allocate the temporary filter array for computing the combined results of + * batch filter, aggregate filter and column validity. + */ + const size_t num_words = (n + 63) / 64; + if (num_words > policy->num_tmp_filter_words) + { + policy->tmp_filter = palloc(sizeof(*policy->tmp_filter) * (num_words * 2 + 1)); + policy->num_tmp_filter_words = (num_words * 2 + 1); + } + + /* + * Arrange the input compressed columns in the order of grouping columns. + */ + for (int i = 0; i < policy->num_grouping_columns; i++) + { + const GroupingColumn *def = &policy->grouping_columns[i]; + const CompressedColumnValues *values = &batch_state->compressed_columns[def->input_offset]; + policy->current_batch_grouping_column_values[i] = *values; + } + + /* + * Call the per-batch initialization function of the hashing strategy. + */ + + policy->hashing.prepare_for_batch(policy, batch_state); + + /* + * Add the batch rows to aggregate function states. + */ + const uint64_t *restrict filter = batch_state->vector_qual_result; + if (filter == NULL) + { + /* + * We don't have a filter on this batch, so aggregate it entirely in one + * go. + */ + add_one_range(policy, batch_state, 0, n); + } + else + { + /* + * If we have a filter, skip the rows for which the entire words of the + * filter bitmap are zero. This improves performance for highly + * selective filters. + */ + int statistics_range_row = 0; + int start_word = 0; + int end_word = 0; + int past_the_end_word = (n - 1) / 64 + 1; + for (;;) + { + /* + * Skip the bitmap words which are zero. + */ + for (start_word = end_word; start_word < past_the_end_word && filter[start_word] == 0; + start_word++) + ; + + if (start_word >= past_the_end_word) + { + break; + } + + /* + * Collect the consecutive bitmap words which are nonzero. + */ + for (end_word = start_word + 1; end_word < past_the_end_word && filter[end_word] != 0; + end_word++) + ; + + /* + * Now we have the [start, end] range of bitmap words that are + * nonzero. + * + * Determine starting and ending rows, also skipping the starting + * and trailing zero bits at the ends of the range. + */ + const int start_row = start_word * 64 + pg_rightmost_one_pos64(filter[start_word]); + Assert(start_row <= n); + + /* + * The bits for past-the-end rows must be set to zero, so this + * calculation should yield no more than n. + */ + Assert(end_word > start_word); + const int end_row = + (end_word - 1) * 64 + pg_leftmost_one_pos64(filter[end_word - 1]) + 1; + Assert(end_row <= n); + + statistics_range_row += end_row - start_row; + + add_one_range(policy, batch_state, start_row, end_row); + } + policy->stat_bulk_filtered_rows += batch_state->total_batch_rows - statistics_range_row; + } + + policy->stat_input_total_rows += batch_state->total_batch_rows; + policy->stat_input_valid_rows += arrow_num_valid(filter, batch_state->total_batch_rows); +} + +static bool +gp_hash_should_emit(GroupingPolicy *gp) +{ + GroupingPolicyHash *policy = (GroupingPolicyHash *) gp; + + if (policy->last_used_key_index > UINT32_MAX - GLOBAL_MAX_ROWS_PER_COMPRESSION) + { + /* + * The max valid key index is UINT32_MAX, so we have to spill if the next + * batch can possibly lead to key index overflow. + */ + return true; + } + + /* + * Don't grow the hash table cardinality too much, otherwise we become bound + * by memory reads. In general, when this first stage of grouping doesn't + * significantly reduce the cardinality, it becomes pure overhead and the + * work will be done by the final Postgres aggregation, so we should bail + * out early here. + */ + return policy->hashing.get_size_bytes(&policy->hashing) > 512 * 1024; +} + +static bool +gp_hash_do_emit(GroupingPolicy *gp, TupleTableSlot *aggregated_slot) +{ + GroupingPolicyHash *policy = (GroupingPolicyHash *) gp; + + if (!policy->returning_results) + { + policy->returning_results = true; + policy->last_returned_key = 1; + + const float keys = policy->last_used_key_index; + if (keys > 0) + { + DEBUG_LOG("spill after %ld input, %ld valid, %ld bulk filtered, %ld cons, %.0f keys, " + "%f ratio, %ld curctx bytes, %ld aggstate bytes", + policy->stat_input_total_rows, + policy->stat_input_valid_rows, + policy->stat_bulk_filtered_rows, + policy->stat_consecutive_keys, + keys, + policy->stat_input_valid_rows / keys, + MemoryContextMemAllocated(CurrentMemoryContext, false), + MemoryContextMemAllocated(policy->agg_extra_mctx, false)); + } + } + else + { + policy->last_returned_key++; + } + + const uint32 current_key = policy->last_returned_key; + const uint32 keys_end = policy->last_used_key_index + 1; + if (current_key >= keys_end) + { + policy->returning_results = false; + return false; + } + + const int naggs = policy->num_agg_defs; + for (int i = 0; i < naggs; i++) + { + const VectorAggDef *agg_def = &policy->agg_defs[i]; + void *agg_states = policy->per_agg_states[i]; + void *agg_state = current_key * agg_def->func.state_bytes + (char *) agg_states; + agg_def->func.agg_emit(agg_state, + &aggregated_slot->tts_values[agg_def->output_offset], + &aggregated_slot->tts_isnull[agg_def->output_offset]); + } + + policy->hashing.emit_key(policy, current_key, aggregated_slot); + + DEBUG_PRINT("%p: output key index %d\n", policy, current_key); + + return true; +} + +static char * +gp_hash_explain(GroupingPolicy *gp) +{ + GroupingPolicyHash *policy = (GroupingPolicyHash *) gp; + return psprintf("hashed with %s key", policy->hashing.explain_name); +} + +static const GroupingPolicy grouping_policy_hash_functions = { + .gp_reset = gp_hash_reset, + .gp_add_batch = gp_hash_add_batch, + .gp_should_emit = gp_hash_should_emit, + .gp_do_emit = gp_hash_do_emit, + .gp_explain = gp_hash_explain, +}; diff --git a/tsl/src/nodes/vector_agg/grouping_policy_hash.h b/tsl/src/nodes/vector_agg/grouping_policy_hash.h new file mode 100644 index 00000000000..9ae8d2420b9 --- /dev/null +++ b/tsl/src/nodes/vector_agg/grouping_policy_hash.h @@ -0,0 +1,159 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ +#pragma once + +#include + +#include + +#include "grouping_policy.h" + +#include "nodes/decompress_chunk/compressed_batch.h" + +#include "hashing/hashing_strategy.h" + +typedef struct GroupingPolicyHash GroupingPolicyHash; + +/* + * Hash grouping policy. + * + * The grouping and aggregation is performed as follows: + * + * 0) The grouping policy keeps track of the unique grouping keys seen in + * the input rows, and the states of aggregate functions for each key. This + * spans multiple input compressed batches, and is reset after the partial + * aggregation results are emitted. + * + * 1) For each row of the new compressed batch, we obtain an index that + * uniquely identifies its grouping key. This is done by matching the row's + * grouping columns to the hash table recording the unique grouping keys and + * their respective indexes. It is performed in bulk for all rows of the batch, + * to improve memory locality. The details of this are managed by the hashing + * strategy. + * + * 2) The key indexes are used to locate the aggregate function states + * corresponding to a given row, and update it. This is done in bulk for all + * rows of the batch, and for each aggregate function separately, to generate + * simpler and potentially vectorizable code, and improve memory locality. + * + * 3) After the input have ended, or if the memory limit is reached, the partial + * results are emitted into the output slot. This is done in the order of unique + * grouping key indexes, thereby preserving the incoming key order. This + * guarantees that this policy works correctly even in a Partial GroupAggregate + * node, even though it's not optimal performance-wise. + */ +typedef struct GroupingPolicyHash +{ + /* + * We're using data inheritance from the GroupingPolicy. + */ + GroupingPolicy funcs; + + /* + * Aggregate function definitions. + */ + int num_agg_defs; + const VectorAggDef *restrict agg_defs; + + /* + * Grouping column definitions. + */ + int num_grouping_columns; + const GroupingColumn *restrict grouping_columns; + + /* + * The values of the grouping columns picked from the compressed batch and + * arranged in the order of grouping column definitions. + */ + CompressedColumnValues *restrict current_batch_grouping_column_values; + + /* + * Hashing strategy that is responsible for mapping the rows to the unique + * indexes of their grouping keys. + */ + HashingStrategy hashing; + + /* + * The last used index of an unique grouping key. Key index 0 is invalid. + */ + uint32 last_used_key_index; + + /* + * Temporary storage of unique indexes of keys corresponding to a given row + * of the compressed batch that is currently being aggregated. We keep it in + * the policy because it is potentially too big to keep on stack, and we + * don't want to reallocate it for each batch. + */ + uint32 *restrict key_index_for_row; + uint64 num_key_index_for_row; + + /* + * The temporary filter bitmap we use to combine the results of the + * vectorized filters in WHERE, validity of the aggregate function argument, + * and the aggregate FILTER clause. It is then used by the aggregate + * function implementation to filter out the rows that don't pass. + */ + uint64 *tmp_filter; + uint64 num_tmp_filter_words; + + /* + * Aggregate function states. Each element is an array of states for the + * respective function from agg_defs. These arrays are indexed by the unique + * grouping key indexes. The state index 0 is invalid, so the corresponding + * states are unused. + * The states of each aggregate function are stored separately and + * contiguously, to achieve better memory locality when updating them. + */ + void **per_agg_states; + uint64 num_agg_state_rows; + + /* + * A memory context for aggregate functions to allocate additional data, + * i.e. if they store strings or float8 datum on 32-bit systems. Valid until + * the grouping policy is reset. + */ + MemoryContext agg_extra_mctx; + + /* + * Whether we are in the mode of returning the partial aggregation results. + * If we are, track the index of the last returned grouping key. + */ + bool returning_results; + uint32 last_returned_key; + + /* + * Some statistics for debugging. + */ + uint64 stat_input_total_rows; + uint64 stat_input_valid_rows; + uint64 stat_bulk_filtered_rows; + uint64 stat_consecutive_keys; + + /* + * FIXME all the stuff below should be moved out. + */ + + /* + * Temporary key storages. Some hashing strategies need to put the key in a + * separate memory area, we don't want to alloc/free it on each row. + */ + uint8 *tmp_key_storage; + uint64 num_tmp_key_storage_bytes; + + /* + * For single text key that uses dictionary encoding, in some cases we first + * calculate the key indexes for the dictionary entries, and then translate + * it to the actual rows. + */ + uint32 *restrict key_index_for_dict; + uint64 num_key_index_for_dict; + bool use_key_index_for_dict; +} GroupingPolicyHash; + +//#define DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__) +#ifndef DEBUG_PRINT +#define DEBUG_PRINT(...) +#endif diff --git a/tsl/src/nodes/vector_agg/hashing/CMakeLists.txt b/tsl/src/nodes/vector_agg/hashing/CMakeLists.txt new file mode 100644 index 00000000000..fab11a7df17 --- /dev/null +++ b/tsl/src/nodes/vector_agg/hashing/CMakeLists.txt @@ -0,0 +1,7 @@ +set(SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/hash_strategy_single_fixed_2.c + ${CMAKE_CURRENT_SOURCE_DIR}/hash_strategy_single_fixed_4.c + ${CMAKE_CURRENT_SOURCE_DIR}/hash_strategy_single_fixed_8.c + ${CMAKE_CURRENT_SOURCE_DIR}/hash_strategy_single_text.c + ${CMAKE_CURRENT_SOURCE_DIR}/hash_strategy_serialized.c) +target_sources(${TSL_LIBRARY_NAME} PRIVATE ${SOURCES}) diff --git a/tsl/src/nodes/vector_agg/hashing/batch_hashing_params.h b/tsl/src/nodes/vector_agg/hashing/batch_hashing_params.h new file mode 100644 index 00000000000..a4db2a19b1c --- /dev/null +++ b/tsl/src/nodes/vector_agg/hashing/batch_hashing_params.h @@ -0,0 +1,55 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ + +#pragma once + +typedef struct BatchHashingParams +{ + const uint64 *batch_filter; + CompressedColumnValues single_key; + + int num_grouping_columns; + const CompressedColumnValues *grouping_column_values; + + /* + * Whether we have any scalar or nullable grouping columns in the current + * batch. This is used to select the more efficient implementation when we + * have none. + */ + bool have_scalar_or_nullable_columns; + + GroupingPolicyHash *restrict policy; + + uint32 *restrict result_key_indexes; +} BatchHashingParams; + +static pg_attribute_always_inline BatchHashingParams +build_batch_hashing_params(GroupingPolicyHash *policy, DecompressBatchState *batch_state) +{ + BatchHashingParams params = { + .policy = policy, + .batch_filter = batch_state->vector_qual_result, + .num_grouping_columns = policy->num_grouping_columns, + .grouping_column_values = policy->current_batch_grouping_column_values, + .result_key_indexes = policy->key_index_for_row, + }; + + Assert(policy->num_grouping_columns > 0); + if (policy->num_grouping_columns == 1) + { + params.single_key = policy->current_batch_grouping_column_values[0]; + } + + for (int i = 0; i < policy->num_grouping_columns; i++) + { + params.have_scalar_or_nullable_columns = + params.have_scalar_or_nullable_columns || + (policy->current_batch_grouping_column_values[i].decompression_type == DT_Scalar || + policy->current_batch_grouping_column_values[i].buffers[0] != NULL); + } + + return params; +} diff --git a/tsl/src/nodes/vector_agg/hashing/bytes_view.h b/tsl/src/nodes/vector_agg/hashing/bytes_view.h new file mode 100644 index 00000000000..f7149c52568 --- /dev/null +++ b/tsl/src/nodes/vector_agg/hashing/bytes_view.h @@ -0,0 +1,24 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ +#pragma once + +#include + +#include + +typedef struct BytesView +{ + const uint8 *data; + uint32 len; +} BytesView; + +static pg_attribute_always_inline uint32 +hash_bytes_view(BytesView view) +{ + uint32 val = -1; + COMP_CRC32C(val, view.data, view.len); + return val; +} diff --git a/tsl/src/nodes/vector_agg/hashing/hash64.h b/tsl/src/nodes/vector_agg/hashing/hash64.h new file mode 100644 index 00000000000..64877a7936e --- /dev/null +++ b/tsl/src/nodes/vector_agg/hashing/hash64.h @@ -0,0 +1,58 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ +#pragma once + +/* + * We can use crc32 as a hash function, it has bad properties but takes only one + * cycle, which is why it is sometimes used in the existing hash table + * implementations. + * When we don't have the crc32 instruction, use the SplitMix64 finalizer. + */ +static pg_attribute_always_inline uint64 +hash64_splitmix(uint64 x) +{ + x ^= x >> 30; + x *= 0xbf58476d1ce4e5b9U; + x ^= x >> 27; + x *= 0x94d049bb133111ebU; + x ^= x >> 31; + return x; +} + +#ifdef USE_SSE42_CRC32C +#include +static pg_attribute_always_inline uint64 +hash64_crc(uint64 x) +{ + return _mm_crc32_u64(~0ULL, x); +} + +#define HASH64 hash64_crc +#else +#define HASH64 hash64_splitmix +#endif + +static pg_attribute_always_inline uint32 +hash32(uint32 x) +{ + x ^= x >> 16; + x *= 0x7feb352d; + x ^= x >> 15; + x *= 0x846ca68b; + x ^= x >> 16; + return x; +} + +static pg_attribute_always_inline uint16 +hash16(uint16 x) +{ + x ^= x >> 8; + x *= 0x88b5U; + x ^= x >> 7; + x *= 0xdb2dU; + x ^= x >> 9; + return x; +} diff --git a/tsl/src/nodes/vector_agg/hashing/hash_strategy_impl.c b/tsl/src/nodes/vector_agg/hashing/hash_strategy_impl.c new file mode 100644 index 00000000000..ebeae2830a7 --- /dev/null +++ b/tsl/src/nodes/vector_agg/hashing/hash_strategy_impl.c @@ -0,0 +1,278 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ + +#include "batch_hashing_params.h" + +#include "import/umash.h" + +/* + * The hash table maps the value of the grouping key to its unique index. + * We don't store any extra information here, because we're accessing the memory + * of the hash table randomly, and want it to be as small as possible to fit the + * caches. + */ +typedef struct FUNCTION_NAME(entry) +{ + /* Key index 0 is invalid. */ + uint32 key_index; + + HASH_TABLE_KEY_TYPE hash_table_key; +} FUNCTION_NAME(entry); + +// #define SH_FILLFACTOR (0.5) +#define SH_PREFIX KEY_VARIANT +#define SH_ELEMENT_TYPE FUNCTION_NAME(entry) +#define SH_KEY_TYPE HASH_TABLE_KEY_TYPE +#define SH_KEY hash_table_key +#define SH_HASH_KEY(tb, key) KEY_HASH(key) +#define SH_EQUAL(tb, a, b) KEY_EQUAL(a, b) +#define SH_SCOPE static inline +#define SH_DECLARE +#define SH_DEFINE +#define SH_ENTRY_EMPTY(entry) ((entry)->key_index == 0) +#ifdef STORE_HASH +#define SH_GET_HASH(tb, entry) entry->hash +#define SH_STORE_HASH +#endif +#include "import/ts_simplehash.h" + +struct FUNCTION_NAME(hash); + +static uint64 +FUNCTION_NAME(get_size_bytes)(HashingStrategy *hashing) +{ + struct FUNCTION_NAME(hash) *hash = (struct FUNCTION_NAME(hash) *) hashing->table; + return hash->members * sizeof(FUNCTION_NAME(entry)); +} + +static void +FUNCTION_NAME(init)(HashingStrategy *hashing, GroupingPolicyHash *policy) +{ + hashing->table = FUNCTION_NAME(create)(CurrentMemoryContext, policy->num_agg_state_rows, NULL); +#ifdef UMASH + hashing->umash_params = palloc0(sizeof(struct umash_params)); + umash_params_derive(hashing->umash_params, 0xabcdef1234567890ull, NULL); +#endif +} + +static void +FUNCTION_NAME(reset_strategy)(HashingStrategy *hashing) +{ + struct FUNCTION_NAME(hash) *table = (struct FUNCTION_NAME(hash) *) hashing->table; + FUNCTION_NAME(reset)(table); + hashing->null_key_index = 0; +} + +/* + * Fill the unique key indexes for all rows using a hash table. + */ +static pg_attribute_always_inline void +FUNCTION_NAME(fill_offsets_impl)(BatchHashingParams params, int start_row, int end_row) +{ + GroupingPolicyHash *policy = params.policy; + HashingStrategy *hashing = &policy->hashing; + + uint32 *restrict indexes = params.result_key_indexes; + + struct FUNCTION_NAME(hash) *restrict table = hashing->table; + + HASH_TABLE_KEY_TYPE prev_hash_table_key; + uint32 previous_key_index = 0; + for (int row = start_row; row < end_row; row++) + { + if (!arrow_row_is_valid(params.batch_filter, row)) + { + /* The row doesn't pass the filter. */ + DEBUG_PRINT("%p: row %d doesn't pass batch filter\n", policy, row); + continue; + } + + bool key_valid = false; + OUTPUT_KEY_TYPE output_key = { 0 }; + HASH_TABLE_KEY_TYPE hash_table_key = { 0 }; + FUNCTION_NAME(get_key)(params, row, &output_key, &hash_table_key, &key_valid); + + if (unlikely(!key_valid)) + { + /* The key is null. */ + if (hashing->null_key_index == 0) + { + hashing->null_key_index = ++policy->last_used_key_index; + } + indexes[row] = hashing->null_key_index; + DEBUG_PRINT("%p: row %d null key index %d\n", policy, row, hashing->null_key_index); + continue; + } + + if (likely(previous_key_index != 0) && KEY_EQUAL(hash_table_key, prev_hash_table_key)) + { + /* + * In real data sets, we often see consecutive rows with the + * same value of a grouping column, so checking for this case + * improves performance. For multi-column keys, this is unlikely, + * but we currently often have suboptimal plans that use this policy + * as a GroupAggregate, so we still use this as an easy optimization + * for that case. + */ + indexes[row] = previous_key_index; + policy->stat_consecutive_keys++; + DEBUG_PRINT("%p: row %d consecutive key index %d\n", policy, row, previous_key_index); + continue; + } + + /* + * Find the key using the hash table. + */ + bool found = false; + FUNCTION_NAME(entry) *restrict entry = FUNCTION_NAME(insert)(table, hash_table_key, &found); + if (!found) + { + /* + * New key, have to store it persistently. + */ + const uint32 index = ++policy->last_used_key_index; + entry->hash_table_key = + FUNCTION_NAME(store_output_key)(policy, index, output_key, hash_table_key); + entry->key_index = index; + DEBUG_PRINT("%p: row %d new key index %d\n", policy, row, index); + } + else + { + DEBUG_PRINT("%p: row %d old key index %d\n", policy, row, entry->key_index); + } + indexes[row] = entry->key_index; + + previous_key_index = entry->key_index; + prev_hash_table_key = entry->hash_table_key; + } +} + +/* + * For some configurations of hashing, we want to generate dedicated + * implementations that will be more efficient. For example, for 2-byte keys + * when all the batch and key rows are valid. + */ +#define APPLY_FOR_BATCH_FILTER(X, NAME, COND) \ + X(NAME##_nofilter, (COND) && (params.batch_filter == NULL)) \ + X(NAME##_filter, (COND) && (params.batch_filter != NULL)) + +#define APPLY_FOR_NULLABILITY(X, NAME, COND) \ + APPLY_FOR_BATCH_FILTER(X, NAME##_notnull, (COND) && params.single_key.buffers[0] == NULL) \ + APPLY_FOR_BATCH_FILTER(X, NAME##_nullable, (COND) && params.single_key.buffers[0] != NULL) + +#define APPLY_FOR_SCALARS(X, NAME, COND) \ + APPLY_FOR_BATCH_FILTER(X, \ + NAME##_noscalar_notnull, \ + (COND) && !params.have_scalar_or_nullable_columns) \ + APPLY_FOR_BATCH_FILTER(X, \ + NAME##_scalar_or_nullable, \ + (COND) && params.have_scalar_or_nullable_columns) + +#define APPLY_FOR_TYPE(X, NAME, COND) \ + APPLY_FOR_NULLABILITY(X, \ + NAME##_byval, \ + (COND) && \ + params.single_key.decompression_type == sizeof(OUTPUT_KEY_TYPE)) \ + APPLY_FOR_NULLABILITY(X, \ + NAME##_text, \ + (COND) && params.single_key.decompression_type == DT_ArrowText) \ + APPLY_FOR_NULLABILITY(X, \ + NAME##_dict, \ + (COND) && params.single_key.decompression_type == DT_ArrowTextDict) \ + APPLY_FOR_SCALARS(X, NAME##_multi, (COND) && params.single_key.decompression_type == DT_Invalid) + +#define APPLY_FOR_SPECIALIZATIONS(X) APPLY_FOR_TYPE(X, index, true) + +#define DEFINE(NAME, CONDITION) \ + static pg_noinline void FUNCTION_NAME( \ + NAME)(BatchHashingParams params, int start_row, int end_row) \ + { \ + if (!(CONDITION)) \ + { \ + pg_unreachable(); \ + } \ + \ + FUNCTION_NAME(fill_offsets_impl)(params, start_row, end_row); \ + } + +APPLY_FOR_SPECIALIZATIONS(DEFINE) + +#undef DEFINE + +static void +FUNCTION_NAME(dispatch_for_params)(BatchHashingParams params, int start_row, int end_row) +{ + if (params.num_grouping_columns == 0) + { + pg_unreachable(); + } + + if ((params.num_grouping_columns == 1) != (params.single_key.decompression_type != DT_Invalid)) + { + pg_unreachable(); + } + +#define DISPATCH(NAME, CONDITION) \ + if (CONDITION) \ + { \ + FUNCTION_NAME(NAME)(params, start_row, end_row); \ + } \ + else + + APPLY_FOR_SPECIALIZATIONS(DISPATCH) + { + /* Use a generic implementation if no specializations matched. */ + FUNCTION_NAME(fill_offsets_impl)(params, start_row, end_row); + } +#undef DISPATCH +} + +#undef APPLY_FOR_SPECIALIZATIONS + +/* + * In some special cases we call a more efficient specialization of the grouping + * function. + */ +static void +FUNCTION_NAME(fill_offsets)(GroupingPolicyHash *policy, DecompressBatchState *batch_state, + int start_row, int end_row) +{ + Assert((size_t) end_row <= policy->num_key_index_for_row); + + BatchHashingParams params = build_batch_hashing_params(policy, batch_state); + +#ifdef USE_DICT_HASHING + if (policy->use_key_index_for_dict) + { + Assert(params.single_key.decompression_type == DT_ArrowTextDict); + single_text_offsets_translate(params, start_row, end_row); + return; + } +#endif + + FUNCTION_NAME(dispatch_for_params)(params, start_row, end_row); +} + +HashingStrategy FUNCTION_NAME(strategy) = { + .emit_key = FUNCTION_NAME(emit_key), + .explain_name = EXPLAIN_NAME, + .fill_offsets = FUNCTION_NAME(fill_offsets), + .get_size_bytes = FUNCTION_NAME(get_size_bytes), + .init = FUNCTION_NAME(init), + .prepare_for_batch = FUNCTION_NAME(prepare_for_batch), + .reset = FUNCTION_NAME(reset_strategy), +}; + +#undef EXPLAIN_NAME +#undef KEY_VARIANT +#undef KEY_EQUAL +#undef STORE_HASH +#undef OUTPUT_KEY_TYPE +#undef HASH_TABLE_KEY_TYPE +#undef DATUM_TO_OUTPUT_KEY +#undef OUTPUT_KEY_TO_DATUM +#undef UMASH +#undef USE_DICT_HASHING diff --git a/tsl/src/nodes/vector_agg/hashing/hash_strategy_impl_single_fixed_key.c b/tsl/src/nodes/vector_agg/hashing/hash_strategy_impl_single_fixed_key.c new file mode 100644 index 00000000000..eca3b21b2ea --- /dev/null +++ b/tsl/src/nodes/vector_agg/hashing/hash_strategy_impl_single_fixed_key.c @@ -0,0 +1,49 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ +#include "batch_hashing_params.h" + +#include "output_key_alloc.c" +#include "output_key_emit_single.c" + +static pg_attribute_always_inline void +FUNCTION_NAME(get_key)(BatchHashingParams params, int row, void *restrict output_key_ptr, + void *restrict hash_table_key_ptr, bool *restrict valid) +{ + OUTPUT_KEY_TYPE *restrict output_key = (OUTPUT_KEY_TYPE *) output_key_ptr; + HASH_TABLE_KEY_TYPE *restrict hash_table_key = (HASH_TABLE_KEY_TYPE *) hash_table_key_ptr; + + if (unlikely(params.single_key.decompression_type == DT_Scalar)) + { + *output_key = DATUM_TO_OUTPUT_KEY(*params.single_key.output_value); + *valid = !*params.single_key.output_isnull; + } + else if (params.single_key.decompression_type == sizeof(OUTPUT_KEY_TYPE)) + { + const OUTPUT_KEY_TYPE *values = params.single_key.buffers[1]; + *valid = arrow_row_is_valid(params.single_key.buffers[0], row); + *output_key = values[row]; + } + else + { + pg_unreachable(); + } + + *hash_table_key = *output_key; +} + +static pg_attribute_always_inline OUTPUT_KEY_TYPE +FUNCTION_NAME(store_output_key)(GroupingPolicyHash *restrict policy, uint32 new_key_index, + OUTPUT_KEY_TYPE output_key, HASH_TABLE_KEY_TYPE hash_table_key) +{ + policy->hashing.output_keys[new_key_index] = OUTPUT_KEY_TO_DATUM(output_key); + return hash_table_key; +} + +static void +FUNCTION_NAME(prepare_for_batch)(GroupingPolicyHash *policy, DecompressBatchState *batch_state) +{ + FUNCTION_NAME(alloc_output_keys)(policy, batch_state); +} diff --git a/tsl/src/nodes/vector_agg/hashing/hash_strategy_serialized.c b/tsl/src/nodes/vector_agg/hashing/hash_strategy_serialized.c new file mode 100644 index 00000000000..e73708966aa --- /dev/null +++ b/tsl/src/nodes/vector_agg/hashing/hash_strategy_serialized.c @@ -0,0 +1,457 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ + +/* + * Implementation of column hashing for multiple serialized columns. + */ + +#include + +#include + +#include "bytes_view.h" +#include "compression/arrow_c_data_interface.h" +#include "nodes/decompress_chunk/compressed_batch.h" +#include "nodes/vector_agg/exec.h" +#include "nodes/vector_agg/grouping_policy_hash.h" +#include "template_helper.h" + +#include "batch_hashing_params.h" + +#include "umash_fingerprint_key.h" + +#define EXPLAIN_NAME "serialized" +#define KEY_VARIANT serialized +#define OUTPUT_KEY_TYPE text * + +static pg_attribute_always_inline bool +byte_bitmap_row_is_valid(const uint8 *bitmap, size_t row_number) +{ + if (likely(bitmap == NULL)) + { + return true; + } + + const size_t byte_index = row_number / 8; + const size_t bit_index = row_number % 8; + const uint8 mask = ((uint8) 1) << bit_index; + return bitmap[byte_index] & mask; +} + +static pg_attribute_always_inline void +byte_bitmap_set_row_validity(uint8 *bitmap, size_t row_number, bool value) +{ + const size_t byte_index = row_number / 8; + const size_t bit_index = row_number % 8; + const uint8 mask = ((uint8) 1) << bit_index; + const uint8 new_bit = ((uint8) value) << bit_index; + + bitmap[byte_index] = (bitmap[byte_index] & ~mask) | new_bit; + + Assert(byte_bitmap_row_is_valid(bitmap, row_number) == value); +} + +static pg_attribute_always_inline void +serialized_get_key(BatchHashingParams params, int row, void *restrict output_key_ptr, + void *restrict hash_table_key_ptr, bool *restrict valid) +{ + GroupingPolicyHash *policy = params.policy; + + text **restrict output_key = (text **) output_key_ptr; + HASH_TABLE_KEY_TYPE *restrict hash_table_key = (HASH_TABLE_KEY_TYPE *) hash_table_key_ptr; + + const int num_columns = params.num_grouping_columns; + + const size_t bitmap_bytes = (num_columns + 7) / 8; + + /* + * Loop through the grouping columns to determine the length of the key. We + * need that to allocate memory to store it. + * + * The key has the null bitmap at the beginning. + */ + size_t num_bytes = bitmap_bytes; + for (int column_index = 0; column_index < num_columns; column_index++) + { + const CompressedColumnValues *column_values = ¶ms.grouping_column_values[column_index]; + + if (params.have_scalar_or_nullable_columns && + column_values->decompression_type == DT_Scalar) + { + if (!*column_values->output_isnull) + { + const GroupingColumn *def = ¶ms.policy->grouping_columns[column_index]; + if (def->by_value) + { + num_bytes += def->value_bytes; + } + else + { + /* + * The default value always has a long varlena header, but + * we are going to use short if it fits. + */ + const int32 value_bytes = VARSIZE_ANY_EXHDR(*column_values->output_value); + if (value_bytes + VARHDRSZ_SHORT <= VARATT_SHORT_MAX) + { + /* Short varlena, unaligned. */ + const int total_bytes = value_bytes + VARHDRSZ_SHORT; + num_bytes += total_bytes; + } + else + { + /* Long varlena, requires alignment. */ + const int total_bytes = value_bytes + VARHDRSZ; + num_bytes = TYPEALIGN(4, num_bytes) + total_bytes; + } + } + } + + continue; + } + + const bool is_valid = !params.have_scalar_or_nullable_columns || + arrow_row_is_valid(column_values->buffers[0], row); + if (!is_valid) + { + continue; + } + + if (column_values->decompression_type > 0) + { + num_bytes += column_values->decompression_type; + } + else + { + Assert(column_values->decompression_type == DT_ArrowText || + column_values->decompression_type == DT_ArrowTextDict); + Assert((column_values->decompression_type == DT_ArrowTextDict) == + (column_values->buffers[3] != NULL)); + + const uint32 data_row = (column_values->decompression_type == DT_ArrowTextDict) ? + ((int16 *) column_values->buffers[3])[row] : + row; + const uint32 start = ((uint32 *) column_values->buffers[1])[data_row]; + const int32 value_bytes = ((uint32 *) column_values->buffers[1])[data_row + 1] - start; + + if (value_bytes + VARHDRSZ_SHORT <= VARATT_SHORT_MAX) + { + /* Short varlena, unaligned. */ + const int total_bytes = value_bytes + VARHDRSZ_SHORT; + num_bytes += total_bytes; + } + else + { + /* Long varlena, requires alignment. */ + const int total_bytes = value_bytes + VARHDRSZ; + num_bytes = TYPEALIGN(4, num_bytes) + total_bytes; + } + } + } + + /* + * The key has short or long varlena header. This is a little tricky, we + * decide the header length after we have counted all the columns, but we + * put it at the beginning. Technically it could change the length because + * of the alignment. In practice, we only use alignment by 4 bytes for long + * varlena strings, and if we have at least one long varlena string column, + * the key is also going to use the long varlena header which is 4 bytes, so + * the alignment is not affected. If we use the short varlena header for the + * key, it necessarily means that there were no long varlena columns and + * therefore no alignment is needed. + */ + const bool key_uses_short_header = num_bytes + VARHDRSZ_SHORT <= VARATT_SHORT_MAX; + num_bytes += key_uses_short_header ? VARHDRSZ_SHORT : VARHDRSZ; + + /* + * Use temporary storage for the new key, reallocate if it's too small. + */ + if (num_bytes > policy->num_tmp_key_storage_bytes) + { + if (policy->tmp_key_storage != NULL) + { + pfree(policy->tmp_key_storage); + } + policy->tmp_key_storage = MemoryContextAlloc(policy->hashing.key_body_mctx, num_bytes); + policy->num_tmp_key_storage_bytes = num_bytes; + } + uint8 *restrict serialized_key_storage = policy->tmp_key_storage; + + /* + * Build the actual grouping key. + */ + uint32 offset = 0; + offset += key_uses_short_header ? VARHDRSZ_SHORT : VARHDRSZ; + + /* + * We must always save the validity bitmap, even when there are no + * null words, so that the key is uniquely deserializable. Otherwise a key + * with some nulls might collide with a key with no nulls. + */ + uint8 *restrict serialized_key_validity_bitmap = &serialized_key_storage[offset]; + offset += bitmap_bytes; + + /* + * Loop through the grouping columns again and add their values to the + * grouping key. + */ + for (int column_index = 0; column_index < num_columns; column_index++) + { + const CompressedColumnValues *column_values = ¶ms.grouping_column_values[column_index]; + + if (params.have_scalar_or_nullable_columns && + column_values->decompression_type == DT_Scalar) + { + const bool is_valid = !*column_values->output_isnull; + byte_bitmap_set_row_validity(serialized_key_validity_bitmap, column_index, is_valid); + if (is_valid) + { + const GroupingColumn *def = ¶ms.policy->grouping_columns[column_index]; + if (def->by_value) + { + memcpy(&serialized_key_storage[offset], + column_values->output_value, + def->value_bytes); + + offset += def->value_bytes; + } + else + { + /* + * The default value always has a long varlena header, but + * we are going to use short if it fits. + */ + const int32 value_bytes = VARSIZE_ANY_EXHDR(*column_values->output_value); + if (value_bytes + VARHDRSZ_SHORT <= VARATT_SHORT_MAX) + { + /* Short varlena, no alignment. */ + const int32 total_bytes = value_bytes + VARHDRSZ_SHORT; + SET_VARSIZE_SHORT(&serialized_key_storage[offset], total_bytes); + offset += VARHDRSZ_SHORT; + } + else + { + /* Long varlena, requires alignment. Zero out the alignment bytes. */ + memset(&serialized_key_storage[offset], 0, 4); + offset = TYPEALIGN(4, offset); + const int32 total_bytes = value_bytes + VARHDRSZ; + SET_VARSIZE(&serialized_key_storage[offset], total_bytes); + offset += VARHDRSZ; + } + + memcpy(&serialized_key_storage[offset], + VARDATA_ANY(*column_values->output_value), + value_bytes); + + offset += value_bytes; + } + } + continue; + } + + const bool is_valid = !params.have_scalar_or_nullable_columns || + arrow_row_is_valid(column_values->buffers[0], row); + byte_bitmap_set_row_validity(serialized_key_validity_bitmap, column_index, is_valid); + + if (!is_valid) + { + continue; + } + + if (column_values->decompression_type > 0) + { + Assert(offset <= UINT_MAX - column_values->decompression_type); + + switch ((int) column_values->decompression_type) + { + case 2: + memcpy(&serialized_key_storage[offset], + row + (int16 *) column_values->buffers[1], + 2); + break; + case 4: + memcpy(&serialized_key_storage[offset], + row + (int32 *) column_values->buffers[1], + 4); + break; + case 8: + memcpy(&serialized_key_storage[offset], + row + (int64 *) column_values->buffers[1], + 8); + break; + default: + pg_unreachable(); + break; + } + + offset += column_values->decompression_type; + + continue; + } + + Assert(column_values->decompression_type == DT_ArrowText || + column_values->decompression_type == DT_ArrowTextDict); + + const uint32 data_row = column_values->decompression_type == DT_ArrowTextDict ? + ((int16 *) column_values->buffers[3])[row] : + row; + const uint32 start = ((uint32 *) column_values->buffers[1])[data_row]; + const int32 value_bytes = ((uint32 *) column_values->buffers[1])[data_row + 1] - start; + + if (value_bytes + VARHDRSZ_SHORT <= VARATT_SHORT_MAX) + { + /* Short varlena, unaligned. */ + const int32 total_bytes = value_bytes + VARHDRSZ_SHORT; + SET_VARSIZE_SHORT(&serialized_key_storage[offset], total_bytes); + offset += VARHDRSZ_SHORT; + } + else + { + /* Long varlena, requires alignment. Zero out the alignment bytes. */ + memset(&serialized_key_storage[offset], 0, 4); + offset = TYPEALIGN(4, offset); + const int32 total_bytes = value_bytes + VARHDRSZ; + SET_VARSIZE(&serialized_key_storage[offset], total_bytes); + offset += VARHDRSZ; + } + memcpy(&serialized_key_storage[offset], + &((uint8 *) column_values->buffers[2])[start], + value_bytes); + + offset += value_bytes; + } + + Assert(offset == num_bytes); + + if (key_uses_short_header) + { + SET_VARSIZE_SHORT(serialized_key_storage, offset); + } + else + { + SET_VARSIZE(serialized_key_storage, offset); + } + + DEBUG_PRINT("key is %d bytes: ", offset); + for (size_t i = 0; i < offset; i++) + { + DEBUG_PRINT("%.2x.", serialized_key_storage[i]); + } + DEBUG_PRINT("\n"); + + *output_key = (text *) serialized_key_storage; + + Assert(VARSIZE_ANY(*output_key) == num_bytes); + + /* + * The multi-column key is always considered non-null, and the null flags + * for the individual columns are stored in a bitmap that is part of the + * key. + */ + *valid = true; + + const struct umash_fp fp = umash_fprint(params.policy->hashing.umash_params, + /* seed = */ -1ull, + serialized_key_storage, + num_bytes); + *hash_table_key = umash_fingerprint_get_key(fp); +} + +static pg_attribute_always_inline HASH_TABLE_KEY_TYPE +serialized_store_output_key(GroupingPolicyHash *restrict policy, uint32 new_key_index, + text *output_key, HASH_TABLE_KEY_TYPE hash_table_key) +{ + /* + * We will store this key so we have to consume the temporary storage that + * was used for it. The subsequent keys will need to allocate new memory. + */ + Assert(policy->tmp_key_storage == (void *) output_key); + policy->tmp_key_storage = NULL; + policy->num_tmp_key_storage_bytes = 0; + + policy->hashing.output_keys[new_key_index] = PointerGetDatum(output_key); + + return hash_table_key; +} + +static void +serialized_emit_key(GroupingPolicyHash *policy, uint32 current_key, TupleTableSlot *aggregated_slot) +{ + const int num_key_columns = policy->num_grouping_columns; + const Datum serialized_key_datum = policy->hashing.output_keys[current_key]; + const uint8 *serialized_key = (const uint8 *) VARDATA_ANY(serialized_key_datum); + PG_USED_FOR_ASSERTS_ONLY const int key_data_bytes = VARSIZE_ANY_EXHDR(serialized_key_datum); + const uint8 *restrict ptr = serialized_key; + + /* + * We have the column validity bitmap at the beginning of the key. + */ + const int bitmap_bytes = (num_key_columns + 7) / 8; + Assert(bitmap_bytes <= key_data_bytes); + const uint8 *restrict key_validity_bitmap = serialized_key; + ptr += bitmap_bytes; + + DEBUG_PRINT("emit key #%d, with header %ld without %d bytes: ", + current_key, + VARSIZE_ANY(serialized_key_datum), + key_data_bytes); + for (size_t i = 0; i < VARSIZE_ANY(serialized_key_datum); i++) + { + DEBUG_PRINT("%.2x.", ((const uint8 *) serialized_key_datum)[i]); + } + DEBUG_PRINT("\n"); + + for (int column_index = 0; column_index < num_key_columns; column_index++) + { + const GroupingColumn *col = &policy->grouping_columns[column_index]; + const bool isnull = !byte_bitmap_row_is_valid(key_validity_bitmap, column_index); + + aggregated_slot->tts_isnull[col->output_offset] = isnull; + + if (isnull) + { + continue; + } + + Datum *output = &aggregated_slot->tts_values[col->output_offset]; + if (col->value_bytes > 0) + { + Assert(col->by_value); + Assert((size_t) col->value_bytes <= sizeof(Datum)); + *output = 0; + memcpy(output, ptr, col->value_bytes); + ptr += col->value_bytes; + } + else + { + Assert(col->value_bytes == -1); + Assert(!col->by_value); + if (VARATT_IS_SHORT(ptr)) + { + *output = PointerGetDatum(ptr); + ptr += VARSIZE_SHORT(ptr); + } + else + { + ptr = (const uint8 *) TYPEALIGN(4, ptr); + *output = PointerGetDatum(ptr); + ptr += VARSIZE(ptr); + } + } + } + + Assert(ptr == serialized_key + key_data_bytes); +} + +#include "output_key_alloc.c" + +static void +serialized_prepare_for_batch(GroupingPolicyHash *policy, DecompressBatchState *batch_state) +{ + serialized_alloc_output_keys(policy, batch_state); +} + +#include "hash_strategy_impl.c" diff --git a/tsl/src/nodes/vector_agg/hashing/hash_strategy_single_fixed_2.c b/tsl/src/nodes/vector_agg/hashing/hash_strategy_single_fixed_2.c new file mode 100644 index 00000000000..8e2a9083d06 --- /dev/null +++ b/tsl/src/nodes/vector_agg/hashing/hash_strategy_single_fixed_2.c @@ -0,0 +1,32 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ + +/* + * Implementation of column hashing for a single fixed size 2-byte column. + */ + +#include + +#include "compression/arrow_c_data_interface.h" +#include "hash64.h" +#include "nodes/decompress_chunk/compressed_batch.h" +#include "nodes/vector_agg/exec.h" +#include "nodes/vector_agg/grouping_policy_hash.h" +#include "template_helper.h" + +#define EXPLAIN_NAME "single 2-byte" +#define KEY_VARIANT single_fixed_2 +#define OUTPUT_KEY_TYPE int16 +#define HASH_TABLE_KEY_TYPE OUTPUT_KEY_TYPE +#define DATUM_TO_OUTPUT_KEY DatumGetInt16 +#define OUTPUT_KEY_TO_DATUM Int16GetDatum + +#include "hash_strategy_impl_single_fixed_key.c" + +#define KEY_EQUAL(a, b) a == b +#define KEY_HASH(X) HASH64(X) + +#include "hash_strategy_impl.c" diff --git a/tsl/src/nodes/vector_agg/hashing/hash_strategy_single_fixed_4.c b/tsl/src/nodes/vector_agg/hashing/hash_strategy_single_fixed_4.c new file mode 100644 index 00000000000..96679548d52 --- /dev/null +++ b/tsl/src/nodes/vector_agg/hashing/hash_strategy_single_fixed_4.c @@ -0,0 +1,32 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ + +/* + * Implementation of column hashing for a single fixed size 2-byte column. + */ + +#include + +#include "compression/arrow_c_data_interface.h" +#include "hash64.h" +#include "nodes/decompress_chunk/compressed_batch.h" +#include "nodes/vector_agg/exec.h" +#include "nodes/vector_agg/grouping_policy_hash.h" +#include "template_helper.h" + +#define EXPLAIN_NAME "single 4-byte" +#define KEY_VARIANT single_fixed_4 +#define OUTPUT_KEY_TYPE int32 +#define HASH_TABLE_KEY_TYPE int32 +#define DATUM_TO_OUTPUT_KEY DatumGetInt32 +#define OUTPUT_KEY_TO_DATUM Int32GetDatum + +#include "hash_strategy_impl_single_fixed_key.c" + +#define KEY_EQUAL(a, b) a == b +#define KEY_HASH(X) HASH64(X) + +#include "hash_strategy_impl.c" diff --git a/tsl/src/nodes/vector_agg/hashing/hash_strategy_single_fixed_8.c b/tsl/src/nodes/vector_agg/hashing/hash_strategy_single_fixed_8.c new file mode 100644 index 00000000000..e0f12adf85b --- /dev/null +++ b/tsl/src/nodes/vector_agg/hashing/hash_strategy_single_fixed_8.c @@ -0,0 +1,32 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ + +/* + * Implementation of column hashing for a single fixed size 8-byte column. + */ + +#include + +#include "compression/arrow_c_data_interface.h" +#include "hash64.h" +#include "nodes/decompress_chunk/compressed_batch.h" +#include "nodes/vector_agg/exec.h" +#include "nodes/vector_agg/grouping_policy_hash.h" +#include "template_helper.h" + +#define EXPLAIN_NAME "single 8-byte" +#define KEY_VARIANT single_fixed_8 +#define OUTPUT_KEY_TYPE int64 +#define HASH_TABLE_KEY_TYPE int64 +#define DATUM_TO_OUTPUT_KEY DatumGetInt64 +#define OUTPUT_KEY_TO_DATUM Int64GetDatum + +#include "hash_strategy_impl_single_fixed_key.c" + +#define KEY_EQUAL(a, b) a == b +#define KEY_HASH(X) HASH64(X) + +#include "hash_strategy_impl.c" diff --git a/tsl/src/nodes/vector_agg/hashing/hash_strategy_single_text.c b/tsl/src/nodes/vector_agg/hashing/hash_strategy_single_text.c new file mode 100644 index 00000000000..6963063c054 --- /dev/null +++ b/tsl/src/nodes/vector_agg/hashing/hash_strategy_single_text.c @@ -0,0 +1,391 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ + +/* + * Implementation of column hashing for a single text column. + */ + +#include + +#include + +#include "bytes_view.h" +#include "compression/arrow_c_data_interface.h" +#include "nodes/decompress_chunk/compressed_batch.h" +#include "nodes/vector_agg/exec.h" +#include "nodes/vector_agg/grouping_policy_hash.h" +#include "template_helper.h" + +#include "batch_hashing_params.h" + +#include "umash_fingerprint_key.h" + +static BytesView +get_bytes_view(CompressedColumnValues *column_values, int arrow_row) +{ + const uint32 start = ((uint32 *) column_values->buffers[1])[arrow_row]; + const int32 value_bytes = ((uint32 *) column_values->buffers[1])[arrow_row + 1] - start; + Assert(value_bytes >= 0); + + return (BytesView){ .len = value_bytes, .data = &((uint8 *) column_values->buffers[2])[start] }; +} + +static pg_attribute_always_inline void +single_text_get_key(BatchHashingParams params, int row, void *restrict output_key_ptr, + void *restrict hash_table_key_ptr, bool *restrict valid) +{ + Assert(params.policy->num_grouping_columns == 1); + + BytesView *restrict output_key = (BytesView *) output_key_ptr; + HASH_TABLE_KEY_TYPE *restrict hash_table_key = (HASH_TABLE_KEY_TYPE *) hash_table_key_ptr; + + if (unlikely(params.single_key.decompression_type == DT_Scalar)) + { + output_key->len = VARSIZE_ANY_EXHDR(*params.single_key.output_value); + output_key->data = (const uint8 *) VARDATA_ANY(*params.single_key.output_value); + *valid = !*params.single_key.output_isnull; + } + else if (params.single_key.decompression_type == DT_ArrowText) + { + *output_key = get_bytes_view(¶ms.single_key, row); + *valid = arrow_row_is_valid(params.single_key.buffers[0], row); + } + else if (params.single_key.decompression_type == DT_ArrowTextDict) + { + const int16 index = ((int16 *) params.single_key.buffers[3])[row]; + *output_key = get_bytes_view(¶ms.single_key, index); + *valid = arrow_row_is_valid(params.single_key.buffers[0], row); + } + else + { + pg_unreachable(); + } + + DEBUG_PRINT("%p consider key row %d key index %d is %d bytes: ", + params.policy, + row, + params.policy->last_used_key_index + 1, + output_key->len); + for (size_t i = 0; i < output_key->len; i++) + { + DEBUG_PRINT("%.2x.", output_key->data[i]); + } + DEBUG_PRINT("\n"); + + const struct umash_fp fp = umash_fprint(params.policy->hashing.umash_params, + /* seed = */ -1ull, + output_key->data, + output_key->len); + *hash_table_key = umash_fingerprint_get_key(fp); +} + +static pg_attribute_always_inline HASH_TABLE_KEY_TYPE +single_text_store_output_key(GroupingPolicyHash *restrict policy, uint32 new_key_index, + BytesView output_key, HASH_TABLE_KEY_TYPE hash_table_key) +{ + const int total_bytes = output_key.len + VARHDRSZ; + text *restrict stored = (text *) MemoryContextAlloc(policy->hashing.key_body_mctx, total_bytes); + SET_VARSIZE(stored, total_bytes); + memcpy(VARDATA(stored), output_key.data, output_key.len); + output_key.data = (uint8 *) VARDATA(stored); + policy->hashing.output_keys[new_key_index] = PointerGetDatum(stored); + return hash_table_key; +} + +/* + * We use the standard single-key key output functions. + */ +#define EXPLAIN_NAME "single text" +#define KEY_VARIANT single_text +#define OUTPUT_KEY_TYPE BytesView + +#include "output_key_alloc.c" +#include "output_key_emit_single.c" + +/* + * We use a special batch preparation function to sometimes hash the dictionary- + * encoded column using the dictionary. + */ + +#define USE_DICT_HASHING + +static pg_attribute_always_inline void single_text_dispatch_for_params(BatchHashingParams params, + int start_row, int end_row); + +static void +single_text_prepare_for_batch(GroupingPolicyHash *policy, DecompressBatchState *batch_state) +{ + /* + * Allocate the key storage. + */ + single_text_alloc_output_keys(policy, batch_state); + + /* + * Determine whether we're going to use the dictionary for hashing. + */ + policy->use_key_index_for_dict = false; + + BatchHashingParams params = build_batch_hashing_params(policy, batch_state); + if (params.single_key.decompression_type != DT_ArrowTextDict) + { + return; + } + + const int dict_rows = params.single_key.arrow->dictionary->length; + if ((size_t) dict_rows > + arrow_num_valid(batch_state->vector_qual_result, batch_state->total_batch_rows)) + { + return; + } + + /* + * Remember which aggregation states have already existed, and which we have + * to initialize. State index zero is invalid. + */ + const uint32 last_initialized_key_index = policy->last_used_key_index; + Assert(last_initialized_key_index <= policy->num_agg_state_rows); + + /* + * Initialize the array for storing the aggregate state offsets corresponding + * to a given batch row. We don't need the offsets for the previous batch + * that are currently stored there, so we don't need to use repalloc. + */ + if ((size_t) dict_rows > policy->num_key_index_for_dict) + { + if (policy->key_index_for_dict != NULL) + { + pfree(policy->key_index_for_dict); + } + policy->num_key_index_for_dict = dict_rows; + policy->key_index_for_dict = + palloc(sizeof(policy->key_index_for_dict[0]) * policy->num_key_index_for_dict); + } + + /* + * We shouldn't add the dictionary entries that are not used by any matching + * rows. Translate the batch filter bitmap to dictionary rows. + */ + const int batch_rows = batch_state->total_batch_rows; + const uint64 *row_filter = batch_state->vector_qual_result; + if (batch_state->vector_qual_result != NULL) + { + uint64 *restrict dict_filter = policy->tmp_filter; + const size_t dict_words = (dict_rows + 63) / 64; + memset(dict_filter, 0, sizeof(*dict_filter) * dict_words); + + bool *restrict tmp = (bool *) policy->key_index_for_dict; + Assert(sizeof(*tmp) <= sizeof(*policy->key_index_for_dict)); + memset(tmp, 0, sizeof(*tmp) * dict_rows); + + int outer; + for (outer = 0; outer < batch_rows / 64; outer++) + { +#define INNER_LOOP(INNER_MAX) \ + const uint64 word = row_filter[outer]; \ + for (int inner = 0; inner < INNER_MAX; inner++) \ + { \ + const int16 index = ((int16 *) params.single_key.buffers[3])[outer * 64 + inner]; \ + tmp[index] = tmp[index] || (word & (1ull << inner)); \ + } + + INNER_LOOP(64) + } + + if (batch_rows % 64) + { + INNER_LOOP(batch_rows % 64) + } +#undef INNER_LOOP + + for (outer = 0; outer < dict_rows / 64; outer++) + { +#define INNER_LOOP(INNER_MAX) \ + uint64 word = 0; \ + for (int inner = 0; inner < INNER_MAX; inner++) \ + { \ + word |= (tmp[outer * 64 + inner] ? 1ull : 0ull) << inner; \ + } \ + dict_filter[outer] = word; + + INNER_LOOP(64) + } + if (dict_rows % 64) + { + INNER_LOOP(dict_rows % 64) + } +#undef INNER_LOOP + + params.batch_filter = dict_filter; + } + else + { + params.batch_filter = NULL; + } + + /* + * The dictionary contains no null entries, so we will be adding the null + * key separately. Determine if we have any null key that also passes the + * batch filter. + */ + bool have_null_key = false; + if (batch_state->vector_qual_result != NULL) + { + if (params.single_key.arrow->null_count > 0) + { + Assert(params.single_key.buffers[0] != NULL); + const size_t batch_words = (batch_rows + 63) / 64; + for (size_t i = 0; i < batch_words; i++) + { + have_null_key = + have_null_key || + (row_filter[i] & (~((uint64 *) params.single_key.buffers[0])[i])) != 0; + } + } + } + else + { + if (params.single_key.arrow->null_count > 0) + { + Assert(params.single_key.buffers[0] != NULL); + have_null_key = true; + } + } + + /* + * Build key indexes for the dictionary entries as for normal non-nullable + * text values. + */ + Assert(params.single_key.decompression_type = DT_ArrowTextDict); + Assert((size_t) dict_rows <= policy->num_key_index_for_dict); + memset(policy->key_index_for_dict, 0, sizeof(*policy->key_index_for_dict) * dict_rows); + + params.single_key.decompression_type = DT_ArrowText; + params.single_key.buffers[0] = NULL; + params.have_scalar_or_nullable_columns = false; + params.result_key_indexes = policy->key_index_for_dict; + + single_text_dispatch_for_params(params, 0, dict_rows); + + /* + * The dictionary doesn't store nulls, so add the null key separately if we + * have one. + * + * FIXME doesn't respect nulls last/first in GroupAggregate. Add a test. + */ + if (have_null_key && policy->hashing.null_key_index == 0) + { + policy->hashing.null_key_index = ++policy->last_used_key_index; + policy->hashing.output_keys[policy->hashing.null_key_index] = PointerGetDatum(NULL); + } + + policy->use_key_index_for_dict = true; + + /* + * Initialize the new keys if we added any. + */ + if (policy->last_used_key_index > last_initialized_key_index) + { + const uint64 new_aggstate_rows = policy->num_agg_state_rows * 2 + 1; + const int num_fns = policy->num_agg_defs; + for (int i = 0; i < num_fns; i++) + { + const VectorAggDef *agg_def = &policy->agg_defs[i]; + if (policy->last_used_key_index >= policy->num_agg_state_rows) + { + policy->per_agg_states[i] = repalloc(policy->per_agg_states[i], + new_aggstate_rows * agg_def->func.state_bytes); + } + + /* + * Initialize the aggregate function states for the newly added keys. + */ + void *first_uninitialized_state = + agg_def->func.state_bytes * (last_initialized_key_index + 1) + + (char *) policy->per_agg_states[i]; + agg_def->func.agg_init(first_uninitialized_state, + policy->last_used_key_index - last_initialized_key_index); + } + + /* + * Record the newly allocated number of rows in case we had to reallocate. + */ + if (policy->last_used_key_index >= policy->num_agg_state_rows) + { + Assert(new_aggstate_rows > policy->num_agg_state_rows); + policy->num_agg_state_rows = new_aggstate_rows; + } + } + + DEBUG_PRINT("computed the dict offsets\n"); +} + +static pg_attribute_always_inline void +single_text_offsets_translate_impl(BatchHashingParams params, int start_row, int end_row) +{ + GroupingPolicyHash *policy = params.policy; + Assert(policy->use_key_index_for_dict); + + uint32 *restrict indexes_for_rows = params.result_key_indexes; + uint32 *restrict indexes_for_dict = policy->key_index_for_dict; + + for (int row = start_row; row < end_row; row++) + { + const bool row_valid = arrow_row_is_valid(params.single_key.buffers[0], row); + const int16 dict_index = ((int16 *) params.single_key.buffers[3])[row]; + + if (row_valid) + { + indexes_for_rows[row] = indexes_for_dict[dict_index]; + } + else + { + indexes_for_rows[row] = policy->hashing.null_key_index; + } + + Assert(indexes_for_rows[row] != 0 || !arrow_row_is_valid(params.batch_filter, row)); + } +} + +#define APPLY_FOR_VALIDITY(X, NAME, COND) \ + X(NAME##_notnull, (COND) && (params.single_key.buffers[0] == NULL)) \ + X(NAME##_nullable, (COND) && (params.single_key.buffers[0] != NULL)) + +#define APPLY_FOR_SPECIALIZATIONS(X) APPLY_FOR_VALIDITY(X, single_text_offsets_translate, true) + +#define DEFINE(NAME, CONDITION) \ + static pg_noinline void NAME(BatchHashingParams params, int start_row, int end_row) \ + { \ + if (!(CONDITION)) \ + { \ + pg_unreachable(); \ + } \ + \ + single_text_offsets_translate_impl(params, start_row, end_row); \ + } + +APPLY_FOR_SPECIALIZATIONS(DEFINE) + +#undef DEFINE + +static void +single_text_offsets_translate(BatchHashingParams params, int start_row, int end_row) +{ +#define DISPATCH(NAME, CONDITION) \ + if (CONDITION) \ + { \ + NAME(params, start_row, end_row); \ + } \ + else + + APPLY_FOR_SPECIALIZATIONS(DISPATCH) { pg_unreachable(); } +#undef DISPATCH +} + +#undef APPLY_FOR_SPECIALIZATIONS +#undef APPLY_FOR_VALIDITY +#undef APPLY_FOR_BATCH_FILTER + +#include "hash_strategy_impl.c" diff --git a/tsl/src/nodes/vector_agg/hashing/hashing_strategy.h b/tsl/src/nodes/vector_agg/hashing/hashing_strategy.h new file mode 100644 index 00000000000..9df36b5a30a --- /dev/null +++ b/tsl/src/nodes/vector_agg/hashing/hashing_strategy.h @@ -0,0 +1,53 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ +#pragma once + +typedef struct GroupingPolicyHash GroupingPolicyHash; + +typedef struct HashingStrategy HashingStrategy; + +typedef struct HashingStrategy +{ + char *explain_name; + void (*init)(HashingStrategy *hashing, GroupingPolicyHash *policy); + void (*reset)(HashingStrategy *hashing); + uint64 (*get_size_bytes)(HashingStrategy *hashing); + void (*prepare_for_batch)(GroupingPolicyHash *policy, DecompressBatchState *batch_state); + void (*fill_offsets)(GroupingPolicyHash *policy, DecompressBatchState *batch_state, + int start_row, int end_row); + void (*emit_key)(GroupingPolicyHash *policy, uint32 current_key, + TupleTableSlot *aggregated_slot); + + /* + * The hash table we use for grouping. It matches each grouping key to its + * unique integer index. + */ + void *table; + + /* + * For each unique grouping key, we store the values of the grouping columns. + * This is stored separately from hash table keys, because they might not + * have the full column values, and also storing them contiguously here + * leads to better memory access patterns when emitting the results. + * The details of the key storage are managed by the hashing strategy. + */ + Datum *restrict output_keys; + uint64 num_output_keys; + MemoryContext key_body_mctx; + + /* + * In single-column grouping, we store the null key outside of the hash + * table, and its index is given by this value. Key index 0 is invalid. + * This is done to avoid having an "is null" flag in the hash table entries, + * to reduce the hash table size. + */ + uint32 null_key_index; + + /* + * UMASH fingerprinting parameters. + */ + struct umash_params *umash_params; +} HashingStrategy; diff --git a/tsl/src/nodes/vector_agg/hashing/output_key_alloc.c b/tsl/src/nodes/vector_agg/hashing/output_key_alloc.c new file mode 100644 index 00000000000..7cda7f340f0 --- /dev/null +++ b/tsl/src/nodes/vector_agg/hashing/output_key_alloc.c @@ -0,0 +1,32 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ + +static void +FUNCTION_NAME(alloc_output_keys)(GroupingPolicyHash *policy, DecompressBatchState *batch_state) +{ + /* + * Allocate enough storage for keys, given that each row of the new + * compressed batch might turn out to be a new grouping key. + * We do this separately to avoid allocations in the hot loop that fills the hash + * table. + */ + HashingStrategy *hashing = &policy->hashing; + const int n = batch_state->total_batch_rows; + const uint32 num_possible_keys = policy->last_used_key_index + 1 + n; + if (num_possible_keys > hashing->num_output_keys) + { + hashing->num_output_keys = num_possible_keys * 2 + 1; + const size_t new_bytes = sizeof(Datum) * hashing->num_output_keys; + if (hashing->output_keys == NULL) + { + hashing->output_keys = palloc(new_bytes); + } + else + { + hashing->output_keys = repalloc(hashing->output_keys, new_bytes); + } + } +} diff --git a/tsl/src/nodes/vector_agg/hashing/output_key_emit_single.c b/tsl/src/nodes/vector_agg/hashing/output_key_emit_single.c new file mode 100644 index 00000000000..ce8764b4f8e --- /dev/null +++ b/tsl/src/nodes/vector_agg/hashing/output_key_emit_single.c @@ -0,0 +1,17 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ + +static void +FUNCTION_NAME(emit_key)(GroupingPolicyHash *policy, uint32 current_key, + TupleTableSlot *aggregated_slot) +{ + HashingStrategy *hashing = &policy->hashing; + Assert(policy->num_grouping_columns == 1); + + const GroupingColumn *col = &policy->grouping_columns[0]; + aggregated_slot->tts_values[col->output_offset] = hashing->output_keys[current_key]; + aggregated_slot->tts_isnull[col->output_offset] = current_key == hashing->null_key_index; +} diff --git a/tsl/src/nodes/vector_agg/hashing/template_helper.h b/tsl/src/nodes/vector_agg/hashing/template_helper.h new file mode 100644 index 00000000000..684186ab27e --- /dev/null +++ b/tsl/src/nodes/vector_agg/hashing/template_helper.h @@ -0,0 +1,10 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ +#pragma once + +#define FUNCTION_NAME_HELPER2(X, Y) X##_##Y +#define FUNCTION_NAME_HELPER(X, Y) FUNCTION_NAME_HELPER2(X, Y) +#define FUNCTION_NAME(Y) FUNCTION_NAME_HELPER(KEY_VARIANT, Y) diff --git a/tsl/src/nodes/vector_agg/hashing/umash_fingerprint_key.h b/tsl/src/nodes/vector_agg/hashing/umash_fingerprint_key.h new file mode 100644 index 00000000000..0201383aa0d --- /dev/null +++ b/tsl/src/nodes/vector_agg/hashing/umash_fingerprint_key.h @@ -0,0 +1,38 @@ +/* + * This file and its contents are licensed under the Timescale License. + * Please see the included NOTICE for copyright information and + * LICENSE-TIMESCALE for a copy of the license. + */ +#pragma once + +/* + * Helpers to use the umash fingerprint as a hash table key in our hashing + * strategies for vectorized grouping. + */ + +#include "import/umash.h" + +/* + * The struct is packed so that the hash table entry fits into 16 + * bytes with the uint32 key index that goes before. + */ +struct umash_fingerprint_key +{ + uint32 hash; + uint64 rest; +} pg_attribute_packed(); + +#define UMASH +#define HASH_TABLE_KEY_TYPE struct umash_fingerprint_key +#define KEY_HASH(X) (X.hash) +#define KEY_EQUAL(a, b) (a.hash == b.hash && a.rest == b.rest) + +static inline struct umash_fingerprint_key +umash_fingerprint_get_key(struct umash_fp fp) +{ + const struct umash_fingerprint_key key = { + .hash = fp.hash[0] & (~(uint32) 0), + .rest = fp.hash[1], + }; + return key; +} diff --git a/tsl/src/nodes/vector_agg/plan.c b/tsl/src/nodes/vector_agg/plan.c index c8c204b5b8d..d8d9500b164 100644 --- a/tsl/src/nodes/vector_agg/plan.c +++ b/tsl/src/nodes/vector_agg/plan.c @@ -17,6 +17,7 @@ #include "exec.h" #include "nodes/decompress_chunk/planner.h" +#include "nodes/decompress_chunk/vector_quals.h" #include "nodes/vector_agg.h" #include "utils.h" @@ -181,6 +182,69 @@ vector_agg_plan_create(Agg *agg, CustomScan *decompress_chunk, List *resolved_ta return (Plan *) vector_agg; } +/* + * Map the custom scan attribute number to the uncompressed chunk attribute + * number. + */ +static int +custom_scan_to_uncompressed_chunk_attno(List *custom_scan_tlist, int custom_scan_attno) +{ + if (custom_scan_tlist == NIL) + { + return custom_scan_attno; + } + + Var *var = + castNode(Var, + castNode(TargetEntry, + list_nth(custom_scan_tlist, AttrNumberGetAttrOffset(custom_scan_attno))) + ->expr); + return var->varattno; +} + +/* + * Whether the given compressed column index corresponds to a vector variable. + */ +static bool +is_vector_compressed_column(CustomScan *custom, int compressed_column_index, bool *out_is_segmentby) +{ + List *bulk_decompression_column = list_nth(custom->custom_private, DCP_BulkDecompressionColumn); + const bool bulk_decompression_enabled_for_column = + list_nth_int(bulk_decompression_column, compressed_column_index); + + /* + * Bulk decompression can be disabled for all columns in the DecompressChunk + * node settings, we can't do vectorized aggregation for compressed columns + * in that case. For segmentby columns it's still possible. + */ + List *settings = linitial(custom->custom_private); + const bool bulk_decompression_enabled_globally = + list_nth_int(settings, DCS_EnableBulkDecompression); + + /* + * Check if this column is a segmentby. + */ + List *is_segmentby_column = list_nth(custom->custom_private, DCP_IsSegmentbyColumn); + const bool is_segmentby = list_nth_int(is_segmentby_column, compressed_column_index); + if (out_is_segmentby) + { + *out_is_segmentby = is_segmentby; + } + + /* + * We support vectorized aggregation either for segmentby columns or for + * columns with bulk decompression enabled. + */ + if (!is_segmentby && + !(bulk_decompression_enabled_for_column && bulk_decompression_enabled_globally)) + { + /* Vectorized aggregation not possible for this particular column. */ + return false; + } + + return true; +} + /* * Whether the expression can be used for vectorized processing: must be a Var * that refers to either a bulk-decompressed or a segmentby column. @@ -229,20 +293,8 @@ is_vector_var(CustomScan *custom, Expr *expr, bool *out_is_segmentby) continue; } - int uncompressed_chunk_attno = 0; - if (custom->custom_scan_tlist == NIL) - { - uncompressed_chunk_attno = custom_scan_attno; - } - else - { - Var *var = castNode(Var, - castNode(TargetEntry, - list_nth(custom->custom_scan_tlist, - AttrNumberGetAttrOffset(custom_scan_attno))) - ->expr); - uncompressed_chunk_attno = var->varattno; - } + const int uncompressed_chunk_attno = + custom_scan_to_uncompressed_chunk_attno(custom->custom_scan_tlist, custom_scan_attno); if (uncompressed_chunk_attno == decompressed_var->varattno) { @@ -250,55 +302,75 @@ is_vector_var(CustomScan *custom, Expr *expr, bool *out_is_segmentby) } } Ensure(compressed_column_index < list_length(decompression_map), "compressed column not found"); + return is_vector_compressed_column(custom, compressed_column_index, out_is_segmentby); +} - List *bulk_decompression_column = list_nth(custom->custom_private, DCP_BulkDecompressionColumn); - Assert(list_length(decompression_map) == list_length(bulk_decompression_column)); - const bool bulk_decompression_enabled_for_column = - list_nth_int(bulk_decompression_column, compressed_column_index); +/* + * Build supplementary info to determine whether we can vectorize the + * aggregate FILTER clauses. + */ +static VectorQualInfo +build_aggfilter_vector_qual_info(CustomScan *custom) +{ + VectorQualInfo vqi = { .rti = custom->scan.scanrelid }; /* - * Bulk decompression can be disabled for all columns in the DecompressChunk - * node settings, we can't do vectorized aggregation for compressed columns - * in that case. For segmentby columns it's still possible. + * Now, we have to translate the decompressed varno into the compressed + * column index, to check if the column supports bulk decompression. */ - List *settings = linitial(custom->custom_private); - const bool bulk_decompression_enabled_globally = - list_nth_int(settings, DCS_EnableBulkDecompression); + List *decompression_map = list_nth(custom->custom_private, DCP_DecompressionMap); /* - * Check if this column is a segmentby. + * There's no easy way to determine maximum attribute number for uncompressed + * chunk at this stage, so we'll have to go through all the compressed columns + * for this. */ - List *is_segmentby_column = list_nth(custom->custom_private, DCP_IsSegmentbyColumn); - Assert(list_length(is_segmentby_column) == list_length(decompression_map)); - const bool is_segmentby = list_nth_int(is_segmentby_column, compressed_column_index); - if (out_is_segmentby) + int maxattno = 0; + for (int compressed_column_index = 0; compressed_column_index < list_length(decompression_map); + compressed_column_index++) { - *out_is_segmentby = is_segmentby; + const int custom_scan_attno = list_nth_int(decompression_map, compressed_column_index); + if (custom_scan_attno <= 0) + { + continue; + } + + const int uncompressed_chunk_attno = + custom_scan_to_uncompressed_chunk_attno(custom->custom_scan_tlist, custom_scan_attno); + + if (uncompressed_chunk_attno > maxattno) + { + maxattno = uncompressed_chunk_attno; + } } - /* - * We support vectorized aggregation either for segmentby columns or for - * columns with bulk decompression enabled. - */ - if (!is_segmentby && - !(bulk_decompression_enabled_for_column && bulk_decompression_enabled_globally)) + vqi.vector_attrs = (bool *) palloc0(sizeof(bool) * (maxattno + 1)); + + for (int compressed_column_index = 0; compressed_column_index < list_length(decompression_map); + compressed_column_index++) { - /* Vectorized aggregation not possible for this particular column. */ - return false; + const int custom_scan_attno = list_nth_int(decompression_map, compressed_column_index); + if (custom_scan_attno <= 0) + { + continue; + } + + const int uncompressed_chunk_attno = + custom_scan_to_uncompressed_chunk_attno(custom->custom_scan_tlist, custom_scan_attno); + + vqi.vector_attrs[uncompressed_chunk_attno] = + is_vector_compressed_column(custom, compressed_column_index, NULL); } - return true; + return vqi; } +/* + * Whether we can vectorize this particular aggregate. + */ static bool -can_vectorize_aggref(Aggref *aggref, CustomScan *custom) +can_vectorize_aggref(Aggref *aggref, CustomScan *custom, VectorQualInfo *vqi) { - if (aggref->aggfilter != NULL) - { - /* Filter clause on aggregate is not supported. */ - return false; - } - if (aggref->aggdirectargs != NIL) { /* Can't process ordered-set aggregates with direct arguments. */ @@ -319,8 +391,13 @@ can_vectorize_aggref(Aggref *aggref, CustomScan *custom) if (aggref->aggfilter != NULL) { - /* Can't process aggregates with filter clause. */ - return false; + /* Can process aggregates with filter clause if it's vectorizable. */ + Node *aggfilter_vectorized = vector_qual_make((Node *) aggref->aggfilter, vqi); + if (aggfilter_vectorized == NULL) + { + return false; + } + aggref->aggfilter = (Expr *) aggfilter_vectorized; } if (get_vector_aggregate(aggref->aggfnoid) == NULL) @@ -356,11 +433,55 @@ can_vectorize_aggref(Aggref *aggref, CustomScan *custom) static bool can_vectorize_grouping(Agg *agg, CustomScan *custom, List *resolved_targetlist) { + /* + * We support vectorized aggregation without grouping. + */ if (agg->numCols == 0) { return true; } + /* + * We support hashed vectorized grouping by one fixed-size by-value + * compressed column. + * We can use our hash table for GroupAggregate as well, because it preserves + * the input order of the keys. + * FIXME write a test for that. + */ + if (true || agg->numCols == 1) + { + bool have_wrong_type = false; + for (int i = 0; i < agg->numCols; i++) + { + int offset = AttrNumberGetAttrOffset(agg->grpColIdx[i]); + TargetEntry *entry = list_nth_node(TargetEntry, resolved_targetlist, offset); + + bool is_segmentby = false; + if (!is_vector_var(custom, entry->expr, &is_segmentby)) + { + have_wrong_type = true; + break; + } + Var *var = castNode(Var, entry->expr); + int16 typlen; + bool typbyval; + get_typlenbyval(var->vartype, &typlen, &typbyval); + if (!((typbyval && typlen > 0 && (size_t) typlen <= sizeof(Datum)) || + (var->vartype == TEXTOID))) + { + have_wrong_type = true; + break; + } + } + if (!have_wrong_type) + { + return true; + } + } + + /* + * We support grouping by any number of columns if all of them are segmentby. + */ for (int i = 0; i < agg->numCols; i++) { int offset = AttrNumberGetAttrOffset(agg->grpColIdx[i]); @@ -569,6 +690,12 @@ try_insert_vector_agg_node(Plan *plan) return plan; } + /* + * Build supplementary info to determine whether we can vectorize the + * aggregate FILTER clauses. + */ + VectorQualInfo vqi = build_aggfilter_vector_qual_info(custom); + /* Now check the output targetlist. */ ListCell *lc; foreach (lc, resolved_targetlist) @@ -577,7 +704,7 @@ try_insert_vector_agg_node(Plan *plan) if (IsA(target_entry->expr, Aggref)) { Aggref *aggref = castNode(Aggref, target_entry->expr); - if (!can_vectorize_aggref(aggref, custom)) + if (!can_vectorize_aggref(aggref, custom, &vqi)) { /* Aggregate function not vectorizable. */ return plan; diff --git a/tsl/test/expected/vector_agg_filter.out b/tsl/test/expected/vector_agg_filter.out new file mode 100644 index 00000000000..9d8cb03a3d4 --- /dev/null +++ b/tsl/test/expected/vector_agg_filter.out @@ -0,0 +1,4946 @@ +-- This file and its contents are licensed under the Timescale License. +-- Please see the included NOTICE for copyright information and +-- LICENSE-TIMESCALE for a copy of the license. +\c :TEST_DBNAME :ROLE_SUPERUSER +-- helper function: float -> pseudorandom float [-0.5..0.5] +CREATE OR REPLACE FUNCTION mix(x anyelement) RETURNS float8 AS $$ + SELECT hashfloat8(x::float8) / pow(2, 32) +$$ LANGUAGE SQL; +-- non-vectorizable equality operator +create operator === (function = 'int4eq', rightarg = int4, leftarg = int4); +-- an abs() function that is stable not immutable +create function stable_abs(x int4) returns int4 as 'int4abs' language internal stable; +\set CHUNKS 2::int +\set CHUNK_ROWS 100000::int +\set GROUPING_CARDINALITY 10::int +create table aggfilter(t int, s int, + cint2 int2, dropped int4, cint4 int4); +select create_hypertable('aggfilter', 's', chunk_time_interval => :GROUPING_CARDINALITY / :CHUNKS); +NOTICE: adding not-null constraint to column "s" + create_hypertable +------------------------ + (1,public,aggfilter,t) +(1 row) + +create view source as +select s * 10000 + t as t, + s, + case when t % 1051 = 0 then null + else (mix(s + t * 1019) * 32767)::int2 end as cint2, + 1 as dropped, + (mix(s + t * 1021) * 32767)::int4 as cint4 +from + generate_series(1::int, :CHUNK_ROWS * :CHUNKS / :GROUPING_CARDINALITY) t, + generate_series(0::int, :GROUPING_CARDINALITY - 1::int) s(s) +; +insert into aggfilter select * from source where s = 1; +alter table aggfilter set (timescaledb.compress, timescaledb.compress_orderby = 't', + timescaledb.compress_segmentby = 's'); +select count(compress_chunk(x)) from show_chunks('aggfilter') x; + count +------- + 1 +(1 row) + +alter table aggfilter add column ss int default 11; +alter table aggfilter drop column dropped; +insert into aggfilter +select t, s, cint2, cint4, + case + -- null in entire batch + when s = 2 then null + -- null for some rows + when s = 3 and t % 1053 = 0 then null + -- for some rows same as default + when s = 4 and t % 1057 = 0 then 11 + -- not null for entire batch + else s + end as ss +from source where s != 1 +; +select count(compress_chunk(x)) from show_chunks('aggfilter') x; + count +------- + 2 +(1 row) + +vacuum freeze analyze aggfilter; +set timescaledb.debug_require_vector_agg = 'require'; +---- Uncomment to generate reference. +--set timescaledb.enable_vectorized_aggregation to off; set timescaledb.debug_require_vector_agg = 'allow'; +select + format('%sselect %s%s(%s)%s from aggfilter%s%s%s;', + explain, + grouping || ', ', + function, variable, + ' filter (where ' || agg_filter || ')', + ' where ' || condition, + ' group by ' || grouping, + format(' order by %s(%s), ', function, variable) || grouping || ' limit 10', + function, variable) +from + unnest(array[ + 'explain (costs off) ', + null]) explain, + unnest(array[ + 's', + 'ss', + 'cint2', + 'cint4', + '*']) variable, + unnest(array[ + 'min', + 'count']) function, + unnest(array[ + null, + 'cint2 > 0', + 'cint2 is null']) with ordinality as condition(condition, n), + unnest(array[ + null, + 's', + 'ss']) with ordinality as grouping(grouping, n), + unnest(array[ + null, + 'cint2 < 0', + 'ss > 1000', + 'cint4 > 0', + 's != 5']) with ordinality as agg_filter(agg_filter, n) +where + true + and (explain is null /* or condition is null and grouping = 's' */) + and (variable != '*' or function = 'count') +order by explain, condition.n, variable, function, grouping.n, agg_filter.n +\gexec +select count(*) from aggfilter; + count +-------- + 200000 +(1 row) + +select count(*) filter (where cint2 < 0) from aggfilter; + count +-------- + 100139 +(1 row) + +select count(*) filter (where ss > 1000) from aggfilter; + count +------- + 0 +(1 row) + +select count(*) filter (where cint4 > 0) from aggfilter; + count +-------- + 100038 +(1 row) + +select count(*) filter (where s != 5) from aggfilter; + count +-------- + 180000 +(1 row) + +select s, count(*) from aggfilter group by s order by count(*), s limit 10; + s | count +---+------- + 0 | 20000 + 1 | 20000 + 2 | 20000 + 3 | 20000 + 4 | 20000 + 5 | 20000 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 +(10 rows) + +select s, count(*) filter (where cint2 < 0) from aggfilter group by s order by count(*), s limit 10; + s | count +---+------- + 0 | 9968 + 1 | 9885 + 2 | 10113 + 3 | 10088 + 4 | 10074 + 5 | 9871 + 6 | 10089 + 7 | 10008 + 8 | 10082 + 9 | 9961 +(10 rows) + +select s, count(*) filter (where ss > 1000) from aggfilter group by s order by count(*), s limit 10; + s | count +---+------- + 0 | 0 + 1 | 0 + 2 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 +(10 rows) + +select s, count(*) filter (where cint4 > 0) from aggfilter group by s order by count(*), s limit 10; + s | count +---+------- + 0 | 10002 + 1 | 10046 + 2 | 9885 + 3 | 10063 + 4 | 9995 + 5 | 10106 + 6 | 9977 + 7 | 9983 + 8 | 10020 + 9 | 9961 +(10 rows) + +select s, count(*) filter (where s != 5) from aggfilter group by s order by count(*), s limit 10; + s | count +---+------- + 0 | 20000 + 1 | 20000 + 2 | 20000 + 3 | 20000 + 4 | 20000 + 5 | 0 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 +(10 rows) + +select ss, count(*) from aggfilter group by ss order by count(*), ss limit 10; + ss | count +----+------- + | 19 + 3 | 19981 + 4 | 19981 + 0 | 20000 + 5 | 20000 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 + 11 | 40019 +(10 rows) + +select ss, count(*) filter (where cint2 < 0) from aggfilter group by ss order by count(*), ss limit 10; + ss | count +----+------- + | 12 + 3 | 10076 + 4 | 10064 + 0 | 9968 + 5 | 9871 + 6 | 10089 + 7 | 10008 + 8 | 10082 + 9 | 9961 + 11 | 20008 +(10 rows) + +select ss, count(*) filter (where ss > 1000) from aggfilter group by ss order by count(*), ss limit 10; + ss | count +----+------- + | 0 + 3 | 0 + 4 | 0 + 0 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 +(10 rows) + +select ss, count(*) filter (where cint4 > 0) from aggfilter group by ss order by count(*), ss limit 10; + ss | count +----+------- + | 11 + 3 | 10052 + 4 | 9988 + 0 | 10002 + 5 | 10106 + 6 | 9977 + 7 | 9983 + 8 | 10020 + 9 | 9961 + 11 | 19938 +(10 rows) + +select ss, count(*) filter (where s != 5) from aggfilter group by ss order by count(*), ss limit 10; + ss | count +----+------- + | 19 + 3 | 19981 + 4 | 19981 + 0 | 20000 + 5 | 0 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 + 11 | 40019 +(10 rows) + +select count(cint2) from aggfilter; + count +-------- + 199810 +(1 row) + +select count(cint2) filter (where cint2 < 0) from aggfilter; + count +-------- + 100139 +(1 row) + +select count(cint2) filter (where ss > 1000) from aggfilter; + count +------- + 0 +(1 row) + +select count(cint2) filter (where cint4 > 0) from aggfilter; + count +------- + 99946 +(1 row) + +select count(cint2) filter (where s != 5) from aggfilter; + count +-------- + 179829 +(1 row) + +select s, count(cint2) from aggfilter group by s order by count(cint2), s limit 10; + s | count +---+------- + 0 | 19981 + 1 | 19981 + 2 | 19981 + 3 | 19981 + 4 | 19981 + 5 | 19981 + 6 | 19981 + 7 | 19981 + 8 | 19981 + 9 | 19981 +(10 rows) + +select s, count(cint2) filter (where cint2 < 0) from aggfilter group by s order by count(cint2), s limit 10; + s | count +---+------- + 0 | 9968 + 1 | 9885 + 2 | 10113 + 3 | 10088 + 4 | 10074 + 5 | 9871 + 6 | 10089 + 7 | 10008 + 8 | 10082 + 9 | 9961 +(10 rows) + +select s, count(cint2) filter (where ss > 1000) from aggfilter group by s order by count(cint2), s limit 10; + s | count +---+------- + 0 | 0 + 1 | 0 + 2 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 +(10 rows) + +select s, count(cint2) filter (where cint4 > 0) from aggfilter group by s order by count(cint2), s limit 10; + s | count +---+------- + 0 | 9993 + 1 | 10034 + 2 | 9876 + 3 | 10052 + 4 | 9990 + 5 | 10095 + 6 | 9968 + 7 | 9976 + 8 | 10010 + 9 | 9952 +(10 rows) + +select s, count(cint2) filter (where s != 5) from aggfilter group by s order by count(cint2), s limit 10; + s | count +---+------- + 0 | 19981 + 1 | 19981 + 2 | 19981 + 3 | 19981 + 4 | 19981 + 5 | 0 + 6 | 19981 + 7 | 19981 + 8 | 19981 + 9 | 19981 +(10 rows) + +select ss, count(cint2) from aggfilter group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + | 19 + 3 | 19962 + 4 | 19962 + 0 | 19981 + 5 | 19981 + 6 | 19981 + 7 | 19981 + 8 | 19981 + 9 | 19981 + 11 | 39981 +(10 rows) + +select ss, count(cint2) filter (where cint2 < 0) from aggfilter group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + | 12 + 3 | 10076 + 4 | 10064 + 0 | 9968 + 5 | 9871 + 6 | 10089 + 7 | 10008 + 8 | 10082 + 9 | 9961 + 11 | 20008 +(10 rows) + +select ss, count(cint2) filter (where ss > 1000) from aggfilter group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + | 0 + 3 | 0 + 4 | 0 + 0 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 +(10 rows) + +select ss, count(cint2) filter (where cint4 > 0) from aggfilter group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + | 11 + 3 | 10041 + 4 | 9983 + 0 | 9993 + 5 | 10095 + 6 | 9968 + 7 | 9976 + 8 | 10010 + 9 | 9952 + 11 | 19917 +(10 rows) + +select ss, count(cint2) filter (where s != 5) from aggfilter group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + | 19 + 3 | 19962 + 4 | 19962 + 0 | 19981 + 5 | 0 + 6 | 19981 + 7 | 19981 + 8 | 19981 + 9 | 19981 + 11 | 39981 +(10 rows) + +select min(cint2) from aggfilter; + min +-------- + -16383 +(1 row) + +select min(cint2) filter (where cint2 < 0) from aggfilter; + min +-------- + -16383 +(1 row) + +select min(cint2) filter (where ss > 1000) from aggfilter; + min +----- + +(1 row) + +select min(cint2) filter (where cint4 > 0) from aggfilter; + min +-------- + -16383 +(1 row) + +select min(cint2) filter (where s != 5) from aggfilter; + min +-------- + -16383 +(1 row) + +select s, min(cint2) from aggfilter group by s order by min(cint2), s limit 10; + s | min +---+-------- + 0 | -16383 + 4 | -16383 + 5 | -16383 + 6 | -16383 + 2 | -16382 + 7 | -16382 + 8 | -16382 + 3 | -16381 + 1 | -16378 + 9 | -16375 +(10 rows) + +select s, min(cint2) filter (where cint2 < 0) from aggfilter group by s order by min(cint2), s limit 10; + s | min +---+-------- + 0 | -16383 + 4 | -16383 + 5 | -16383 + 6 | -16383 + 2 | -16382 + 7 | -16382 + 8 | -16382 + 3 | -16381 + 1 | -16378 + 9 | -16375 +(10 rows) + +select s, min(cint2) filter (where ss > 1000) from aggfilter group by s order by min(cint2), s limit 10; + s | min +---+----- + 0 | + 4 | + 5 | + 6 | + 2 | + 7 | + 8 | + 3 | + 1 | + 9 | +(10 rows) + +select s, min(cint2) filter (where cint4 > 0) from aggfilter group by s order by min(cint2), s limit 10; + s | min +---+-------- + 0 | -16380 + 4 | -16381 + 5 | -16383 + 6 | -16379 + 2 | -16382 + 7 | -16382 + 8 | -16382 + 3 | -16380 + 1 | -16378 + 9 | -16375 +(10 rows) + +select s, min(cint2) filter (where s != 5) from aggfilter group by s order by min(cint2), s limit 10; + s | min +---+-------- + 0 | -16383 + 4 | -16383 + 5 | + 6 | -16383 + 2 | -16382 + 7 | -16382 + 8 | -16382 + 3 | -16381 + 1 | -16378 + 9 | -16375 +(10 rows) + +select ss, min(cint2) from aggfilter group by ss order by min(cint2), ss limit 10; + ss | min +----+-------- + 0 | -16383 + 4 | -16383 + 5 | -16383 + 6 | -16383 + 7 | -16382 + 8 | -16382 + 11 | -16382 + 3 | -16381 + 9 | -16375 + | -16100 +(10 rows) + +select ss, min(cint2) filter (where cint2 < 0) from aggfilter group by ss order by min(cint2), ss limit 10; + ss | min +----+-------- + 0 | -16383 + 4 | -16383 + 5 | -16383 + 6 | -16383 + 7 | -16382 + 8 | -16382 + 11 | -16382 + 3 | -16381 + 9 | -16375 + | -16100 +(10 rows) + +select ss, min(cint2) filter (where ss > 1000) from aggfilter group by ss order by min(cint2), ss limit 10; + ss | min +----+----- + 0 | + 4 | + 5 | + 6 | + 7 | + 8 | + 11 | + 3 | + 9 | + | +(10 rows) + +select ss, min(cint2) filter (where cint4 > 0) from aggfilter group by ss order by min(cint2), ss limit 10; + ss | min +----+-------- + 0 | -16380 + 4 | -16381 + 5 | -16383 + 6 | -16379 + 7 | -16382 + 8 | -16382 + 11 | -16382 + 3 | -16380 + 9 | -16375 + | -16100 +(10 rows) + +select ss, min(cint2) filter (where s != 5) from aggfilter group by ss order by min(cint2), ss limit 10; + ss | min +----+-------- + 0 | -16383 + 4 | -16383 + 5 | + 6 | -16383 + 7 | -16382 + 8 | -16382 + 11 | -16382 + 3 | -16381 + 9 | -16375 + | -16100 +(10 rows) + +select count(cint4) from aggfilter; + count +-------- + 200000 +(1 row) + +select count(cint4) filter (where cint2 < 0) from aggfilter; + count +-------- + 100139 +(1 row) + +select count(cint4) filter (where ss > 1000) from aggfilter; + count +------- + 0 +(1 row) + +select count(cint4) filter (where cint4 > 0) from aggfilter; + count +-------- + 100038 +(1 row) + +select count(cint4) filter (where s != 5) from aggfilter; + count +-------- + 180000 +(1 row) + +select s, count(cint4) from aggfilter group by s order by count(cint4), s limit 10; + s | count +---+------- + 0 | 20000 + 1 | 20000 + 2 | 20000 + 3 | 20000 + 4 | 20000 + 5 | 20000 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 +(10 rows) + +select s, count(cint4) filter (where cint2 < 0) from aggfilter group by s order by count(cint4), s limit 10; + s | count +---+------- + 0 | 9968 + 1 | 9885 + 2 | 10113 + 3 | 10088 + 4 | 10074 + 5 | 9871 + 6 | 10089 + 7 | 10008 + 8 | 10082 + 9 | 9961 +(10 rows) + +select s, count(cint4) filter (where ss > 1000) from aggfilter group by s order by count(cint4), s limit 10; + s | count +---+------- + 0 | 0 + 1 | 0 + 2 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 +(10 rows) + +select s, count(cint4) filter (where cint4 > 0) from aggfilter group by s order by count(cint4), s limit 10; + s | count +---+------- + 0 | 10002 + 1 | 10046 + 2 | 9885 + 3 | 10063 + 4 | 9995 + 5 | 10106 + 6 | 9977 + 7 | 9983 + 8 | 10020 + 9 | 9961 +(10 rows) + +select s, count(cint4) filter (where s != 5) from aggfilter group by s order by count(cint4), s limit 10; + s | count +---+------- + 0 | 20000 + 1 | 20000 + 2 | 20000 + 3 | 20000 + 4 | 20000 + 5 | 0 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 +(10 rows) + +select ss, count(cint4) from aggfilter group by ss order by count(cint4), ss limit 10; + ss | count +----+------- + | 19 + 3 | 19981 + 4 | 19981 + 0 | 20000 + 5 | 20000 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 + 11 | 40019 +(10 rows) + +select ss, count(cint4) filter (where cint2 < 0) from aggfilter group by ss order by count(cint4), ss limit 10; + ss | count +----+------- + | 12 + 3 | 10076 + 4 | 10064 + 0 | 9968 + 5 | 9871 + 6 | 10089 + 7 | 10008 + 8 | 10082 + 9 | 9961 + 11 | 20008 +(10 rows) + +select ss, count(cint4) filter (where ss > 1000) from aggfilter group by ss order by count(cint4), ss limit 10; + ss | count +----+------- + | 0 + 3 | 0 + 4 | 0 + 0 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 +(10 rows) + +select ss, count(cint4) filter (where cint4 > 0) from aggfilter group by ss order by count(cint4), ss limit 10; + ss | count +----+------- + | 11 + 3 | 10052 + 4 | 9988 + 0 | 10002 + 5 | 10106 + 6 | 9977 + 7 | 9983 + 8 | 10020 + 9 | 9961 + 11 | 19938 +(10 rows) + +select ss, count(cint4) filter (where s != 5) from aggfilter group by ss order by count(cint4), ss limit 10; + ss | count +----+------- + | 19 + 3 | 19981 + 4 | 19981 + 0 | 20000 + 5 | 0 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 + 11 | 40019 +(10 rows) + +select min(cint4) from aggfilter; + min +-------- + -16383 +(1 row) + +select min(cint4) filter (where cint2 < 0) from aggfilter; + min +-------- + -16383 +(1 row) + +select min(cint4) filter (where ss > 1000) from aggfilter; + min +----- + +(1 row) + +select min(cint4) filter (where cint4 > 0) from aggfilter; + min +----- + 1 +(1 row) + +select min(cint4) filter (where s != 5) from aggfilter; + min +-------- + -16383 +(1 row) + +select s, min(cint4) from aggfilter group by s order by min(cint4), s limit 10; + s | min +---+-------- + 0 | -16383 + 2 | -16383 + 7 | -16383 + 1 | -16382 + 3 | -16382 + 4 | -16382 + 6 | -16382 + 8 | -16382 + 9 | -16382 + 5 | -16380 +(10 rows) + +select s, min(cint4) filter (where cint2 < 0) from aggfilter group by s order by min(cint4), s limit 10; + s | min +---+-------- + 0 | -16382 + 2 | -16383 + 7 | -16383 + 1 | -16382 + 3 | -16382 + 4 | -16382 + 6 | -16381 + 8 | -16382 + 9 | -16381 + 5 | -16380 +(10 rows) + +select s, min(cint4) filter (where ss > 1000) from aggfilter group by s order by min(cint4), s limit 10; + s | min +---+----- + 0 | + 2 | + 7 | + 1 | + 3 | + 4 | + 6 | + 8 | + 9 | + 5 | +(10 rows) + +select s, min(cint4) filter (where cint4 > 0) from aggfilter group by s order by min(cint4), s limit 10; + s | min +---+----- + 0 | 1 + 2 | 2 + 7 | 1 + 1 | 3 + 3 | 2 + 4 | 2 + 6 | 2 + 8 | 2 + 9 | 2 + 5 | 2 +(10 rows) + +select s, min(cint4) filter (where s != 5) from aggfilter group by s order by min(cint4), s limit 10; + s | min +---+-------- + 0 | -16383 + 2 | -16383 + 7 | -16383 + 1 | -16382 + 3 | -16382 + 4 | -16382 + 6 | -16382 + 8 | -16382 + 9 | -16382 + 5 | +(10 rows) + +select ss, min(cint4) from aggfilter group by ss order by min(cint4), ss limit 10; + ss | min +----+-------- + 0 | -16383 + 7 | -16383 + 11 | -16383 + 3 | -16382 + 4 | -16382 + 6 | -16382 + 8 | -16382 + 9 | -16382 + 5 | -16380 + | -15907 +(10 rows) + +select ss, min(cint4) filter (where cint2 < 0) from aggfilter group by ss order by min(cint4), ss limit 10; + ss | min +----+-------- + 0 | -16382 + 7 | -16383 + 11 | -16383 + 3 | -16382 + 4 | -16382 + 6 | -16381 + 8 | -16382 + 9 | -16381 + 5 | -16380 + | -15907 +(10 rows) + +select ss, min(cint4) filter (where ss > 1000) from aggfilter group by ss order by min(cint4), ss limit 10; + ss | min +----+----- + 0 | + 7 | + 11 | + 3 | + 4 | + 6 | + 8 | + 9 | + 5 | + | +(10 rows) + +select ss, min(cint4) filter (where cint4 > 0) from aggfilter group by ss order by min(cint4), ss limit 10; + ss | min +----+------ + 0 | 1 + 7 | 1 + 11 | 2 + 3 | 2 + 4 | 2 + 6 | 2 + 8 | 2 + 9 | 2 + 5 | 2 + | 4132 +(10 rows) + +select ss, min(cint4) filter (where s != 5) from aggfilter group by ss order by min(cint4), ss limit 10; + ss | min +----+-------- + 0 | -16383 + 7 | -16383 + 11 | -16383 + 3 | -16382 + 4 | -16382 + 6 | -16382 + 8 | -16382 + 9 | -16382 + 5 | + | -15907 +(10 rows) + +select count(s) from aggfilter; + count +-------- + 200000 +(1 row) + +select count(s) filter (where cint2 < 0) from aggfilter; + count +-------- + 100139 +(1 row) + +select count(s) filter (where ss > 1000) from aggfilter; + count +------- + 0 +(1 row) + +select count(s) filter (where cint4 > 0) from aggfilter; + count +-------- + 100038 +(1 row) + +select count(s) filter (where s != 5) from aggfilter; + count +-------- + 180000 +(1 row) + +select s, count(s) from aggfilter group by s order by count(s), s limit 10; + s | count +---+------- + 0 | 20000 + 1 | 20000 + 2 | 20000 + 3 | 20000 + 4 | 20000 + 5 | 20000 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 +(10 rows) + +select s, count(s) filter (where cint2 < 0) from aggfilter group by s order by count(s), s limit 10; + s | count +---+------- + 0 | 9968 + 1 | 9885 + 2 | 10113 + 3 | 10088 + 4 | 10074 + 5 | 9871 + 6 | 10089 + 7 | 10008 + 8 | 10082 + 9 | 9961 +(10 rows) + +select s, count(s) filter (where ss > 1000) from aggfilter group by s order by count(s), s limit 10; + s | count +---+------- + 0 | 0 + 1 | 0 + 2 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 +(10 rows) + +select s, count(s) filter (where cint4 > 0) from aggfilter group by s order by count(s), s limit 10; + s | count +---+------- + 0 | 10002 + 1 | 10046 + 2 | 9885 + 3 | 10063 + 4 | 9995 + 5 | 10106 + 6 | 9977 + 7 | 9983 + 8 | 10020 + 9 | 9961 +(10 rows) + +select s, count(s) filter (where s != 5) from aggfilter group by s order by count(s), s limit 10; + s | count +---+------- + 0 | 20000 + 1 | 20000 + 2 | 20000 + 3 | 20000 + 4 | 20000 + 5 | 0 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 +(10 rows) + +select ss, count(s) from aggfilter group by ss order by count(s), ss limit 10; + ss | count +----+------- + | 19 + 3 | 19981 + 4 | 19981 + 0 | 20000 + 5 | 20000 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 + 11 | 40019 +(10 rows) + +select ss, count(s) filter (where cint2 < 0) from aggfilter group by ss order by count(s), ss limit 10; + ss | count +----+------- + | 12 + 3 | 10076 + 4 | 10064 + 0 | 9968 + 5 | 9871 + 6 | 10089 + 7 | 10008 + 8 | 10082 + 9 | 9961 + 11 | 20008 +(10 rows) + +select ss, count(s) filter (where ss > 1000) from aggfilter group by ss order by count(s), ss limit 10; + ss | count +----+------- + | 0 + 3 | 0 + 4 | 0 + 0 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 +(10 rows) + +select ss, count(s) filter (where cint4 > 0) from aggfilter group by ss order by count(s), ss limit 10; + ss | count +----+------- + | 11 + 3 | 10052 + 4 | 9988 + 0 | 10002 + 5 | 10106 + 6 | 9977 + 7 | 9983 + 8 | 10020 + 9 | 9961 + 11 | 19938 +(10 rows) + +select ss, count(s) filter (where s != 5) from aggfilter group by ss order by count(s), ss limit 10; + ss | count +----+------- + | 19 + 3 | 19981 + 4 | 19981 + 0 | 20000 + 5 | 0 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 + 11 | 40019 +(10 rows) + +select min(s) from aggfilter; + min +----- + 0 +(1 row) + +select min(s) filter (where cint2 < 0) from aggfilter; + min +----- + 0 +(1 row) + +select min(s) filter (where ss > 1000) from aggfilter; + min +----- + +(1 row) + +select min(s) filter (where cint4 > 0) from aggfilter; + min +----- + 0 +(1 row) + +select min(s) filter (where s != 5) from aggfilter; + min +----- + 0 +(1 row) + +select s, min(s) from aggfilter group by s order by min(s), s limit 10; + s | min +---+----- + 0 | 0 + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + +select s, min(s) filter (where cint2 < 0) from aggfilter group by s order by min(s), s limit 10; + s | min +---+----- + 0 | 0 + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + +select s, min(s) filter (where ss > 1000) from aggfilter group by s order by min(s), s limit 10; + s | min +---+----- + 0 | + 1 | + 2 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +(10 rows) + +select s, min(s) filter (where cint4 > 0) from aggfilter group by s order by min(s), s limit 10; + s | min +---+----- + 0 | 0 + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + +select s, min(s) filter (where s != 5) from aggfilter group by s order by min(s), s limit 10; + s | min +---+----- + 0 | 0 + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + +select ss, min(s) from aggfilter group by ss order by min(s), ss limit 10; + ss | min +----+----- + 0 | 0 + 11 | 1 + 3 | 3 + | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + +select ss, min(s) filter (where cint2 < 0) from aggfilter group by ss order by min(s), ss limit 10; + ss | min +----+----- + 0 | 0 + 11 | 1 + 3 | 3 + | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + +select ss, min(s) filter (where ss > 1000) from aggfilter group by ss order by min(s), ss limit 10; + ss | min +----+----- + 0 | + 11 | + 3 | + | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +(10 rows) + +select ss, min(s) filter (where cint4 > 0) from aggfilter group by ss order by min(s), ss limit 10; + ss | min +----+----- + 0 | 0 + 11 | 1 + 3 | 3 + | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + +select ss, min(s) filter (where s != 5) from aggfilter group by ss order by min(s), ss limit 10; + ss | min +----+----- + 0 | 0 + 11 | 1 + 3 | 3 + | 3 + 4 | 4 + 5 | + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + +select count(ss) from aggfilter; + count +-------- + 199981 +(1 row) + +select count(ss) filter (where cint2 < 0) from aggfilter; + count +-------- + 100127 +(1 row) + +select count(ss) filter (where ss > 1000) from aggfilter; + count +------- + 0 +(1 row) + +select count(ss) filter (where cint4 > 0) from aggfilter; + count +-------- + 100027 +(1 row) + +select count(ss) filter (where s != 5) from aggfilter; + count +-------- + 179981 +(1 row) + +select s, count(ss) from aggfilter group by s order by count(ss), s limit 10; + s | count +---+------- + 3 | 19981 + 0 | 20000 + 1 | 20000 + 2 | 20000 + 4 | 20000 + 5 | 20000 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 +(10 rows) + +select s, count(ss) filter (where cint2 < 0) from aggfilter group by s order by count(ss), s limit 10; + s | count +---+------- + 3 | 10076 + 0 | 9968 + 1 | 9885 + 2 | 10113 + 4 | 10074 + 5 | 9871 + 6 | 10089 + 7 | 10008 + 8 | 10082 + 9 | 9961 +(10 rows) + +select s, count(ss) filter (where ss > 1000) from aggfilter group by s order by count(ss), s limit 10; + s | count +---+------- + 3 | 0 + 0 | 0 + 1 | 0 + 2 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 +(10 rows) + +select s, count(ss) filter (where cint4 > 0) from aggfilter group by s order by count(ss), s limit 10; + s | count +---+------- + 3 | 10052 + 0 | 10002 + 1 | 10046 + 2 | 9885 + 4 | 9995 + 5 | 10106 + 6 | 9977 + 7 | 9983 + 8 | 10020 + 9 | 9961 +(10 rows) + +select s, count(ss) filter (where s != 5) from aggfilter group by s order by count(ss), s limit 10; + s | count +---+------- + 3 | 19981 + 0 | 20000 + 1 | 20000 + 2 | 20000 + 4 | 20000 + 5 | 0 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 +(10 rows) + +select ss, count(ss) from aggfilter group by ss order by count(ss), ss limit 10; + ss | count +----+------- + | 0 + 3 | 19981 + 4 | 19981 + 0 | 20000 + 5 | 20000 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 + 11 | 40019 +(10 rows) + +select ss, count(ss) filter (where cint2 < 0) from aggfilter group by ss order by count(ss), ss limit 10; + ss | count +----+------- + | 0 + 3 | 10076 + 4 | 10064 + 0 | 9968 + 5 | 9871 + 6 | 10089 + 7 | 10008 + 8 | 10082 + 9 | 9961 + 11 | 20008 +(10 rows) + +select ss, count(ss) filter (where ss > 1000) from aggfilter group by ss order by count(ss), ss limit 10; + ss | count +----+------- + | 0 + 3 | 0 + 4 | 0 + 0 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 +(10 rows) + +select ss, count(ss) filter (where cint4 > 0) from aggfilter group by ss order by count(ss), ss limit 10; + ss | count +----+------- + | 0 + 3 | 10052 + 4 | 9988 + 0 | 10002 + 5 | 10106 + 6 | 9977 + 7 | 9983 + 8 | 10020 + 9 | 9961 + 11 | 19938 +(10 rows) + +select ss, count(ss) filter (where s != 5) from aggfilter group by ss order by count(ss), ss limit 10; + ss | count +----+------- + | 0 + 3 | 19981 + 4 | 19981 + 0 | 20000 + 5 | 0 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 + 11 | 40019 +(10 rows) + +select min(ss) from aggfilter; + min +----- + 0 +(1 row) + +select min(ss) filter (where cint2 < 0) from aggfilter; + min +----- + 0 +(1 row) + +select min(ss) filter (where ss > 1000) from aggfilter; + min +----- + +(1 row) + +select min(ss) filter (where cint4 > 0) from aggfilter; + min +----- + 0 +(1 row) + +select min(ss) filter (where s != 5) from aggfilter; + min +----- + 0 +(1 row) + +select s, min(ss) from aggfilter group by s order by min(ss), s limit 10; + s | min +---+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 1 | 11 + 2 | 11 +(10 rows) + +select s, min(ss) filter (where cint2 < 0) from aggfilter group by s order by min(ss), s limit 10; + s | min +---+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 1 | 11 + 2 | 11 +(10 rows) + +select s, min(ss) filter (where ss > 1000) from aggfilter group by s order by min(ss), s limit 10; + s | min +---+----- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 1 | + 2 | +(10 rows) + +select s, min(ss) filter (where cint4 > 0) from aggfilter group by s order by min(ss), s limit 10; + s | min +---+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 1 | 11 + 2 | 11 +(10 rows) + +select s, min(ss) filter (where s != 5) from aggfilter group by s order by min(ss), s limit 10; + s | min +---+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 1 | 11 + 2 | 11 +(10 rows) + +select ss, min(ss) from aggfilter group by ss order by min(ss), ss limit 10; + ss | min +----+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 11 | 11 + | +(10 rows) + +select ss, min(ss) filter (where cint2 < 0) from aggfilter group by ss order by min(ss), ss limit 10; + ss | min +----+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 11 | 11 + | +(10 rows) + +select ss, min(ss) filter (where ss > 1000) from aggfilter group by ss order by min(ss), ss limit 10; + ss | min +----+----- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 11 | + | +(10 rows) + +select ss, min(ss) filter (where cint4 > 0) from aggfilter group by ss order by min(ss), ss limit 10; + ss | min +----+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 11 | 11 + | +(10 rows) + +select ss, min(ss) filter (where s != 5) from aggfilter group by ss order by min(ss), ss limit 10; + ss | min +----+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 11 | 11 + | +(10 rows) + +select count(*) from aggfilter where cint2 > 0; + count +------- + 99664 +(1 row) + +select count(*) filter (where cint2 < 0) from aggfilter where cint2 > 0; + count +------- + 0 +(1 row) + +select count(*) filter (where ss > 1000) from aggfilter where cint2 > 0; + count +------- + 0 +(1 row) + +select count(*) filter (where cint4 > 0) from aggfilter where cint2 > 0; + count +------- + 49817 +(1 row) + +select count(*) filter (where s != 5) from aggfilter where cint2 > 0; + count +------- + 89554 +(1 row) + +select s, count(*) from aggfilter where cint2 > 0 group by s order by count(*), s limit 10; + s | count +---+------- + 2 | 9868 + 6 | 9890 + 3 | 9893 + 8 | 9898 + 4 | 9906 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 1 | 10096 + 5 | 10110 +(10 rows) + +select s, count(*) filter (where cint2 < 0) from aggfilter where cint2 > 0 group by s order by count(*), s limit 10; + s | count +---+------- + 2 | 0 + 6 | 0 + 3 | 0 + 8 | 0 + 4 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 1 | 0 + 5 | 0 +(10 rows) + +select s, count(*) filter (where ss > 1000) from aggfilter where cint2 > 0 group by s order by count(*), s limit 10; + s | count +---+------- + 2 | 0 + 6 | 0 + 3 | 0 + 8 | 0 + 4 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 1 | 0 + 5 | 0 +(10 rows) + +select s, count(*) filter (where cint4 > 0) from aggfilter where cint2 > 0 group by s order by count(*), s limit 10; + s | count +---+------- + 2 | 4923 + 6 | 4911 + 3 | 4972 + 8 | 4929 + 4 | 4944 + 7 | 4990 + 0 | 4963 + 9 | 4951 + 1 | 5067 + 5 | 5167 +(10 rows) + +select s, count(*) filter (where s != 5) from aggfilter where cint2 > 0 group by s order by count(*), s limit 10; + s | count +---+------- + 2 | 9868 + 6 | 9890 + 3 | 9893 + 8 | 9898 + 4 | 9906 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 1 | 10096 + 5 | 0 +(10 rows) + +select ss, count(*) from aggfilter where cint2 > 0 group by ss order by count(*), ss limit 10; + ss | count +----+------- + | 7 + 3 | 9886 + 6 | 9890 + 4 | 9897 + 8 | 9898 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 5 | 10110 + 11 | 19973 +(10 rows) + +select ss, count(*) filter (where cint2 < 0) from aggfilter where cint2 > 0 group by ss order by count(*), ss limit 10; + ss | count +----+------- + | 0 + 3 | 0 + 6 | 0 + 4 | 0 + 8 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 5 | 0 + 11 | 0 +(10 rows) + +select ss, count(*) filter (where ss > 1000) from aggfilter where cint2 > 0 group by ss order by count(*), ss limit 10; + ss | count +----+------- + | 0 + 3 | 0 + 6 | 0 + 4 | 0 + 8 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 5 | 0 + 11 | 0 +(10 rows) + +select ss, count(*) filter (where cint4 > 0) from aggfilter where cint2 > 0 group by ss order by count(*), ss limit 10; + ss | count +----+------- + | 4 + 3 | 4968 + 6 | 4911 + 4 | 4944 + 8 | 4929 + 7 | 4990 + 0 | 4963 + 9 | 4951 + 5 | 5167 + 11 | 9990 +(10 rows) + +select ss, count(*) filter (where s != 5) from aggfilter where cint2 > 0 group by ss order by count(*), ss limit 10; + ss | count +----+------- + | 7 + 3 | 9886 + 6 | 9890 + 4 | 9897 + 8 | 9898 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 5 | 0 + 11 | 19973 +(10 rows) + +select count(cint2) from aggfilter where cint2 > 0; + count +------- + 99664 +(1 row) + +select count(cint2) filter (where cint2 < 0) from aggfilter where cint2 > 0; + count +------- + 0 +(1 row) + +select count(cint2) filter (where ss > 1000) from aggfilter where cint2 > 0; + count +------- + 0 +(1 row) + +select count(cint2) filter (where cint4 > 0) from aggfilter where cint2 > 0; + count +------- + 49817 +(1 row) + +select count(cint2) filter (where s != 5) from aggfilter where cint2 > 0; + count +------- + 89554 +(1 row) + +select s, count(cint2) from aggfilter where cint2 > 0 group by s order by count(cint2), s limit 10; + s | count +---+------- + 2 | 9868 + 6 | 9890 + 3 | 9893 + 8 | 9898 + 4 | 9906 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 1 | 10096 + 5 | 10110 +(10 rows) + +select s, count(cint2) filter (where cint2 < 0) from aggfilter where cint2 > 0 group by s order by count(cint2), s limit 10; + s | count +---+------- + 2 | 0 + 6 | 0 + 3 | 0 + 8 | 0 + 4 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 1 | 0 + 5 | 0 +(10 rows) + +select s, count(cint2) filter (where ss > 1000) from aggfilter where cint2 > 0 group by s order by count(cint2), s limit 10; + s | count +---+------- + 2 | 0 + 6 | 0 + 3 | 0 + 8 | 0 + 4 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 1 | 0 + 5 | 0 +(10 rows) + +select s, count(cint2) filter (where cint4 > 0) from aggfilter where cint2 > 0 group by s order by count(cint2), s limit 10; + s | count +---+------- + 2 | 4923 + 6 | 4911 + 3 | 4972 + 8 | 4929 + 4 | 4944 + 7 | 4990 + 0 | 4963 + 9 | 4951 + 1 | 5067 + 5 | 5167 +(10 rows) + +select s, count(cint2) filter (where s != 5) from aggfilter where cint2 > 0 group by s order by count(cint2), s limit 10; + s | count +---+------- + 2 | 9868 + 6 | 9890 + 3 | 9893 + 8 | 9898 + 4 | 9906 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 1 | 10096 + 5 | 0 +(10 rows) + +select ss, count(cint2) from aggfilter where cint2 > 0 group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + | 7 + 3 | 9886 + 6 | 9890 + 4 | 9897 + 8 | 9898 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 5 | 10110 + 11 | 19973 +(10 rows) + +select ss, count(cint2) filter (where cint2 < 0) from aggfilter where cint2 > 0 group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + | 0 + 3 | 0 + 6 | 0 + 4 | 0 + 8 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 5 | 0 + 11 | 0 +(10 rows) + +select ss, count(cint2) filter (where ss > 1000) from aggfilter where cint2 > 0 group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + | 0 + 3 | 0 + 6 | 0 + 4 | 0 + 8 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 5 | 0 + 11 | 0 +(10 rows) + +select ss, count(cint2) filter (where cint4 > 0) from aggfilter where cint2 > 0 group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + | 4 + 3 | 4968 + 6 | 4911 + 4 | 4944 + 8 | 4929 + 7 | 4990 + 0 | 4963 + 9 | 4951 + 5 | 5167 + 11 | 9990 +(10 rows) + +select ss, count(cint2) filter (where s != 5) from aggfilter where cint2 > 0 group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + | 7 + 3 | 9886 + 6 | 9890 + 4 | 9897 + 8 | 9898 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 5 | 0 + 11 | 19973 +(10 rows) + +select min(cint2) from aggfilter where cint2 > 0; + min +----- + 1 +(1 row) + +select min(cint2) filter (where cint2 < 0) from aggfilter where cint2 > 0; + min +----- + +(1 row) + +select min(cint2) filter (where ss > 1000) from aggfilter where cint2 > 0; + min +----- + +(1 row) + +select min(cint2) filter (where cint4 > 0) from aggfilter where cint2 > 0; + min +----- + 1 +(1 row) + +select min(cint2) filter (where s != 5) from aggfilter where cint2 > 0; + min +----- + 1 +(1 row) + +select s, min(cint2) from aggfilter where cint2 > 0 group by s order by min(cint2), s limit 10; + s | min +---+----- + 1 | 1 + 2 | 1 + 3 | 1 + 5 | 1 + 7 | 1 + 8 | 1 + 9 | 2 + 6 | 3 + 0 | 4 + 4 | 4 +(10 rows) + +select s, min(cint2) filter (where cint2 < 0) from aggfilter where cint2 > 0 group by s order by min(cint2), s limit 10; + s | min +---+----- + 1 | + 2 | + 3 | + 5 | + 7 | + 8 | + 9 | + 6 | + 0 | + 4 | +(10 rows) + +select s, min(cint2) filter (where ss > 1000) from aggfilter where cint2 > 0 group by s order by min(cint2), s limit 10; + s | min +---+----- + 1 | + 2 | + 3 | + 5 | + 7 | + 8 | + 9 | + 6 | + 0 | + 4 | +(10 rows) + +select s, min(cint2) filter (where cint4 > 0) from aggfilter where cint2 > 0 group by s order by min(cint2), s limit 10; + s | min +---+----- + 1 | 4 + 2 | 4 + 3 | 1 + 5 | 1 + 7 | 1 + 8 | 1 + 9 | 6 + 6 | 3 + 0 | 6 + 4 | 4 +(10 rows) + +select s, min(cint2) filter (where s != 5) from aggfilter where cint2 > 0 group by s order by min(cint2), s limit 10; + s | min +---+----- + 1 | 1 + 2 | 1 + 3 | 1 + 5 | + 7 | 1 + 8 | 1 + 9 | 2 + 6 | 3 + 0 | 4 + 4 | 4 +(10 rows) + +select ss, min(cint2) from aggfilter where cint2 > 0 group by ss order by min(cint2), ss limit 10; + ss | min +----+------ + 3 | 1 + 5 | 1 + 7 | 1 + 8 | 1 + 11 | 1 + 9 | 2 + 6 | 3 + 0 | 4 + 4 | 4 + | 3667 +(10 rows) + +select ss, min(cint2) filter (where cint2 < 0) from aggfilter where cint2 > 0 group by ss order by min(cint2), ss limit 10; + ss | min +----+----- + 3 | + 5 | + 7 | + 8 | + 11 | + 9 | + 6 | + 0 | + 4 | + | +(10 rows) + +select ss, min(cint2) filter (where ss > 1000) from aggfilter where cint2 > 0 group by ss order by min(cint2), ss limit 10; + ss | min +----+----- + 3 | + 5 | + 7 | + 8 | + 11 | + 9 | + 6 | + 0 | + 4 | + | +(10 rows) + +select ss, min(cint2) filter (where cint4 > 0) from aggfilter where cint2 > 0 group by ss order by min(cint2), ss limit 10; + ss | min +----+------ + 3 | 1 + 5 | 1 + 7 | 1 + 8 | 1 + 11 | 4 + 9 | 6 + 6 | 3 + 0 | 6 + 4 | 4 + | 3667 +(10 rows) + +select ss, min(cint2) filter (where s != 5) from aggfilter where cint2 > 0 group by ss order by min(cint2), ss limit 10; + ss | min +----+------ + 3 | 1 + 5 | + 7 | 1 + 8 | 1 + 11 | 1 + 9 | 2 + 6 | 3 + 0 | 4 + 4 | 4 + | 3667 +(10 rows) + +select count(cint4) from aggfilter where cint2 > 0; + count +------- + 99664 +(1 row) + +select count(cint4) filter (where cint2 < 0) from aggfilter where cint2 > 0; + count +------- + 0 +(1 row) + +select count(cint4) filter (where ss > 1000) from aggfilter where cint2 > 0; + count +------- + 0 +(1 row) + +select count(cint4) filter (where cint4 > 0) from aggfilter where cint2 > 0; + count +------- + 49817 +(1 row) + +select count(cint4) filter (where s != 5) from aggfilter where cint2 > 0; + count +------- + 89554 +(1 row) + +select s, count(cint4) from aggfilter where cint2 > 0 group by s order by count(cint4), s limit 10; + s | count +---+------- + 2 | 9868 + 6 | 9890 + 3 | 9893 + 8 | 9898 + 4 | 9906 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 1 | 10096 + 5 | 10110 +(10 rows) + +select s, count(cint4) filter (where cint2 < 0) from aggfilter where cint2 > 0 group by s order by count(cint4), s limit 10; + s | count +---+------- + 2 | 0 + 6 | 0 + 3 | 0 + 8 | 0 + 4 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 1 | 0 + 5 | 0 +(10 rows) + +select s, count(cint4) filter (where ss > 1000) from aggfilter where cint2 > 0 group by s order by count(cint4), s limit 10; + s | count +---+------- + 2 | 0 + 6 | 0 + 3 | 0 + 8 | 0 + 4 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 1 | 0 + 5 | 0 +(10 rows) + +select s, count(cint4) filter (where cint4 > 0) from aggfilter where cint2 > 0 group by s order by count(cint4), s limit 10; + s | count +---+------- + 2 | 4923 + 6 | 4911 + 3 | 4972 + 8 | 4929 + 4 | 4944 + 7 | 4990 + 0 | 4963 + 9 | 4951 + 1 | 5067 + 5 | 5167 +(10 rows) + +select s, count(cint4) filter (where s != 5) from aggfilter where cint2 > 0 group by s order by count(cint4), s limit 10; + s | count +---+------- + 2 | 9868 + 6 | 9890 + 3 | 9893 + 8 | 9898 + 4 | 9906 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 1 | 10096 + 5 | 0 +(10 rows) + +select ss, count(cint4) from aggfilter where cint2 > 0 group by ss order by count(cint4), ss limit 10; + ss | count +----+------- + | 7 + 3 | 9886 + 6 | 9890 + 4 | 9897 + 8 | 9898 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 5 | 10110 + 11 | 19973 +(10 rows) + +select ss, count(cint4) filter (where cint2 < 0) from aggfilter where cint2 > 0 group by ss order by count(cint4), ss limit 10; + ss | count +----+------- + | 0 + 3 | 0 + 6 | 0 + 4 | 0 + 8 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 5 | 0 + 11 | 0 +(10 rows) + +select ss, count(cint4) filter (where ss > 1000) from aggfilter where cint2 > 0 group by ss order by count(cint4), ss limit 10; + ss | count +----+------- + | 0 + 3 | 0 + 6 | 0 + 4 | 0 + 8 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 5 | 0 + 11 | 0 +(10 rows) + +select ss, count(cint4) filter (where cint4 > 0) from aggfilter where cint2 > 0 group by ss order by count(cint4), ss limit 10; + ss | count +----+------- + | 4 + 3 | 4968 + 6 | 4911 + 4 | 4944 + 8 | 4929 + 7 | 4990 + 0 | 4963 + 9 | 4951 + 5 | 5167 + 11 | 9990 +(10 rows) + +select ss, count(cint4) filter (where s != 5) from aggfilter where cint2 > 0 group by ss order by count(cint4), ss limit 10; + ss | count +----+------- + | 7 + 3 | 9886 + 6 | 9890 + 4 | 9897 + 8 | 9898 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 5 | 0 + 11 | 19973 +(10 rows) + +select min(cint4) from aggfilter where cint2 > 0; + min +-------- + -16383 +(1 row) + +select min(cint4) filter (where cint2 < 0) from aggfilter where cint2 > 0; + min +----- + +(1 row) + +select min(cint4) filter (where ss > 1000) from aggfilter where cint2 > 0; + min +----- + +(1 row) + +select min(cint4) filter (where cint4 > 0) from aggfilter where cint2 > 0; + min +----- + 1 +(1 row) + +select min(cint4) filter (where s != 5) from aggfilter where cint2 > 0; + min +-------- + -16383 +(1 row) + +select s, min(cint4) from aggfilter where cint2 > 0 group by s order by min(cint4), s limit 10; + s | min +---+-------- + 0 | -16383 + 1 | -16382 + 3 | -16382 + 4 | -16382 + 6 | -16382 + 7 | -16382 + 9 | -16382 + 2 | -16377 + 8 | -16377 + 5 | -16375 +(10 rows) + +select s, min(cint4) filter (where cint2 < 0) from aggfilter where cint2 > 0 group by s order by min(cint4), s limit 10; + s | min +---+----- + 0 | + 1 | + 3 | + 4 | + 6 | + 7 | + 9 | + 2 | + 8 | + 5 | +(10 rows) + +select s, min(cint4) filter (where ss > 1000) from aggfilter where cint2 > 0 group by s order by min(cint4), s limit 10; + s | min +---+----- + 0 | + 1 | + 3 | + 4 | + 6 | + 7 | + 9 | + 2 | + 8 | + 5 | +(10 rows) + +select s, min(cint4) filter (where cint4 > 0) from aggfilter where cint2 > 0 group by s order by min(cint4), s limit 10; + s | min +---+----- + 0 | 1 + 1 | 7 + 3 | 2 + 4 | 5 + 6 | 2 + 7 | 1 + 9 | 2 + 2 | 2 + 8 | 5 + 5 | 2 +(10 rows) + +select s, min(cint4) filter (where s != 5) from aggfilter where cint2 > 0 group by s order by min(cint4), s limit 10; + s | min +---+-------- + 0 | -16383 + 1 | -16382 + 3 | -16382 + 4 | -16382 + 6 | -16382 + 7 | -16382 + 9 | -16382 + 2 | -16377 + 8 | -16377 + 5 | +(10 rows) + +select ss, min(cint4) from aggfilter where cint2 > 0 group by ss order by min(cint4), ss limit 10; + ss | min +----+-------- + 0 | -16383 + 3 | -16382 + 4 | -16382 + 6 | -16382 + 7 | -16382 + 9 | -16382 + 11 | -16382 + 8 | -16377 + 5 | -16375 + | -11573 +(10 rows) + +select ss, min(cint4) filter (where cint2 < 0) from aggfilter where cint2 > 0 group by ss order by min(cint4), ss limit 10; + ss | min +----+----- + 0 | + 3 | + 4 | + 6 | + 7 | + 9 | + 11 | + 8 | + 5 | + | +(10 rows) + +select ss, min(cint4) filter (where ss > 1000) from aggfilter where cint2 > 0 group by ss order by min(cint4), ss limit 10; + ss | min +----+----- + 0 | + 3 | + 4 | + 6 | + 7 | + 9 | + 11 | + 8 | + 5 | + | +(10 rows) + +select ss, min(cint4) filter (where cint4 > 0) from aggfilter where cint2 > 0 group by ss order by min(cint4), ss limit 10; + ss | min +----+------ + 0 | 1 + 3 | 2 + 4 | 5 + 6 | 2 + 7 | 1 + 9 | 2 + 11 | 2 + 8 | 5 + 5 | 2 + | 4132 +(10 rows) + +select ss, min(cint4) filter (where s != 5) from aggfilter where cint2 > 0 group by ss order by min(cint4), ss limit 10; + ss | min +----+-------- + 0 | -16383 + 3 | -16382 + 4 | -16382 + 6 | -16382 + 7 | -16382 + 9 | -16382 + 11 | -16382 + 8 | -16377 + 5 | + | -11573 +(10 rows) + +select count(s) from aggfilter where cint2 > 0; + count +------- + 99664 +(1 row) + +select count(s) filter (where cint2 < 0) from aggfilter where cint2 > 0; + count +------- + 0 +(1 row) + +select count(s) filter (where ss > 1000) from aggfilter where cint2 > 0; + count +------- + 0 +(1 row) + +select count(s) filter (where cint4 > 0) from aggfilter where cint2 > 0; + count +------- + 49817 +(1 row) + +select count(s) filter (where s != 5) from aggfilter where cint2 > 0; + count +------- + 89554 +(1 row) + +select s, count(s) from aggfilter where cint2 > 0 group by s order by count(s), s limit 10; + s | count +---+------- + 2 | 9868 + 6 | 9890 + 3 | 9893 + 8 | 9898 + 4 | 9906 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 1 | 10096 + 5 | 10110 +(10 rows) + +select s, count(s) filter (where cint2 < 0) from aggfilter where cint2 > 0 group by s order by count(s), s limit 10; + s | count +---+------- + 2 | 0 + 6 | 0 + 3 | 0 + 8 | 0 + 4 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 1 | 0 + 5 | 0 +(10 rows) + +select s, count(s) filter (where ss > 1000) from aggfilter where cint2 > 0 group by s order by count(s), s limit 10; + s | count +---+------- + 2 | 0 + 6 | 0 + 3 | 0 + 8 | 0 + 4 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 1 | 0 + 5 | 0 +(10 rows) + +select s, count(s) filter (where cint4 > 0) from aggfilter where cint2 > 0 group by s order by count(s), s limit 10; + s | count +---+------- + 2 | 4923 + 6 | 4911 + 3 | 4972 + 8 | 4929 + 4 | 4944 + 7 | 4990 + 0 | 4963 + 9 | 4951 + 1 | 5067 + 5 | 5167 +(10 rows) + +select s, count(s) filter (where s != 5) from aggfilter where cint2 > 0 group by s order by count(s), s limit 10; + s | count +---+------- + 2 | 9868 + 6 | 9890 + 3 | 9893 + 8 | 9898 + 4 | 9906 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 1 | 10096 + 5 | 0 +(10 rows) + +select ss, count(s) from aggfilter where cint2 > 0 group by ss order by count(s), ss limit 10; + ss | count +----+------- + | 7 + 3 | 9886 + 6 | 9890 + 4 | 9897 + 8 | 9898 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 5 | 10110 + 11 | 19973 +(10 rows) + +select ss, count(s) filter (where cint2 < 0) from aggfilter where cint2 > 0 group by ss order by count(s), ss limit 10; + ss | count +----+------- + | 0 + 3 | 0 + 6 | 0 + 4 | 0 + 8 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 5 | 0 + 11 | 0 +(10 rows) + +select ss, count(s) filter (where ss > 1000) from aggfilter where cint2 > 0 group by ss order by count(s), ss limit 10; + ss | count +----+------- + | 0 + 3 | 0 + 6 | 0 + 4 | 0 + 8 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 5 | 0 + 11 | 0 +(10 rows) + +select ss, count(s) filter (where cint4 > 0) from aggfilter where cint2 > 0 group by ss order by count(s), ss limit 10; + ss | count +----+------- + | 4 + 3 | 4968 + 6 | 4911 + 4 | 4944 + 8 | 4929 + 7 | 4990 + 0 | 4963 + 9 | 4951 + 5 | 5167 + 11 | 9990 +(10 rows) + +select ss, count(s) filter (where s != 5) from aggfilter where cint2 > 0 group by ss order by count(s), ss limit 10; + ss | count +----+------- + | 7 + 3 | 9886 + 6 | 9890 + 4 | 9897 + 8 | 9898 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 5 | 0 + 11 | 19973 +(10 rows) + +select min(s) from aggfilter where cint2 > 0; + min +----- + 0 +(1 row) + +select min(s) filter (where cint2 < 0) from aggfilter where cint2 > 0; + min +----- + +(1 row) + +select min(s) filter (where ss > 1000) from aggfilter where cint2 > 0; + min +----- + +(1 row) + +select min(s) filter (where cint4 > 0) from aggfilter where cint2 > 0; + min +----- + 0 +(1 row) + +select min(s) filter (where s != 5) from aggfilter where cint2 > 0; + min +----- + 0 +(1 row) + +select s, min(s) from aggfilter where cint2 > 0 group by s order by min(s), s limit 10; + s | min +---+----- + 0 | 0 + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + +select s, min(s) filter (where cint2 < 0) from aggfilter where cint2 > 0 group by s order by min(s), s limit 10; + s | min +---+----- + 0 | + 1 | + 2 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +(10 rows) + +select s, min(s) filter (where ss > 1000) from aggfilter where cint2 > 0 group by s order by min(s), s limit 10; + s | min +---+----- + 0 | + 1 | + 2 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +(10 rows) + +select s, min(s) filter (where cint4 > 0) from aggfilter where cint2 > 0 group by s order by min(s), s limit 10; + s | min +---+----- + 0 | 0 + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + +select s, min(s) filter (where s != 5) from aggfilter where cint2 > 0 group by s order by min(s), s limit 10; + s | min +---+----- + 0 | 0 + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + +select ss, min(s) from aggfilter where cint2 > 0 group by ss order by min(s), ss limit 10; + ss | min +----+----- + 0 | 0 + 11 | 1 + 3 | 3 + | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + +select ss, min(s) filter (where cint2 < 0) from aggfilter where cint2 > 0 group by ss order by min(s), ss limit 10; + ss | min +----+----- + 0 | + 11 | + 3 | + | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +(10 rows) + +select ss, min(s) filter (where ss > 1000) from aggfilter where cint2 > 0 group by ss order by min(s), ss limit 10; + ss | min +----+----- + 0 | + 11 | + 3 | + | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +(10 rows) + +select ss, min(s) filter (where cint4 > 0) from aggfilter where cint2 > 0 group by ss order by min(s), ss limit 10; + ss | min +----+----- + 0 | 0 + 11 | 1 + 3 | 3 + | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + +select ss, min(s) filter (where s != 5) from aggfilter where cint2 > 0 group by ss order by min(s), ss limit 10; + ss | min +----+----- + 0 | 0 + 11 | 1 + 3 | 3 + | 3 + 4 | 4 + 5 | + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + +select count(ss) from aggfilter where cint2 > 0; + count +------- + 99657 +(1 row) + +select count(ss) filter (where cint2 < 0) from aggfilter where cint2 > 0; + count +------- + 0 +(1 row) + +select count(ss) filter (where ss > 1000) from aggfilter where cint2 > 0; + count +------- + 0 +(1 row) + +select count(ss) filter (where cint4 > 0) from aggfilter where cint2 > 0; + count +------- + 49813 +(1 row) + +select count(ss) filter (where s != 5) from aggfilter where cint2 > 0; + count +------- + 89547 +(1 row) + +select s, count(ss) from aggfilter where cint2 > 0 group by s order by count(ss), s limit 10; + s | count +---+------- + 2 | 9868 + 3 | 9886 + 6 | 9890 + 8 | 9898 + 4 | 9906 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 1 | 10096 + 5 | 10110 +(10 rows) + +select s, count(ss) filter (where cint2 < 0) from aggfilter where cint2 > 0 group by s order by count(ss), s limit 10; + s | count +---+------- + 2 | 0 + 3 | 0 + 6 | 0 + 8 | 0 + 4 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 1 | 0 + 5 | 0 +(10 rows) + +select s, count(ss) filter (where ss > 1000) from aggfilter where cint2 > 0 group by s order by count(ss), s limit 10; + s | count +---+------- + 2 | 0 + 3 | 0 + 6 | 0 + 8 | 0 + 4 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 1 | 0 + 5 | 0 +(10 rows) + +select s, count(ss) filter (where cint4 > 0) from aggfilter where cint2 > 0 group by s order by count(ss), s limit 10; + s | count +---+------- + 2 | 4923 + 3 | 4968 + 6 | 4911 + 8 | 4929 + 4 | 4944 + 7 | 4990 + 0 | 4963 + 9 | 4951 + 1 | 5067 + 5 | 5167 +(10 rows) + +select s, count(ss) filter (where s != 5) from aggfilter where cint2 > 0 group by s order by count(ss), s limit 10; + s | count +---+------- + 2 | 9868 + 3 | 9886 + 6 | 9890 + 8 | 9898 + 4 | 9906 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 1 | 10096 + 5 | 0 +(10 rows) + +select ss, count(ss) from aggfilter where cint2 > 0 group by ss order by count(ss), ss limit 10; + ss | count +----+------- + | 0 + 3 | 9886 + 6 | 9890 + 4 | 9897 + 8 | 9898 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 5 | 10110 + 11 | 19973 +(10 rows) + +select ss, count(ss) filter (where cint2 < 0) from aggfilter where cint2 > 0 group by ss order by count(ss), ss limit 10; + ss | count +----+------- + | 0 + 3 | 0 + 6 | 0 + 4 | 0 + 8 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 5 | 0 + 11 | 0 +(10 rows) + +select ss, count(ss) filter (where ss > 1000) from aggfilter where cint2 > 0 group by ss order by count(ss), ss limit 10; + ss | count +----+------- + | 0 + 3 | 0 + 6 | 0 + 4 | 0 + 8 | 0 + 7 | 0 + 0 | 0 + 9 | 0 + 5 | 0 + 11 | 0 +(10 rows) + +select ss, count(ss) filter (where cint4 > 0) from aggfilter where cint2 > 0 group by ss order by count(ss), ss limit 10; + ss | count +----+------- + | 0 + 3 | 4968 + 6 | 4911 + 4 | 4944 + 8 | 4929 + 7 | 4990 + 0 | 4963 + 9 | 4951 + 5 | 5167 + 11 | 9990 +(10 rows) + +select ss, count(ss) filter (where s != 5) from aggfilter where cint2 > 0 group by ss order by count(ss), ss limit 10; + ss | count +----+------- + | 0 + 3 | 9886 + 6 | 9890 + 4 | 9897 + 8 | 9898 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 5 | 0 + 11 | 19973 +(10 rows) + +select min(ss) from aggfilter where cint2 > 0; + min +----- + 0 +(1 row) + +select min(ss) filter (where cint2 < 0) from aggfilter where cint2 > 0; + min +----- + +(1 row) + +select min(ss) filter (where ss > 1000) from aggfilter where cint2 > 0; + min +----- + +(1 row) + +select min(ss) filter (where cint4 > 0) from aggfilter where cint2 > 0; + min +----- + 0 +(1 row) + +select min(ss) filter (where s != 5) from aggfilter where cint2 > 0; + min +----- + 0 +(1 row) + +select s, min(ss) from aggfilter where cint2 > 0 group by s order by min(ss), s limit 10; + s | min +---+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 1 | 11 + 2 | 11 +(10 rows) + +select s, min(ss) filter (where cint2 < 0) from aggfilter where cint2 > 0 group by s order by min(ss), s limit 10; + s | min +---+----- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 1 | + 2 | +(10 rows) + +select s, min(ss) filter (where ss > 1000) from aggfilter where cint2 > 0 group by s order by min(ss), s limit 10; + s | min +---+----- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 1 | + 2 | +(10 rows) + +select s, min(ss) filter (where cint4 > 0) from aggfilter where cint2 > 0 group by s order by min(ss), s limit 10; + s | min +---+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 1 | 11 + 2 | 11 +(10 rows) + +select s, min(ss) filter (where s != 5) from aggfilter where cint2 > 0 group by s order by min(ss), s limit 10; + s | min +---+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 1 | 11 + 2 | 11 +(10 rows) + +select ss, min(ss) from aggfilter where cint2 > 0 group by ss order by min(ss), ss limit 10; + ss | min +----+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 11 | 11 + | +(10 rows) + +select ss, min(ss) filter (where cint2 < 0) from aggfilter where cint2 > 0 group by ss order by min(ss), ss limit 10; + ss | min +----+----- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 11 | + | +(10 rows) + +select ss, min(ss) filter (where ss > 1000) from aggfilter where cint2 > 0 group by ss order by min(ss), ss limit 10; + ss | min +----+----- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 11 | + | +(10 rows) + +select ss, min(ss) filter (where cint4 > 0) from aggfilter where cint2 > 0 group by ss order by min(ss), ss limit 10; + ss | min +----+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 11 | 11 + | +(10 rows) + +select ss, min(ss) filter (where s != 5) from aggfilter where cint2 > 0 group by ss order by min(ss), ss limit 10; + ss | min +----+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 11 | 11 + | +(10 rows) + +select count(*) from aggfilter where cint2 is null; + count +------- + 190 +(1 row) + +select count(*) filter (where cint2 < 0) from aggfilter where cint2 is null; + count +------- + 0 +(1 row) + +select count(*) filter (where ss > 1000) from aggfilter where cint2 is null; + count +------- + 0 +(1 row) + +select count(*) filter (where cint4 > 0) from aggfilter where cint2 is null; + count +------- + 92 +(1 row) + +select count(*) filter (where s != 5) from aggfilter where cint2 is null; + count +------- + 171 +(1 row) + +select s, count(*) from aggfilter where cint2 is null group by s order by count(*), s limit 10; + s | count +---+------- + 0 | 19 + 1 | 19 + 2 | 19 + 3 | 19 + 4 | 19 + 5 | 19 + 6 | 19 + 7 | 19 + 8 | 19 + 9 | 19 +(10 rows) + +select s, count(*) filter (where cint2 < 0) from aggfilter where cint2 is null group by s order by count(*), s limit 10; + s | count +---+------- + 0 | 0 + 1 | 0 + 2 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 +(10 rows) + +select s, count(*) filter (where ss > 1000) from aggfilter where cint2 is null group by s order by count(*), s limit 10; + s | count +---+------- + 0 | 0 + 1 | 0 + 2 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 +(10 rows) + +select s, count(*) filter (where cint4 > 0) from aggfilter where cint2 is null group by s order by count(*), s limit 10; + s | count +---+------- + 0 | 9 + 1 | 12 + 2 | 9 + 3 | 11 + 4 | 5 + 5 | 11 + 6 | 9 + 7 | 7 + 8 | 10 + 9 | 9 +(10 rows) + +select s, count(*) filter (where s != 5) from aggfilter where cint2 is null group by s order by count(*), s limit 10; + s | count +---+------- + 0 | 19 + 1 | 19 + 2 | 19 + 3 | 19 + 4 | 19 + 5 | 0 + 6 | 19 + 7 | 19 + 8 | 19 + 9 | 19 +(10 rows) + +select ss, count(*) from aggfilter where cint2 is null group by ss order by count(*), ss limit 10; + ss | count +----+------- + 0 | 19 + 3 | 19 + 4 | 19 + 5 | 19 + 6 | 19 + 7 | 19 + 8 | 19 + 9 | 19 + 11 | 38 +(9 rows) + +select ss, count(*) filter (where cint2 < 0) from aggfilter where cint2 is null group by ss order by count(*), ss limit 10; + ss | count +----+------- + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 +(9 rows) + +select ss, count(*) filter (where ss > 1000) from aggfilter where cint2 is null group by ss order by count(*), ss limit 10; + ss | count +----+------- + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 +(9 rows) + +select ss, count(*) filter (where cint4 > 0) from aggfilter where cint2 is null group by ss order by count(*), ss limit 10; + ss | count +----+------- + 0 | 9 + 3 | 11 + 4 | 5 + 5 | 11 + 6 | 9 + 7 | 7 + 8 | 10 + 9 | 9 + 11 | 21 +(9 rows) + +select ss, count(*) filter (where s != 5) from aggfilter where cint2 is null group by ss order by count(*), ss limit 10; + ss | count +----+------- + 0 | 19 + 3 | 19 + 4 | 19 + 5 | 0 + 6 | 19 + 7 | 19 + 8 | 19 + 9 | 19 + 11 | 38 +(9 rows) + +select count(cint2) from aggfilter where cint2 is null; + count +------- + 0 +(1 row) + +select count(cint2) filter (where cint2 < 0) from aggfilter where cint2 is null; + count +------- + 0 +(1 row) + +select count(cint2) filter (where ss > 1000) from aggfilter where cint2 is null; + count +------- + 0 +(1 row) + +select count(cint2) filter (where cint4 > 0) from aggfilter where cint2 is null; + count +------- + 0 +(1 row) + +select count(cint2) filter (where s != 5) from aggfilter where cint2 is null; + count +------- + 0 +(1 row) + +select s, count(cint2) from aggfilter where cint2 is null group by s order by count(cint2), s limit 10; + s | count +---+------- + 0 | 0 + 1 | 0 + 2 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 +(10 rows) + +select s, count(cint2) filter (where cint2 < 0) from aggfilter where cint2 is null group by s order by count(cint2), s limit 10; + s | count +---+------- + 0 | 0 + 1 | 0 + 2 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 +(10 rows) + +select s, count(cint2) filter (where ss > 1000) from aggfilter where cint2 is null group by s order by count(cint2), s limit 10; + s | count +---+------- + 0 | 0 + 1 | 0 + 2 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 +(10 rows) + +select s, count(cint2) filter (where cint4 > 0) from aggfilter where cint2 is null group by s order by count(cint2), s limit 10; + s | count +---+------- + 0 | 0 + 1 | 0 + 2 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 +(10 rows) + +select s, count(cint2) filter (where s != 5) from aggfilter where cint2 is null group by s order by count(cint2), s limit 10; + s | count +---+------- + 0 | 0 + 1 | 0 + 2 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 +(10 rows) + +select ss, count(cint2) from aggfilter where cint2 is null group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 +(9 rows) + +select ss, count(cint2) filter (where cint2 < 0) from aggfilter where cint2 is null group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 +(9 rows) + +select ss, count(cint2) filter (where ss > 1000) from aggfilter where cint2 is null group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 +(9 rows) + +select ss, count(cint2) filter (where cint4 > 0) from aggfilter where cint2 is null group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 +(9 rows) + +select ss, count(cint2) filter (where s != 5) from aggfilter where cint2 is null group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 +(9 rows) + +select min(cint2) from aggfilter where cint2 is null; + min +----- + +(1 row) + +select min(cint2) filter (where cint2 < 0) from aggfilter where cint2 is null; + min +----- + +(1 row) + +select min(cint2) filter (where ss > 1000) from aggfilter where cint2 is null; + min +----- + +(1 row) + +select min(cint2) filter (where cint4 > 0) from aggfilter where cint2 is null; + min +----- + +(1 row) + +select min(cint2) filter (where s != 5) from aggfilter where cint2 is null; + min +----- + +(1 row) + +select s, min(cint2) from aggfilter where cint2 is null group by s order by min(cint2), s limit 10; + s | min +---+----- + 0 | + 1 | + 2 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +(10 rows) + +select s, min(cint2) filter (where cint2 < 0) from aggfilter where cint2 is null group by s order by min(cint2), s limit 10; + s | min +---+----- + 0 | + 1 | + 2 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +(10 rows) + +select s, min(cint2) filter (where ss > 1000) from aggfilter where cint2 is null group by s order by min(cint2), s limit 10; + s | min +---+----- + 0 | + 1 | + 2 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +(10 rows) + +select s, min(cint2) filter (where cint4 > 0) from aggfilter where cint2 is null group by s order by min(cint2), s limit 10; + s | min +---+----- + 0 | + 1 | + 2 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +(10 rows) + +select s, min(cint2) filter (where s != 5) from aggfilter where cint2 is null group by s order by min(cint2), s limit 10; + s | min +---+----- + 0 | + 1 | + 2 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +(10 rows) + +select ss, min(cint2) from aggfilter where cint2 is null group by ss order by min(cint2), ss limit 10; + ss | min +----+----- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 11 | +(9 rows) + +select ss, min(cint2) filter (where cint2 < 0) from aggfilter where cint2 is null group by ss order by min(cint2), ss limit 10; + ss | min +----+----- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 11 | +(9 rows) + +select ss, min(cint2) filter (where ss > 1000) from aggfilter where cint2 is null group by ss order by min(cint2), ss limit 10; + ss | min +----+----- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 11 | +(9 rows) + +select ss, min(cint2) filter (where cint4 > 0) from aggfilter where cint2 is null group by ss order by min(cint2), ss limit 10; + ss | min +----+----- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 11 | +(9 rows) + +select ss, min(cint2) filter (where s != 5) from aggfilter where cint2 is null group by ss order by min(cint2), ss limit 10; + ss | min +----+----- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 11 | +(9 rows) + +select count(cint4) from aggfilter where cint2 is null; + count +------- + 190 +(1 row) + +select count(cint4) filter (where cint2 < 0) from aggfilter where cint2 is null; + count +------- + 0 +(1 row) + +select count(cint4) filter (where ss > 1000) from aggfilter where cint2 is null; + count +------- + 0 +(1 row) + +select count(cint4) filter (where cint4 > 0) from aggfilter where cint2 is null; + count +------- + 92 +(1 row) + +select count(cint4) filter (where s != 5) from aggfilter where cint2 is null; + count +------- + 171 +(1 row) + +select s, count(cint4) from aggfilter where cint2 is null group by s order by count(cint4), s limit 10; + s | count +---+------- + 0 | 19 + 1 | 19 + 2 | 19 + 3 | 19 + 4 | 19 + 5 | 19 + 6 | 19 + 7 | 19 + 8 | 19 + 9 | 19 +(10 rows) + +select s, count(cint4) filter (where cint2 < 0) from aggfilter where cint2 is null group by s order by count(cint4), s limit 10; + s | count +---+------- + 0 | 0 + 1 | 0 + 2 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 +(10 rows) + +select s, count(cint4) filter (where ss > 1000) from aggfilter where cint2 is null group by s order by count(cint4), s limit 10; + s | count +---+------- + 0 | 0 + 1 | 0 + 2 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 +(10 rows) + +select s, count(cint4) filter (where cint4 > 0) from aggfilter where cint2 is null group by s order by count(cint4), s limit 10; + s | count +---+------- + 0 | 9 + 1 | 12 + 2 | 9 + 3 | 11 + 4 | 5 + 5 | 11 + 6 | 9 + 7 | 7 + 8 | 10 + 9 | 9 +(10 rows) + +select s, count(cint4) filter (where s != 5) from aggfilter where cint2 is null group by s order by count(cint4), s limit 10; + s | count +---+------- + 0 | 19 + 1 | 19 + 2 | 19 + 3 | 19 + 4 | 19 + 5 | 0 + 6 | 19 + 7 | 19 + 8 | 19 + 9 | 19 +(10 rows) + +select ss, count(cint4) from aggfilter where cint2 is null group by ss order by count(cint4), ss limit 10; + ss | count +----+------- + 0 | 19 + 3 | 19 + 4 | 19 + 5 | 19 + 6 | 19 + 7 | 19 + 8 | 19 + 9 | 19 + 11 | 38 +(9 rows) + +select ss, count(cint4) filter (where cint2 < 0) from aggfilter where cint2 is null group by ss order by count(cint4), ss limit 10; + ss | count +----+------- + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 +(9 rows) + +select ss, count(cint4) filter (where ss > 1000) from aggfilter where cint2 is null group by ss order by count(cint4), ss limit 10; + ss | count +----+------- + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 +(9 rows) + +select ss, count(cint4) filter (where cint4 > 0) from aggfilter where cint2 is null group by ss order by count(cint4), ss limit 10; + ss | count +----+------- + 0 | 9 + 3 | 11 + 4 | 5 + 5 | 11 + 6 | 9 + 7 | 7 + 8 | 10 + 9 | 9 + 11 | 21 +(9 rows) + +select ss, count(cint4) filter (where s != 5) from aggfilter where cint2 is null group by ss order by count(cint4), ss limit 10; + ss | count +----+------- + 0 | 19 + 3 | 19 + 4 | 19 + 5 | 0 + 6 | 19 + 7 | 19 + 8 | 19 + 9 | 19 + 11 | 38 +(9 rows) + +select min(cint4) from aggfilter where cint2 is null; + min +-------- + -16291 +(1 row) + +select min(cint4) filter (where cint2 < 0) from aggfilter where cint2 is null; + min +----- + +(1 row) + +select min(cint4) filter (where ss > 1000) from aggfilter where cint2 is null; + min +----- + +(1 row) + +select min(cint4) filter (where cint4 > 0) from aggfilter where cint2 is null; + min +----- + 473 +(1 row) + +select min(cint4) filter (where s != 5) from aggfilter where cint2 is null; + min +-------- + -16291 +(1 row) + +select s, min(cint4) from aggfilter where cint2 is null group by s order by min(cint4), s limit 10; + s | min +---+-------- + 0 | -16291 + 7 | -16091 + 4 | -15724 + 5 | -15279 + 2 | -15063 + 6 | -14998 + 9 | -14699 + 8 | -14214 + 1 | -12217 + 3 | -9908 +(10 rows) + +select s, min(cint4) filter (where cint2 < 0) from aggfilter where cint2 is null group by s order by min(cint4), s limit 10; + s | min +---+----- + 0 | + 7 | + 4 | + 5 | + 2 | + 6 | + 9 | + 8 | + 1 | + 3 | +(10 rows) + +select s, min(cint4) filter (where ss > 1000) from aggfilter where cint2 is null group by s order by min(cint4), s limit 10; + s | min +---+----- + 0 | + 7 | + 4 | + 5 | + 2 | + 6 | + 9 | + 8 | + 1 | + 3 | +(10 rows) + +select s, min(cint4) filter (where cint4 > 0) from aggfilter where cint2 is null group by s order by min(cint4), s limit 10; + s | min +---+------ + 0 | 701 + 7 | 1695 + 4 | 1821 + 5 | 587 + 2 | 2876 + 6 | 1003 + 9 | 2489 + 8 | 1334 + 1 | 2034 + 3 | 473 +(10 rows) + +select s, min(cint4) filter (where s != 5) from aggfilter where cint2 is null group by s order by min(cint4), s limit 10; + s | min +---+-------- + 0 | -16291 + 7 | -16091 + 4 | -15724 + 5 | + 2 | -15063 + 6 | -14998 + 9 | -14699 + 8 | -14214 + 1 | -12217 + 3 | -9908 +(10 rows) + +select ss, min(cint4) from aggfilter where cint2 is null group by ss order by min(cint4), ss limit 10; + ss | min +----+-------- + 0 | -16291 + 7 | -16091 + 4 | -15724 + 5 | -15279 + 11 | -15063 + 6 | -14998 + 9 | -14699 + 8 | -14214 + 3 | -9908 +(9 rows) + +select ss, min(cint4) filter (where cint2 < 0) from aggfilter where cint2 is null group by ss order by min(cint4), ss limit 10; + ss | min +----+----- + 0 | + 7 | + 4 | + 5 | + 11 | + 6 | + 9 | + 8 | + 3 | +(9 rows) + +select ss, min(cint4) filter (where ss > 1000) from aggfilter where cint2 is null group by ss order by min(cint4), ss limit 10; + ss | min +----+----- + 0 | + 7 | + 4 | + 5 | + 11 | + 6 | + 9 | + 8 | + 3 | +(9 rows) + +select ss, min(cint4) filter (where cint4 > 0) from aggfilter where cint2 is null group by ss order by min(cint4), ss limit 10; + ss | min +----+------ + 0 | 701 + 7 | 1695 + 4 | 1821 + 5 | 587 + 11 | 2034 + 6 | 1003 + 9 | 2489 + 8 | 1334 + 3 | 473 +(9 rows) + +select ss, min(cint4) filter (where s != 5) from aggfilter where cint2 is null group by ss order by min(cint4), ss limit 10; + ss | min +----+-------- + 0 | -16291 + 7 | -16091 + 4 | -15724 + 5 | + 11 | -15063 + 6 | -14998 + 9 | -14699 + 8 | -14214 + 3 | -9908 +(9 rows) + +select count(s) from aggfilter where cint2 is null; + count +------- + 190 +(1 row) + +select count(s) filter (where cint2 < 0) from aggfilter where cint2 is null; + count +------- + 0 +(1 row) + +select count(s) filter (where ss > 1000) from aggfilter where cint2 is null; + count +------- + 0 +(1 row) + +select count(s) filter (where cint4 > 0) from aggfilter where cint2 is null; + count +------- + 92 +(1 row) + +select count(s) filter (where s != 5) from aggfilter where cint2 is null; + count +------- + 171 +(1 row) + +select s, count(s) from aggfilter where cint2 is null group by s order by count(s), s limit 10; + s | count +---+------- + 0 | 19 + 1 | 19 + 2 | 19 + 3 | 19 + 4 | 19 + 5 | 19 + 6 | 19 + 7 | 19 + 8 | 19 + 9 | 19 +(10 rows) + +select s, count(s) filter (where cint2 < 0) from aggfilter where cint2 is null group by s order by count(s), s limit 10; + s | count +---+------- + 0 | 0 + 1 | 0 + 2 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 +(10 rows) + +select s, count(s) filter (where ss > 1000) from aggfilter where cint2 is null group by s order by count(s), s limit 10; + s | count +---+------- + 0 | 0 + 1 | 0 + 2 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 +(10 rows) + +select s, count(s) filter (where cint4 > 0) from aggfilter where cint2 is null group by s order by count(s), s limit 10; + s | count +---+------- + 0 | 9 + 1 | 12 + 2 | 9 + 3 | 11 + 4 | 5 + 5 | 11 + 6 | 9 + 7 | 7 + 8 | 10 + 9 | 9 +(10 rows) + +select s, count(s) filter (where s != 5) from aggfilter where cint2 is null group by s order by count(s), s limit 10; + s | count +---+------- + 0 | 19 + 1 | 19 + 2 | 19 + 3 | 19 + 4 | 19 + 5 | 0 + 6 | 19 + 7 | 19 + 8 | 19 + 9 | 19 +(10 rows) + +select ss, count(s) from aggfilter where cint2 is null group by ss order by count(s), ss limit 10; + ss | count +----+------- + 0 | 19 + 3 | 19 + 4 | 19 + 5 | 19 + 6 | 19 + 7 | 19 + 8 | 19 + 9 | 19 + 11 | 38 +(9 rows) + +select ss, count(s) filter (where cint2 < 0) from aggfilter where cint2 is null group by ss order by count(s), ss limit 10; + ss | count +----+------- + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 +(9 rows) + +select ss, count(s) filter (where ss > 1000) from aggfilter where cint2 is null group by ss order by count(s), ss limit 10; + ss | count +----+------- + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 +(9 rows) + +select ss, count(s) filter (where cint4 > 0) from aggfilter where cint2 is null group by ss order by count(s), ss limit 10; + ss | count +----+------- + 0 | 9 + 3 | 11 + 4 | 5 + 5 | 11 + 6 | 9 + 7 | 7 + 8 | 10 + 9 | 9 + 11 | 21 +(9 rows) + +select ss, count(s) filter (where s != 5) from aggfilter where cint2 is null group by ss order by count(s), ss limit 10; + ss | count +----+------- + 0 | 19 + 3 | 19 + 4 | 19 + 5 | 0 + 6 | 19 + 7 | 19 + 8 | 19 + 9 | 19 + 11 | 38 +(9 rows) + +select min(s) from aggfilter where cint2 is null; + min +----- + 0 +(1 row) + +select min(s) filter (where cint2 < 0) from aggfilter where cint2 is null; + min +----- + +(1 row) + +select min(s) filter (where ss > 1000) from aggfilter where cint2 is null; + min +----- + +(1 row) + +select min(s) filter (where cint4 > 0) from aggfilter where cint2 is null; + min +----- + 0 +(1 row) + +select min(s) filter (where s != 5) from aggfilter where cint2 is null; + min +----- + 0 +(1 row) + +select s, min(s) from aggfilter where cint2 is null group by s order by min(s), s limit 10; + s | min +---+----- + 0 | 0 + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + +select s, min(s) filter (where cint2 < 0) from aggfilter where cint2 is null group by s order by min(s), s limit 10; + s | min +---+----- + 0 | + 1 | + 2 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +(10 rows) + +select s, min(s) filter (where ss > 1000) from aggfilter where cint2 is null group by s order by min(s), s limit 10; + s | min +---+----- + 0 | + 1 | + 2 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +(10 rows) + +select s, min(s) filter (where cint4 > 0) from aggfilter where cint2 is null group by s order by min(s), s limit 10; + s | min +---+----- + 0 | 0 + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + +select s, min(s) filter (where s != 5) from aggfilter where cint2 is null group by s order by min(s), s limit 10; + s | min +---+----- + 0 | 0 + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + +select ss, min(s) from aggfilter where cint2 is null group by ss order by min(s), ss limit 10; + ss | min +----+----- + 0 | 0 + 11 | 1 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(9 rows) + +select ss, min(s) filter (where cint2 < 0) from aggfilter where cint2 is null group by ss order by min(s), ss limit 10; + ss | min +----+----- + 0 | + 11 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +(9 rows) + +select ss, min(s) filter (where ss > 1000) from aggfilter where cint2 is null group by ss order by min(s), ss limit 10; + ss | min +----+----- + 0 | + 11 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +(9 rows) + +select ss, min(s) filter (where cint4 > 0) from aggfilter where cint2 is null group by ss order by min(s), ss limit 10; + ss | min +----+----- + 0 | 0 + 11 | 1 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(9 rows) + +select ss, min(s) filter (where s != 5) from aggfilter where cint2 is null group by ss order by min(s), ss limit 10; + ss | min +----+----- + 0 | 0 + 11 | 1 + 3 | 3 + 4 | 4 + 5 | + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(9 rows) + +select count(ss) from aggfilter where cint2 is null; + count +------- + 190 +(1 row) + +select count(ss) filter (where cint2 < 0) from aggfilter where cint2 is null; + count +------- + 0 +(1 row) + +select count(ss) filter (where ss > 1000) from aggfilter where cint2 is null; + count +------- + 0 +(1 row) + +select count(ss) filter (where cint4 > 0) from aggfilter where cint2 is null; + count +------- + 92 +(1 row) + +select count(ss) filter (where s != 5) from aggfilter where cint2 is null; + count +------- + 171 +(1 row) + +select s, count(ss) from aggfilter where cint2 is null group by s order by count(ss), s limit 10; + s | count +---+------- + 0 | 19 + 1 | 19 + 2 | 19 + 3 | 19 + 4 | 19 + 5 | 19 + 6 | 19 + 7 | 19 + 8 | 19 + 9 | 19 +(10 rows) + +select s, count(ss) filter (where cint2 < 0) from aggfilter where cint2 is null group by s order by count(ss), s limit 10; + s | count +---+------- + 0 | 0 + 1 | 0 + 2 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 +(10 rows) + +select s, count(ss) filter (where ss > 1000) from aggfilter where cint2 is null group by s order by count(ss), s limit 10; + s | count +---+------- + 0 | 0 + 1 | 0 + 2 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 +(10 rows) + +select s, count(ss) filter (where cint4 > 0) from aggfilter where cint2 is null group by s order by count(ss), s limit 10; + s | count +---+------- + 0 | 9 + 1 | 12 + 2 | 9 + 3 | 11 + 4 | 5 + 5 | 11 + 6 | 9 + 7 | 7 + 8 | 10 + 9 | 9 +(10 rows) + +select s, count(ss) filter (where s != 5) from aggfilter where cint2 is null group by s order by count(ss), s limit 10; + s | count +---+------- + 0 | 19 + 1 | 19 + 2 | 19 + 3 | 19 + 4 | 19 + 5 | 0 + 6 | 19 + 7 | 19 + 8 | 19 + 9 | 19 +(10 rows) + +select ss, count(ss) from aggfilter where cint2 is null group by ss order by count(ss), ss limit 10; + ss | count +----+------- + 0 | 19 + 3 | 19 + 4 | 19 + 5 | 19 + 6 | 19 + 7 | 19 + 8 | 19 + 9 | 19 + 11 | 38 +(9 rows) + +select ss, count(ss) filter (where cint2 < 0) from aggfilter where cint2 is null group by ss order by count(ss), ss limit 10; + ss | count +----+------- + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 +(9 rows) + +select ss, count(ss) filter (where ss > 1000) from aggfilter where cint2 is null group by ss order by count(ss), ss limit 10; + ss | count +----+------- + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 +(9 rows) + +select ss, count(ss) filter (where cint4 > 0) from aggfilter where cint2 is null group by ss order by count(ss), ss limit 10; + ss | count +----+------- + 0 | 9 + 3 | 11 + 4 | 5 + 5 | 11 + 6 | 9 + 7 | 7 + 8 | 10 + 9 | 9 + 11 | 21 +(9 rows) + +select ss, count(ss) filter (where s != 5) from aggfilter where cint2 is null group by ss order by count(ss), ss limit 10; + ss | count +----+------- + 0 | 19 + 3 | 19 + 4 | 19 + 5 | 0 + 6 | 19 + 7 | 19 + 8 | 19 + 9 | 19 + 11 | 38 +(9 rows) + +select min(ss) from aggfilter where cint2 is null; + min +----- + 0 +(1 row) + +select min(ss) filter (where cint2 < 0) from aggfilter where cint2 is null; + min +----- + +(1 row) + +select min(ss) filter (where ss > 1000) from aggfilter where cint2 is null; + min +----- + +(1 row) + +select min(ss) filter (where cint4 > 0) from aggfilter where cint2 is null; + min +----- + 0 +(1 row) + +select min(ss) filter (where s != 5) from aggfilter where cint2 is null; + min +----- + 0 +(1 row) + +select s, min(ss) from aggfilter where cint2 is null group by s order by min(ss), s limit 10; + s | min +---+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 1 | 11 + 2 | 11 +(10 rows) + +select s, min(ss) filter (where cint2 < 0) from aggfilter where cint2 is null group by s order by min(ss), s limit 10; + s | min +---+----- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 1 | + 2 | +(10 rows) + +select s, min(ss) filter (where ss > 1000) from aggfilter where cint2 is null group by s order by min(ss), s limit 10; + s | min +---+----- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 1 | + 2 | +(10 rows) + +select s, min(ss) filter (where cint4 > 0) from aggfilter where cint2 is null group by s order by min(ss), s limit 10; + s | min +---+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 1 | 11 + 2 | 11 +(10 rows) + +select s, min(ss) filter (where s != 5) from aggfilter where cint2 is null group by s order by min(ss), s limit 10; + s | min +---+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 1 | 11 + 2 | 11 +(10 rows) + +select ss, min(ss) from aggfilter where cint2 is null group by ss order by min(ss), ss limit 10; + ss | min +----+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 11 | 11 +(9 rows) + +select ss, min(ss) filter (where cint2 < 0) from aggfilter where cint2 is null group by ss order by min(ss), ss limit 10; + ss | min +----+----- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 11 | +(9 rows) + +select ss, min(ss) filter (where ss > 1000) from aggfilter where cint2 is null group by ss order by min(ss), ss limit 10; + ss | min +----+----- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 11 | +(9 rows) + +select ss, min(ss) filter (where cint4 > 0) from aggfilter where cint2 is null group by ss order by min(ss), ss limit 10; + ss | min +----+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 11 | 11 +(9 rows) + +select ss, min(ss) filter (where s != 5) from aggfilter where cint2 is null group by ss order by min(ss), ss limit 10; + ss | min +----+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 11 | 11 +(9 rows) + +reset timescaledb.debug_require_vector_agg; +-- FILTER that is not vectorizable +set timescaledb.debug_require_vector_agg = 'forbid'; +select count(*) filter (where cint2 === 0) from aggfilter; + count +------- + 7 +(1 row) + +-- FILTER with stable function +set timescaledb.debug_require_vector_agg = 'require'; +select count(*) filter (where cint2 = stable_abs(0)) from aggfilter; + count +------- + 7 +(1 row) + +reset timescaledb.debug_require_vector_agg; diff --git a/tsl/test/expected/vector_agg_functions.out b/tsl/test/expected/vector_agg_functions.out index bdb17aacb29..bffb8d7af7d 100644 --- a/tsl/test/expected/vector_agg_functions.out +++ b/tsl/test/expected/vector_agg_functions.out @@ -114,7 +114,7 @@ limit 1 set timescaledb.debug_require_vector_agg = :'guc_value'; ---- Uncomment to generate reference. Note that there are minor discrepancies ---- on float4 due to different numeric stability in our and PG implementations. --- set timescaledb.enable_vectorized_aggregation to off; set timescaledb.debug_require_vector_agg = 'allow'; +--set timescaledb.enable_vectorized_aggregation to off; set timescaledb.debug_require_vector_agg = 'forbid'; select format('%sselect %s%s(%s) from aggfns%s%s%s;', explain, @@ -157,7 +157,8 @@ from 'cint2 is null']) with ordinality as condition(condition, n), unnest(array[ null, - 's']) with ordinality as grouping(grouping, n) + 's', + 'ss']) with ordinality as grouping(grouping, n) where true and (explain is null /* or condition is null and grouping = 's' */) @@ -190,6 +191,21 @@ select s, count(*) from aggfns group by s order by count(*), s limit 10; 9 | 20000 (10 rows) +select ss, count(*) from aggfns group by ss order by count(*), ss limit 10; + ss | count +----+------- + | 19 + 3 | 19981 + 4 | 19981 + 0 | 20000 + 5 | 20000 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 + 11 | 40019 +(10 rows) + select max(cdate) from aggfns; max ------------ @@ -211,6 +227,21 @@ select s, max(cdate) from aggfns group by s order by max(cdate), s limit 10; 9 | 06-01-2267 (10 rows) +select ss, max(cdate) from aggfns group by ss order by max(cdate), ss limit 10; + ss | max +----+------------ + 0 | 01-01-2021 + 3 | 02-21-2103 + | 02-21-2103 + 4 | 07-09-2130 + 11 | 07-09-2130 + 5 | 11-24-2157 + 6 | 04-11-2185 + 7 | 08-28-2212 + 8 | 01-14-2240 + 9 | 06-01-2267 +(10 rows) + select min(cdate) from aggfns; min ------------ @@ -232,6 +263,21 @@ select s, min(cdate) from aggfns group by s order by min(cdate), s limit 10; 9 | 06-01-2267 (10 rows) +select ss, min(cdate) from aggfns group by ss order by min(cdate), ss limit 10; + ss | min +----+------------ + 0 | 01-01-2021 + 11 | 05-19-2048 + 3 | 02-21-2103 + | 02-21-2103 + 4 | 07-09-2130 + 5 | 11-24-2157 + 6 | 04-11-2185 + 7 | 08-28-2212 + 8 | 01-14-2240 + 9 | 06-01-2267 +(10 rows) + select avg(cfloat4) from aggfns; avg ----- @@ -253,6 +299,21 @@ select s, avg(cfloat4) from aggfns group by s order by avg(cfloat4), s limit 10; 1 | NaN (10 rows) +select ss, avg(cfloat4) from aggfns group by ss order by avg(cfloat4), ss limit 10; + ss | avg +----+---------------------- + 3 | -Infinity + | -1.39583652270468 + 9 | -0.292700759558938 + 4 | -0.169252917487522 + 6 | -0.00610964622725733 + 5 | 0.0107821527590975 + 0 | 0.0862269837114494 + 7 | 0.19168354413514 + 8 | 0.456703752867272 + 11 | NaN +(10 rows) + select max(cfloat4) from aggfns; max ----- @@ -274,6 +335,21 @@ select s, max(cfloat4) from aggfns group by s order by max(cfloat4), s limit 10; 1 | NaN (10 rows) +select ss, max(cfloat4) from aggfns group by ss order by max(cfloat4), ss limit 10; + ss | max +----+--------- + | 47.2047 + 9 | 49.9899 + 4 | 49.9946 + 6 | 49.9956 + 7 | 49.9969 + 3 | 49.9979 + 5 | 49.9992 + 0 | 49.9995 + 8 | 49.9997 + 11 | NaN +(10 rows) + select min(cfloat4) from aggfns; min ----------- @@ -295,6 +371,21 @@ select s, min(cfloat4) from aggfns group by s order by min(cfloat4), s limit 10; 9 | -49.9911 (10 rows) +select ss, min(cfloat4) from aggfns group by ss order by min(cfloat4), ss limit 10; + ss | min +----+----------- + 3 | -Infinity + 4 | -49.9999 + 6 | -49.9995 + 7 | -49.9984 + 8 | -49.9969 + 0 | -49.9949 + 5 | -49.9942 + 9 | -49.9911 + | -45.4083 + 11 | NaN +(10 rows) + select stddev(cfloat4) from aggfns; stddev -------- @@ -316,6 +407,21 @@ select s, stddev(cfloat4) from aggfns group by s order by stddev(cfloat4), s lim 3 | NaN (10 rows) +select ss, stddev(cfloat4) from aggfns group by ss order by stddev(cfloat4), ss limit 10; + ss | stddev +----+------------------ + 0 | 28.7274163912974 + 7 | 28.7892027644318 + 4 | 28.8220943927954 + 9 | 28.8426424990846 + 6 | 28.9190577543738 + 8 | 29.0040125904064 + 5 | 29.0213532270614 + | 30.6324072248673 + 3 | NaN + 11 | NaN +(10 rows) + select sum(cfloat4) from aggfns; sum ----- @@ -337,6 +443,21 @@ select s, sum(cfloat4) from aggfns group by s order by sum(cfloat4), s limit 10; 1 | NaN (10 rows) +select ss, sum(cfloat4) from aggfns group by ss order by sum(cfloat4), ss limit 10; + ss | sum +----+----------- + 3 | -Infinity + 9 | -5854.02 + 4 | -3381.84 + 6 | -122.193 + | -26.5209 + 5 | 215.643 + 0 | 1724.54 + 7 | 3833.67 + 8 | 9134.08 + 11 | NaN +(10 rows) + select avg(cfloat8) from aggfns; avg ----------------- @@ -358,6 +479,21 @@ select s, avg(cfloat8) from aggfns group by s order by avg(cfloat8), s limit 10; 1 | 13 (10 rows) +select ss, avg(cfloat8) from aggfns group by ss order by avg(cfloat8), ss limit 10; + ss | avg +----+-------------------- + 0 | -0.306925132697215 + 8 | -0.268692900155438 + 4 | -0.224160255000712 + 3 | -0.153492446187821 + 9 | -0.114842409039848 + 7 | -0.063637967283139 + 5 | 0.0438265096326359 + 6 | 0.169599099685438 + | 5.42090986487701 + 11 | 6.59778165165114 +(10 rows) + select max(cfloat8) from aggfns; max ------------------ @@ -379,6 +515,21 @@ select s, max(cfloat8) from aggfns group by s order by max(cfloat8), s limit 10; 9 | 49.9995574122295 (10 rows) +select ss, max(cfloat8) from aggfns group by ss order by max(cfloat8), ss limit 10; + ss | max +----+------------------ + | 46.3985309237614 + 5 | 49.9874341068789 + 3 | 49.9890822684392 + 6 | 49.9939429108053 + 8 | 49.9963666079566 + 0 | 49.9965498689562 + 7 | 49.9973275698721 + 11 | 49.9975695507601 + 4 | 49.9978997278959 + 9 | 49.9995574122295 +(10 rows) + select min(cfloat8) from aggfns; min ------------------- @@ -400,6 +551,21 @@ select s, min(cfloat8) from aggfns group by s order by min(cfloat8), s limit 10; 1 | 13 (10 rows) +select ss, min(cfloat8) from aggfns group by ss order by min(cfloat8), ss limit 10; + ss | min +----+------------------- + 0 | -49.9994775978848 + 11 | -49.9985320260748 + 4 | -49.9983572866768 + 3 | -49.9977725092322 + 6 | -49.9967515002936 + 9 | -49.992344272323 + 5 | -49.9921301845461 + 7 | -49.99003498815 + 8 | -49.9897602945566 + | -38.5084833716974 +(10 rows) + select stddev(cfloat8) from aggfns; stddev ------------------ @@ -421,6 +587,21 @@ select s, stddev(cfloat8) from aggfns group by s order by stddev(cfloat8), s lim 7 | 28.9656492103737 (10 rows) +select ss, stddev(cfloat8) from aggfns group by ss order by stddev(cfloat8), ss limit 10; + ss | stddev +----+------------------ + 11 | 21.3262797346004 + | 22.894065438835 + 9 | 28.7642081921344 + 4 | 28.7760615445521 + 5 | 28.7843925303698 + 6 | 28.8543767497508 + 3 | 28.926156595386 + 8 | 28.96331707256 + 0 | 28.9653425568561 + 7 | 28.9656492103736 +(10 rows) + select sum(cfloat8) from aggfns; sum ----------------- @@ -442,6 +623,21 @@ select s, sum(cfloat8) from aggfns group by s order by sum(cfloat8), s limit 10; 1 | 260000 (10 rows) +select ss, sum(cfloat8) from aggfns group by ss order by sum(cfloat8), ss limit 10; + ss | sum +----+------------------- + 0 | -6138.50265394431 + 8 | -5373.85800310876 + 4 | -4478.94605516922 + 3 | -3066.93256727885 + 9 | -2296.84818079695 + 7 | -1272.75934566278 + | 102.997287432663 + 5 | 876.530192652717 + 6 | 3391.98199370876 + 11 | 264036.623917427 +(10 rows) + select avg(cint2) from aggfns; avg ---------------------- @@ -463,6 +659,21 @@ select s, avg(cint2) from aggfns group by s order by avg(cint2), s limit 10; 5 | 110.0305290025524248 (10 rows) +select ss, avg(cint2) from aggfns group by ss order by avg(cint2), ss limit 10; + ss | avg +----+------------------------ + | -1368.1578947368421053 + 8 | -129.4959711726139833 + 3 | -94.5546037471195271 + 6 | -61.0756218407487113 + 7 | -55.8695260497472599 + 11 | -33.7550336409794652 + 4 | -27.5652740206392145 + 9 | -21.7994594865121866 + 0 | 17.5951654071367799 + 5 | 110.0305290025524248 +(10 rows) + select count(cint2) from aggfns; count -------- @@ -484,6 +695,21 @@ select s, count(cint2) from aggfns group by s order by count(cint2), s limit 10; 9 | 19981 (10 rows) +select ss, count(cint2) from aggfns group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + | 19 + 3 | 19962 + 4 | 19962 + 0 | 19981 + 5 | 19981 + 6 | 19981 + 7 | 19981 + 8 | 19981 + 9 | 19981 + 11 | 39981 +(10 rows) + select max(cint2) from aggfns; max ------- @@ -505,6 +731,21 @@ select s, max(cint2) from aggfns group by s order by max(cint2), s limit 10; 9 | 16383 (10 rows) +select ss, max(cint2) from aggfns group by ss order by max(cint2), ss limit 10; + ss | max +----+------- + | 16362 + 3 | 16380 + 5 | 16381 + 7 | 16381 + 8 | 16382 + 0 | 16383 + 4 | 16383 + 6 | 16383 + 9 | 16383 + 11 | 16383 +(10 rows) + select min(cint2) from aggfns; min -------- @@ -526,6 +767,21 @@ select s, min(cint2) from aggfns group by s order by min(cint2), s limit 10; 9 | -16375 (10 rows) +select ss, min(cint2) from aggfns group by ss order by min(cint2), ss limit 10; + ss | min +----+-------- + 0 | -16383 + 4 | -16383 + 5 | -16383 + 6 | -16383 + 7 | -16382 + 8 | -16382 + 11 | -16382 + 3 | -16381 + 9 | -16375 + | -16100 +(10 rows) + select stddev(cint2) from aggfns; stddev ------------------- @@ -547,6 +803,21 @@ select s, stddev(cint2) from aggfns group by s order by stddev(cint2), s limit 1 1 | 9528.039076724276 (10 rows) +select ss, stddev(cint2) from aggfns group by ss order by stddev(cint2), ss limit 10; + ss | stddev +----+------------------- + | 8413.549166956554 + 9 | 9450.322790943425 + 7 | 9462.161209850735 + 6 | 9467.569674984571 + 5 | 9467.776835158782 + 3 | 9474.482349111595 + 8 | 9477.586839536066 + 4 | 9483.611454519949 + 0 | 9484.907423282680 + 11 | 9494.206429493352 +(10 rows) + select sum(cint2) from aggfns; sum ---------- @@ -568,6 +839,21 @@ select s, sum(cint2) from aggfns group by s order by sum(cint2), s limit 10; 5 | 2198520 (10 rows) +select ss, sum(cint2) from aggfns group by ss order by sum(cint2), ss limit 10; + ss | sum +----+---------- + 8 | -2587459 + 3 | -1887499 + 11 | -1349560 + 6 | -1220352 + 7 | -1116329 + 4 | -550258 + 9 | -435575 + | -25995 + 0 | 351569 + 5 | 2198520 +(10 rows) + select avg(cint4) from aggfns; avg --------------------- @@ -589,6 +875,21 @@ select s, avg(cint4) from aggfns group by s order by avg(cint4), s limit 10; 5 | 103.1069000000000000 (10 rows) +select ss, avg(cint4) from aggfns group by ss order by avg(cint4), ss limit 10; + ss | avg +----+----------------------- + 9 | -102.4283000000000000 + 6 | -53.1566500000000000 + 7 | -42.6121500000000000 + 8 | -29.2615500000000000 + 11 | -16.4247732327144606 + 4 | 9.6930584054852110 + 0 | 27.7536500000000000 + 3 | 68.3874180471447875 + 5 | 103.1069000000000000 + | 2197.6842105263157895 +(10 rows) + select max(cint4) from aggfns; max ------- @@ -610,6 +911,21 @@ select s, max(cint4) from aggfns group by s order by max(cint4), s limit 10; 9 | 16383 (10 rows) +select ss, max(cint4) from aggfns group by ss order by max(cint4), ss limit 10; + ss | max +----+------- + | 14812 + 3 | 16379 + 5 | 16379 + 7 | 16379 + 0 | 16383 + 4 | 16383 + 6 | 16383 + 8 | 16383 + 9 | 16383 + 11 | 16383 +(10 rows) + select min(cint4) from aggfns; min -------- @@ -631,6 +947,21 @@ select s, min(cint4) from aggfns group by s order by min(cint4), s limit 10; 5 | -16380 (10 rows) +select ss, min(cint4) from aggfns group by ss order by min(cint4), ss limit 10; + ss | min +----+-------- + 0 | -16383 + 7 | -16383 + 11 | -16383 + 3 | -16382 + 4 | -16382 + 6 | -16382 + 8 | -16382 + 9 | -16382 + 5 | -16380 + | -15907 +(10 rows) + select stddev(cint4) from aggfns; stddev ------------------- @@ -652,6 +983,21 @@ select s, stddev(cint4) from aggfns group by s order by stddev(cint4), s limit 1 5 | 9504.684751625578 (10 rows) +select ss, stddev(cint4) from aggfns group by ss order by stddev(cint4), ss limit 10; + ss | stddev +----+------------------- + | 9361.317298404296 + 0 | 9406.815855797801 + 6 | 9410.397911988306 + 9 | 9426.452583637956 + 4 | 9442.480718256247 + 8 | 9450.281544631633 + 11 | 9450.690059613938 + 3 | 9474.873657491443 + 7 | 9485.765898279180 + 5 | 9504.684751625578 +(10 rows) + select sum(cint4) from aggfns; sum --------- @@ -673,6 +1019,21 @@ select s, sum(cint4) from aggfns group by s order by sum(cint4), s limit 10; 5 | 2062138 (10 rows) +select ss, sum(cint4) from aggfns group by ss order by sum(cint4), ss limit 10; + ss | sum +----+---------- + 9 | -2048566 + 6 | -1063133 + 7 | -852243 + 11 | -657303 + 8 | -585231 + | 41756 + 4 | 193677 + 0 | 555073 + 3 | 1366449 + 5 | 2062138 +(10 rows) + select avg(cint8) from aggfns; avg ---------------------- @@ -694,6 +1055,21 @@ select s, avg(cint8) from aggfns group by s order by avg(cint8), s limit 10; 9 | 61.7467500000000000 (10 rows) +select ss, avg(cint8) from aggfns group by ss order by avg(cint8), ss limit 10; + ss | avg +----+----------------------- + 8 | -118.4870000000000000 + 5 | -81.6955500000000000 + 4 | -17.0811771182623492 + 11 | -15.1685449411529523 + 7 | -2.3563500000000000 + 6 | 11.9056500000000000 + 0 | 15.3018000000000000 + 3 | 37.6662329212752115 + 9 | 61.7467500000000000 + | 2467.2631578947368421 +(10 rows) + select max(cint8) from aggfns; max ------- @@ -715,6 +1091,21 @@ select s, max(cint8) from aggfns group by s order by max(cint8), s limit 10; 5 | 16383 (10 rows) +select ss, max(cint8) from aggfns group by ss order by max(cint8), ss limit 10; + ss | max +----+------- + | 13750 + 6 | 16380 + 7 | 16380 + 8 | 16380 + 3 | 16382 + 9 | 16382 + 0 | 16383 + 4 | 16383 + 5 | 16383 + 11 | 16383 +(10 rows) + select min(cint8) from aggfns; min -------- @@ -736,6 +1127,21 @@ select s, min(cint8) from aggfns group by s order by min(cint8), s limit 10; 3 | -16378 (10 rows) +select ss, min(cint8) from aggfns group by ss order by min(cint8), ss limit 10; + ss | min +----+-------- + 0 | -16383 + 6 | -16383 + 7 | -16383 + 8 | -16383 + 11 | -16383 + 5 | -16382 + 4 | -16381 + 9 | -16380 + 3 | -16378 + | -14174 +(10 rows) + select sum(cint8) from aggfns; sum ---------- @@ -757,6 +1163,21 @@ select s, sum(cint8) from aggfns group by s order by sum(cint8), s limit 10; 9 | 1234935 (10 rows) +select ss, sum(cint8) from aggfns group by ss order by sum(cint8), ss limit 10; + ss | sum +----+---------- + 8 | -2369740 + 5 | -1633911 + 11 | -607030 + 4 | -341299 + 7 | -47127 + | 46878 + 6 | 238113 + 0 | 306036 + 3 | 752609 + 9 | 1234935 +(10 rows) + select max(cts) from aggfns; max -------------------------- @@ -778,6 +1199,21 @@ select s, max(cts) from aggfns group by s order by max(cts), s limit 10; 9 | Sat Jan 02 02:01:01 2021 (10 rows) +select ss, max(cts) from aggfns group by ss order by max(cts), ss limit 10; + ss | max +----+-------------------------- + 0 | Fri Jan 01 01:01:01 2021 + 3 | Fri Jan 01 09:21:01 2021 + | Fri Jan 01 09:21:01 2021 + 4 | Fri Jan 01 12:07:41 2021 + 11 | Fri Jan 01 12:07:41 2021 + 5 | Fri Jan 01 14:54:21 2021 + 6 | Fri Jan 01 17:41:01 2021 + 7 | Fri Jan 01 20:27:41 2021 + 8 | Fri Jan 01 23:14:21 2021 + 9 | Sat Jan 02 02:01:01 2021 +(10 rows) + select min(cts) from aggfns; min -------------------------- @@ -799,6 +1235,21 @@ select s, min(cts) from aggfns group by s order by min(cts), s limit 10; 9 | Sat Jan 02 02:01:01 2021 (10 rows) +select ss, min(cts) from aggfns group by ss order by min(cts), ss limit 10; + ss | min +----+-------------------------- + 0 | Fri Jan 01 01:01:01 2021 + 11 | Fri Jan 01 03:47:41 2021 + 3 | Fri Jan 01 09:21:01 2021 + | Fri Jan 01 09:21:01 2021 + 4 | Fri Jan 01 12:07:41 2021 + 5 | Fri Jan 01 14:54:21 2021 + 6 | Fri Jan 01 17:41:01 2021 + 7 | Fri Jan 01 20:27:41 2021 + 8 | Fri Jan 01 23:14:21 2021 + 9 | Sat Jan 02 02:01:01 2021 +(10 rows) + select max(ctstz) from aggfns; max ------------------------------ @@ -820,6 +1271,21 @@ select s, max(ctstz) from aggfns group by s order by max(ctstz), s limit 10; 9 | Sat Jan 02 02:01:01 2021 PST (10 rows) +select ss, max(ctstz) from aggfns group by ss order by max(ctstz), ss limit 10; + ss | max +----+------------------------------ + 0 | Fri Jan 01 01:01:01 2021 PST + 3 | Fri Jan 01 09:21:01 2021 PST + | Fri Jan 01 09:21:01 2021 PST + 4 | Fri Jan 01 12:07:41 2021 PST + 11 | Fri Jan 01 12:07:41 2021 PST + 5 | Fri Jan 01 14:54:21 2021 PST + 6 | Fri Jan 01 17:41:01 2021 PST + 7 | Fri Jan 01 20:27:41 2021 PST + 8 | Fri Jan 01 23:14:21 2021 PST + 9 | Sat Jan 02 02:01:01 2021 PST +(10 rows) + select min(ctstz) from aggfns; min ------------------------------ @@ -841,6 +1307,21 @@ select s, min(ctstz) from aggfns group by s order by min(ctstz), s limit 10; 9 | Sat Jan 02 02:01:01 2021 PST (10 rows) +select ss, min(ctstz) from aggfns group by ss order by min(ctstz), ss limit 10; + ss | min +----+------------------------------ + 0 | Fri Jan 01 01:01:01 2021 PST + 11 | Fri Jan 01 03:47:41 2021 PST + 3 | Fri Jan 01 09:21:01 2021 PST + | Fri Jan 01 09:21:01 2021 PST + 4 | Fri Jan 01 12:07:41 2021 PST + 5 | Fri Jan 01 14:54:21 2021 PST + 6 | Fri Jan 01 17:41:01 2021 PST + 7 | Fri Jan 01 20:27:41 2021 PST + 8 | Fri Jan 01 23:14:21 2021 PST + 9 | Sat Jan 02 02:01:01 2021 PST +(10 rows) + select avg(s) from aggfns; avg -------------------- @@ -862,6 +1343,21 @@ select s, avg(s) from aggfns group by s order by avg(s), s limit 10; 9 | 9.0000000000000000 (10 rows) +select ss, avg(s) from aggfns group by ss order by avg(s), ss limit 10; + ss | avg +----+---------------------------- + 0 | 0.000000000000000000000000 + 11 | 1.5011869362053025 + 3 | 3.0000000000000000 + | 3.0000000000000000 + 4 | 4.0000000000000000 + 5 | 5.0000000000000000 + 6 | 6.0000000000000000 + 7 | 7.0000000000000000 + 8 | 8.0000000000000000 + 9 | 9.0000000000000000 +(10 rows) + select count(s) from aggfns; count -------- @@ -883,6 +1379,21 @@ select s, count(s) from aggfns group by s order by count(s), s limit 10; 9 | 20000 (10 rows) +select ss, count(s) from aggfns group by ss order by count(s), ss limit 10; + ss | count +----+------- + | 19 + 3 | 19981 + 4 | 19981 + 0 | 20000 + 5 | 20000 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 + 11 | 40019 +(10 rows) + select max(s) from aggfns; max ----- @@ -904,6 +1415,21 @@ select s, max(s) from aggfns group by s order by max(s), s limit 10; 9 | 9 (10 rows) +select ss, max(s) from aggfns group by ss order by max(s), ss limit 10; + ss | max +----+----- + 0 | 0 + 3 | 3 + | 3 + 4 | 4 + 11 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + select min(s) from aggfns; min ----- @@ -925,6 +1451,21 @@ select s, min(s) from aggfns group by s order by min(s), s limit 10; 9 | 9 (10 rows) +select ss, min(s) from aggfns group by ss order by min(s), ss limit 10; + ss | min +----+----- + 0 | 0 + 11 | 1 + 3 | 3 + | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + select stddev(s) from aggfns; stddev -------------------- @@ -946,6 +1487,21 @@ select s, stddev(s) from aggfns group by s order by stddev(s), s limit 10; 9 | 0 (10 rows) +select ss, stddev(s) from aggfns group by ss order by stddev(s), ss limit 10; + ss | stddev +----+------------------------ + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + | 0 + 11 | 0.50284545977155885187 +(10 rows) + select sum(s) from aggfns; sum -------- @@ -967,6 +1523,21 @@ select s, sum(s) from aggfns group by s order by sum(s), s limit 10; 9 | 180000 (10 rows) +select ss, sum(s) from aggfns group by ss order by sum(s), ss limit 10; + ss | sum +----+-------- + 0 | 0 + | 57 + 3 | 59943 + 11 | 60076 + 4 | 79924 + 5 | 100000 + 6 | 120000 + 7 | 140000 + 8 | 160000 + 9 | 180000 +(10 rows) + select avg(ss) from aggfns; avg -------------------- @@ -988,6 +1559,21 @@ select s, avg(ss) from aggfns group by s order by avg(ss), s limit 10; 2 | 11.0000000000000000 (10 rows) +select ss, avg(ss) from aggfns group by ss order by avg(ss), ss limit 10; + ss | avg +----+---------------------------- + 0 | 0.000000000000000000000000 + 3 | 3.0000000000000000 + 4 | 4.0000000000000000 + 5 | 5.0000000000000000 + 6 | 6.0000000000000000 + 7 | 7.0000000000000000 + 8 | 8.0000000000000000 + 9 | 9.0000000000000000 + 11 | 11.0000000000000000 + | +(10 rows) + select max(ss) from aggfns; max ----- @@ -1009,6 +1595,21 @@ select s, max(ss) from aggfns group by s order by max(ss), s limit 10; 4 | 11 (10 rows) +select ss, max(ss) from aggfns group by ss order by max(ss), ss limit 10; + ss | max +----+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 11 | 11 + | +(10 rows) + select min(ss) from aggfns; min ----- @@ -1030,6 +1631,21 @@ select s, min(ss) from aggfns group by s order by min(ss), s limit 10; 2 | 11 (10 rows) +select ss, min(ss) from aggfns group by ss order by min(ss), ss limit 10; + ss | min +----+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 11 | 11 + | +(10 rows) + select stddev(ss) from aggfns; stddev -------------------- @@ -1051,6 +1667,21 @@ select s, stddev(ss) from aggfns group by s order by stddev(ss), s limit 10; 4 | 0.21565737387148452722 (10 rows) +select ss, stddev(ss) from aggfns group by ss order by stddev(ss), ss limit 10; + ss | stddev +----+-------- + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 + | +(10 rows) + select sum(ss) from aggfns; sum --------- @@ -1072,6 +1703,21 @@ select s, sum(ss) from aggfns group by s order by sum(ss), s limit 10; 2 | 220000 (10 rows) +select ss, sum(ss) from aggfns group by ss order by sum(ss), ss limit 10; + ss | sum +----+-------- + 0 | 0 + 3 | 59943 + 4 | 79924 + 5 | 100000 + 6 | 120000 + 7 | 140000 + 8 | 160000 + 9 | 180000 + 11 | 440209 + | +(10 rows) + select max(t) from aggfns; max -------- @@ -1093,6 +1739,21 @@ select s, max(t) from aggfns group by s order by max(t), s limit 10; 9 | 110000 (10 rows) +select ss, max(t) from aggfns group by ss order by max(t), ss limit 10; + ss | max +----+-------- + 0 | 20000 + | 49491 + 3 | 50000 + 11 | 59192 + 4 | 60000 + 5 | 70000 + 6 | 80000 + 7 | 90000 + 8 | 100000 + 9 | 110000 +(10 rows) + select min(t) from aggfns; min ----- @@ -1114,6 +1775,21 @@ select s, min(t) from aggfns group by s order by min(t), s limit 10; 9 | 90001 (10 rows) +select ss, min(t) from aggfns group by ss order by min(t), ss limit 10; + ss | min +----+------- + 0 | 1 + 11 | 10001 + 3 | 30001 + | 30537 + 4 | 40001 + 5 | 50001 + 6 | 60001 + 7 | 70001 + 8 | 80001 + 9 | 90001 +(10 rows) + select count(*) from aggfns where cfloat8 > 0; count -------- @@ -1135,6 +1811,21 @@ select s, count(*) from aggfns where cfloat8 > 0 group by s order by count(*), s 1 | 20000 (10 rows) +select ss, count(*) from aggfns where cfloat8 > 0 group by ss order by count(*), ss limit 10; + ss | count +----+------- + | 13 + 4 | 9872 + 0 | 9881 + 9 | 9945 + 3 | 9950 + 8 | 9950 + 5 | 9972 + 7 | 10021 + 6 | 10097 + 11 | 30084 +(10 rows) + select max(cdate) from aggfns where cfloat8 > 0; max ------------ @@ -1156,6 +1847,21 @@ select s, max(cdate) from aggfns where cfloat8 > 0 group by s order by max(cdate 9 | 06-01-2267 (10 rows) +select ss, max(cdate) from aggfns where cfloat8 > 0 group by ss order by max(cdate), ss limit 10; + ss | max +----+------------ + 0 | 01-01-2021 + 3 | 02-21-2103 + | 02-21-2103 + 4 | 07-09-2130 + 11 | 07-09-2130 + 5 | 11-24-2157 + 6 | 04-11-2185 + 7 | 08-28-2212 + 8 | 01-14-2240 + 9 | 06-01-2267 +(10 rows) + select min(cdate) from aggfns where cfloat8 > 0; min ------------ @@ -1177,6 +1883,21 @@ select s, min(cdate) from aggfns where cfloat8 > 0 group by s order by min(cdate 9 | 06-01-2267 (10 rows) +select ss, min(cdate) from aggfns where cfloat8 > 0 group by ss order by min(cdate), ss limit 10; + ss | min +----+------------ + 0 | 01-01-2021 + 11 | 05-19-2048 + 3 | 02-21-2103 + | 02-21-2103 + 4 | 07-09-2130 + 5 | 11-24-2157 + 6 | 04-11-2185 + 7 | 08-28-2212 + 8 | 01-14-2240 + 9 | 06-01-2267 +(10 rows) + select avg(cfloat4) from aggfns where cfloat8 > 0; avg ----- @@ -1198,6 +1919,21 @@ select s, avg(cfloat4) from aggfns where cfloat8 > 0 group by s order by avg(cfl 1 | NaN (10 rows) +select ss, avg(cfloat4) from aggfns where cfloat8 > 0 group by ss order by avg(cfloat4), ss limit 10; + ss | avg +----+-------------------- + 3 | -Infinity + 4 | -0.458554823065329 + 0 | -0.334856044433109 + 9 | -0.208302219537011 + 6 | 0.199537611181853 + 7 | 0.313851696029514 + 5 | 0.374879026647364 + 8 | 0.606801085094336 + | 1.47322510755979 + 11 | NaN +(10 rows) + select max(cfloat4) from aggfns where cfloat8 > 0; max ----- @@ -1219,6 +1955,21 @@ select s, max(cfloat4) from aggfns where cfloat8 > 0 group by s order by max(cfl 1 | NaN (10 rows) +select ss, max(cfloat4) from aggfns where cfloat8 > 0 group by ss order by max(cfloat4), ss limit 10; + ss | max +----+--------- + | 47.2047 + 9 | 49.9744 + 3 | 49.9744 + 0 | 49.9863 + 8 | 49.9923 + 4 | 49.9928 + 6 | 49.9956 + 7 | 49.9969 + 5 | 49.9992 + 11 | NaN +(10 rows) + select min(cfloat4) from aggfns where cfloat8 > 0; min ----------- @@ -1240,6 +1991,21 @@ select s, min(cfloat4) from aggfns where cfloat8 > 0 group by s order by min(cfl 6 | -49.9891 (10 rows) +select ss, min(cfloat4) from aggfns where cfloat8 > 0 group by ss order by min(cfloat4), ss limit 10; + ss | min +----+----------- + 3 | -Infinity + 4 | -49.9993 + 8 | -49.9969 + 7 | -49.9969 + 0 | -49.9915 + 9 | -49.9911 + 5 | -49.9892 + 6 | -49.9891 + | -41.6131 + 11 | NaN +(10 rows) + select stddev(cfloat4) from aggfns where cfloat8 > 0; stddev -------- @@ -1261,6 +2027,21 @@ select s, stddev(cfloat4) from aggfns where cfloat8 > 0 group by s order by stdd 3 | NaN (10 rows) +select ss, stddev(cfloat4) from aggfns where cfloat8 > 0 group by ss order by stddev(cfloat4), ss limit 10; + ss | stddev +----+------------------ + 7 | 28.7246858657947 + 0 | 28.7315562731003 + 9 | 28.7729261590403 + 4 | 28.8497176060195 + 5 | 28.9107809470208 + 6 | 28.9388387251543 + 8 | 29.1042713834566 + | 29.539145536489 + 3 | NaN + 11 | NaN +(10 rows) + select sum(cfloat4) from aggfns where cfloat8 > 0; sum ----- @@ -1282,6 +2063,21 @@ select s, sum(cfloat4) from aggfns where cfloat8 > 0 group by s order by sum(cfl 1 | NaN (10 rows) +select ss, sum(cfloat4) from aggfns where cfloat8 > 0 group by ss order by sum(cfloat4), ss limit 10; + ss | sum +----+----------- + 3 | -Infinity + 4 | -4526.85 + 0 | -3308.71 + 9 | -2071.57 + | 19.1519 + 6 | 2014.73 + 7 | 3145.11 + 5 | 3738.29 + 8 | 6037.67 + 11 | NaN +(10 rows) + select avg(cfloat8) from aggfns where cfloat8 > 0; avg ------------------ @@ -1303,6 +2099,21 @@ select s, avg(cfloat8) from aggfns where cfloat8 > 0 group by s order by avg(cfl 0 | 25.0776526587937 (10 rows) +select ss, avg(cfloat8) from aggfns where cfloat8 > 0 group by ss order by avg(cfloat8), ss limit 10; + ss | avg +----+------------------ + | 16.6705740293345 + 11 | 16.9860875451313 + 6 | 24.9229571834467 + 9 | 24.933601739557 + 8 | 24.9404756362227 + 4 | 24.9719502302445 + 7 | 24.9965050319499 + 5 | 25.0141908239782 + 3 | 25.0352176289523 + 0 | 25.0776526587937 +(10 rows) + select max(cfloat8) from aggfns where cfloat8 > 0; max ------------------ @@ -1324,6 +2135,21 @@ select s, max(cfloat8) from aggfns where cfloat8 > 0 group by s order by max(cfl 9 | 49.9995574122295 (10 rows) +select ss, max(cfloat8) from aggfns where cfloat8 > 0 group by ss order by max(cfloat8), ss limit 10; + ss | max +----+------------------ + | 46.3985309237614 + 5 | 49.9874341068789 + 3 | 49.9890822684392 + 6 | 49.9939429108053 + 8 | 49.9963666079566 + 0 | 49.9965498689562 + 7 | 49.9973275698721 + 11 | 49.9975695507601 + 4 | 49.9978997278959 + 9 | 49.9995574122295 +(10 rows) + select min(cfloat8) from aggfns where cfloat8 > 0; min ---------------------- @@ -1345,6 +2171,21 @@ select s, min(cfloat8) from aggfns where cfloat8 > 0 group by s order by min(cfl 1 | 13 (10 rows) +select ss, min(cfloat8) from aggfns where cfloat8 > 0 group by ss order by min(cfloat8), ss limit 10; + ss | min +----+---------------------- + 4 | 0.000765081495046616 + 7 | 0.000956561416387558 + 6 | 0.00179046764969826 + 0 | 0.00247885473072529 + 11 | 0.00441970769315958 + 3 | 0.00545482616871595 + 5 | 0.00628724228590727 + 9 | 0.0187294092029333 + 8 | 0.0195798231288791 + | 0.312147964723408 +(10 rows) + select stddev(cfloat8) from aggfns where cfloat8 > 0; stddev ------------------ @@ -1366,6 +2207,21 @@ select s, stddev(cfloat8) from aggfns where cfloat8 > 0 group by s order by stdd 8 | 14.507225286092 (10 rows) +select ss, stddev(cfloat8) from aggfns where cfloat8 > 0 group by ss order by stddev(cfloat8), ss limit 10; + ss | stddev +----+------------------ + 11 | 10.0892977778207 + 9 | 14.3145979997847 + 3 | 14.3656116060957 + 4 | 14.4158826742614 + 6 | 14.4175557556357 + 5 | 14.4400766885504 + 0 | 14.4509605112521 + 7 | 14.4643374353136 + 8 | 14.507225286092 + | 15.8897779049656 +(10 rows) + select sum(cfloat8) from aggfns where cfloat8 > 0; sum ------------------ @@ -1387,6 +2243,21 @@ select s, sum(cfloat8) from aggfns where cfloat8 > 0 group by s order by sum(cfl 1 | 260000 (10 rows) +select ss, sum(cfloat8) from aggfns where cfloat8 > 0 group by ss order by sum(cfloat8), ss limit 10; + ss | sum +----+------------------ + | 216.717462381348 + 4 | 246523.092672974 + 0 | 247792.285921541 + 9 | 247964.669299894 + 8 | 248157.732580416 + 3 | 249100.415408076 + 5 | 249441.510896711 + 7 | 250489.97692517 + 6 | 251647.098681261 + 11 | 511009.457707731 +(10 rows) + select avg(cint2) from aggfns where cfloat8 > 0; avg ---------------------- @@ -1408,6 +2279,21 @@ select s, avg(cint2) from aggfns where cfloat8 > 0 group by s order by avg(cint2 5 | 153.6364822808954924 (10 rows) +select ss, avg(cint2) from aggfns where cfloat8 > 0 group by ss order by avg(cint2), ss limit 10; + ss | avg +----+------------------------ + | -2431.3076923076923077 + 9 | -192.8237544036235531 + 3 | -156.9368272809576501 + 7 | -142.7671027664036752 + 4 | -119.1966149792236749 + 6 | -98.2421689135606661 + 8 | -1.6297525648762824 + 11 | 7.3528100356037667 + 0 | 28.7771364925070879 + 5 | 153.6364822808954924 +(10 rows) + select count(cint2) from aggfns where cfloat8 > 0; count -------- @@ -1429,6 +2315,21 @@ select s, count(cint2) from aggfns where cfloat8 > 0 group by s order by count(c 1 | 19981 (10 rows) +select ss, count(cint2) from aggfns where cfloat8 > 0 group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + | 13 + 4 | 9867 + 0 | 9876 + 9 | 9935 + 3 | 9941 + 8 | 9942 + 5 | 9961 + 7 | 10013 + 6 | 10088 + 11 | 30053 +(10 rows) + select max(cint2) from aggfns where cfloat8 > 0; max ------- @@ -1450,6 +2351,21 @@ select s, max(cint2) from aggfns where cfloat8 > 0 group by s order by max(cint2 9 | 16383 (10 rows) +select ss, max(cint2) from aggfns where cfloat8 > 0 group by ss order by max(cint2), ss limit 10; + ss | max +----+------- + | 7971 + 3 | 16380 + 8 | 16380 + 5 | 16381 + 6 | 16381 + 7 | 16381 + 0 | 16383 + 4 | 16383 + 9 | 16383 + 11 | 16383 +(10 rows) + select min(cint2) from aggfns where cfloat8 > 0; min -------- @@ -1471,6 +2387,21 @@ select s, min(cint2) from aggfns where cfloat8 > 0 group by s order by min(cint2 9 | -16375 (10 rows) +select ss, min(cint2) from aggfns where cfloat8 > 0 group by ss order by min(cint2), ss limit 10; + ss | min +----+-------- + 0 | -16383 + 4 | -16383 + 6 | -16383 + 8 | -16382 + 5 | -16381 + 7 | -16380 + 3 | -16378 + 11 | -16378 + 9 | -16375 + | -16100 +(10 rows) + select stddev(cint2) from aggfns where cfloat8 > 0; stddev ------------------- @@ -1492,6 +2423,21 @@ select s, stddev(cint2) from aggfns where cfloat8 > 0 group by s order by stddev 1 | 9528.039076724276 (10 rows) +select ss, stddev(cint2) from aggfns where cfloat8 > 0 group by ss order by stddev(cint2), ss limit 10; + ss | stddev +----+------------------- + | 7759.524506314969 + 5 | 9422.095841513016 + 6 | 9433.502305093184 + 9 | 9441.945023643920 + 4 | 9447.849754018911 + 7 | 9460.956887483220 + 3 | 9463.490872675688 + 8 | 9466.374225763893 + 11 | 9488.645998388904 + 0 | 9519.824544774386 +(10 rows) + select sum(cint2) from aggfns where cfloat8 > 0; sum ---------- @@ -1513,6 +2459,21 @@ select s, sum(cint2) from aggfns where cfloat8 > 0 group by s order by sum(cint2 1 | 1837240 (10 rows) +select ss, sum(cint2) from aggfns where cfloat8 > 0 group by ss order by sum(cint2), ss limit 10; + ss | sum +----+---------- + 9 | -1915704 + 3 | -1560109 + 7 | -1429527 + 4 | -1176113 + 6 | -991067 + | -31607 + 8 | -16203 + 11 | 220974 + 0 | 284203 + 5 | 1530373 +(10 rows) + select avg(cint4) from aggfns where cfloat8 > 0; avg --------------------- @@ -1534,6 +2495,21 @@ select s, avg(cint4) from aggfns where cfloat8 > 0 group by s order by avg(cint4 3 | 170.6088527551942186 (10 rows) +select ss, avg(cint4) from aggfns where cfloat8 > 0 group by ss order by avg(cint4), ss limit 10; + ss | avg +----+----------------------- + 9 | -227.0452488687782805 + 6 | -94.7697335842329405 + 4 | -40.9285858995137763 + 7 | -7.9618800518910288 + 11 | -4.2226765057838053 + 8 | 30.7776884422110553 + 5 | 70.0002005615724027 + 0 | 78.5152312518975812 + 3 | 169.6967839195979899 + | 868.6923076923076923 +(10 rows) + select max(cint4) from aggfns where cfloat8 > 0; max ------- @@ -1555,6 +2531,21 @@ select s, max(cint4) from aggfns where cfloat8 > 0 group by s order by max(cint4 1 | 16383 (10 rows) +select ss, max(cint4) from aggfns where cfloat8 > 0 group by ss order by max(cint4), ss limit 10; + ss | max +----+------- + | 14812 + 3 | 16379 + 5 | 16379 + 7 | 16379 + 0 | 16380 + 6 | 16380 + 9 | 16381 + 4 | 16382 + 8 | 16382 + 11 | 16383 +(10 rows) + select min(cint4) from aggfns where cfloat8 > 0; min -------- @@ -1576,6 +2567,21 @@ select s, min(cint4) from aggfns where cfloat8 > 0 group by s order by min(cint4 8 | -16377 (10 rows) +select ss, min(cint4) from aggfns where cfloat8 > 0 group by ss order by min(cint4), ss limit 10; + ss | min +----+-------- + 7 | -16383 + 11 | -16383 + 0 | -16382 + 9 | -16382 + 5 | -16380 + 3 | -16379 + 4 | -16378 + 6 | -16378 + 8 | -16377 + | -15907 +(10 rows) + select stddev(cint4) from aggfns where cfloat8 > 0; stddev ------------------- @@ -1597,6 +2603,21 @@ select s, stddev(cint4) from aggfns where cfloat8 > 0 group by s order by stddev 3 | 9509.065450373130 (10 rows) +select ss, stddev(cint4) from aggfns where cfloat8 > 0 group by ss order by stddev(cint4), ss limit 10; + ss | stddev +----+------------------- + | 8985.945186647640 + 0 | 9368.404782340758 + 6 | 9385.470128440942 + 8 | 9411.536015886790 + 4 | 9416.391322858156 + 11 | 9460.260597896060 + 9 | 9474.284943213442 + 5 | 9475.929892556881 + 7 | 9500.872262505529 + 3 | 9510.123363067463 +(10 rows) + select sum(cint4) from aggfns where cfloat8 > 0; sum --------- @@ -1618,6 +2639,21 @@ select s, sum(cint4) from aggfns where cfloat8 > 0 group by s order by sum(cint4 3 | 1699776 (10 rows) +select ss, sum(cint4) from aggfns where cfloat8 > 0 group by ss order by sum(cint4), ss limit 10; + ss | sum +----+---------- + 9 | -2257965 + 6 | -956890 + 4 | -404047 + 11 | -127035 + 7 | -79786 + | 11293 + 8 | 306238 + 5 | 698042 + 0 | 775809 + 3 | 1688483 +(10 rows) + select avg(cint8) from aggfns where cfloat8 > 0; avg --------------------- @@ -1639,6 +2675,21 @@ select s, avg(cint8) from aggfns where cfloat8 > 0 group by s order by avg(cint8 2 | 148.9026206075044669 (10 rows) +select ss, avg(cint8) from aggfns where cfloat8 > 0 group by ss order by avg(cint8), ss limit 10; + ss | avg +----+------------------------ + 8 | -166.4501507537688442 + 5 | -78.9197753710389089 + 4 | -61.5197528363047002 + 6 | -32.8705556105773992 + 7 | 1.15707015267937331604 + 11 | 33.0028919026725170 + 0 | 42.9815808116587390 + 9 | 44.5682252388134741 + 3 | 106.1022110552763819 + | 2876.8461538461538462 +(10 rows) + select max(cint8) from aggfns where cfloat8 > 0; max ------- @@ -1660,6 +2711,21 @@ select s, max(cint8) from aggfns where cfloat8 > 0 group by s order by max(cint8 5 | 16383 (10 rows) +select ss, max(cint8) from aggfns where cfloat8 > 0 group by ss order by max(cint8), ss limit 10; + ss | max +----+------- + | 13750 + 7 | 16378 + 6 | 16379 + 0 | 16380 + 8 | 16380 + 3 | 16381 + 4 | 16382 + 9 | 16382 + 5 | 16383 + 11 | 16383 +(10 rows) + select min(cint8) from aggfns where cfloat8 > 0; min -------- @@ -1681,6 +2747,21 @@ select s, min(cint8) from aggfns where cfloat8 > 0 group by s order by min(cint8 3 | -16378 (10 rows) +select ss, min(cint8) from aggfns where cfloat8 > 0 group by ss order by min(cint8), ss limit 10; + ss | min +----+-------- + 7 | -16383 + 8 | -16383 + 11 | -16383 + 5 | -16382 + 4 | -16381 + 6 | -16381 + 9 | -16380 + 0 | -16379 + 3 | -16378 + | -11918 +(10 rows) + select sum(cint8) from aggfns where cfloat8 > 0; sum --------- @@ -1702,6 +2783,21 @@ select s, sum(cint8) from aggfns where cfloat8 > 0 group by s order by sum(cint8 2 | 1500045 (10 rows) +select ss, sum(cint8) from aggfns where cfloat8 > 0 group by ss order by sum(cint8), ss limit 10; + ss | sum +----+---------- + 8 | -1656179 + 5 | -786988 + 4 | -607323 + 6 | -331894 + 7 | 11595 + | 37399 + 0 | 424701 + 9 | 443231 + 11 | 992859 + 3 | 1055717 +(10 rows) + select max(cts) from aggfns where cfloat8 > 0; max -------------------------- @@ -1723,6 +2819,21 @@ select s, max(cts) from aggfns where cfloat8 > 0 group by s order by max(cts), s 9 | Sat Jan 02 02:01:01 2021 (10 rows) +select ss, max(cts) from aggfns where cfloat8 > 0 group by ss order by max(cts), ss limit 10; + ss | max +----+-------------------------- + 0 | Fri Jan 01 01:01:01 2021 + 3 | Fri Jan 01 09:21:01 2021 + | Fri Jan 01 09:21:01 2021 + 4 | Fri Jan 01 12:07:41 2021 + 11 | Fri Jan 01 12:07:41 2021 + 5 | Fri Jan 01 14:54:21 2021 + 6 | Fri Jan 01 17:41:01 2021 + 7 | Fri Jan 01 20:27:41 2021 + 8 | Fri Jan 01 23:14:21 2021 + 9 | Sat Jan 02 02:01:01 2021 +(10 rows) + select min(cts) from aggfns where cfloat8 > 0; min -------------------------- @@ -1744,6 +2855,21 @@ select s, min(cts) from aggfns where cfloat8 > 0 group by s order by min(cts), s 9 | Sat Jan 02 02:01:01 2021 (10 rows) +select ss, min(cts) from aggfns where cfloat8 > 0 group by ss order by min(cts), ss limit 10; + ss | min +----+-------------------------- + 0 | Fri Jan 01 01:01:01 2021 + 11 | Fri Jan 01 03:47:41 2021 + 3 | Fri Jan 01 09:21:01 2021 + | Fri Jan 01 09:21:01 2021 + 4 | Fri Jan 01 12:07:41 2021 + 5 | Fri Jan 01 14:54:21 2021 + 6 | Fri Jan 01 17:41:01 2021 + 7 | Fri Jan 01 20:27:41 2021 + 8 | Fri Jan 01 23:14:21 2021 + 9 | Sat Jan 02 02:01:01 2021 +(10 rows) + select max(ctstz) from aggfns where cfloat8 > 0; max ------------------------------ @@ -1765,6 +2891,21 @@ select s, max(ctstz) from aggfns where cfloat8 > 0 group by s order by max(ctstz 9 | Sat Jan 02 02:01:01 2021 PST (10 rows) +select ss, max(ctstz) from aggfns where cfloat8 > 0 group by ss order by max(ctstz), ss limit 10; + ss | max +----+------------------------------ + 0 | Fri Jan 01 01:01:01 2021 PST + 3 | Fri Jan 01 09:21:01 2021 PST + | Fri Jan 01 09:21:01 2021 PST + 4 | Fri Jan 01 12:07:41 2021 PST + 11 | Fri Jan 01 12:07:41 2021 PST + 5 | Fri Jan 01 14:54:21 2021 PST + 6 | Fri Jan 01 17:41:01 2021 PST + 7 | Fri Jan 01 20:27:41 2021 PST + 8 | Fri Jan 01 23:14:21 2021 PST + 9 | Sat Jan 02 02:01:01 2021 PST +(10 rows) + select min(ctstz) from aggfns where cfloat8 > 0; min ------------------------------ @@ -1786,6 +2927,21 @@ select s, min(ctstz) from aggfns where cfloat8 > 0 group by s order by min(ctstz 9 | Sat Jan 02 02:01:01 2021 PST (10 rows) +select ss, min(ctstz) from aggfns where cfloat8 > 0 group by ss order by min(ctstz), ss limit 10; + ss | min +----+------------------------------ + 0 | Fri Jan 01 01:01:01 2021 PST + 11 | Fri Jan 01 03:47:41 2021 PST + 3 | Fri Jan 01 09:21:01 2021 PST + | Fri Jan 01 09:21:01 2021 PST + 4 | Fri Jan 01 12:07:41 2021 PST + 5 | Fri Jan 01 14:54:21 2021 PST + 6 | Fri Jan 01 17:41:01 2021 PST + 7 | Fri Jan 01 20:27:41 2021 PST + 8 | Fri Jan 01 23:14:21 2021 PST + 9 | Sat Jan 02 02:01:01 2021 PST +(10 rows) + select avg(s) from aggfns where cfloat8 > 0; avg -------------------- @@ -1807,6 +2963,21 @@ select s, avg(s) from aggfns where cfloat8 > 0 group by s order by avg(s), s lim 9 | 9.0000000000000000 (10 rows) +select ss, avg(s) from aggfns where cfloat8 > 0 group by ss order by avg(s), ss limit 10; + ss | avg +----+------------------------ + 0 | 0.00000000000000000000 + 11 | 1.3358595931392102 + 3 | 3.0000000000000000 + | 3.0000000000000000 + 4 | 4.0000000000000000 + 5 | 5.0000000000000000 + 6 | 6.0000000000000000 + 7 | 7.0000000000000000 + 8 | 8.0000000000000000 + 9 | 9.0000000000000000 +(10 rows) + select count(s) from aggfns where cfloat8 > 0; count -------- @@ -1828,6 +2999,21 @@ select s, count(s) from aggfns where cfloat8 > 0 group by s order by count(s), s 1 | 20000 (10 rows) +select ss, count(s) from aggfns where cfloat8 > 0 group by ss order by count(s), ss limit 10; + ss | count +----+------- + | 13 + 4 | 9872 + 0 | 9881 + 9 | 9945 + 3 | 9950 + 8 | 9950 + 5 | 9972 + 7 | 10021 + 6 | 10097 + 11 | 30084 +(10 rows) + select max(s) from aggfns where cfloat8 > 0; max ----- @@ -1849,6 +3035,21 @@ select s, max(s) from aggfns where cfloat8 > 0 group by s order by max(s), s lim 9 | 9 (10 rows) +select ss, max(s) from aggfns where cfloat8 > 0 group by ss order by max(s), ss limit 10; + ss | max +----+----- + 0 | 0 + 3 | 3 + | 3 + 4 | 4 + 11 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + select min(s) from aggfns where cfloat8 > 0; min ----- @@ -1870,6 +3071,21 @@ select s, min(s) from aggfns where cfloat8 > 0 group by s order by min(s), s lim 9 | 9 (10 rows) +select ss, min(s) from aggfns where cfloat8 > 0 group by ss order by min(s), ss limit 10; + ss | min +----+----- + 0 | 0 + 11 | 1 + 3 | 3 + | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + select stddev(s) from aggfns where cfloat8 > 0; stddev -------------------- @@ -1891,6 +3107,21 @@ select s, stddev(s) from aggfns where cfloat8 > 0 group by s order by stddev(s), 9 | 0 (10 rows) +select ss, stddev(s) from aggfns where cfloat8 > 0 group by ss order by stddev(s), ss limit 10; + ss | stddev +----+------------------------ + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + | 0 + 11 | 0.47440470436008342899 +(10 rows) + select sum(s) from aggfns where cfloat8 > 0; sum -------- @@ -1912,6 +3143,21 @@ select s, sum(s) from aggfns where cfloat8 > 0 group by s order by sum(s), s lim 9 | 89505 (10 rows) +select ss, sum(s) from aggfns where cfloat8 > 0 group by ss order by sum(s), ss limit 10; + ss | sum +----+------- + 0 | 0 + | 39 + 3 | 29850 + 4 | 39488 + 11 | 40188 + 5 | 49860 + 6 | 60582 + 7 | 70147 + 8 | 79600 + 9 | 89505 +(10 rows) + select avg(ss) from aggfns where cfloat8 > 0; avg -------------------- @@ -1933,6 +3179,21 @@ select s, avg(ss) from aggfns where cfloat8 > 0 group by s order by avg(ss), s l 2 | 11.0000000000000000 (10 rows) +select ss, avg(ss) from aggfns where cfloat8 > 0 group by ss order by avg(ss), ss limit 10; + ss | avg +----+------------------------ + 0 | 0.00000000000000000000 + 3 | 3.0000000000000000 + 4 | 4.0000000000000000 + 5 | 5.0000000000000000 + 6 | 6.0000000000000000 + 7 | 7.0000000000000000 + 8 | 8.0000000000000000 + 9 | 9.0000000000000000 + 11 | 11.0000000000000000 + | +(10 rows) + select max(ss) from aggfns where cfloat8 > 0; max ----- @@ -1954,6 +3215,21 @@ select s, max(ss) from aggfns where cfloat8 > 0 group by s order by max(ss), s l 4 | 11 (10 rows) +select ss, max(ss) from aggfns where cfloat8 > 0 group by ss order by max(ss), ss limit 10; + ss | max +----+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 11 | 11 + | +(10 rows) + select min(ss) from aggfns where cfloat8 > 0; min ----- @@ -1975,6 +3251,21 @@ select s, min(ss) from aggfns where cfloat8 > 0 group by s order by min(ss), s l 2 | 11 (10 rows) +select ss, min(ss) from aggfns where cfloat8 > 0 group by ss order by min(ss), ss limit 10; + ss | min +----+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 11 | 11 + | +(10 rows) + select stddev(ss) from aggfns where cfloat8 > 0; stddev -------------------- @@ -1996,6 +3287,21 @@ select s, stddev(ss) from aggfns where cfloat8 > 0 group by s order by stddev(ss 4 | 0.22257569540261848080 (10 rows) +select ss, stddev(ss) from aggfns where cfloat8 > 0 group by ss order by stddev(ss), ss limit 10; + ss | stddev +----+-------- + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 + | +(10 rows) + select sum(ss) from aggfns where cfloat8 > 0; sum -------- @@ -2017,6 +3323,21 @@ select s, sum(ss) from aggfns where cfloat8 > 0 group by s order by sum(ss), s l 1 | 220000 (10 rows) +select ss, sum(ss) from aggfns where cfloat8 > 0 group by ss order by sum(ss), ss limit 10; + ss | sum +----+-------- + 0 | 0 + 3 | 29850 + 4 | 39488 + 5 | 49860 + 6 | 60582 + 7 | 70147 + 8 | 79600 + 9 | 89505 + 11 | 330924 + | +(10 rows) + select max(t) from aggfns where cfloat8 > 0; max -------- @@ -2038,6 +3359,21 @@ select s, max(t) from aggfns where cfloat8 > 0 group by s order by max(t), s lim 9 | 110000 (10 rows) +select ss, max(t) from aggfns where cfloat8 > 0 group by ss order by max(t), ss limit 10; + ss | max +----+-------- + 0 | 19999 + | 49491 + 3 | 49999 + 11 | 59192 + 4 | 60000 + 5 | 70000 + 6 | 79998 + 7 | 89995 + 8 | 99997 + 9 | 110000 +(10 rows) + select min(t) from aggfns where cfloat8 > 0; min ----- @@ -2059,6 +3395,21 @@ select s, min(t) from aggfns where cfloat8 > 0 group by s order by min(t), s lim 9 | 90002 (10 rows) +select ss, min(t) from aggfns where cfloat8 > 0 group by ss order by min(t), ss limit 10; + ss | min +----+------- + 0 | 1 + 11 | 10001 + 3 | 30001 + | 30537 + 4 | 40003 + 5 | 50001 + 6 | 60002 + 7 | 70001 + 8 | 80003 + 9 | 90002 +(10 rows) + select count(*) from aggfns where cfloat8 <= 0; count ------- @@ -2079,6 +3430,21 @@ select s, count(*) from aggfns where cfloat8 <= 0 group by s order by count(*), 0 | 10119 (9 rows) +select ss, count(*) from aggfns where cfloat8 <= 0 group by ss order by count(*), ss limit 10; + ss | count +----+------- + | 6 + 6 | 9903 + 11 | 9935 + 7 | 9979 + 5 | 10028 + 3 | 10031 + 8 | 10050 + 9 | 10055 + 4 | 10109 + 0 | 10119 +(10 rows) + select max(cdate) from aggfns where cfloat8 <= 0; max ------------ @@ -2099,6 +3465,21 @@ select s, max(cdate) from aggfns where cfloat8 <= 0 group by s order by max(cdat 9 | 06-01-2267 (9 rows) +select ss, max(cdate) from aggfns where cfloat8 <= 0 group by ss order by max(cdate), ss limit 10; + ss | max +----+------------ + 0 | 01-01-2021 + 3 | 02-21-2103 + | 02-21-2103 + 4 | 07-09-2130 + 11 | 07-09-2130 + 5 | 11-24-2157 + 6 | 04-11-2185 + 7 | 08-28-2212 + 8 | 01-14-2240 + 9 | 06-01-2267 +(10 rows) + select min(cdate) from aggfns where cfloat8 <= 0; min ------------ @@ -2119,6 +3500,21 @@ select s, min(cdate) from aggfns where cfloat8 <= 0 group by s order by min(cdat 9 | 06-01-2267 (9 rows) +select ss, min(cdate) from aggfns where cfloat8 <= 0 group by ss order by min(cdate), ss limit 10; + ss | min +----+------------ + 0 | 01-01-2021 + 11 | 10-05-2075 + 3 | 02-21-2103 + | 02-21-2103 + 4 | 07-09-2130 + 5 | 11-24-2157 + 6 | 04-11-2185 + 7 | 08-28-2212 + 8 | 01-14-2240 + 9 | 06-01-2267 +(10 rows) + select avg(cfloat4) from aggfns where cfloat8 <= 0; avg ---------- @@ -2139,6 +3535,21 @@ select s, avg(cfloat4) from aggfns where cfloat8 <= 0 group by s order by avg(cf 2 | Infinity (9 rows) +select ss, avg(cfloat4) from aggfns where cfloat8 <= 0 group by ss order by avg(cfloat4), ss limit 10; + ss | avg +----+-------------------- + | -7.61213672161102 + 9 | -0.376175993822296 + 5 | -0.351281471733702 + 3 | -0.323676224863234 + 6 | -0.215785538185229 + 7 | 0.0690012062121504 + 4 | 0.113266462457489 + 8 | 0.308099926433512 + 0 | 0.497406092427368 + 11 | Infinity +(10 rows) + select max(cfloat4) from aggfns where cfloat8 <= 0; max ---------- @@ -2159,6 +3570,21 @@ select s, max(cfloat4) from aggfns where cfloat8 <= 0 group by s order by max(cf 2 | Infinity (9 rows) +select ss, max(cfloat4) from aggfns where cfloat8 <= 0 group by ss order by max(cfloat4), ss limit 10; + ss | max +----+---------- + | 43.8334 + 5 | 49.9753 + 9 | 49.9899 + 7 | 49.992 + 6 | 49.9938 + 4 | 49.9946 + 3 | 49.9979 + 0 | 49.9995 + 8 | 49.9997 + 11 | Infinity +(10 rows) + select min(cfloat4) from aggfns where cfloat8 <= 0; min ---------- @@ -2179,6 +3605,21 @@ select s, min(cfloat4) from aggfns where cfloat8 <= 0 group by s order by min(cf 3 | -49.974 (9 rows) +select ss, min(cfloat4) from aggfns where cfloat8 <= 0 group by ss order by min(cfloat4), ss limit 10; + ss | min +----+---------- + 4 | -49.9999 + 6 | -49.9995 + 11 | -49.9991 + 7 | -49.9984 + 0 | -49.9949 + 5 | -49.9942 + 9 | -49.9874 + 8 | -49.9853 + 3 | -49.974 + | -45.4083 +(10 rows) + select stddev(cfloat4) from aggfns where cfloat8 <= 0; stddev -------- @@ -2199,6 +3640,21 @@ select s, stddev(cfloat4) from aggfns where cfloat8 <= 0 group by s order by std 2 | NaN (9 rows) +select ss, stddev(cfloat4) from aggfns where cfloat8 <= 0 group by ss order by stddev(cfloat4), ss limit 10; + ss | stddev +----+------------------ + 0 | 28.7188352112159 + 3 | 28.7564997868619 + 4 | 28.7937148382071 + 7 | 28.8547648614793 + 6 | 28.89882973622 + 8 | 28.9050890855561 + 9 | 28.9126192916064 + 5 | 29.1278202173095 + | 34.8729157239149 + 11 | NaN +(10 rows) + select sum(cfloat4) from aggfns where cfloat8 <= 0; sum ---------- @@ -2219,6 +3675,21 @@ select s, sum(cfloat4) from aggfns where cfloat8 <= 0 group by s order by sum(cf 2 | Infinity (9 rows) +select ss, sum(cfloat4) from aggfns where cfloat8 <= 0 group by ss order by sum(cfloat4), ss limit 10; + ss | sum +----+---------- + 9 | -3782.45 + 5 | -3522.65 + 3 | -3246.8 + 6 | -2136.92 + | -45.6728 + 7 | 688.563 + 4 | 1145.01 + 8 | 3096.4 + 0 | 5033.25 + 11 | Infinity +(10 rows) + select avg(cfloat8) from aggfns where cfloat8 <= 0; avg ------------------- @@ -2239,6 +3710,21 @@ select s, avg(cfloat8) from aggfns where cfloat8 <= 0 group by s order by avg(cf 5 | -24.7870942066272 (9 rows) +select ss, avg(cfloat8) from aggfns where cfloat8 <= 0 group by ss order by avg(cfloat8), ss limit 10; + ss | avg +----+------------------- + 7 | -25.229255062715 + 8 | -25.2270239386592 + 3 | -25.1388045035744 + 0 | -25.0944548448943 + 6 | -25.0686778438405 + 9 | -24.8892608135943 + 11 | -24.858866008083 + 4 | -24.8295616508204 + 5 | -24.7870942066272 + | -18.9533624914475 +(10 rows) + select max(cfloat8) from aggfns where cfloat8 <= 0; max ---------------------- @@ -2259,6 +3745,21 @@ select s, max(cfloat8) from aggfns where cfloat8 <= 0 group by s order by max(cf 2 | -0.00172397121787071 (9 rows) +select ss, max(cfloat8) from aggfns where cfloat8 <= 0 group by ss order by max(cfloat8), ss limit 10; + ss | max +----+---------------------- + | -5.18986904062331 + 0 | -0.00547224190086126 + 9 | -0.00466627534478903 + 4 | -0.0041270861402154 + 6 | -0.00408347696065903 + 7 | -0.00273226760327816 + 3 | -0.00268903095275164 + 5 | -0.00228420831263065 + 8 | -0.00182925723493099 + 11 | -0.00172397121787071 +(10 rows) + select min(cfloat8) from aggfns where cfloat8 <= 0; min ------------------- @@ -2279,6 +3780,21 @@ select s, min(cfloat8) from aggfns where cfloat8 <= 0 group by s order by min(cf 8 | -49.9897602945566 (9 rows) +select ss, min(cfloat8) from aggfns where cfloat8 <= 0 group by ss order by min(cfloat8), ss limit 10; + ss | min +----+------------------- + 0 | -49.9994775978848 + 11 | -49.9985320260748 + 4 | -49.9983572866768 + 3 | -49.9977725092322 + 6 | -49.9967515002936 + 9 | -49.992344272323 + 5 | -49.9921301845461 + 7 | -49.99003498815 + 8 | -49.9897602945566 + | -38.5084833716974 +(10 rows) + select stddev(cfloat8) from aggfns where cfloat8 <= 0; stddev ------------------ @@ -2299,6 +3815,21 @@ select s, stddev(cfloat8) from aggfns where cfloat8 <= 0 group by s order by std 0 | 14.5136612753879 (9 rows) +select ss, stddev(cfloat8) from aggfns where cfloat8 <= 0 group by ss order by stddev(cfloat8), ss limit 10; + ss | stddev +----+------------------ + 7 | 14.4030112329563 + 11 | 14.4033336871388 + 6 | 14.4144870413512 + 3 | 14.4335904065982 + 4 | 14.4339025361113 + 5 | 14.4378475427373 + 9 | 14.445355480345 + 8 | 14.4532419971748 + 0 | 14.5136612753879 + | 15.4584765893444 +(10 rows) + select sum(cfloat8) from aggfns where cfloat8 <= 0; sum ------------------- @@ -2319,6 +3850,21 @@ select s, sum(cfloat8) from aggfns where cfloat8 <= 0 group by s order by sum(cf 2 | -246743.521314557 (9 rows) +select ss, sum(cfloat8) from aggfns where cfloat8 <= 0 group by ss order by sum(cfloat8), ss limit 10; + ss | sum +----+------------------- + 0 | -253930.788575485 + 8 | -253531.590583525 + 3 | -252167.347975355 + 7 | -251762.736270833 + 4 | -251002.038728143 + 9 | -250261.517480691 + 5 | -248564.980704058 + 6 | -248255.116687552 + 11 | -246972.833790304 + | -113.720174948685 +(10 rows) + select avg(cint2) from aggfns where cfloat8 <= 0; avg ---------------------- @@ -2339,6 +3885,21 @@ select s, avg(cint2) from aggfns where cfloat8 <= 0 group by s order by avg(cint 9 | 147.3351582719490344 (9 rows) +select ss, avg(cint2) from aggfns where cfloat8 <= 0 group by ss order by avg(cint2), ss limit 10; + ss | avg +----+----------------------- + 8 | -256.1267058471959359 + 11 | -158.1923851732473811 + 3 | -32.6703921764294981 + 6 | -23.1764884261599110 + 0 | 6.6666006927263731 + 7 | 31.4203451043338684 + 4 | 61.9965329370975731 + 5 | 66.6813373253493014 + 9 | 147.3351582719490344 + | 935.3333333333333333 +(10 rows) + select count(cint2) from aggfns where cfloat8 <= 0; count ------- @@ -2359,6 +3920,21 @@ select s, count(cint2) from aggfns where cfloat8 <= 0 group by s order by count( 0 | 10105 (9 rows) +select ss, count(cint2) from aggfns where cfloat8 <= 0 group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + | 6 + 6 | 9893 + 11 | 9928 + 7 | 9968 + 5 | 10020 + 3 | 10021 + 8 | 10039 + 9 | 10046 + 4 | 10095 + 0 | 10105 +(10 rows) + select max(cint2) from aggfns where cfloat8 <= 0; max ------- @@ -2379,6 +3955,21 @@ select s, max(cint2) from aggfns where cfloat8 <= 0 group by s order by max(cint 6 | 16383 (9 rows) +select ss, max(cint2) from aggfns where cfloat8 <= 0 group by ss order by max(cint2), ss limit 10; + ss | max +----+------- + | 16362 + 7 | 16376 + 9 | 16376 + 3 | 16378 + 0 | 16381 + 5 | 16381 + 11 | 16381 + 8 | 16382 + 4 | 16383 + 6 | 16383 +(10 rows) + select min(cint2) from aggfns where cfloat8 <= 0; min -------- @@ -2399,6 +3990,21 @@ select s, min(cint2) from aggfns where cfloat8 <= 0 group by s order by min(cint 9 | -16374 (9 rows) +select ss, min(cint2) from aggfns where cfloat8 <= 0 group by ss order by min(cint2), ss limit 10; + ss | min +----+-------- + 0 | -16383 + 5 | -16383 + 6 | -16383 + 7 | -16382 + 8 | -16382 + 11 | -16382 + 3 | -16381 + 4 | -16379 + 9 | -16374 + | -7696 +(10 rows) + select stddev(cint2) from aggfns where cfloat8 <= 0; stddev ------------------- @@ -2419,6 +4025,21 @@ select s, stddev(cint2) from aggfns where cfloat8 <= 0 group by s order by stdde 4 | 9517.027301293118 (9 rows) +select ss, stddev(cint2) from aggfns where cfloat8 <= 0 group by ss order by stddev(cint2), ss limit 10; + ss | stddev +----+-------------------- + 0 | 9451.115288155243 + 9 | 9456.028731464701 + 7 | 9463.041992703462 + 3 | 9485.440311868001 + 8 | 9487.451140540082 + 6 | 9502.509922580216 + 11 | 9510.413974851870 + 5 | 9513.243501566793 + 4 | 9518.051043653511 + | 10051.146773710285 +(10 rows) + select sum(cint2) from aggfns where cfloat8 <= 0; sum ---------- @@ -2439,6 +4060,21 @@ select s, sum(cint2) from aggfns where cfloat8 <= 0 group by s order by sum(cint 9 | 1480129 (9 rows) +select ss, sum(cint2) from aggfns where cfloat8 <= 0 group by ss order by sum(cint2), ss limit 10; + ss | sum +----+---------- + 8 | -2571256 + 11 | -1570534 + 3 | -327390 + 6 | -229285 + | 5612 + 0 | 67366 + 7 | 313198 + 4 | 625855 + 5 | 668147 + 9 | 1480129 +(10 rows) + select avg(cint4) from aggfns where cfloat8 <= 0; avg --------------------- @@ -2459,6 +4095,21 @@ select s, avg(cint4) from aggfns where cfloat8 <= 0 group by s order by avg(cint 5 | 136.0287195851615477 (9 rows) +select ss, avg(cint4) from aggfns where cfloat8 <= 0 group by ss order by avg(cint4), ss limit 10; + ss | avg +----+----------------------- + 8 | -88.7033830845771144 + 7 | -77.4082573404148712 + 11 | -53.3737292400603926 + 3 | -32.1038779782673711 + 0 | -21.8140132424152584 + 6 | -10.7283651418761991 + 9 | 20.8253605171556440 + 4 | 59.1279058264912454 + 5 | 136.0287195851615477 + | 5077.1666666666666667 +(10 rows) + select max(cint4) from aggfns where cfloat8 <= 0; max ------- @@ -2479,6 +4130,21 @@ select s, max(cint4) from aggfns where cfloat8 <= 0 group by s order by max(cint 9 | 16383 (9 rows) +select ss, max(cint4) from aggfns where cfloat8 <= 0 group by ss order by max(cint4), ss limit 10; + ss | max +----+------- + | 13078 + 5 | 16364 + 7 | 16378 + 3 | 16379 + 11 | 16381 + 0 | 16383 + 4 | 16383 + 6 | 16383 + 8 | 16383 + 9 | 16383 +(10 rows) + select min(cint4) from aggfns where cfloat8 <= 0; min -------- @@ -2499,6 +4165,21 @@ select s, min(cint4) from aggfns where cfloat8 <= 0 group by s order by min(cint 5 | -16374 (9 rows) +select ss, min(cint4) from aggfns where cfloat8 <= 0 group by ss order by min(cint4), ss limit 10; + ss | min +----+-------- + 0 | -16383 + 3 | -16382 + 4 | -16382 + 6 | -16382 + 8 | -16382 + 9 | -16381 + 7 | -16379 + 11 | -16377 + 5 | -16374 + | -8992 +(10 rows) + select stddev(cint4) from aggfns where cfloat8 <= 0; stddev ------------------- @@ -2519,6 +4200,21 @@ select s, stddev(cint4) from aggfns where cfloat8 <= 0 group by s order by stdde 5 | 9533.551517829360 (9 rows) +select ss, stddev(cint4) from aggfns where cfloat8 <= 0 group by ss order by stddev(cint4), ss limit 10; + ss | stddev +----+------------------- + 9 | 9377.745829196558 + 11 | 9422.029173765748 + 6 | 9436.031206307503 + 3 | 9439.178404000439 + 0 | 9444.372352979574 + 4 | 9468.093604068949 + 7 | 9470.920199125109 + 8 | 9488.579674823607 + 5 | 9533.551517829360 + | 10351.23962464 +(10 rows) + select sum(cint4) from aggfns where cfloat8 <= 0; sum --------- @@ -2539,6 +4235,21 @@ select s, sum(cint4) from aggfns where cfloat8 <= 0 group by s order by sum(cint 5 | 1364096 (9 rows) +select ss, sum(cint4) from aggfns where cfloat8 <= 0 group by ss order by sum(cint4), ss limit 10; + ss | sum +----+--------- + 8 | -891469 + 7 | -772457 + 11 | -530268 + 3 | -322034 + 0 | -220736 + 6 | -106243 + | 30463 + 9 | 209399 + 4 | 597724 + 5 | 1364096 +(10 rows) + select avg(cint8) from aggfns where cfloat8 <= 0; avg ---------------------- @@ -2559,6 +4270,21 @@ select s, avg(cint8) from aggfns where cfloat8 <= 0 group by s order by avg(cint 9 | 78.7373446046742914 (9 rows) +select ss, avg(cint8) from aggfns where cfloat8 <= 0 group by ss order by avg(cint8), ss limit 10; + ss | avg +----+----------------------- + 11 | -161.0356316054353296 + 5 | -84.4558236936577583 + 8 | -71.0010945273631841 + 3 | -30.2171269065895723 + 0 | -11.7269493032908390 + 7 | -5.8845575708988877 + 4 | 26.3155603917301415 + 6 | 57.5590225184287590 + 9 | 78.7373446046742914 + | 1579.8333333333333333 +(10 rows) + select max(cint8) from aggfns where cfloat8 <= 0; max ------- @@ -2579,6 +4305,21 @@ select s, max(cint8) from aggfns where cfloat8 <= 0 group by s order by max(cint 4 | 16383 (9 rows) +select ss, max(cint8) from aggfns where cfloat8 <= 0 group by ss order by max(cint8), ss limit 10; + ss | max +----+------- + | 12678 + 8 | 16379 + 11 | 16379 + 6 | 16380 + 7 | 16380 + 5 | 16381 + 9 | 16381 + 3 | 16382 + 0 | 16383 + 4 | 16383 +(10 rows) + select min(cint8) from aggfns where cfloat8 <= 0; min -------- @@ -2599,6 +4340,21 @@ select s, min(cint8) from aggfns where cfloat8 <= 0 group by s order by min(cint 9 | -16372 (9 rows) +select ss, min(cint8) from aggfns where cfloat8 <= 0 group by ss order by min(cint8), ss limit 10; + ss | min +----+-------- + 0 | -16383 + 6 | -16383 + 8 | -16383 + 5 | -16382 + 4 | -16381 + 7 | -16381 + 3 | -16375 + 11 | -16375 + 9 | -16372 + | -14174 +(10 rows) + select sum(cint8) from aggfns where cfloat8 <= 0; sum ---------- @@ -2619,6 +4375,21 @@ select s, sum(cint8) from aggfns where cfloat8 <= 0 group by s order by sum(cint 9 | 791704 (9 rows) +select ss, sum(cint8) from aggfns where cfloat8 <= 0 group by ss order by sum(cint8), ss limit 10; + ss | sum +----+---------- + 11 | -1599889 + 5 | -846923 + 8 | -713561 + 3 | -303108 + 0 | -118665 + 7 | -58722 + | 9479 + 4 | 266024 + 6 | 570007 + 9 | 791704 +(10 rows) + select max(cts) from aggfns where cfloat8 <= 0; max -------------------------- @@ -2639,6 +4410,21 @@ select s, max(cts) from aggfns where cfloat8 <= 0 group by s order by max(cts), 9 | Sat Jan 02 02:01:01 2021 (9 rows) +select ss, max(cts) from aggfns where cfloat8 <= 0 group by ss order by max(cts), ss limit 10; + ss | max +----+-------------------------- + 0 | Fri Jan 01 01:01:01 2021 + 3 | Fri Jan 01 09:21:01 2021 + | Fri Jan 01 09:21:01 2021 + 4 | Fri Jan 01 12:07:41 2021 + 11 | Fri Jan 01 12:07:41 2021 + 5 | Fri Jan 01 14:54:21 2021 + 6 | Fri Jan 01 17:41:01 2021 + 7 | Fri Jan 01 20:27:41 2021 + 8 | Fri Jan 01 23:14:21 2021 + 9 | Sat Jan 02 02:01:01 2021 +(10 rows) + select min(cts) from aggfns where cfloat8 <= 0; min -------------------------- @@ -2659,6 +4445,21 @@ select s, min(cts) from aggfns where cfloat8 <= 0 group by s order by min(cts), 9 | Sat Jan 02 02:01:01 2021 (9 rows) +select ss, min(cts) from aggfns where cfloat8 <= 0 group by ss order by min(cts), ss limit 10; + ss | min +----+-------------------------- + 0 | Fri Jan 01 01:01:01 2021 + 11 | Fri Jan 01 06:34:21 2021 + 3 | Fri Jan 01 09:21:01 2021 + | Fri Jan 01 09:21:01 2021 + 4 | Fri Jan 01 12:07:41 2021 + 5 | Fri Jan 01 14:54:21 2021 + 6 | Fri Jan 01 17:41:01 2021 + 7 | Fri Jan 01 20:27:41 2021 + 8 | Fri Jan 01 23:14:21 2021 + 9 | Sat Jan 02 02:01:01 2021 +(10 rows) + select max(ctstz) from aggfns where cfloat8 <= 0; max ------------------------------ @@ -2679,6 +4480,21 @@ select s, max(ctstz) from aggfns where cfloat8 <= 0 group by s order by max(ctst 9 | Sat Jan 02 02:01:01 2021 PST (9 rows) +select ss, max(ctstz) from aggfns where cfloat8 <= 0 group by ss order by max(ctstz), ss limit 10; + ss | max +----+------------------------------ + 0 | Fri Jan 01 01:01:01 2021 PST + 3 | Fri Jan 01 09:21:01 2021 PST + | Fri Jan 01 09:21:01 2021 PST + 4 | Fri Jan 01 12:07:41 2021 PST + 11 | Fri Jan 01 12:07:41 2021 PST + 5 | Fri Jan 01 14:54:21 2021 PST + 6 | Fri Jan 01 17:41:01 2021 PST + 7 | Fri Jan 01 20:27:41 2021 PST + 8 | Fri Jan 01 23:14:21 2021 PST + 9 | Sat Jan 02 02:01:01 2021 PST +(10 rows) + select min(ctstz) from aggfns where cfloat8 <= 0; min ------------------------------ @@ -2699,6 +4515,21 @@ select s, min(ctstz) from aggfns where cfloat8 <= 0 group by s order by min(ctst 9 | Sat Jan 02 02:01:01 2021 PST (9 rows) +select ss, min(ctstz) from aggfns where cfloat8 <= 0 group by ss order by min(ctstz), ss limit 10; + ss | min +----+------------------------------ + 0 | Fri Jan 01 01:01:01 2021 PST + 11 | Fri Jan 01 06:34:21 2021 PST + 3 | Fri Jan 01 09:21:01 2021 PST + | Fri Jan 01 09:21:01 2021 PST + 4 | Fri Jan 01 12:07:41 2021 PST + 5 | Fri Jan 01 14:54:21 2021 PST + 6 | Fri Jan 01 17:41:01 2021 PST + 7 | Fri Jan 01 20:27:41 2021 PST + 8 | Fri Jan 01 23:14:21 2021 PST + 9 | Sat Jan 02 02:01:01 2021 PST +(10 rows) + select avg(s) from aggfns where cfloat8 <= 0; avg -------------------- @@ -2719,6 +4550,21 @@ select s, avg(s) from aggfns where cfloat8 <= 0 group by s order by avg(s), s li 9 | 9.0000000000000000 (9 rows) +select ss, avg(s) from aggfns where cfloat8 <= 0 group by ss order by avg(s), ss limit 10; + ss | avg +----+---------------------------- + 0 | 0.000000000000000000000000 + 11 | 2.0018117765475591 + 3 | 3.0000000000000000 + | 3.0000000000000000 + 4 | 4.0000000000000000 + 5 | 5.0000000000000000 + 6 | 6.0000000000000000 + 7 | 7.0000000000000000 + 8 | 8.0000000000000000 + 9 | 9.0000000000000000 +(10 rows) + select count(s) from aggfns where cfloat8 <= 0; count ------- @@ -2739,6 +4585,21 @@ select s, count(s) from aggfns where cfloat8 <= 0 group by s order by count(s), 0 | 10119 (9 rows) +select ss, count(s) from aggfns where cfloat8 <= 0 group by ss order by count(s), ss limit 10; + ss | count +----+------- + | 6 + 6 | 9903 + 11 | 9935 + 7 | 9979 + 5 | 10028 + 3 | 10031 + 8 | 10050 + 9 | 10055 + 4 | 10109 + 0 | 10119 +(10 rows) + select max(s) from aggfns where cfloat8 <= 0; max ----- @@ -2759,6 +4620,21 @@ select s, max(s) from aggfns where cfloat8 <= 0 group by s order by max(s), s li 9 | 9 (9 rows) +select ss, max(s) from aggfns where cfloat8 <= 0 group by ss order by max(s), ss limit 10; + ss | max +----+----- + 0 | 0 + 3 | 3 + | 3 + 4 | 4 + 11 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + select min(s) from aggfns where cfloat8 <= 0; min ----- @@ -2779,6 +4655,21 @@ select s, min(s) from aggfns where cfloat8 <= 0 group by s order by min(s), s li 9 | 9 (9 rows) +select ss, min(s) from aggfns where cfloat8 <= 0 group by ss order by min(s), ss limit 10; + ss | min +----+----- + 0 | 0 + 11 | 2 + 3 | 3 + | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + select stddev(s) from aggfns where cfloat8 <= 0; stddev -------------------- @@ -2799,6 +4690,21 @@ select s, stddev(s) from aggfns where cfloat8 <= 0 group by s order by stddev(s) 9 | 0 (9 rows) +select ss, stddev(s) from aggfns where cfloat8 <= 0 group by ss order by stddev(s), ss limit 10; + ss | stddev +----+------------------------ + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + | 0 + 11 | 0.06017171256636552646 +(10 rows) + select sum(s) from aggfns where cfloat8 <= 0; sum -------- @@ -2819,6 +4725,21 @@ select s, sum(s) from aggfns where cfloat8 <= 0 group by s order by sum(s), s li 9 | 90495 (9 rows) +select ss, sum(s) from aggfns where cfloat8 <= 0 group by ss order by sum(s), ss limit 10; + ss | sum +----+------- + 0 | 0 + | 18 + 11 | 19888 + 3 | 30093 + 4 | 40436 + 5 | 50140 + 6 | 59418 + 7 | 69853 + 8 | 80400 + 9 | 90495 +(10 rows) + select avg(ss) from aggfns where cfloat8 <= 0; avg -------------------- @@ -2839,6 +4760,21 @@ select s, avg(ss) from aggfns where cfloat8 <= 0 group by s order by avg(ss), s 2 | 11.0000000000000000 (9 rows) +select ss, avg(ss) from aggfns where cfloat8 <= 0 group by ss order by avg(ss), ss limit 10; + ss | avg +----+---------------------------- + 0 | 0.000000000000000000000000 + 3 | 3.0000000000000000 + 4 | 4.0000000000000000 + 5 | 5.0000000000000000 + 6 | 6.0000000000000000 + 7 | 7.0000000000000000 + 8 | 8.0000000000000000 + 9 | 9.0000000000000000 + 11 | 11.0000000000000000 + | +(10 rows) + select max(ss) from aggfns where cfloat8 <= 0; max ----- @@ -2859,6 +4795,21 @@ select s, max(ss) from aggfns where cfloat8 <= 0 group by s order by max(ss), s 4 | 11 (9 rows) +select ss, max(ss) from aggfns where cfloat8 <= 0 group by ss order by max(ss), ss limit 10; + ss | max +----+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 11 | 11 + | +(10 rows) + select min(ss) from aggfns where cfloat8 <= 0; min ----- @@ -2879,6 +4830,21 @@ select s, min(ss) from aggfns where cfloat8 <= 0 group by s order by min(ss), s 2 | 11 (9 rows) +select ss, min(ss) from aggfns where cfloat8 <= 0 group by ss order by min(ss), ss limit 10; + ss | min +----+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 11 | 11 + | +(10 rows) + select stddev(ss) from aggfns where cfloat8 <= 0; stddev -------------------- @@ -2899,6 +4865,21 @@ select s, stddev(ss) from aggfns where cfloat8 <= 0 group by s order by stddev(s 4 | 0.20868929911309143893 (9 rows) +select ss, stddev(ss) from aggfns where cfloat8 <= 0 group by ss order by stddev(ss), ss limit 10; + ss | stddev +----+-------- + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 + | +(10 rows) + select sum(ss) from aggfns where cfloat8 <= 0; sum -------- @@ -2919,6 +4900,21 @@ select s, sum(ss) from aggfns where cfloat8 <= 0 group by s order by sum(ss), s 2 | 109186 (9 rows) +select ss, sum(ss) from aggfns where cfloat8 <= 0 group by ss order by sum(ss), ss limit 10; + ss | sum +----+-------- + 0 | 0 + 3 | 30093 + 4 | 40436 + 5 | 50140 + 6 | 59418 + 7 | 69853 + 8 | 80400 + 9 | 90495 + 11 | 109285 + | +(10 rows) + select max(t) from aggfns where cfloat8 <= 0; max -------- @@ -2939,6 +4935,21 @@ select s, max(t) from aggfns where cfloat8 <= 0 group by s order by max(t), s li 9 | 109998 (9 rows) +select ss, max(t) from aggfns where cfloat8 <= 0 group by ss order by max(t), ss limit 10; + ss | max +----+-------- + 0 | 20000 + | 48438 + 3 | 50000 + 11 | 58135 + 4 | 59998 + 5 | 69999 + 6 | 80000 + 7 | 90000 + 8 | 100000 + 9 | 109998 +(10 rows) + select min(t) from aggfns where cfloat8 <= 0; min ----- @@ -2959,6 +4970,21 @@ select s, min(t) from aggfns where cfloat8 <= 0 group by s order by min(t), s li 9 | 90001 (9 rows) +select ss, min(t) from aggfns where cfloat8 <= 0 group by ss order by min(t), ss limit 10; + ss | min +----+------- + 0 | 8 + 11 | 20003 + 3 | 30002 + | 33696 + 4 | 40001 + 5 | 50004 + 6 | 60001 + 7 | 70002 + 8 | 80001 + 9 | 90001 +(10 rows) + select count(*) from aggfns where cfloat8 < 1000; count -------- @@ -2980,6 +5006,21 @@ select s, count(*) from aggfns where cfloat8 < 1000 group by s order by count(*) 9 | 20000 (10 rows) +select ss, count(*) from aggfns where cfloat8 < 1000 group by ss order by count(*), ss limit 10; + ss | count +----+------- + | 19 + 3 | 19981 + 4 | 19981 + 0 | 20000 + 5 | 20000 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 + 11 | 40019 +(10 rows) + select max(cdate) from aggfns where cfloat8 < 1000; max ------------ @@ -3001,6 +5042,21 @@ select s, max(cdate) from aggfns where cfloat8 < 1000 group by s order by max(cd 9 | 06-01-2267 (10 rows) +select ss, max(cdate) from aggfns where cfloat8 < 1000 group by ss order by max(cdate), ss limit 10; + ss | max +----+------------ + 0 | 01-01-2021 + 3 | 02-21-2103 + | 02-21-2103 + 4 | 07-09-2130 + 11 | 07-09-2130 + 5 | 11-24-2157 + 6 | 04-11-2185 + 7 | 08-28-2212 + 8 | 01-14-2240 + 9 | 06-01-2267 +(10 rows) + select min(cdate) from aggfns where cfloat8 < 1000; min ------------ @@ -3022,6 +5078,21 @@ select s, min(cdate) from aggfns where cfloat8 < 1000 group by s order by min(cd 9 | 06-01-2267 (10 rows) +select ss, min(cdate) from aggfns where cfloat8 < 1000 group by ss order by min(cdate), ss limit 10; + ss | min +----+------------ + 0 | 01-01-2021 + 11 | 05-19-2048 + 3 | 02-21-2103 + | 02-21-2103 + 4 | 07-09-2130 + 5 | 11-24-2157 + 6 | 04-11-2185 + 7 | 08-28-2212 + 8 | 01-14-2240 + 9 | 06-01-2267 +(10 rows) + select avg(cfloat4) from aggfns where cfloat8 < 1000; avg ----- @@ -3043,6 +5114,21 @@ select s, avg(cfloat4) from aggfns where cfloat8 < 1000 group by s order by avg( 1 | NaN (10 rows) +select ss, avg(cfloat4) from aggfns where cfloat8 < 1000 group by ss order by avg(cfloat4), ss limit 10; + ss | avg +----+---------------------- + 3 | -Infinity + | -1.39583652270468 + 9 | -0.292700759558938 + 4 | -0.169252917487522 + 6 | -0.00610964622725733 + 5 | 0.0107821527590975 + 0 | 0.0862269837114494 + 7 | 0.19168354413514 + 8 | 0.456703752867272 + 11 | NaN +(10 rows) + select max(cfloat4) from aggfns where cfloat8 < 1000; max ----- @@ -3064,6 +5150,21 @@ select s, max(cfloat4) from aggfns where cfloat8 < 1000 group by s order by max( 1 | NaN (10 rows) +select ss, max(cfloat4) from aggfns where cfloat8 < 1000 group by ss order by max(cfloat4), ss limit 10; + ss | max +----+--------- + | 47.2047 + 9 | 49.9899 + 4 | 49.9946 + 6 | 49.9956 + 7 | 49.9969 + 3 | 49.9979 + 5 | 49.9992 + 0 | 49.9995 + 8 | 49.9997 + 11 | NaN +(10 rows) + select min(cfloat4) from aggfns where cfloat8 < 1000; min ----------- @@ -3085,6 +5186,21 @@ select s, min(cfloat4) from aggfns where cfloat8 < 1000 group by s order by min( 9 | -49.9911 (10 rows) +select ss, min(cfloat4) from aggfns where cfloat8 < 1000 group by ss order by min(cfloat4), ss limit 10; + ss | min +----+----------- + 3 | -Infinity + 4 | -49.9999 + 6 | -49.9995 + 7 | -49.9984 + 8 | -49.9969 + 0 | -49.9949 + 5 | -49.9942 + 9 | -49.9911 + | -45.4083 + 11 | NaN +(10 rows) + select stddev(cfloat4) from aggfns where cfloat8 < 1000; stddev -------- @@ -3106,6 +5222,21 @@ select s, stddev(cfloat4) from aggfns where cfloat8 < 1000 group by s order by s 3 | NaN (10 rows) +select ss, stddev(cfloat4) from aggfns where cfloat8 < 1000 group by ss order by stddev(cfloat4), ss limit 10; + ss | stddev +----+------------------ + 0 | 28.7274163912974 + 7 | 28.7892027644318 + 4 | 28.8220943927954 + 9 | 28.8426424990846 + 6 | 28.9190577543738 + 8 | 29.0040125904064 + 5 | 29.0213532270614 + | 30.6324072248673 + 3 | NaN + 11 | NaN +(10 rows) + select sum(cfloat4) from aggfns where cfloat8 < 1000; sum ----- @@ -3127,6 +5258,21 @@ select s, sum(cfloat4) from aggfns where cfloat8 < 1000 group by s order by sum( 1 | NaN (10 rows) +select ss, sum(cfloat4) from aggfns where cfloat8 < 1000 group by ss order by sum(cfloat4), ss limit 10; + ss | sum +----+----------- + 3 | -Infinity + 9 | -5854.02 + 4 | -3381.84 + 6 | -122.193 + | -26.5209 + 5 | 215.643 + 0 | 1724.54 + 7 | 3833.67 + 8 | 9134.08 + 11 | NaN +(10 rows) + select avg(cfloat8) from aggfns where cfloat8 < 1000; avg ----------------- @@ -3148,6 +5294,21 @@ select s, avg(cfloat8) from aggfns where cfloat8 < 1000 group by s order by avg( 1 | 13 (10 rows) +select ss, avg(cfloat8) from aggfns where cfloat8 < 1000 group by ss order by avg(cfloat8), ss limit 10; + ss | avg +----+-------------------- + 0 | -0.306925132697215 + 8 | -0.268692900155438 + 4 | -0.224160255000712 + 3 | -0.153492446187821 + 9 | -0.114842409039848 + 7 | -0.063637967283139 + 5 | 0.0438265096326359 + 6 | 0.169599099685438 + | 5.42090986487701 + 11 | 6.59778165165114 +(10 rows) + select max(cfloat8) from aggfns where cfloat8 < 1000; max ------------------ @@ -3169,6 +5330,21 @@ select s, max(cfloat8) from aggfns where cfloat8 < 1000 group by s order by max( 9 | 49.9995574122295 (10 rows) +select ss, max(cfloat8) from aggfns where cfloat8 < 1000 group by ss order by max(cfloat8), ss limit 10; + ss | max +----+------------------ + | 46.3985309237614 + 5 | 49.9874341068789 + 3 | 49.9890822684392 + 6 | 49.9939429108053 + 8 | 49.9963666079566 + 0 | 49.9965498689562 + 7 | 49.9973275698721 + 11 | 49.9975695507601 + 4 | 49.9978997278959 + 9 | 49.9995574122295 +(10 rows) + select min(cfloat8) from aggfns where cfloat8 < 1000; min ------------------- @@ -3190,6 +5366,21 @@ select s, min(cfloat8) from aggfns where cfloat8 < 1000 group by s order by min( 1 | 13 (10 rows) +select ss, min(cfloat8) from aggfns where cfloat8 < 1000 group by ss order by min(cfloat8), ss limit 10; + ss | min +----+------------------- + 0 | -49.9994775978848 + 11 | -49.9985320260748 + 4 | -49.9983572866768 + 3 | -49.9977725092322 + 6 | -49.9967515002936 + 9 | -49.992344272323 + 5 | -49.9921301845461 + 7 | -49.99003498815 + 8 | -49.9897602945566 + | -38.5084833716974 +(10 rows) + select stddev(cfloat8) from aggfns where cfloat8 < 1000; stddev ------------------ @@ -3211,6 +5402,21 @@ select s, stddev(cfloat8) from aggfns where cfloat8 < 1000 group by s order by s 7 | 28.9656492103737 (10 rows) +select ss, stddev(cfloat8) from aggfns where cfloat8 < 1000 group by ss order by stddev(cfloat8), ss limit 10; + ss | stddev +----+------------------ + 11 | 21.3262797346004 + | 22.894065438835 + 9 | 28.7642081921344 + 4 | 28.7760615445521 + 5 | 28.7843925303698 + 6 | 28.8543767497508 + 3 | 28.926156595386 + 8 | 28.96331707256 + 0 | 28.9653425568561 + 7 | 28.9656492103736 +(10 rows) + select sum(cfloat8) from aggfns where cfloat8 < 1000; sum ----------------- @@ -3232,6 +5438,21 @@ select s, sum(cfloat8) from aggfns where cfloat8 < 1000 group by s order by sum( 1 | 260000 (10 rows) +select ss, sum(cfloat8) from aggfns where cfloat8 < 1000 group by ss order by sum(cfloat8), ss limit 10; + ss | sum +----+------------------- + 0 | -6138.50265394431 + 8 | -5373.85800310876 + 4 | -4478.94605516922 + 3 | -3066.93256727885 + 9 | -2296.84818079695 + 7 | -1272.75934566278 + | 102.997287432663 + 5 | 876.530192652717 + 6 | 3391.98199370876 + 11 | 264036.623917427 +(10 rows) + select avg(cint2) from aggfns where cfloat8 < 1000; avg ---------------------- @@ -3253,6 +5474,21 @@ select s, avg(cint2) from aggfns where cfloat8 < 1000 group by s order by avg(ci 5 | 110.0305290025524248 (10 rows) +select ss, avg(cint2) from aggfns where cfloat8 < 1000 group by ss order by avg(cint2), ss limit 10; + ss | avg +----+------------------------ + | -1368.1578947368421053 + 8 | -129.4959711726139833 + 3 | -94.5546037471195271 + 6 | -61.0756218407487113 + 7 | -55.8695260497472599 + 11 | -33.7550336409794652 + 4 | -27.5652740206392145 + 9 | -21.7994594865121866 + 0 | 17.5951654071367799 + 5 | 110.0305290025524248 +(10 rows) + select count(cint2) from aggfns where cfloat8 < 1000; count -------- @@ -3274,6 +5510,21 @@ select s, count(cint2) from aggfns where cfloat8 < 1000 group by s order by coun 9 | 19981 (10 rows) +select ss, count(cint2) from aggfns where cfloat8 < 1000 group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + | 19 + 3 | 19962 + 4 | 19962 + 0 | 19981 + 5 | 19981 + 6 | 19981 + 7 | 19981 + 8 | 19981 + 9 | 19981 + 11 | 39981 +(10 rows) + select max(cint2) from aggfns where cfloat8 < 1000; max ------- @@ -3295,6 +5546,21 @@ select s, max(cint2) from aggfns where cfloat8 < 1000 group by s order by max(ci 9 | 16383 (10 rows) +select ss, max(cint2) from aggfns where cfloat8 < 1000 group by ss order by max(cint2), ss limit 10; + ss | max +----+------- + | 16362 + 3 | 16380 + 5 | 16381 + 7 | 16381 + 8 | 16382 + 0 | 16383 + 4 | 16383 + 6 | 16383 + 9 | 16383 + 11 | 16383 +(10 rows) + select min(cint2) from aggfns where cfloat8 < 1000; min -------- @@ -3316,6 +5582,21 @@ select s, min(cint2) from aggfns where cfloat8 < 1000 group by s order by min(ci 9 | -16375 (10 rows) +select ss, min(cint2) from aggfns where cfloat8 < 1000 group by ss order by min(cint2), ss limit 10; + ss | min +----+-------- + 0 | -16383 + 4 | -16383 + 5 | -16383 + 6 | -16383 + 7 | -16382 + 8 | -16382 + 11 | -16382 + 3 | -16381 + 9 | -16375 + | -16100 +(10 rows) + select stddev(cint2) from aggfns where cfloat8 < 1000; stddev ------------------- @@ -3337,6 +5618,21 @@ select s, stddev(cint2) from aggfns where cfloat8 < 1000 group by s order by std 1 | 9528.039076724276 (10 rows) +select ss, stddev(cint2) from aggfns where cfloat8 < 1000 group by ss order by stddev(cint2), ss limit 10; + ss | stddev +----+------------------- + | 8413.549166956554 + 9 | 9450.322790943425 + 7 | 9462.161209850735 + 6 | 9467.569674984571 + 5 | 9467.776835158782 + 3 | 9474.482349111595 + 8 | 9477.586839536066 + 4 | 9483.611454519949 + 0 | 9484.907423282680 + 11 | 9494.206429493352 +(10 rows) + select sum(cint2) from aggfns where cfloat8 < 1000; sum ---------- @@ -3358,6 +5654,21 @@ select s, sum(cint2) from aggfns where cfloat8 < 1000 group by s order by sum(ci 5 | 2198520 (10 rows) +select ss, sum(cint2) from aggfns where cfloat8 < 1000 group by ss order by sum(cint2), ss limit 10; + ss | sum +----+---------- + 8 | -2587459 + 3 | -1887499 + 11 | -1349560 + 6 | -1220352 + 7 | -1116329 + 4 | -550258 + 9 | -435575 + | -25995 + 0 | 351569 + 5 | 2198520 +(10 rows) + select avg(cint4) from aggfns where cfloat8 < 1000; avg --------------------- @@ -3379,6 +5690,21 @@ select s, avg(cint4) from aggfns where cfloat8 < 1000 group by s order by avg(ci 5 | 103.1069000000000000 (10 rows) +select ss, avg(cint4) from aggfns where cfloat8 < 1000 group by ss order by avg(cint4), ss limit 10; + ss | avg +----+----------------------- + 9 | -102.4283000000000000 + 6 | -53.1566500000000000 + 7 | -42.6121500000000000 + 8 | -29.2615500000000000 + 11 | -16.4247732327144606 + 4 | 9.6930584054852110 + 0 | 27.7536500000000000 + 3 | 68.3874180471447875 + 5 | 103.1069000000000000 + | 2197.6842105263157895 +(10 rows) + select max(cint4) from aggfns where cfloat8 < 1000; max ------- @@ -3400,6 +5726,21 @@ select s, max(cint4) from aggfns where cfloat8 < 1000 group by s order by max(ci 9 | 16383 (10 rows) +select ss, max(cint4) from aggfns where cfloat8 < 1000 group by ss order by max(cint4), ss limit 10; + ss | max +----+------- + | 14812 + 3 | 16379 + 5 | 16379 + 7 | 16379 + 0 | 16383 + 4 | 16383 + 6 | 16383 + 8 | 16383 + 9 | 16383 + 11 | 16383 +(10 rows) + select min(cint4) from aggfns where cfloat8 < 1000; min -------- @@ -3421,6 +5762,21 @@ select s, min(cint4) from aggfns where cfloat8 < 1000 group by s order by min(ci 5 | -16380 (10 rows) +select ss, min(cint4) from aggfns where cfloat8 < 1000 group by ss order by min(cint4), ss limit 10; + ss | min +----+-------- + 0 | -16383 + 7 | -16383 + 11 | -16383 + 3 | -16382 + 4 | -16382 + 6 | -16382 + 8 | -16382 + 9 | -16382 + 5 | -16380 + | -15907 +(10 rows) + select stddev(cint4) from aggfns where cfloat8 < 1000; stddev ------------------- @@ -3442,6 +5798,21 @@ select s, stddev(cint4) from aggfns where cfloat8 < 1000 group by s order by std 5 | 9504.684751625578 (10 rows) +select ss, stddev(cint4) from aggfns where cfloat8 < 1000 group by ss order by stddev(cint4), ss limit 10; + ss | stddev +----+------------------- + | 9361.317298404296 + 0 | 9406.815855797801 + 6 | 9410.397911988306 + 9 | 9426.452583637956 + 4 | 9442.480718256247 + 8 | 9450.281544631633 + 11 | 9450.690059613938 + 3 | 9474.873657491443 + 7 | 9485.765898279180 + 5 | 9504.684751625578 +(10 rows) + select sum(cint4) from aggfns where cfloat8 < 1000; sum --------- @@ -3463,6 +5834,21 @@ select s, sum(cint4) from aggfns where cfloat8 < 1000 group by s order by sum(ci 5 | 2062138 (10 rows) +select ss, sum(cint4) from aggfns where cfloat8 < 1000 group by ss order by sum(cint4), ss limit 10; + ss | sum +----+---------- + 9 | -2048566 + 6 | -1063133 + 7 | -852243 + 11 | -657303 + 8 | -585231 + | 41756 + 4 | 193677 + 0 | 555073 + 3 | 1366449 + 5 | 2062138 +(10 rows) + select avg(cint8) from aggfns where cfloat8 < 1000; avg ---------------------- @@ -3484,6 +5870,21 @@ select s, avg(cint8) from aggfns where cfloat8 < 1000 group by s order by avg(ci 9 | 61.7467500000000000 (10 rows) +select ss, avg(cint8) from aggfns where cfloat8 < 1000 group by ss order by avg(cint8), ss limit 10; + ss | avg +----+----------------------- + 8 | -118.4870000000000000 + 5 | -81.6955500000000000 + 4 | -17.0811771182623492 + 11 | -15.1685449411529523 + 7 | -2.3563500000000000 + 6 | 11.9056500000000000 + 0 | 15.3018000000000000 + 3 | 37.6662329212752115 + 9 | 61.7467500000000000 + | 2467.2631578947368421 +(10 rows) + select max(cint8) from aggfns where cfloat8 < 1000; max ------- @@ -3505,6 +5906,21 @@ select s, max(cint8) from aggfns where cfloat8 < 1000 group by s order by max(ci 5 | 16383 (10 rows) +select ss, max(cint8) from aggfns where cfloat8 < 1000 group by ss order by max(cint8), ss limit 10; + ss | max +----+------- + | 13750 + 6 | 16380 + 7 | 16380 + 8 | 16380 + 3 | 16382 + 9 | 16382 + 0 | 16383 + 4 | 16383 + 5 | 16383 + 11 | 16383 +(10 rows) + select min(cint8) from aggfns where cfloat8 < 1000; min -------- @@ -3526,6 +5942,21 @@ select s, min(cint8) from aggfns where cfloat8 < 1000 group by s order by min(ci 3 | -16378 (10 rows) +select ss, min(cint8) from aggfns where cfloat8 < 1000 group by ss order by min(cint8), ss limit 10; + ss | min +----+-------- + 0 | -16383 + 6 | -16383 + 7 | -16383 + 8 | -16383 + 11 | -16383 + 5 | -16382 + 4 | -16381 + 9 | -16380 + 3 | -16378 + | -14174 +(10 rows) + select sum(cint8) from aggfns where cfloat8 < 1000; sum ---------- @@ -3547,6 +5978,21 @@ select s, sum(cint8) from aggfns where cfloat8 < 1000 group by s order by sum(ci 9 | 1234935 (10 rows) +select ss, sum(cint8) from aggfns where cfloat8 < 1000 group by ss order by sum(cint8), ss limit 10; + ss | sum +----+---------- + 8 | -2369740 + 5 | -1633911 + 11 | -607030 + 4 | -341299 + 7 | -47127 + | 46878 + 6 | 238113 + 0 | 306036 + 3 | 752609 + 9 | 1234935 +(10 rows) + select max(cts) from aggfns where cfloat8 < 1000; max -------------------------- @@ -3568,6 +6014,21 @@ select s, max(cts) from aggfns where cfloat8 < 1000 group by s order by max(cts) 9 | Sat Jan 02 02:01:01 2021 (10 rows) +select ss, max(cts) from aggfns where cfloat8 < 1000 group by ss order by max(cts), ss limit 10; + ss | max +----+-------------------------- + 0 | Fri Jan 01 01:01:01 2021 + 3 | Fri Jan 01 09:21:01 2021 + | Fri Jan 01 09:21:01 2021 + 4 | Fri Jan 01 12:07:41 2021 + 11 | Fri Jan 01 12:07:41 2021 + 5 | Fri Jan 01 14:54:21 2021 + 6 | Fri Jan 01 17:41:01 2021 + 7 | Fri Jan 01 20:27:41 2021 + 8 | Fri Jan 01 23:14:21 2021 + 9 | Sat Jan 02 02:01:01 2021 +(10 rows) + select min(cts) from aggfns where cfloat8 < 1000; min -------------------------- @@ -3589,6 +6050,21 @@ select s, min(cts) from aggfns where cfloat8 < 1000 group by s order by min(cts) 9 | Sat Jan 02 02:01:01 2021 (10 rows) +select ss, min(cts) from aggfns where cfloat8 < 1000 group by ss order by min(cts), ss limit 10; + ss | min +----+-------------------------- + 0 | Fri Jan 01 01:01:01 2021 + 11 | Fri Jan 01 03:47:41 2021 + 3 | Fri Jan 01 09:21:01 2021 + | Fri Jan 01 09:21:01 2021 + 4 | Fri Jan 01 12:07:41 2021 + 5 | Fri Jan 01 14:54:21 2021 + 6 | Fri Jan 01 17:41:01 2021 + 7 | Fri Jan 01 20:27:41 2021 + 8 | Fri Jan 01 23:14:21 2021 + 9 | Sat Jan 02 02:01:01 2021 +(10 rows) + select max(ctstz) from aggfns where cfloat8 < 1000; max ------------------------------ @@ -3610,6 +6086,21 @@ select s, max(ctstz) from aggfns where cfloat8 < 1000 group by s order by max(ct 9 | Sat Jan 02 02:01:01 2021 PST (10 rows) +select ss, max(ctstz) from aggfns where cfloat8 < 1000 group by ss order by max(ctstz), ss limit 10; + ss | max +----+------------------------------ + 0 | Fri Jan 01 01:01:01 2021 PST + 3 | Fri Jan 01 09:21:01 2021 PST + | Fri Jan 01 09:21:01 2021 PST + 4 | Fri Jan 01 12:07:41 2021 PST + 11 | Fri Jan 01 12:07:41 2021 PST + 5 | Fri Jan 01 14:54:21 2021 PST + 6 | Fri Jan 01 17:41:01 2021 PST + 7 | Fri Jan 01 20:27:41 2021 PST + 8 | Fri Jan 01 23:14:21 2021 PST + 9 | Sat Jan 02 02:01:01 2021 PST +(10 rows) + select min(ctstz) from aggfns where cfloat8 < 1000; min ------------------------------ @@ -3631,6 +6122,21 @@ select s, min(ctstz) from aggfns where cfloat8 < 1000 group by s order by min(ct 9 | Sat Jan 02 02:01:01 2021 PST (10 rows) +select ss, min(ctstz) from aggfns where cfloat8 < 1000 group by ss order by min(ctstz), ss limit 10; + ss | min +----+------------------------------ + 0 | Fri Jan 01 01:01:01 2021 PST + 11 | Fri Jan 01 03:47:41 2021 PST + 3 | Fri Jan 01 09:21:01 2021 PST + | Fri Jan 01 09:21:01 2021 PST + 4 | Fri Jan 01 12:07:41 2021 PST + 5 | Fri Jan 01 14:54:21 2021 PST + 6 | Fri Jan 01 17:41:01 2021 PST + 7 | Fri Jan 01 20:27:41 2021 PST + 8 | Fri Jan 01 23:14:21 2021 PST + 9 | Sat Jan 02 02:01:01 2021 PST +(10 rows) + select avg(s) from aggfns where cfloat8 < 1000; avg -------------------- @@ -3652,6 +6158,21 @@ select s, avg(s) from aggfns where cfloat8 < 1000 group by s order by avg(s), s 9 | 9.0000000000000000 (10 rows) +select ss, avg(s) from aggfns where cfloat8 < 1000 group by ss order by avg(s), ss limit 10; + ss | avg +----+---------------------------- + 0 | 0.000000000000000000000000 + 11 | 1.5011869362053025 + 3 | 3.0000000000000000 + | 3.0000000000000000 + 4 | 4.0000000000000000 + 5 | 5.0000000000000000 + 6 | 6.0000000000000000 + 7 | 7.0000000000000000 + 8 | 8.0000000000000000 + 9 | 9.0000000000000000 +(10 rows) + select count(s) from aggfns where cfloat8 < 1000; count -------- @@ -3673,6 +6194,21 @@ select s, count(s) from aggfns where cfloat8 < 1000 group by s order by count(s) 9 | 20000 (10 rows) +select ss, count(s) from aggfns where cfloat8 < 1000 group by ss order by count(s), ss limit 10; + ss | count +----+------- + | 19 + 3 | 19981 + 4 | 19981 + 0 | 20000 + 5 | 20000 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 + 11 | 40019 +(10 rows) + select max(s) from aggfns where cfloat8 < 1000; max ----- @@ -3694,6 +6230,21 @@ select s, max(s) from aggfns where cfloat8 < 1000 group by s order by max(s), s 9 | 9 (10 rows) +select ss, max(s) from aggfns where cfloat8 < 1000 group by ss order by max(s), ss limit 10; + ss | max +----+----- + 0 | 0 + 3 | 3 + | 3 + 4 | 4 + 11 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + select min(s) from aggfns where cfloat8 < 1000; min ----- @@ -3715,6 +6266,21 @@ select s, min(s) from aggfns where cfloat8 < 1000 group by s order by min(s), s 9 | 9 (10 rows) +select ss, min(s) from aggfns where cfloat8 < 1000 group by ss order by min(s), ss limit 10; + ss | min +----+----- + 0 | 0 + 11 | 1 + 3 | 3 + | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + select stddev(s) from aggfns where cfloat8 < 1000; stddev -------------------- @@ -3736,6 +6302,21 @@ select s, stddev(s) from aggfns where cfloat8 < 1000 group by s order by stddev( 9 | 0 (10 rows) +select ss, stddev(s) from aggfns where cfloat8 < 1000 group by ss order by stddev(s), ss limit 10; + ss | stddev +----+------------------------ + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + | 0 + 11 | 0.50284545977155885187 +(10 rows) + select sum(s) from aggfns where cfloat8 < 1000; sum -------- @@ -3757,6 +6338,21 @@ select s, sum(s) from aggfns where cfloat8 < 1000 group by s order by sum(s), s 9 | 180000 (10 rows) +select ss, sum(s) from aggfns where cfloat8 < 1000 group by ss order by sum(s), ss limit 10; + ss | sum +----+-------- + 0 | 0 + | 57 + 3 | 59943 + 11 | 60076 + 4 | 79924 + 5 | 100000 + 6 | 120000 + 7 | 140000 + 8 | 160000 + 9 | 180000 +(10 rows) + select avg(ss) from aggfns where cfloat8 < 1000; avg -------------------- @@ -3778,6 +6374,21 @@ select s, avg(ss) from aggfns where cfloat8 < 1000 group by s order by avg(ss), 2 | 11.0000000000000000 (10 rows) +select ss, avg(ss) from aggfns where cfloat8 < 1000 group by ss order by avg(ss), ss limit 10; + ss | avg +----+---------------------------- + 0 | 0.000000000000000000000000 + 3 | 3.0000000000000000 + 4 | 4.0000000000000000 + 5 | 5.0000000000000000 + 6 | 6.0000000000000000 + 7 | 7.0000000000000000 + 8 | 8.0000000000000000 + 9 | 9.0000000000000000 + 11 | 11.0000000000000000 + | +(10 rows) + select max(ss) from aggfns where cfloat8 < 1000; max ----- @@ -3799,6 +6410,21 @@ select s, max(ss) from aggfns where cfloat8 < 1000 group by s order by max(ss), 4 | 11 (10 rows) +select ss, max(ss) from aggfns where cfloat8 < 1000 group by ss order by max(ss), ss limit 10; + ss | max +----+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 11 | 11 + | +(10 rows) + select min(ss) from aggfns where cfloat8 < 1000; min ----- @@ -3820,6 +6446,21 @@ select s, min(ss) from aggfns where cfloat8 < 1000 group by s order by min(ss), 2 | 11 (10 rows) +select ss, min(ss) from aggfns where cfloat8 < 1000 group by ss order by min(ss), ss limit 10; + ss | min +----+----- + 0 | 0 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 11 | 11 + | +(10 rows) + select stddev(ss) from aggfns where cfloat8 < 1000; stddev -------------------- @@ -3841,6 +6482,21 @@ select s, stddev(ss) from aggfns where cfloat8 < 1000 group by s order by stddev 4 | 0.21565737387148452722 (10 rows) +select ss, stddev(ss) from aggfns where cfloat8 < 1000 group by ss order by stddev(ss), ss limit 10; + ss | stddev +----+-------- + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 + | +(10 rows) + select sum(ss) from aggfns where cfloat8 < 1000; sum --------- @@ -3862,6 +6518,21 @@ select s, sum(ss) from aggfns where cfloat8 < 1000 group by s order by sum(ss), 2 | 220000 (10 rows) +select ss, sum(ss) from aggfns where cfloat8 < 1000 group by ss order by sum(ss), ss limit 10; + ss | sum +----+-------- + 0 | 0 + 3 | 59943 + 4 | 79924 + 5 | 100000 + 6 | 120000 + 7 | 140000 + 8 | 160000 + 9 | 180000 + 11 | 440209 + | +(10 rows) + select max(t) from aggfns where cfloat8 < 1000; max -------- @@ -3883,6 +6554,21 @@ select s, max(t) from aggfns where cfloat8 < 1000 group by s order by max(t), s 9 | 110000 (10 rows) +select ss, max(t) from aggfns where cfloat8 < 1000 group by ss order by max(t), ss limit 10; + ss | max +----+-------- + 0 | 20000 + | 49491 + 3 | 50000 + 11 | 59192 + 4 | 60000 + 5 | 70000 + 6 | 80000 + 7 | 90000 + 8 | 100000 + 9 | 110000 +(10 rows) + select min(t) from aggfns where cfloat8 < 1000; min ----- @@ -3904,6 +6590,21 @@ select s, min(t) from aggfns where cfloat8 < 1000 group by s order by min(t), s 9 | 90001 (10 rows) +select ss, min(t) from aggfns where cfloat8 < 1000 group by ss order by min(t), ss limit 10; + ss | min +----+------- + 0 | 1 + 11 | 10001 + 3 | 30001 + | 30537 + 4 | 40001 + 5 | 50001 + 6 | 60001 + 7 | 70001 + 8 | 80001 + 9 | 90001 +(10 rows) + select count(*) from aggfns where cfloat8 > 1000; count ------- @@ -3915,6 +6616,11 @@ select s, count(*) from aggfns where cfloat8 > 1000 group by s order by count(*) ---+------- (0 rows) +select ss, count(*) from aggfns where cfloat8 > 1000 group by ss order by count(*), ss limit 10; + ss | count +----+------- +(0 rows) + select max(cdate) from aggfns where cfloat8 > 1000; max ----- @@ -3926,6 +6632,11 @@ select s, max(cdate) from aggfns where cfloat8 > 1000 group by s order by max(cd ---+----- (0 rows) +select ss, max(cdate) from aggfns where cfloat8 > 1000 group by ss order by max(cdate), ss limit 10; + ss | max +----+----- +(0 rows) + select min(cdate) from aggfns where cfloat8 > 1000; min ----- @@ -3937,6 +6648,11 @@ select s, min(cdate) from aggfns where cfloat8 > 1000 group by s order by min(cd ---+----- (0 rows) +select ss, min(cdate) from aggfns where cfloat8 > 1000 group by ss order by min(cdate), ss limit 10; + ss | min +----+----- +(0 rows) + select avg(cfloat4) from aggfns where cfloat8 > 1000; avg ----- @@ -3948,6 +6664,11 @@ select s, avg(cfloat4) from aggfns where cfloat8 > 1000 group by s order by avg( ---+----- (0 rows) +select ss, avg(cfloat4) from aggfns where cfloat8 > 1000 group by ss order by avg(cfloat4), ss limit 10; + ss | avg +----+----- +(0 rows) + select max(cfloat4) from aggfns where cfloat8 > 1000; max ----- @@ -3959,6 +6680,11 @@ select s, max(cfloat4) from aggfns where cfloat8 > 1000 group by s order by max( ---+----- (0 rows) +select ss, max(cfloat4) from aggfns where cfloat8 > 1000 group by ss order by max(cfloat4), ss limit 10; + ss | max +----+----- +(0 rows) + select min(cfloat4) from aggfns where cfloat8 > 1000; min ----- @@ -3970,6 +6696,11 @@ select s, min(cfloat4) from aggfns where cfloat8 > 1000 group by s order by min( ---+----- (0 rows) +select ss, min(cfloat4) from aggfns where cfloat8 > 1000 group by ss order by min(cfloat4), ss limit 10; + ss | min +----+----- +(0 rows) + select stddev(cfloat4) from aggfns where cfloat8 > 1000; stddev -------- @@ -3981,6 +6712,11 @@ select s, stddev(cfloat4) from aggfns where cfloat8 > 1000 group by s order by s ---+-------- (0 rows) +select ss, stddev(cfloat4) from aggfns where cfloat8 > 1000 group by ss order by stddev(cfloat4), ss limit 10; + ss | stddev +----+-------- +(0 rows) + select sum(cfloat4) from aggfns where cfloat8 > 1000; sum ----- @@ -3992,6 +6728,11 @@ select s, sum(cfloat4) from aggfns where cfloat8 > 1000 group by s order by sum( ---+----- (0 rows) +select ss, sum(cfloat4) from aggfns where cfloat8 > 1000 group by ss order by sum(cfloat4), ss limit 10; + ss | sum +----+----- +(0 rows) + select avg(cfloat8) from aggfns where cfloat8 > 1000; avg ----- @@ -4003,6 +6744,11 @@ select s, avg(cfloat8) from aggfns where cfloat8 > 1000 group by s order by avg( ---+----- (0 rows) +select ss, avg(cfloat8) from aggfns where cfloat8 > 1000 group by ss order by avg(cfloat8), ss limit 10; + ss | avg +----+----- +(0 rows) + select max(cfloat8) from aggfns where cfloat8 > 1000; max ----- @@ -4014,6 +6760,11 @@ select s, max(cfloat8) from aggfns where cfloat8 > 1000 group by s order by max( ---+----- (0 rows) +select ss, max(cfloat8) from aggfns where cfloat8 > 1000 group by ss order by max(cfloat8), ss limit 10; + ss | max +----+----- +(0 rows) + select min(cfloat8) from aggfns where cfloat8 > 1000; min ----- @@ -4025,6 +6776,11 @@ select s, min(cfloat8) from aggfns where cfloat8 > 1000 group by s order by min( ---+----- (0 rows) +select ss, min(cfloat8) from aggfns where cfloat8 > 1000 group by ss order by min(cfloat8), ss limit 10; + ss | min +----+----- +(0 rows) + select stddev(cfloat8) from aggfns where cfloat8 > 1000; stddev -------- @@ -4036,6 +6792,11 @@ select s, stddev(cfloat8) from aggfns where cfloat8 > 1000 group by s order by s ---+-------- (0 rows) +select ss, stddev(cfloat8) from aggfns where cfloat8 > 1000 group by ss order by stddev(cfloat8), ss limit 10; + ss | stddev +----+-------- +(0 rows) + select sum(cfloat8) from aggfns where cfloat8 > 1000; sum ----- @@ -4047,6 +6808,11 @@ select s, sum(cfloat8) from aggfns where cfloat8 > 1000 group by s order by sum( ---+----- (0 rows) +select ss, sum(cfloat8) from aggfns where cfloat8 > 1000 group by ss order by sum(cfloat8), ss limit 10; + ss | sum +----+----- +(0 rows) + select avg(cint2) from aggfns where cfloat8 > 1000; avg ----- @@ -4058,6 +6824,11 @@ select s, avg(cint2) from aggfns where cfloat8 > 1000 group by s order by avg(ci ---+----- (0 rows) +select ss, avg(cint2) from aggfns where cfloat8 > 1000 group by ss order by avg(cint2), ss limit 10; + ss | avg +----+----- +(0 rows) + select count(cint2) from aggfns where cfloat8 > 1000; count ------- @@ -4069,6 +6840,11 @@ select s, count(cint2) from aggfns where cfloat8 > 1000 group by s order by coun ---+------- (0 rows) +select ss, count(cint2) from aggfns where cfloat8 > 1000 group by ss order by count(cint2), ss limit 10; + ss | count +----+------- +(0 rows) + select max(cint2) from aggfns where cfloat8 > 1000; max ----- @@ -4080,6 +6856,11 @@ select s, max(cint2) from aggfns where cfloat8 > 1000 group by s order by max(ci ---+----- (0 rows) +select ss, max(cint2) from aggfns where cfloat8 > 1000 group by ss order by max(cint2), ss limit 10; + ss | max +----+----- +(0 rows) + select min(cint2) from aggfns where cfloat8 > 1000; min ----- @@ -4091,6 +6872,11 @@ select s, min(cint2) from aggfns where cfloat8 > 1000 group by s order by min(ci ---+----- (0 rows) +select ss, min(cint2) from aggfns where cfloat8 > 1000 group by ss order by min(cint2), ss limit 10; + ss | min +----+----- +(0 rows) + select stddev(cint2) from aggfns where cfloat8 > 1000; stddev -------- @@ -4101,6 +6887,11 @@ select s, stddev(cint2) from aggfns where cfloat8 > 1000 group by s order by std ---+-------- (0 rows) +select ss, stddev(cint2) from aggfns where cfloat8 > 1000 group by ss order by stddev(cint2), ss limit 10; + ss | stddev +----+-------- +(0 rows) + select sum(cint2) from aggfns where cfloat8 > 1000; sum ----- @@ -4112,6 +6903,11 @@ select s, sum(cint2) from aggfns where cfloat8 > 1000 group by s order by sum(ci ---+----- (0 rows) +select ss, sum(cint2) from aggfns where cfloat8 > 1000 group by ss order by sum(cint2), ss limit 10; + ss | sum +----+----- +(0 rows) + select avg(cint4) from aggfns where cfloat8 > 1000; avg ----- @@ -4123,6 +6919,11 @@ select s, avg(cint4) from aggfns where cfloat8 > 1000 group by s order by avg(ci ---+----- (0 rows) +select ss, avg(cint4) from aggfns where cfloat8 > 1000 group by ss order by avg(cint4), ss limit 10; + ss | avg +----+----- +(0 rows) + select max(cint4) from aggfns where cfloat8 > 1000; max ----- @@ -4134,6 +6935,11 @@ select s, max(cint4) from aggfns where cfloat8 > 1000 group by s order by max(ci ---+----- (0 rows) +select ss, max(cint4) from aggfns where cfloat8 > 1000 group by ss order by max(cint4), ss limit 10; + ss | max +----+----- +(0 rows) + select min(cint4) from aggfns where cfloat8 > 1000; min ----- @@ -4145,6 +6951,11 @@ select s, min(cint4) from aggfns where cfloat8 > 1000 group by s order by min(ci ---+----- (0 rows) +select ss, min(cint4) from aggfns where cfloat8 > 1000 group by ss order by min(cint4), ss limit 10; + ss | min +----+----- +(0 rows) + select stddev(cint4) from aggfns where cfloat8 > 1000; stddev -------- @@ -4155,6 +6966,11 @@ select s, stddev(cint4) from aggfns where cfloat8 > 1000 group by s order by std ---+-------- (0 rows) +select ss, stddev(cint4) from aggfns where cfloat8 > 1000 group by ss order by stddev(cint4), ss limit 10; + ss | stddev +----+-------- +(0 rows) + select sum(cint4) from aggfns where cfloat8 > 1000; sum ----- @@ -4166,6 +6982,11 @@ select s, sum(cint4) from aggfns where cfloat8 > 1000 group by s order by sum(ci ---+----- (0 rows) +select ss, sum(cint4) from aggfns where cfloat8 > 1000 group by ss order by sum(cint4), ss limit 10; + ss | sum +----+----- +(0 rows) + select avg(cint8) from aggfns where cfloat8 > 1000; avg ----- @@ -4176,6 +6997,11 @@ select s, avg(cint8) from aggfns where cfloat8 > 1000 group by s order by avg(ci ---+----- (0 rows) +select ss, avg(cint8) from aggfns where cfloat8 > 1000 group by ss order by avg(cint8), ss limit 10; + ss | avg +----+----- +(0 rows) + select max(cint8) from aggfns where cfloat8 > 1000; max ----- @@ -4187,6 +7013,11 @@ select s, max(cint8) from aggfns where cfloat8 > 1000 group by s order by max(ci ---+----- (0 rows) +select ss, max(cint8) from aggfns where cfloat8 > 1000 group by ss order by max(cint8), ss limit 10; + ss | max +----+----- +(0 rows) + select min(cint8) from aggfns where cfloat8 > 1000; min ----- @@ -4198,6 +7029,11 @@ select s, min(cint8) from aggfns where cfloat8 > 1000 group by s order by min(ci ---+----- (0 rows) +select ss, min(cint8) from aggfns where cfloat8 > 1000 group by ss order by min(cint8), ss limit 10; + ss | min +----+----- +(0 rows) + select sum(cint8) from aggfns where cfloat8 > 1000; sum ----- @@ -4208,6 +7044,11 @@ select s, sum(cint8) from aggfns where cfloat8 > 1000 group by s order by sum(ci ---+----- (0 rows) +select ss, sum(cint8) from aggfns where cfloat8 > 1000 group by ss order by sum(cint8), ss limit 10; + ss | sum +----+----- +(0 rows) + select max(cts) from aggfns where cfloat8 > 1000; max ----- @@ -4219,6 +7060,11 @@ select s, max(cts) from aggfns where cfloat8 > 1000 group by s order by max(cts) ---+----- (0 rows) +select ss, max(cts) from aggfns where cfloat8 > 1000 group by ss order by max(cts), ss limit 10; + ss | max +----+----- +(0 rows) + select min(cts) from aggfns where cfloat8 > 1000; min ----- @@ -4230,6 +7076,11 @@ select s, min(cts) from aggfns where cfloat8 > 1000 group by s order by min(cts) ---+----- (0 rows) +select ss, min(cts) from aggfns where cfloat8 > 1000 group by ss order by min(cts), ss limit 10; + ss | min +----+----- +(0 rows) + select max(ctstz) from aggfns where cfloat8 > 1000; max ----- @@ -4241,6 +7092,11 @@ select s, max(ctstz) from aggfns where cfloat8 > 1000 group by s order by max(ct ---+----- (0 rows) +select ss, max(ctstz) from aggfns where cfloat8 > 1000 group by ss order by max(ctstz), ss limit 10; + ss | max +----+----- +(0 rows) + select min(ctstz) from aggfns where cfloat8 > 1000; min ----- @@ -4252,6 +7108,11 @@ select s, min(ctstz) from aggfns where cfloat8 > 1000 group by s order by min(ct ---+----- (0 rows) +select ss, min(ctstz) from aggfns where cfloat8 > 1000 group by ss order by min(ctstz), ss limit 10; + ss | min +----+----- +(0 rows) + select avg(s) from aggfns where cfloat8 > 1000; avg ----- @@ -4263,6 +7124,11 @@ select s, avg(s) from aggfns where cfloat8 > 1000 group by s order by avg(s), s ---+----- (0 rows) +select ss, avg(s) from aggfns where cfloat8 > 1000 group by ss order by avg(s), ss limit 10; + ss | avg +----+----- +(0 rows) + select count(s) from aggfns where cfloat8 > 1000; count ------- @@ -4274,6 +7140,11 @@ select s, count(s) from aggfns where cfloat8 > 1000 group by s order by count(s) ---+------- (0 rows) +select ss, count(s) from aggfns where cfloat8 > 1000 group by ss order by count(s), ss limit 10; + ss | count +----+------- +(0 rows) + select max(s) from aggfns where cfloat8 > 1000; max ----- @@ -4285,6 +7156,11 @@ select s, max(s) from aggfns where cfloat8 > 1000 group by s order by max(s), s ---+----- (0 rows) +select ss, max(s) from aggfns where cfloat8 > 1000 group by ss order by max(s), ss limit 10; + ss | max +----+----- +(0 rows) + select min(s) from aggfns where cfloat8 > 1000; min ----- @@ -4296,6 +7172,11 @@ select s, min(s) from aggfns where cfloat8 > 1000 group by s order by min(s), s ---+----- (0 rows) +select ss, min(s) from aggfns where cfloat8 > 1000 group by ss order by min(s), ss limit 10; + ss | min +----+----- +(0 rows) + select stddev(s) from aggfns where cfloat8 > 1000; stddev -------- @@ -4306,6 +7187,11 @@ select s, stddev(s) from aggfns where cfloat8 > 1000 group by s order by stddev( ---+-------- (0 rows) +select ss, stddev(s) from aggfns where cfloat8 > 1000 group by ss order by stddev(s), ss limit 10; + ss | stddev +----+-------- +(0 rows) + select sum(s) from aggfns where cfloat8 > 1000; sum ----- @@ -4317,6 +7203,11 @@ select s, sum(s) from aggfns where cfloat8 > 1000 group by s order by sum(s), s ---+----- (0 rows) +select ss, sum(s) from aggfns where cfloat8 > 1000 group by ss order by sum(s), ss limit 10; + ss | sum +----+----- +(0 rows) + select avg(ss) from aggfns where cfloat8 > 1000; avg ----- @@ -4328,6 +7219,11 @@ select s, avg(ss) from aggfns where cfloat8 > 1000 group by s order by avg(ss), ---+----- (0 rows) +select ss, avg(ss) from aggfns where cfloat8 > 1000 group by ss order by avg(ss), ss limit 10; + ss | avg +----+----- +(0 rows) + select max(ss) from aggfns where cfloat8 > 1000; max ----- @@ -4339,6 +7235,11 @@ select s, max(ss) from aggfns where cfloat8 > 1000 group by s order by max(ss), ---+----- (0 rows) +select ss, max(ss) from aggfns where cfloat8 > 1000 group by ss order by max(ss), ss limit 10; + ss | max +----+----- +(0 rows) + select min(ss) from aggfns where cfloat8 > 1000; min ----- @@ -4350,6 +7251,11 @@ select s, min(ss) from aggfns where cfloat8 > 1000 group by s order by min(ss), ---+----- (0 rows) +select ss, min(ss) from aggfns where cfloat8 > 1000 group by ss order by min(ss), ss limit 10; + ss | min +----+----- +(0 rows) + select stddev(ss) from aggfns where cfloat8 > 1000; stddev -------- @@ -4360,6 +7266,11 @@ select s, stddev(ss) from aggfns where cfloat8 > 1000 group by s order by stddev ---+-------- (0 rows) +select ss, stddev(ss) from aggfns where cfloat8 > 1000 group by ss order by stddev(ss), ss limit 10; + ss | stddev +----+-------- +(0 rows) + select sum(ss) from aggfns where cfloat8 > 1000; sum ----- @@ -4371,6 +7282,11 @@ select s, sum(ss) from aggfns where cfloat8 > 1000 group by s order by sum(ss), ---+----- (0 rows) +select ss, sum(ss) from aggfns where cfloat8 > 1000 group by ss order by sum(ss), ss limit 10; + ss | sum +----+----- +(0 rows) + select max(t) from aggfns where cfloat8 > 1000; max ----- @@ -4382,6 +7298,11 @@ select s, max(t) from aggfns where cfloat8 > 1000 group by s order by max(t), s ---+----- (0 rows) +select ss, max(t) from aggfns where cfloat8 > 1000 group by ss order by max(t), ss limit 10; + ss | max +----+----- +(0 rows) + select min(t) from aggfns where cfloat8 > 1000; min ----- @@ -4393,6 +7314,11 @@ select s, min(t) from aggfns where cfloat8 > 1000 group by s order by min(t), s ---+----- (0 rows) +select ss, min(t) from aggfns where cfloat8 > 1000 group by ss order by min(t), ss limit 10; + ss | min +----+----- +(0 rows) + select avg(cint2) from aggfns where cint2 is null; avg ----- @@ -4414,6 +7340,20 @@ select s, avg(cint2) from aggfns where cint2 is null group by s order by avg(cin 9 | (10 rows) +select ss, avg(cint2) from aggfns where cint2 is null group by ss order by avg(cint2), ss limit 10; + ss | avg +----+----- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 11 | +(9 rows) + select count(cint2) from aggfns where cint2 is null; count ------- @@ -4435,6 +7375,20 @@ select s, count(cint2) from aggfns where cint2 is null group by s order by count 9 | 0 (10 rows) +select ss, count(cint2) from aggfns where cint2 is null group by ss order by count(cint2), ss limit 10; + ss | count +----+------- + 0 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 + 11 | 0 +(9 rows) + select max(cint2) from aggfns where cint2 is null; max ----- @@ -4456,6 +7410,20 @@ select s, max(cint2) from aggfns where cint2 is null group by s order by max(cin 9 | (10 rows) +select ss, max(cint2) from aggfns where cint2 is null group by ss order by max(cint2), ss limit 10; + ss | max +----+----- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 11 | +(9 rows) + select min(cint2) from aggfns where cint2 is null; min ----- @@ -4477,6 +7445,20 @@ select s, min(cint2) from aggfns where cint2 is null group by s order by min(cin 9 | (10 rows) +select ss, min(cint2) from aggfns where cint2 is null group by ss order by min(cint2), ss limit 10; + ss | min +----+----- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 11 | +(9 rows) + select stddev(cint2) from aggfns where cint2 is null; stddev -------- @@ -4498,6 +7480,20 @@ select s, stddev(cint2) from aggfns where cint2 is null group by s order by stdd 9 | (10 rows) +select ss, stddev(cint2) from aggfns where cint2 is null group by ss order by stddev(cint2), ss limit 10; + ss | stddev +----+-------- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 11 | +(9 rows) + select sum(cint2) from aggfns where cint2 is null; sum ----- @@ -4519,6 +7515,38 @@ select s, sum(cint2) from aggfns where cint2 is null group by s order by sum(cin 9 | (10 rows) +select ss, sum(cint2) from aggfns where cint2 is null group by ss order by sum(cint2), ss limit 10; + ss | sum +----+----- + 0 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + 11 | +(9 rows) + +-- Test multiple aggregate functions as well. +select count(*), count(cint2), min(cfloat4), cint2 from aggfns group by cint2 +order by count(*) desc, cint2 limit 10 +; + count | count | min | cint2 +-------+-------+----------+-------- + 190 | 0 | -49.6644 | + 19 | 19 | -49.5299 | -8743 + 17 | 17 | -48.5497 | -12921 + 17 | 17 | -48.5697 | -701 + 17 | 17 | -47.2641 | 525 + 16 | 16 | -42.41 | -10234 + 16 | 16 | -47.2083 | -4609 + 16 | 16 | -49.9555 | -4261 + 16 | 16 | -35.1643 | -296 + 16 | 16 | -45.4426 | 1373 +(10 rows) + -- Test edge cases for various batch sizes and the filter matching around batch -- end. select count(*) from edges; @@ -4588,3 +7616,45 @@ select s, count(*), min(f1) from edges where f1 = 65 group by 1 order by 1; 12 | 1 | 65 (8 rows) +select ss, count(*), min(f1) from edges where f1 = 63 group by 1 order by 1; + ss | count | min +----+-------+----- + 3 | 1 | 63 + 4 | 1 | 63 + 5 | 1 | 63 + 6 | 1 | 63 + 7 | 1 | 63 + 8 | 1 | 63 + 9 | 1 | 63 + 10 | 1 | 63 + 11 | 1 | 63 + 12 | 1 | 63 +(10 rows) + +select ss, count(*), min(f1) from edges where f1 = 64 group by 1 order by 1; + ss | count | min +----+-------+----- + 4 | 1 | 64 + 5 | 1 | 64 + 6 | 1 | 64 + 7 | 1 | 64 + 8 | 1 | 64 + 9 | 1 | 64 + 10 | 1 | 64 + 11 | 1 | 64 + 12 | 1 | 64 +(9 rows) + +select ss, count(*), min(f1) from edges where f1 = 65 group by 1 order by 1; + ss | count | min +----+-------+----- + 5 | 1 | 65 + 6 | 1 | 65 + 7 | 1 | 65 + 8 | 1 | 65 + 9 | 1 | 65 + 10 | 1 | 65 + 11 | 1 | 65 + 12 | 1 | 65 +(8 rows) + diff --git a/tsl/test/expected/vector_agg_grouping.out b/tsl/test/expected/vector_agg_grouping.out new file mode 100644 index 00000000000..a4bdc3bed86 --- /dev/null +++ b/tsl/test/expected/vector_agg_grouping.out @@ -0,0 +1,1985 @@ +-- This file and its contents are licensed under the Timescale License. +-- Please see the included NOTICE for copyright information and +-- LICENSE-TIMESCALE for a copy of the license. +\c :TEST_DBNAME :ROLE_SUPERUSER +-- helper function: float -> pseudorandom float [-0.5..0.5] +CREATE OR REPLACE FUNCTION mix(x anyelement) RETURNS float8 AS $$ + SELECT hashfloat8(x::float8) / pow(2, 32) +$$ LANGUAGE SQL; +\set CHUNKS 2::int +\set CHUNK_ROWS 100000::int +\set GROUPING_CARDINALITY 10::int +create table agggroup(t int, s int, + cint2 int2, cint4 int4, cint8 int8); +select create_hypertable('agggroup', 's', chunk_time_interval => :GROUPING_CARDINALITY / :CHUNKS); +NOTICE: adding not-null constraint to column "s" + create_hypertable +----------------------- + (1,public,agggroup,t) +(1 row) + +create view source as +select s * 10000 + t as t, + s, + case when t % 1051 = 0 then null + else (mix(s + t * 1019) * 32767)::int2 end as cint2, + (mix(s + t * 1021) * 32767)::int4 as cint4, + (mix(s + t * 1031) * 32767)::int8 as cint8 +from + generate_series(1::int, :CHUNK_ROWS * :CHUNKS / :GROUPING_CARDINALITY) t, + generate_series(0::int, :GROUPING_CARDINALITY - 1::int) s(s) +; +insert into agggroup select * from source where s = 1; +alter table agggroup set (timescaledb.compress, timescaledb.compress_orderby = 't', + timescaledb.compress_segmentby = 's'); +select count(compress_chunk(x)) from show_chunks('agggroup') x; + count +------- + 1 +(1 row) + +alter table agggroup add column ss int default 11; +alter table agggroup add column x text default '11'; +insert into agggroup +select *, ss::text as x from ( + select *, + case + -- null in entire batch + when s = 2 then null + -- null for some rows + when s = 3 and t % 1051 = 0 then null + -- for some rows same as default + when s = 4 and t % 1057 = 0 then 11 + -- not null for entire batch + else s + end as ss + from source where s != 1 +) t +; +select count(compress_chunk(x)) from show_chunks('agggroup') x; + count +------- + 2 +(1 row) + +vacuum freeze analyze agggroup; +set timescaledb.debug_require_vector_agg = 'require'; +---- Uncomment to generate reference. Note that there are minor discrepancies +---- on float4 due to different numeric stability in our and PG implementations. +--set timescaledb.enable_vectorized_aggregation to off; set timescaledb.debug_require_vector_agg = 'allow'; +select + format('%sselect %s%s(%s) from agggroup%s%s%s;', + explain, + grouping || ', ', + function, variable, + ' where ' || condition, + ' group by ' || grouping, + format(' order by %s(%s), ', function, variable) || grouping || ' limit 10', + function, variable) +from + unnest(array[ + 'explain (costs off) ', + null]) explain, + unnest(array[ + 'cint2', + '*']) variable, + unnest(array[ + 'min', + 'count']) function, + unnest(array[ + null, + 'cint2 > 0', + 'cint2 is null', + 'cint2 is null and x is null']) with ordinality as condition(condition, n), + unnest(array[ + null, + 'cint2', + 'cint4', + 'cint4, cint8', + 'cint8', + 's, cint2', + 's, ss', + 's, x', + 'ss, cint2, x', + 'ss, s', + 'ss, x, cint2', + 't, s, ss, x, cint4, cint8, cint2', + 'x']) with ordinality as grouping(grouping, n) +where + true + and (explain is null /* or condition is null and grouping = 's' */) + and (variable != '*' or function = 'count') +order by explain, condition.n, variable, function, grouping.n +\gexec +select count(*) from agggroup; + count +-------- + 200000 +(1 row) + +select cint2, count(*) from agggroup group by cint2 order by count(*), cint2 limit 10; + cint2 | count +--------+------- + -16216 | 1 + -16071 | 1 + -15916 | 1 + -15892 | 1 + -15891 | 1 + -15732 | 1 + -15693 | 1 + -15637 | 1 + -15620 | 1 + -15615 | 1 +(10 rows) + +select cint4, count(*) from agggroup group by cint4 order by count(*), cint4 limit 10; + cint4 | count +--------+------- + -16350 | 1 + -16237 | 1 + -16144 | 1 + -15987 | 1 + -15925 | 1 + -15862 | 1 + -15849 | 1 + -15825 | 1 + -15804 | 1 + -15760 | 1 +(10 rows) + +select cint4, cint8, count(*) from agggroup group by cint4, cint8 order by count(*), cint4, cint8 limit 10; + cint4 | cint8 | count +--------+-------+------- + -16383 | 4889 | 1 + -16383 | 7417 | 1 + -16383 | 8953 | 1 + -16382 | -8851 | 1 + -16382 | -8612 | 1 + -16382 | -5254 | 1 + -16382 | -4489 | 1 + -16382 | -470 | 1 + -16382 | 411 | 1 + -16382 | 899 | 1 +(10 rows) + +select cint8, count(*) from agggroup group by cint8 order by count(*), cint8 limit 10; + cint8 | count +--------+------- + -16342 | 1 + -16246 | 1 + -16197 | 1 + -16152 | 1 + -16064 | 1 + -15932 | 1 + -15908 | 1 + -15869 | 1 + -15819 | 1 + -15753 | 1 +(10 rows) + +select s, cint2, count(*) from agggroup group by s, cint2 order by count(*), s, cint2 limit 10; + s | cint2 | count +---+--------+------- + 0 | -16377 | 1 + 0 | -16376 | 1 + 0 | -16375 | 1 + 0 | -16373 | 1 + 0 | -16372 | 1 + 0 | -16371 | 1 + 0 | -16370 | 1 + 0 | -16369 | 1 + 0 | -16368 | 1 + 0 | -16367 | 1 +(10 rows) + +select s, ss, count(*) from agggroup group by s, ss order by count(*), s, ss limit 10; + s | ss | count +---+----+------- + 3 | | 19 + 4 | 11 | 19 + 3 | 3 | 19981 + 4 | 4 | 19981 + 0 | 0 | 20000 + 1 | 11 | 20000 + 2 | 11 | 20000 + 5 | 5 | 20000 + 6 | 6 | 20000 + 7 | 7 | 20000 +(10 rows) + +select s, x, count(*) from agggroup group by s, x order by count(*), s, x limit 10; + s | x | count +---+----+------- + 3 | | 19 + 4 | 11 | 19 + 3 | 3 | 19981 + 4 | 4 | 19981 + 0 | 0 | 20000 + 1 | 11 | 20000 + 2 | 11 | 20000 + 5 | 5 | 20000 + 6 | 6 | 20000 + 7 | 7 | 20000 +(10 rows) + +select ss, cint2, x, count(*) from agggroup group by ss, cint2, x order by count(*), ss, cint2, x limit 10; + ss | cint2 | x | count +----+--------+---+------- + 0 | -16377 | 0 | 1 + 0 | -16376 | 0 | 1 + 0 | -16375 | 0 | 1 + 0 | -16373 | 0 | 1 + 0 | -16372 | 0 | 1 + 0 | -16371 | 0 | 1 + 0 | -16370 | 0 | 1 + 0 | -16369 | 0 | 1 + 0 | -16368 | 0 | 1 + 0 | -16367 | 0 | 1 +(10 rows) + +select ss, s, count(*) from agggroup group by ss, s order by count(*), ss, s limit 10; + ss | s | count +----+---+------- + 11 | 4 | 19 + | 3 | 19 + 3 | 3 | 19981 + 4 | 4 | 19981 + 0 | 0 | 20000 + 5 | 5 | 20000 + 6 | 6 | 20000 + 7 | 7 | 20000 + 8 | 8 | 20000 + 9 | 9 | 20000 +(10 rows) + +select ss, x, cint2, count(*) from agggroup group by ss, x, cint2 order by count(*), ss, x, cint2 limit 10; + ss | x | cint2 | count +----+---+--------+------- + 0 | 0 | -16377 | 1 + 0 | 0 | -16376 | 1 + 0 | 0 | -16375 | 1 + 0 | 0 | -16373 | 1 + 0 | 0 | -16372 | 1 + 0 | 0 | -16371 | 1 + 0 | 0 | -16370 | 1 + 0 | 0 | -16369 | 1 + 0 | 0 | -16368 | 1 + 0 | 0 | -16367 | 1 +(10 rows) + +select t, s, ss, x, cint4, cint8, cint2, count(*) from agggroup group by t, s, ss, x, cint4, cint8, cint2 order by count(*), t, s, ss, x, cint4, cint8, cint2 limit 10; + t | s | ss | x | cint4 | cint8 | cint2 | count +----+---+----+---+--------+-------+--------+------- + 1 | 0 | 0 | 0 | -15736 | 12910 | 3398 | 1 + 2 | 0 | 0 | 0 | 1096 | -6638 | -5373 | 1 + 3 | 0 | 0 | 0 | -15920 | 13672 | -7109 | 1 + 4 | 0 | 0 | 0 | 14299 | -8187 | -4927 | 1 + 5 | 0 | 0 | 0 | 9267 | 6436 | 4859 | 1 + 6 | 0 | 0 | 0 | -5203 | 9870 | 12177 | 1 + 7 | 0 | 0 | 0 | 6620 | -781 | 5174 | 1 + 8 | 0 | 0 | 0 | -10427 | 876 | -12705 | 1 + 9 | 0 | 0 | 0 | -14954 | -1593 | 2257 | 1 + 10 | 0 | 0 | 0 | 10047 | -7626 | 3923 | 1 +(10 rows) + +select x, count(*) from agggroup group by x order by count(*), x limit 10; + x | count +----+------- + | 19 + 3 | 19981 + 4 | 19981 + 0 | 20000 + 5 | 20000 + 6 | 20000 + 7 | 20000 + 8 | 20000 + 9 | 20000 + 11 | 40019 +(10 rows) + +select count(cint2) from agggroup; + count +-------- + 199810 +(1 row) + +select cint2, count(cint2) from agggroup group by cint2 order by count(cint2), cint2 limit 10; + cint2 | count +--------+------- + | 0 + -16216 | 1 + -16071 | 1 + -15916 | 1 + -15892 | 1 + -15891 | 1 + -15732 | 1 + -15693 | 1 + -15637 | 1 + -15620 | 1 +(10 rows) + +select cint4, count(cint2) from agggroup group by cint4 order by count(cint2), cint4 limit 10; + cint4 | count +--------+------- + 8426 | 0 + -16350 | 1 + -16237 | 1 + -16144 | 1 + -15987 | 1 + -15925 | 1 + -15862 | 1 + -15849 | 1 + -15825 | 1 + -15804 | 1 +(10 rows) + +select cint4, cint8, count(cint2) from agggroup group by cint4, cint8 order by count(cint2), cint4, cint8 limit 10; + cint4 | cint8 | count +--------+--------+------- + -16291 | 113 | 0 + -16091 | -4084 | 0 + -15799 | 12603 | 0 + -15724 | 15426 | 0 + -15328 | -6092 | 0 + -15279 | -3475 | 0 + -15063 | 3990 | 0 + -14998 | 14464 | 0 + -14949 | -10395 | 0 + -14848 | 3110 | 0 +(10 rows) + +select cint8, count(cint2) from agggroup group by cint8 order by count(cint2), cint8 limit 10; + cint8 | count +--------+------- + -16342 | 1 + -16246 | 1 + -16197 | 1 + -16152 | 1 + -16064 | 1 + -15932 | 1 + -15908 | 1 + -15869 | 1 + -15819 | 1 + -15753 | 1 +(10 rows) + +select s, cint2, count(cint2) from agggroup group by s, cint2 order by count(cint2), s, cint2 limit 10; + s | cint2 | count +---+-------+------- + 0 | | 0 + 1 | | 0 + 2 | | 0 + 3 | | 0 + 4 | | 0 + 5 | | 0 + 6 | | 0 + 7 | | 0 + 8 | | 0 + 9 | | 0 +(10 rows) + +select s, ss, count(cint2) from agggroup group by s, ss order by count(cint2), s, ss limit 10; + s | ss | count +---+----+------- + 3 | | 19 + 4 | 11 | 19 + 3 | 3 | 19962 + 4 | 4 | 19962 + 0 | 0 | 19981 + 1 | 11 | 19981 + 2 | 11 | 19981 + 5 | 5 | 19981 + 6 | 6 | 19981 + 7 | 7 | 19981 +(10 rows) + +select s, x, count(cint2) from agggroup group by s, x order by count(cint2), s, x limit 10; + s | x | count +---+----+------- + 3 | | 19 + 4 | 11 | 19 + 3 | 3 | 19962 + 4 | 4 | 19962 + 0 | 0 | 19981 + 1 | 11 | 19981 + 2 | 11 | 19981 + 5 | 5 | 19981 + 6 | 6 | 19981 + 7 | 7 | 19981 +(10 rows) + +select ss, cint2, x, count(cint2) from agggroup group by ss, cint2, x order by count(cint2), ss, cint2, x limit 10; + ss | cint2 | x | count +----+--------+----+------- + 0 | | 0 | 0 + 3 | | 3 | 0 + 4 | | 4 | 0 + 5 | | 5 | 0 + 6 | | 6 | 0 + 7 | | 7 | 0 + 8 | | 8 | 0 + 9 | | 9 | 0 + 11 | | 11 | 0 + 0 | -16377 | 0 | 1 +(10 rows) + +select ss, s, count(cint2) from agggroup group by ss, s order by count(cint2), ss, s limit 10; + ss | s | count +----+---+------- + 11 | 4 | 19 + | 3 | 19 + 3 | 3 | 19962 + 4 | 4 | 19962 + 0 | 0 | 19981 + 5 | 5 | 19981 + 6 | 6 | 19981 + 7 | 7 | 19981 + 8 | 8 | 19981 + 9 | 9 | 19981 +(10 rows) + +select ss, x, cint2, count(cint2) from agggroup group by ss, x, cint2 order by count(cint2), ss, x, cint2 limit 10; + ss | x | cint2 | count +----+----+--------+------- + 0 | 0 | | 0 + 3 | 3 | | 0 + 4 | 4 | | 0 + 5 | 5 | | 0 + 6 | 6 | | 0 + 7 | 7 | | 0 + 8 | 8 | | 0 + 9 | 9 | | 0 + 11 | 11 | | 0 + 0 | 0 | -16377 | 1 +(10 rows) + +select t, s, ss, x, cint4, cint8, cint2, count(cint2) from agggroup group by t, s, ss, x, cint4, cint8, cint2 order by count(cint2), t, s, ss, x, cint4, cint8, cint2 limit 10; + t | s | ss | x | cint4 | cint8 | cint2 | count +-------+---+----+---+--------+--------+-------+------- + 1051 | 0 | 0 | 0 | -8612 | 14327 | | 0 + 2102 | 0 | 0 | 0 | 11069 | 16047 | | 0 + 3153 | 0 | 0 | 0 | 6192 | 12700 | | 0 + 4204 | 0 | 0 | 0 | 4165 | -10102 | | 0 + 5255 | 0 | 0 | 0 | 16314 | 13418 | | 0 + 6306 | 0 | 0 | 0 | 701 | -3029 | | 0 + 7357 | 0 | 0 | 0 | 1115 | 4913 | | 0 + 8408 | 0 | 0 | 0 | 15553 | 1743 | | 0 + 9459 | 0 | 0 | 0 | -14640 | 11933 | | 0 + 10510 | 0 | 0 | 0 | -14725 | 6531 | | 0 +(10 rows) + +select x, count(cint2) from agggroup group by x order by count(cint2), x limit 10; + x | count +----+------- + | 19 + 3 | 19962 + 4 | 19962 + 0 | 19981 + 5 | 19981 + 6 | 19981 + 7 | 19981 + 8 | 19981 + 9 | 19981 + 11 | 39981 +(10 rows) + +select min(cint2) from agggroup; + min +-------- + -16383 +(1 row) + +select cint2, min(cint2) from agggroup group by cint2 order by min(cint2), cint2 limit 10; + cint2 | min +--------+-------- + -16383 | -16383 + -16382 | -16382 + -16381 | -16381 + -16380 | -16380 + -16379 | -16379 + -16378 | -16378 + -16377 | -16377 + -16376 | -16376 + -16375 | -16375 + -16374 | -16374 +(10 rows) + +select cint4, min(cint2) from agggroup group by cint4 order by min(cint2), cint4 limit 10; + cint4 | min +--------+-------- + -16190 | -16383 + -13372 | -16383 + -10318 | -16383 + -9008 | -16383 + -3043 | -16383 + 6729 | -16383 + -14012 | -16382 + -8606 | -16382 + -3080 | -16382 + 2223 | -16382 +(10 rows) + +select cint4, cint8, min(cint2) from agggroup group by cint4, cint8 order by min(cint2), cint4, cint8 limit 10; + cint4 | cint8 | min +--------+--------+-------- + -16190 | 13646 | -16383 + -13372 | 11094 | -16383 + -10318 | 6326 | -16383 + -9008 | 4390 | -16383 + -3043 | -1794 | -16383 + 6729 | 6717 | -16383 + -14012 | -9888 | -16382 + -8606 | -10357 | -16382 + -3080 | -15609 | -16382 + 2223 | 9035 | -16382 +(10 rows) + +select cint8, min(cint2) from agggroup group by cint8 order by min(cint2), cint8 limit 10; + cint8 | min +--------+-------- + -1794 | -16383 + 4390 | -16383 + 6326 | -16383 + 6717 | -16383 + 11094 | -16383 + 13646 | -16383 + -15609 | -16382 + -10357 | -16382 + -9888 | -16382 + 206 | -16382 +(10 rows) + +select s, cint2, min(cint2) from agggroup group by s, cint2 order by min(cint2), s, cint2 limit 10; + s | cint2 | min +---+--------+-------- + 0 | -16383 | -16383 + 4 | -16383 | -16383 + 5 | -16383 | -16383 + 6 | -16383 | -16383 + 2 | -16382 | -16382 + 7 | -16382 | -16382 + 8 | -16382 | -16382 + 2 | -16381 | -16381 + 3 | -16381 | -16381 + 4 | -16381 | -16381 +(10 rows) + +select s, ss, min(cint2) from agggroup group by s, ss order by min(cint2), s, ss limit 10; + s | ss | min +---+----+-------- + 0 | 0 | -16383 + 4 | 4 | -16383 + 5 | 5 | -16383 + 6 | 6 | -16383 + 2 | 11 | -16382 + 7 | 7 | -16382 + 8 | 8 | -16382 + 3 | 3 | -16381 + 1 | 11 | -16378 + 9 | 9 | -16375 +(10 rows) + +select s, x, min(cint2) from agggroup group by s, x order by min(cint2), s, x limit 10; + s | x | min +---+----+-------- + 0 | 0 | -16383 + 4 | 4 | -16383 + 5 | 5 | -16383 + 6 | 6 | -16383 + 2 | 11 | -16382 + 7 | 7 | -16382 + 8 | 8 | -16382 + 3 | 3 | -16381 + 1 | 11 | -16378 + 9 | 9 | -16375 +(10 rows) + +select ss, cint2, x, min(cint2) from agggroup group by ss, cint2, x order by min(cint2), ss, cint2, x limit 10; + ss | cint2 | x | min +----+--------+----+-------- + 0 | -16383 | 0 | -16383 + 4 | -16383 | 4 | -16383 + 5 | -16383 | 5 | -16383 + 6 | -16383 | 6 | -16383 + 7 | -16382 | 7 | -16382 + 8 | -16382 | 8 | -16382 + 11 | -16382 | 11 | -16382 + 3 | -16381 | 3 | -16381 + 4 | -16381 | 4 | -16381 + 5 | -16381 | 5 | -16381 +(10 rows) + +select ss, s, min(cint2) from agggroup group by ss, s order by min(cint2), ss, s limit 10; + ss | s | min +----+---+-------- + 0 | 0 | -16383 + 4 | 4 | -16383 + 5 | 5 | -16383 + 6 | 6 | -16383 + 7 | 7 | -16382 + 8 | 8 | -16382 + 11 | 2 | -16382 + 3 | 3 | -16381 + 11 | 1 | -16378 + 9 | 9 | -16375 +(10 rows) + +select ss, x, cint2, min(cint2) from agggroup group by ss, x, cint2 order by min(cint2), ss, x, cint2 limit 10; + ss | x | cint2 | min +----+----+--------+-------- + 0 | 0 | -16383 | -16383 + 4 | 4 | -16383 | -16383 + 5 | 5 | -16383 | -16383 + 6 | 6 | -16383 | -16383 + 7 | 7 | -16382 | -16382 + 8 | 8 | -16382 | -16382 + 11 | 11 | -16382 | -16382 + 3 | 3 | -16381 | -16381 + 4 | 4 | -16381 | -16381 + 5 | 5 | -16381 | -16381 +(10 rows) + +select t, s, ss, x, cint4, cint8, cint2, min(cint2) from agggroup group by t, s, ss, x, cint4, cint8, cint2 order by min(cint2), t, s, ss, x, cint4, cint8, cint2 limit 10; + t | s | ss | x | cint4 | cint8 | cint2 | min +-------+---+----+----+--------+--------+--------+-------- + 6194 | 0 | 0 | 0 | -13372 | 11094 | -16383 | -16383 + 17044 | 0 | 0 | 0 | -10318 | 6326 | -16383 | -16383 + 53843 | 4 | 4 | 4 | -9008 | 4390 | -16383 | -16383 + 60530 | 5 | 5 | 5 | 6729 | 6717 | -16383 | -16383 + 73208 | 6 | 6 | 6 | -3043 | -1794 | -16383 | -16383 + 74870 | 6 | 6 | 6 | -16190 | 13646 | -16383 | -16383 + 22836 | 2 | 11 | 11 | -3080 | -15609 | -16382 | -16382 + 29858 | 2 | 11 | 11 | -14012 | -9888 | -16382 | -16382 + 31516 | 2 | 11 | 11 | 6193 | 206 | -16382 | -16382 + 76781 | 7 | 7 | 7 | 9938 | 6519 | -16382 | -16382 +(10 rows) + +select x, min(cint2) from agggroup group by x order by min(cint2), x limit 10; + x | min +----+-------- + 0 | -16383 + 4 | -16383 + 5 | -16383 + 6 | -16383 + 11 | -16382 + 7 | -16382 + 8 | -16382 + 3 | -16381 + 9 | -16375 + | -16295 +(10 rows) + +select count(*) from agggroup where cint2 > 0; + count +------- + 99664 +(1 row) + +select cint2, count(*) from agggroup where cint2 > 0 group by cint2 order by count(*), cint2 limit 10; + cint2 | count +-------+------- + 153 | 1 + 290 | 1 + 490 | 1 + 605 | 1 + 666 | 1 + 700 | 1 + 780 | 1 + 851 | 1 + 936 | 1 + 1001 | 1 +(10 rows) + +select cint4, count(*) from agggroup where cint2 > 0 group by cint4 order by count(*), cint4 limit 10; + cint4 | count +--------+------- + -16383 | 1 + -16380 | 1 + -16371 | 1 + -16368 | 1 + -16366 | 1 + -16365 | 1 + -16363 | 1 + -16360 | 1 + -16356 | 1 + -16350 | 1 +(10 rows) + +select cint4, cint8, count(*) from agggroup where cint2 > 0 group by cint4, cint8 order by count(*), cint4, cint8 limit 10; + cint4 | cint8 | count +--------+-------+------- + -16383 | 4889 | 1 + -16382 | -8851 | 1 + -16382 | -4489 | 1 + -16382 | -470 | 1 + -16382 | 411 | 1 + -16382 | 8377 | 1 + -16382 | 8832 | 1 + -16382 | 15709 | 1 + -16380 | 1449 | 1 + -16379 | 1234 | 1 +(10 rows) + +select cint8, count(*) from agggroup where cint2 > 0 group by cint8 order by count(*), cint8 limit 10; + cint8 | count +--------+------- + -16382 | 1 + -16378 | 1 + -16372 | 1 + -16353 | 1 + -16342 | 1 + -16338 | 1 + -16337 | 1 + -16336 | 1 + -16330 | 1 + -16328 | 1 +(10 rows) + +select s, cint2, count(*) from agggroup where cint2 > 0 group by s, cint2 order by count(*), s, cint2 limit 10; + s | cint2 | count +---+-------+------- + 0 | 4 | 1 + 0 | 7 | 1 + 0 | 8 | 1 + 0 | 9 | 1 + 0 | 10 | 1 + 0 | 11 | 1 + 0 | 18 | 1 + 0 | 24 | 1 + 0 | 28 | 1 + 0 | 31 | 1 +(10 rows) + +select s, ss, count(*) from agggroup where cint2 > 0 group by s, ss order by count(*), s, ss limit 10; + s | ss | count +---+----+------- + 3 | | 9 + 4 | 11 | 9 + 2 | 11 | 9868 + 3 | 3 | 9884 + 6 | 6 | 9890 + 4 | 4 | 9897 + 8 | 8 | 9898 + 7 | 7 | 9973 + 0 | 0 | 10012 + 9 | 9 | 10018 +(10 rows) + +select s, x, count(*) from agggroup where cint2 > 0 group by s, x order by count(*), s, x limit 10; + s | x | count +---+----+------- + 3 | | 9 + 4 | 11 | 9 + 2 | 11 | 9868 + 3 | 3 | 9884 + 6 | 6 | 9890 + 4 | 4 | 9897 + 8 | 8 | 9898 + 7 | 7 | 9973 + 0 | 0 | 10012 + 9 | 9 | 10018 +(10 rows) + +select ss, cint2, x, count(*) from agggroup where cint2 > 0 group by ss, cint2, x order by count(*), ss, cint2, x limit 10; + ss | cint2 | x | count +----+-------+---+------- + 0 | 4 | 0 | 1 + 0 | 7 | 0 | 1 + 0 | 8 | 0 | 1 + 0 | 9 | 0 | 1 + 0 | 10 | 0 | 1 + 0 | 11 | 0 | 1 + 0 | 18 | 0 | 1 + 0 | 24 | 0 | 1 + 0 | 28 | 0 | 1 + 0 | 31 | 0 | 1 +(10 rows) + +select ss, s, count(*) from agggroup where cint2 > 0 group by ss, s order by count(*), ss, s limit 10; + ss | s | count +----+---+------- + 11 | 4 | 9 + | 3 | 9 + 11 | 2 | 9868 + 3 | 3 | 9884 + 6 | 6 | 9890 + 4 | 4 | 9897 + 8 | 8 | 9898 + 7 | 7 | 9973 + 0 | 0 | 10012 + 9 | 9 | 10018 +(10 rows) + +select ss, x, cint2, count(*) from agggroup where cint2 > 0 group by ss, x, cint2 order by count(*), ss, x, cint2 limit 10; + ss | x | cint2 | count +----+---+-------+------- + 0 | 0 | 4 | 1 + 0 | 0 | 7 | 1 + 0 | 0 | 8 | 1 + 0 | 0 | 9 | 1 + 0 | 0 | 10 | 1 + 0 | 0 | 11 | 1 + 0 | 0 | 18 | 1 + 0 | 0 | 24 | 1 + 0 | 0 | 28 | 1 + 0 | 0 | 31 | 1 +(10 rows) + +select t, s, ss, x, cint4, cint8, cint2, count(*) from agggroup where cint2 > 0 group by t, s, ss, x, cint4, cint8, cint2 order by count(*), t, s, ss, x, cint4, cint8, cint2 limit 10; + t | s | ss | x | cint4 | cint8 | cint2 | count +----+---+----+---+--------+-------+-------+------- + 1 | 0 | 0 | 0 | -15736 | 12910 | 3398 | 1 + 5 | 0 | 0 | 0 | 9267 | 6436 | 4859 | 1 + 6 | 0 | 0 | 0 | -5203 | 9870 | 12177 | 1 + 7 | 0 | 0 | 0 | 6620 | -781 | 5174 | 1 + 9 | 0 | 0 | 0 | -14954 | -1593 | 2257 | 1 + 10 | 0 | 0 | 0 | 10047 | -7626 | 3923 | 1 + 14 | 0 | 0 | 0 | -13766 | -398 | 4669 | 1 + 15 | 0 | 0 | 0 | -13009 | 14045 | 15101 | 1 + 19 | 0 | 0 | 0 | -16257 | 4566 | 7684 | 1 + 22 | 0 | 0 | 0 | -6345 | -8658 | 11755 | 1 +(10 rows) + +select x, count(*) from agggroup where cint2 > 0 group by x order by count(*), x limit 10; + x | count +----+------- + | 9 + 3 | 9884 + 6 | 9890 + 4 | 9897 + 8 | 9898 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 5 | 10110 + 11 | 19973 +(10 rows) + +select count(cint2) from agggroup where cint2 > 0; + count +------- + 99664 +(1 row) + +select cint2, count(cint2) from agggroup where cint2 > 0 group by cint2 order by count(cint2), cint2 limit 10; + cint2 | count +-------+------- + 153 | 1 + 290 | 1 + 490 | 1 + 605 | 1 + 666 | 1 + 700 | 1 + 780 | 1 + 851 | 1 + 936 | 1 + 1001 | 1 +(10 rows) + +select cint4, count(cint2) from agggroup where cint2 > 0 group by cint4 order by count(cint2), cint4 limit 10; + cint4 | count +--------+------- + -16383 | 1 + -16380 | 1 + -16371 | 1 + -16368 | 1 + -16366 | 1 + -16365 | 1 + -16363 | 1 + -16360 | 1 + -16356 | 1 + -16350 | 1 +(10 rows) + +select cint4, cint8, count(cint2) from agggroup where cint2 > 0 group by cint4, cint8 order by count(cint2), cint4, cint8 limit 10; + cint4 | cint8 | count +--------+-------+------- + -16383 | 4889 | 1 + -16382 | -8851 | 1 + -16382 | -4489 | 1 + -16382 | -470 | 1 + -16382 | 411 | 1 + -16382 | 8377 | 1 + -16382 | 8832 | 1 + -16382 | 15709 | 1 + -16380 | 1449 | 1 + -16379 | 1234 | 1 +(10 rows) + +select cint8, count(cint2) from agggroup where cint2 > 0 group by cint8 order by count(cint2), cint8 limit 10; + cint8 | count +--------+------- + -16382 | 1 + -16378 | 1 + -16372 | 1 + -16353 | 1 + -16342 | 1 + -16338 | 1 + -16337 | 1 + -16336 | 1 + -16330 | 1 + -16328 | 1 +(10 rows) + +select s, cint2, count(cint2) from agggroup where cint2 > 0 group by s, cint2 order by count(cint2), s, cint2 limit 10; + s | cint2 | count +---+-------+------- + 0 | 4 | 1 + 0 | 7 | 1 + 0 | 8 | 1 + 0 | 9 | 1 + 0 | 10 | 1 + 0 | 11 | 1 + 0 | 18 | 1 + 0 | 24 | 1 + 0 | 28 | 1 + 0 | 31 | 1 +(10 rows) + +select s, ss, count(cint2) from agggroup where cint2 > 0 group by s, ss order by count(cint2), s, ss limit 10; + s | ss | count +---+----+------- + 3 | | 9 + 4 | 11 | 9 + 2 | 11 | 9868 + 3 | 3 | 9884 + 6 | 6 | 9890 + 4 | 4 | 9897 + 8 | 8 | 9898 + 7 | 7 | 9973 + 0 | 0 | 10012 + 9 | 9 | 10018 +(10 rows) + +select s, x, count(cint2) from agggroup where cint2 > 0 group by s, x order by count(cint2), s, x limit 10; + s | x | count +---+----+------- + 3 | | 9 + 4 | 11 | 9 + 2 | 11 | 9868 + 3 | 3 | 9884 + 6 | 6 | 9890 + 4 | 4 | 9897 + 8 | 8 | 9898 + 7 | 7 | 9973 + 0 | 0 | 10012 + 9 | 9 | 10018 +(10 rows) + +select ss, cint2, x, count(cint2) from agggroup where cint2 > 0 group by ss, cint2, x order by count(cint2), ss, cint2, x limit 10; + ss | cint2 | x | count +----+-------+---+------- + 0 | 4 | 0 | 1 + 0 | 7 | 0 | 1 + 0 | 8 | 0 | 1 + 0 | 9 | 0 | 1 + 0 | 10 | 0 | 1 + 0 | 11 | 0 | 1 + 0 | 18 | 0 | 1 + 0 | 24 | 0 | 1 + 0 | 28 | 0 | 1 + 0 | 31 | 0 | 1 +(10 rows) + +select ss, s, count(cint2) from agggroup where cint2 > 0 group by ss, s order by count(cint2), ss, s limit 10; + ss | s | count +----+---+------- + 11 | 4 | 9 + | 3 | 9 + 11 | 2 | 9868 + 3 | 3 | 9884 + 6 | 6 | 9890 + 4 | 4 | 9897 + 8 | 8 | 9898 + 7 | 7 | 9973 + 0 | 0 | 10012 + 9 | 9 | 10018 +(10 rows) + +select ss, x, cint2, count(cint2) from agggroup where cint2 > 0 group by ss, x, cint2 order by count(cint2), ss, x, cint2 limit 10; + ss | x | cint2 | count +----+---+-------+------- + 0 | 0 | 4 | 1 + 0 | 0 | 7 | 1 + 0 | 0 | 8 | 1 + 0 | 0 | 9 | 1 + 0 | 0 | 10 | 1 + 0 | 0 | 11 | 1 + 0 | 0 | 18 | 1 + 0 | 0 | 24 | 1 + 0 | 0 | 28 | 1 + 0 | 0 | 31 | 1 +(10 rows) + +select t, s, ss, x, cint4, cint8, cint2, count(cint2) from agggroup where cint2 > 0 group by t, s, ss, x, cint4, cint8, cint2 order by count(cint2), t, s, ss, x, cint4, cint8, cint2 limit 10; + t | s | ss | x | cint4 | cint8 | cint2 | count +----+---+----+---+--------+-------+-------+------- + 1 | 0 | 0 | 0 | -15736 | 12910 | 3398 | 1 + 5 | 0 | 0 | 0 | 9267 | 6436 | 4859 | 1 + 6 | 0 | 0 | 0 | -5203 | 9870 | 12177 | 1 + 7 | 0 | 0 | 0 | 6620 | -781 | 5174 | 1 + 9 | 0 | 0 | 0 | -14954 | -1593 | 2257 | 1 + 10 | 0 | 0 | 0 | 10047 | -7626 | 3923 | 1 + 14 | 0 | 0 | 0 | -13766 | -398 | 4669 | 1 + 15 | 0 | 0 | 0 | -13009 | 14045 | 15101 | 1 + 19 | 0 | 0 | 0 | -16257 | 4566 | 7684 | 1 + 22 | 0 | 0 | 0 | -6345 | -8658 | 11755 | 1 +(10 rows) + +select x, count(cint2) from agggroup where cint2 > 0 group by x order by count(cint2), x limit 10; + x | count +----+------- + | 9 + 3 | 9884 + 6 | 9890 + 4 | 9897 + 8 | 9898 + 7 | 9973 + 0 | 10012 + 9 | 10018 + 5 | 10110 + 11 | 19973 +(10 rows) + +select min(cint2) from agggroup where cint2 > 0; + min +----- + 1 +(1 row) + +select cint2, min(cint2) from agggroup where cint2 > 0 group by cint2 order by min(cint2), cint2 limit 10; + cint2 | min +-------+----- + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 10 | 10 +(10 rows) + +select cint4, min(cint2) from agggroup where cint2 > 0 group by cint4 order by min(cint2), cint4 limit 10; + cint4 | min +--------+----- + -12025 | 1 + -10344 | 1 + -4190 | 1 + -1493 | 1 + 1863 | 1 + 9242 | 1 + 11189 | 1 + 14078 | 1 + 15656 | 1 + -11410 | 2 +(10 rows) + +select cint4, cint8, min(cint2) from agggroup where cint2 > 0 group by cint4, cint8 order by min(cint2), cint4, cint8 limit 10; + cint4 | cint8 | min +--------+--------+----- + -12025 | -2210 | 1 + -10344 | -13684 | 1 + -4190 | -2827 | 1 + -1493 | -1043 | 1 + 1863 | 7650 | 1 + 9242 | -9798 | 1 + 11189 | -5168 | 1 + 14078 | 9929 | 1 + 15656 | 12597 | 1 + -11410 | 6033 | 2 +(10 rows) + +select cint8, min(cint2) from agggroup where cint2 > 0 group by cint8 order by min(cint2), cint8 limit 10; + cint8 | min +--------+----- + -13684 | 1 + -9798 | 1 + -5168 | 1 + -2827 | 1 + -2210 | 1 + -1043 | 1 + 7650 | 1 + 9929 | 1 + 12597 | 1 + -13639 | 2 +(10 rows) + +select s, cint2, min(cint2) from agggroup where cint2 > 0 group by s, cint2 order by min(cint2), s, cint2 limit 10; + s | cint2 | min +---+-------+----- + 1 | 1 | 1 + 2 | 1 | 1 + 3 | 1 | 1 + 5 | 1 | 1 + 7 | 1 | 1 + 8 | 1 | 1 + 1 | 2 | 2 + 3 | 2 | 2 + 7 | 2 | 2 + 9 | 2 | 2 +(10 rows) + +select s, ss, min(cint2) from agggroup where cint2 > 0 group by s, ss order by min(cint2), s, ss limit 10; + s | ss | min +---+----+----- + 1 | 11 | 1 + 2 | 11 | 1 + 3 | 3 | 1 + 5 | 5 | 1 + 7 | 7 | 1 + 8 | 8 | 1 + 9 | 9 | 2 + 6 | 6 | 3 + 0 | 0 | 4 + 4 | 4 | 4 +(10 rows) + +select s, x, min(cint2) from agggroup where cint2 > 0 group by s, x order by min(cint2), s, x limit 10; + s | x | min +---+----+----- + 1 | 11 | 1 + 2 | 11 | 1 + 3 | 3 | 1 + 5 | 5 | 1 + 7 | 7 | 1 + 8 | 8 | 1 + 9 | 9 | 2 + 6 | 6 | 3 + 0 | 0 | 4 + 4 | 4 | 4 +(10 rows) + +select ss, cint2, x, min(cint2) from agggroup where cint2 > 0 group by ss, cint2, x order by min(cint2), ss, cint2, x limit 10; + ss | cint2 | x | min +----+-------+----+----- + 3 | 1 | 3 | 1 + 5 | 1 | 5 | 1 + 7 | 1 | 7 | 1 + 8 | 1 | 8 | 1 + 11 | 1 | 11 | 1 + 3 | 2 | 3 | 2 + 7 | 2 | 7 | 2 + 9 | 2 | 9 | 2 + 11 | 2 | 11 | 2 + 3 | 3 | 3 | 3 +(10 rows) + +select ss, s, min(cint2) from agggroup where cint2 > 0 group by ss, s order by min(cint2), ss, s limit 10; + ss | s | min +----+---+----- + 3 | 3 | 1 + 5 | 5 | 1 + 7 | 7 | 1 + 8 | 8 | 1 + 11 | 1 | 1 + 11 | 2 | 1 + 9 | 9 | 2 + 6 | 6 | 3 + 0 | 0 | 4 + 4 | 4 | 4 +(10 rows) + +select ss, x, cint2, min(cint2) from agggroup where cint2 > 0 group by ss, x, cint2 order by min(cint2), ss, x, cint2 limit 10; + ss | x | cint2 | min +----+----+-------+----- + 3 | 3 | 1 | 1 + 5 | 5 | 1 | 1 + 7 | 7 | 1 | 1 + 8 | 8 | 1 | 1 + 11 | 11 | 1 | 1 + 3 | 3 | 2 | 2 + 7 | 7 | 2 | 2 + 9 | 9 | 2 | 2 + 11 | 11 | 2 | 2 + 3 | 3 | 3 | 3 +(10 rows) + +select t, s, ss, x, cint4, cint8, cint2, min(cint2) from agggroup where cint2 > 0 group by t, s, ss, x, cint4, cint8, cint2 order by min(cint2), t, s, ss, x, cint4, cint8, cint2 limit 10; + t | s | ss | x | cint4 | cint8 | cint2 | min +-------+---+----+----+--------+--------+-------+----- + 11611 | 1 | 11 | 11 | -12025 | -2210 | 1 | 1 + 28649 | 2 | 11 | 11 | -1493 | -1043 | 1 | 1 + 28786 | 1 | 11 | 11 | -4190 | -2827 | 1 | 1 + 41774 | 3 | 3 | 3 | 1863 | 7650 | 1 | 1 + 41779 | 3 | 3 | 3 | 14078 | 9929 | 1 | 1 + 51152 | 5 | 5 | 5 | 9242 | -9798 | 1 | 1 + 70932 | 7 | 7 | 7 | -10344 | -13684 | 1 | 1 + 86957 | 7 | 7 | 7 | 15656 | 12597 | 1 | 1 + 89689 | 8 | 8 | 8 | 11189 | -5168 | 1 | 1 + 22147 | 1 | 11 | 11 | -9569 | 9760 | 2 | 2 +(10 rows) + +select x, min(cint2) from agggroup where cint2 > 0 group by x order by min(cint2), x limit 10; + x | min +----+------ + 11 | 1 + 3 | 1 + 5 | 1 + 7 | 1 + 8 | 1 + 9 | 2 + 6 | 3 + 0 | 4 + 4 | 4 + | 4895 +(10 rows) + +select count(*) from agggroup where cint2 is null; + count +------- + 190 +(1 row) + +select cint2, count(*) from agggroup where cint2 is null group by cint2 order by count(*), cint2 limit 10; + cint2 | count +-------+------- + | 190 +(1 row) + +select cint4, count(*) from agggroup where cint2 is null group by cint4 order by count(*), cint4 limit 10; + cint4 | count +--------+------- + -16291 | 1 + -16091 | 1 + -15799 | 1 + -15724 | 1 + -15328 | 1 + -15279 | 1 + -15063 | 1 + -14998 | 1 + -14949 | 1 + -14848 | 1 +(10 rows) + +select cint4, cint8, count(*) from agggroup where cint2 is null group by cint4, cint8 order by count(*), cint4, cint8 limit 10; + cint4 | cint8 | count +--------+--------+------- + -16291 | 113 | 1 + -16091 | -4084 | 1 + -15799 | 12603 | 1 + -15724 | 15426 | 1 + -15328 | -6092 | 1 + -15279 | -3475 | 1 + -15063 | 3990 | 1 + -14998 | 14464 | 1 + -14949 | -10395 | 1 + -14848 | 3110 | 1 +(10 rows) + +select cint8, count(*) from agggroup where cint2 is null group by cint8 order by count(*), cint8 limit 10; + cint8 | count +--------+------- + -16026 | 1 + -15987 | 1 + -15904 | 1 + -15897 | 1 + -15761 | 1 + -15506 | 1 + -15346 | 1 + -14986 | 1 + -14811 | 1 + -14674 | 1 +(10 rows) + +select s, cint2, count(*) from agggroup where cint2 is null group by s, cint2 order by count(*), s, cint2 limit 10; + s | cint2 | count +---+-------+------- + 0 | | 19 + 1 | | 19 + 2 | | 19 + 3 | | 19 + 4 | | 19 + 5 | | 19 + 6 | | 19 + 7 | | 19 + 8 | | 19 + 9 | | 19 +(10 rows) + +select s, ss, count(*) from agggroup where cint2 is null group by s, ss order by count(*), s, ss limit 10; + s | ss | count +---+----+------- + 0 | 0 | 19 + 1 | 11 | 19 + 2 | 11 | 19 + 3 | 3 | 19 + 4 | 4 | 19 + 5 | 5 | 19 + 6 | 6 | 19 + 7 | 7 | 19 + 8 | 8 | 19 + 9 | 9 | 19 +(10 rows) + +select s, x, count(*) from agggroup where cint2 is null group by s, x order by count(*), s, x limit 10; + s | x | count +---+----+------- + 0 | 0 | 19 + 1 | 11 | 19 + 2 | 11 | 19 + 3 | 3 | 19 + 4 | 4 | 19 + 5 | 5 | 19 + 6 | 6 | 19 + 7 | 7 | 19 + 8 | 8 | 19 + 9 | 9 | 19 +(10 rows) + +select ss, cint2, x, count(*) from agggroup where cint2 is null group by ss, cint2, x order by count(*), ss, cint2, x limit 10; + ss | cint2 | x | count +----+-------+----+------- + 0 | | 0 | 19 + 3 | | 3 | 19 + 4 | | 4 | 19 + 5 | | 5 | 19 + 6 | | 6 | 19 + 7 | | 7 | 19 + 8 | | 8 | 19 + 9 | | 9 | 19 + 11 | | 11 | 38 +(9 rows) + +select ss, s, count(*) from agggroup where cint2 is null group by ss, s order by count(*), ss, s limit 10; + ss | s | count +----+---+------- + 0 | 0 | 19 + 3 | 3 | 19 + 4 | 4 | 19 + 5 | 5 | 19 + 6 | 6 | 19 + 7 | 7 | 19 + 8 | 8 | 19 + 9 | 9 | 19 + 11 | 1 | 19 + 11 | 2 | 19 +(10 rows) + +select ss, x, cint2, count(*) from agggroup where cint2 is null group by ss, x, cint2 order by count(*), ss, x, cint2 limit 10; + ss | x | cint2 | count +----+----+-------+------- + 0 | 0 | | 19 + 3 | 3 | | 19 + 4 | 4 | | 19 + 5 | 5 | | 19 + 6 | 6 | | 19 + 7 | 7 | | 19 + 8 | 8 | | 19 + 9 | 9 | | 19 + 11 | 11 | | 38 +(9 rows) + +select t, s, ss, x, cint4, cint8, cint2, count(*) from agggroup where cint2 is null group by t, s, ss, x, cint4, cint8, cint2 order by count(*), t, s, ss, x, cint4, cint8, cint2 limit 10; + t | s | ss | x | cint4 | cint8 | cint2 | count +-------+---+----+---+--------+--------+-------+------- + 1051 | 0 | 0 | 0 | -8612 | 14327 | | 1 + 2102 | 0 | 0 | 0 | 11069 | 16047 | | 1 + 3153 | 0 | 0 | 0 | 6192 | 12700 | | 1 + 4204 | 0 | 0 | 0 | 4165 | -10102 | | 1 + 5255 | 0 | 0 | 0 | 16314 | 13418 | | 1 + 6306 | 0 | 0 | 0 | 701 | -3029 | | 1 + 7357 | 0 | 0 | 0 | 1115 | 4913 | | 1 + 8408 | 0 | 0 | 0 | 15553 | 1743 | | 1 + 9459 | 0 | 0 | 0 | -14640 | 11933 | | 1 + 10510 | 0 | 0 | 0 | -14725 | 6531 | | 1 +(10 rows) + +select x, count(*) from agggroup where cint2 is null group by x order by count(*), x limit 10; + x | count +----+------- + 0 | 19 + 3 | 19 + 4 | 19 + 5 | 19 + 6 | 19 + 7 | 19 + 8 | 19 + 9 | 19 + 11 | 38 +(9 rows) + +select count(cint2) from agggroup where cint2 is null; + count +------- + 0 +(1 row) + +select cint2, count(cint2) from agggroup where cint2 is null group by cint2 order by count(cint2), cint2 limit 10; + cint2 | count +-------+------- + | 0 +(1 row) + +select cint4, count(cint2) from agggroup where cint2 is null group by cint4 order by count(cint2), cint4 limit 10; + cint4 | count +--------+------- + -16291 | 0 + -16091 | 0 + -15799 | 0 + -15724 | 0 + -15328 | 0 + -15279 | 0 + -15063 | 0 + -14998 | 0 + -14949 | 0 + -14848 | 0 +(10 rows) + +select cint4, cint8, count(cint2) from agggroup where cint2 is null group by cint4, cint8 order by count(cint2), cint4, cint8 limit 10; + cint4 | cint8 | count +--------+--------+------- + -16291 | 113 | 0 + -16091 | -4084 | 0 + -15799 | 12603 | 0 + -15724 | 15426 | 0 + -15328 | -6092 | 0 + -15279 | -3475 | 0 + -15063 | 3990 | 0 + -14998 | 14464 | 0 + -14949 | -10395 | 0 + -14848 | 3110 | 0 +(10 rows) + +select cint8, count(cint2) from agggroup where cint2 is null group by cint8 order by count(cint2), cint8 limit 10; + cint8 | count +--------+------- + -16026 | 0 + -15987 | 0 + -15904 | 0 + -15897 | 0 + -15761 | 0 + -15506 | 0 + -15346 | 0 + -14986 | 0 + -14811 | 0 + -14674 | 0 +(10 rows) + +select s, cint2, count(cint2) from agggroup where cint2 is null group by s, cint2 order by count(cint2), s, cint2 limit 10; + s | cint2 | count +---+-------+------- + 0 | | 0 + 1 | | 0 + 2 | | 0 + 3 | | 0 + 4 | | 0 + 5 | | 0 + 6 | | 0 + 7 | | 0 + 8 | | 0 + 9 | | 0 +(10 rows) + +select s, ss, count(cint2) from agggroup where cint2 is null group by s, ss order by count(cint2), s, ss limit 10; + s | ss | count +---+----+------- + 0 | 0 | 0 + 1 | 11 | 0 + 2 | 11 | 0 + 3 | 3 | 0 + 4 | 4 | 0 + 5 | 5 | 0 + 6 | 6 | 0 + 7 | 7 | 0 + 8 | 8 | 0 + 9 | 9 | 0 +(10 rows) + +select s, x, count(cint2) from agggroup where cint2 is null group by s, x order by count(cint2), s, x limit 10; + s | x | count +---+----+------- + 0 | 0 | 0 + 1 | 11 | 0 + 2 | 11 | 0 + 3 | 3 | 0 + 4 | 4 | 0 + 5 | 5 | 0 + 6 | 6 | 0 + 7 | 7 | 0 + 8 | 8 | 0 + 9 | 9 | 0 +(10 rows) + +select ss, cint2, x, count(cint2) from agggroup where cint2 is null group by ss, cint2, x order by count(cint2), ss, cint2, x limit 10; + ss | cint2 | x | count +----+-------+----+------- + 0 | | 0 | 0 + 3 | | 3 | 0 + 4 | | 4 | 0 + 5 | | 5 | 0 + 6 | | 6 | 0 + 7 | | 7 | 0 + 8 | | 8 | 0 + 9 | | 9 | 0 + 11 | | 11 | 0 +(9 rows) + +select ss, s, count(cint2) from agggroup where cint2 is null group by ss, s order by count(cint2), ss, s limit 10; + ss | s | count +----+---+------- + 0 | 0 | 0 + 3 | 3 | 0 + 4 | 4 | 0 + 5 | 5 | 0 + 6 | 6 | 0 + 7 | 7 | 0 + 8 | 8 | 0 + 9 | 9 | 0 + 11 | 1 | 0 + 11 | 2 | 0 +(10 rows) + +select ss, x, cint2, count(cint2) from agggroup where cint2 is null group by ss, x, cint2 order by count(cint2), ss, x, cint2 limit 10; + ss | x | cint2 | count +----+----+-------+------- + 0 | 0 | | 0 + 3 | 3 | | 0 + 4 | 4 | | 0 + 5 | 5 | | 0 + 6 | 6 | | 0 + 7 | 7 | | 0 + 8 | 8 | | 0 + 9 | 9 | | 0 + 11 | 11 | | 0 +(9 rows) + +select t, s, ss, x, cint4, cint8, cint2, count(cint2) from agggroup where cint2 is null group by t, s, ss, x, cint4, cint8, cint2 order by count(cint2), t, s, ss, x, cint4, cint8, cint2 limit 10; + t | s | ss | x | cint4 | cint8 | cint2 | count +-------+---+----+---+--------+--------+-------+------- + 1051 | 0 | 0 | 0 | -8612 | 14327 | | 0 + 2102 | 0 | 0 | 0 | 11069 | 16047 | | 0 + 3153 | 0 | 0 | 0 | 6192 | 12700 | | 0 + 4204 | 0 | 0 | 0 | 4165 | -10102 | | 0 + 5255 | 0 | 0 | 0 | 16314 | 13418 | | 0 + 6306 | 0 | 0 | 0 | 701 | -3029 | | 0 + 7357 | 0 | 0 | 0 | 1115 | 4913 | | 0 + 8408 | 0 | 0 | 0 | 15553 | 1743 | | 0 + 9459 | 0 | 0 | 0 | -14640 | 11933 | | 0 + 10510 | 0 | 0 | 0 | -14725 | 6531 | | 0 +(10 rows) + +select x, count(cint2) from agggroup where cint2 is null group by x order by count(cint2), x limit 10; + x | count +----+------- + 0 | 0 + 11 | 0 + 3 | 0 + 4 | 0 + 5 | 0 + 6 | 0 + 7 | 0 + 8 | 0 + 9 | 0 +(9 rows) + +select min(cint2) from agggroup where cint2 is null; + min +----- + +(1 row) + +select cint2, min(cint2) from agggroup where cint2 is null group by cint2 order by min(cint2), cint2 limit 10; + cint2 | min +-------+----- + | +(1 row) + +select cint4, min(cint2) from agggroup where cint2 is null group by cint4 order by min(cint2), cint4 limit 10; + cint4 | min +--------+----- + -16291 | + -16091 | + -15799 | + -15724 | + -15328 | + -15279 | + -15063 | + -14998 | + -14949 | + -14848 | +(10 rows) + +select cint4, cint8, min(cint2) from agggroup where cint2 is null group by cint4, cint8 order by min(cint2), cint4, cint8 limit 10; + cint4 | cint8 | min +--------+--------+----- + -16291 | 113 | + -16091 | -4084 | + -15799 | 12603 | + -15724 | 15426 | + -15328 | -6092 | + -15279 | -3475 | + -15063 | 3990 | + -14998 | 14464 | + -14949 | -10395 | + -14848 | 3110 | +(10 rows) + +select cint8, min(cint2) from agggroup where cint2 is null group by cint8 order by min(cint2), cint8 limit 10; + cint8 | min +--------+----- + -16026 | + -15987 | + -15904 | + -15897 | + -15761 | + -15506 | + -15346 | + -14986 | + -14811 | + -14674 | +(10 rows) + +select s, cint2, min(cint2) from agggroup where cint2 is null group by s, cint2 order by min(cint2), s, cint2 limit 10; + s | cint2 | min +---+-------+----- + 0 | | + 1 | | + 2 | | + 3 | | + 4 | | + 5 | | + 6 | | + 7 | | + 8 | | + 9 | | +(10 rows) + +select s, ss, min(cint2) from agggroup where cint2 is null group by s, ss order by min(cint2), s, ss limit 10; + s | ss | min +---+----+----- + 0 | 0 | + 1 | 11 | + 2 | 11 | + 3 | 3 | + 4 | 4 | + 5 | 5 | + 6 | 6 | + 7 | 7 | + 8 | 8 | + 9 | 9 | +(10 rows) + +select s, x, min(cint2) from agggroup where cint2 is null group by s, x order by min(cint2), s, x limit 10; + s | x | min +---+----+----- + 0 | 0 | + 1 | 11 | + 2 | 11 | + 3 | 3 | + 4 | 4 | + 5 | 5 | + 6 | 6 | + 7 | 7 | + 8 | 8 | + 9 | 9 | +(10 rows) + +select ss, cint2, x, min(cint2) from agggroup where cint2 is null group by ss, cint2, x order by min(cint2), ss, cint2, x limit 10; + ss | cint2 | x | min +----+-------+----+----- + 0 | | 0 | + 3 | | 3 | + 4 | | 4 | + 5 | | 5 | + 6 | | 6 | + 7 | | 7 | + 8 | | 8 | + 9 | | 9 | + 11 | | 11 | +(9 rows) + +select ss, s, min(cint2) from agggroup where cint2 is null group by ss, s order by min(cint2), ss, s limit 10; + ss | s | min +----+---+----- + 0 | 0 | + 3 | 3 | + 4 | 4 | + 5 | 5 | + 6 | 6 | + 7 | 7 | + 8 | 8 | + 9 | 9 | + 11 | 1 | + 11 | 2 | +(10 rows) + +select ss, x, cint2, min(cint2) from agggroup where cint2 is null group by ss, x, cint2 order by min(cint2), ss, x, cint2 limit 10; + ss | x | cint2 | min +----+----+-------+----- + 0 | 0 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | | + 7 | 7 | | + 8 | 8 | | + 9 | 9 | | + 11 | 11 | | +(9 rows) + +select t, s, ss, x, cint4, cint8, cint2, min(cint2) from agggroup where cint2 is null group by t, s, ss, x, cint4, cint8, cint2 order by min(cint2), t, s, ss, x, cint4, cint8, cint2 limit 10; + t | s | ss | x | cint4 | cint8 | cint2 | min +-------+---+----+---+--------+--------+-------+----- + 1051 | 0 | 0 | 0 | -8612 | 14327 | | + 2102 | 0 | 0 | 0 | 11069 | 16047 | | + 3153 | 0 | 0 | 0 | 6192 | 12700 | | + 4204 | 0 | 0 | 0 | 4165 | -10102 | | + 5255 | 0 | 0 | 0 | 16314 | 13418 | | + 6306 | 0 | 0 | 0 | 701 | -3029 | | + 7357 | 0 | 0 | 0 | 1115 | 4913 | | + 8408 | 0 | 0 | 0 | 15553 | 1743 | | + 9459 | 0 | 0 | 0 | -14640 | 11933 | | + 10510 | 0 | 0 | 0 | -14725 | 6531 | | +(10 rows) + +select x, min(cint2) from agggroup where cint2 is null group by x order by min(cint2), x limit 10; + x | min +----+----- + 0 | + 11 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +(9 rows) + +select count(*) from agggroup where cint2 is null and x is null; + count +------- + 0 +(1 row) + +select cint2, count(*) from agggroup where cint2 is null and x is null group by cint2 order by count(*), cint2 limit 10; + cint2 | count +-------+------- +(0 rows) + +select cint4, count(*) from agggroup where cint2 is null and x is null group by cint4 order by count(*), cint4 limit 10; + cint4 | count +-------+------- +(0 rows) + +select cint4, cint8, count(*) from agggroup where cint2 is null and x is null group by cint4, cint8 order by count(*), cint4, cint8 limit 10; + cint4 | cint8 | count +-------+-------+------- +(0 rows) + +select cint8, count(*) from agggroup where cint2 is null and x is null group by cint8 order by count(*), cint8 limit 10; + cint8 | count +-------+------- +(0 rows) + +select s, cint2, count(*) from agggroup where cint2 is null and x is null group by s, cint2 order by count(*), s, cint2 limit 10; + s | cint2 | count +---+-------+------- +(0 rows) + +select s, ss, count(*) from agggroup where cint2 is null and x is null group by s, ss order by count(*), s, ss limit 10; + s | ss | count +---+----+------- +(0 rows) + +select s, x, count(*) from agggroup where cint2 is null and x is null group by s, x order by count(*), s, x limit 10; + s | x | count +---+---+------- +(0 rows) + +select ss, cint2, x, count(*) from agggroup where cint2 is null and x is null group by ss, cint2, x order by count(*), ss, cint2, x limit 10; + ss | cint2 | x | count +----+-------+---+------- +(0 rows) + +select ss, s, count(*) from agggroup where cint2 is null and x is null group by ss, s order by count(*), ss, s limit 10; + ss | s | count +----+---+------- +(0 rows) + +select ss, x, cint2, count(*) from agggroup where cint2 is null and x is null group by ss, x, cint2 order by count(*), ss, x, cint2 limit 10; + ss | x | cint2 | count +----+---+-------+------- +(0 rows) + +select t, s, ss, x, cint4, cint8, cint2, count(*) from agggroup where cint2 is null and x is null group by t, s, ss, x, cint4, cint8, cint2 order by count(*), t, s, ss, x, cint4, cint8, cint2 limit 10; + t | s | ss | x | cint4 | cint8 | cint2 | count +---+---+----+---+-------+-------+-------+------- +(0 rows) + +select x, count(*) from agggroup where cint2 is null and x is null group by x order by count(*), x limit 10; + x | count +---+------- +(0 rows) + +select count(cint2) from agggroup where cint2 is null and x is null; + count +------- + 0 +(1 row) + +select cint2, count(cint2) from agggroup where cint2 is null and x is null group by cint2 order by count(cint2), cint2 limit 10; + cint2 | count +-------+------- +(0 rows) + +select cint4, count(cint2) from agggroup where cint2 is null and x is null group by cint4 order by count(cint2), cint4 limit 10; + cint4 | count +-------+------- +(0 rows) + +select cint4, cint8, count(cint2) from agggroup where cint2 is null and x is null group by cint4, cint8 order by count(cint2), cint4, cint8 limit 10; + cint4 | cint8 | count +-------+-------+------- +(0 rows) + +select cint8, count(cint2) from agggroup where cint2 is null and x is null group by cint8 order by count(cint2), cint8 limit 10; + cint8 | count +-------+------- +(0 rows) + +select s, cint2, count(cint2) from agggroup where cint2 is null and x is null group by s, cint2 order by count(cint2), s, cint2 limit 10; + s | cint2 | count +---+-------+------- +(0 rows) + +select s, ss, count(cint2) from agggroup where cint2 is null and x is null group by s, ss order by count(cint2), s, ss limit 10; + s | ss | count +---+----+------- +(0 rows) + +select s, x, count(cint2) from agggroup where cint2 is null and x is null group by s, x order by count(cint2), s, x limit 10; + s | x | count +---+---+------- +(0 rows) + +select ss, cint2, x, count(cint2) from agggroup where cint2 is null and x is null group by ss, cint2, x order by count(cint2), ss, cint2, x limit 10; + ss | cint2 | x | count +----+-------+---+------- +(0 rows) + +select ss, s, count(cint2) from agggroup where cint2 is null and x is null group by ss, s order by count(cint2), ss, s limit 10; + ss | s | count +----+---+------- +(0 rows) + +select ss, x, cint2, count(cint2) from agggroup where cint2 is null and x is null group by ss, x, cint2 order by count(cint2), ss, x, cint2 limit 10; + ss | x | cint2 | count +----+---+-------+------- +(0 rows) + +select t, s, ss, x, cint4, cint8, cint2, count(cint2) from agggroup where cint2 is null and x is null group by t, s, ss, x, cint4, cint8, cint2 order by count(cint2), t, s, ss, x, cint4, cint8, cint2 limit 10; + t | s | ss | x | cint4 | cint8 | cint2 | count +---+---+----+---+-------+-------+-------+------- +(0 rows) + +select x, count(cint2) from agggroup where cint2 is null and x is null group by x order by count(cint2), x limit 10; + x | count +---+------- +(0 rows) + +select min(cint2) from agggroup where cint2 is null and x is null; + min +----- + +(1 row) + +select cint2, min(cint2) from agggroup where cint2 is null and x is null group by cint2 order by min(cint2), cint2 limit 10; + cint2 | min +-------+----- +(0 rows) + +select cint4, min(cint2) from agggroup where cint2 is null and x is null group by cint4 order by min(cint2), cint4 limit 10; + cint4 | min +-------+----- +(0 rows) + +select cint4, cint8, min(cint2) from agggroup where cint2 is null and x is null group by cint4, cint8 order by min(cint2), cint4, cint8 limit 10; + cint4 | cint8 | min +-------+-------+----- +(0 rows) + +select cint8, min(cint2) from agggroup where cint2 is null and x is null group by cint8 order by min(cint2), cint8 limit 10; + cint8 | min +-------+----- +(0 rows) + +select s, cint2, min(cint2) from agggroup where cint2 is null and x is null group by s, cint2 order by min(cint2), s, cint2 limit 10; + s | cint2 | min +---+-------+----- +(0 rows) + +select s, ss, min(cint2) from agggroup where cint2 is null and x is null group by s, ss order by min(cint2), s, ss limit 10; + s | ss | min +---+----+----- +(0 rows) + +select s, x, min(cint2) from agggroup where cint2 is null and x is null group by s, x order by min(cint2), s, x limit 10; + s | x | min +---+---+----- +(0 rows) + +select ss, cint2, x, min(cint2) from agggroup where cint2 is null and x is null group by ss, cint2, x order by min(cint2), ss, cint2, x limit 10; + ss | cint2 | x | min +----+-------+---+----- +(0 rows) + +select ss, s, min(cint2) from agggroup where cint2 is null and x is null group by ss, s order by min(cint2), ss, s limit 10; + ss | s | min +----+---+----- +(0 rows) + +select ss, x, cint2, min(cint2) from agggroup where cint2 is null and x is null group by ss, x, cint2 order by min(cint2), ss, x, cint2 limit 10; + ss | x | cint2 | min +----+---+-------+----- +(0 rows) + +select t, s, ss, x, cint4, cint8, cint2, min(cint2) from agggroup where cint2 is null and x is null group by t, s, ss, x, cint4, cint8, cint2 order by min(cint2), t, s, ss, x, cint4, cint8, cint2 limit 10; + t | s | ss | x | cint4 | cint8 | cint2 | min +---+---+----+---+-------+-------+-------+----- +(0 rows) + +select x, min(cint2) from agggroup where cint2 is null and x is null group by x order by min(cint2), x limit 10; + x | min +---+----- +(0 rows) + +reset timescaledb.debug_require_vector_agg; +create table long(t int, a text, b text, c text, d text); +select create_hypertable('long', 't'); +NOTICE: adding not-null constraint to column "t" + create_hypertable +------------------- + (3,public,long,t) +(1 row) + +insert into long select n, x, x, x, x from ( + select n, repeat('1', 100 * 4 + n) x + from generate_series(1, 4) n) t +; +insert into long values (-1, 'a', 'b', 'c', 'd'); +alter table long set (timescaledb.compress); +WARNING: there was some uncertainty picking the default segment by for the hypertable: You do not have any indexes on columns that can be used for segment_by and thus we are not using segment_by for compression. Please make sure you are not missing any indexes +NOTICE: default segment by for hypertable "long" is set to "" +NOTICE: default order by for hypertable "long" is set to "t DESC" +select count(compress_chunk(x)) from show_chunks('long') x; + count +------- + 2 +(1 row) + +set timescaledb.debug_require_vector_agg = 'require'; +select count(*) from long group by a, b, c, d order by 1 limit 10; + count +------- + 1 + 1 + 1 + 1 + 1 +(5 rows) + +reset timescaledb.debug_require_vector_agg; diff --git a/tsl/test/expected/vectorized_aggregation.out b/tsl/test/expected/vectorized_aggregation.out index 63ff6ed337c..687c566abfe 100644 --- a/tsl/test/expected/vectorized_aggregation.out +++ b/tsl/test/expected/vectorized_aggregation.out @@ -403,23 +403,23 @@ SELECT sum(segment_by_value) FROM testtable GROUP BY float_value; Output: _hyper_1_1_chunk.float_value, (PARTIAL sum(_hyper_1_1_chunk.segment_by_value)) Workers Planned: 2 -> Parallel Append - -> Partial HashAggregate - Output: _hyper_1_1_chunk.float_value, PARTIAL sum(_hyper_1_1_chunk.segment_by_value) - Group Key: _hyper_1_1_chunk.float_value + -> Custom Scan (VectorAgg) + Output: _hyper_1_1_chunk.float_value, (PARTIAL sum(_hyper_1_1_chunk.segment_by_value)) + Grouping Policy: hashed with single 8-byte key -> Custom Scan (DecompressChunk) on _timescaledb_internal._hyper_1_1_chunk Output: _hyper_1_1_chunk.float_value, _hyper_1_1_chunk.segment_by_value -> Parallel Seq Scan on _timescaledb_internal.compress_hyper_2_11_chunk Output: compress_hyper_2_11_chunk._ts_meta_count, compress_hyper_2_11_chunk.segment_by_value, compress_hyper_2_11_chunk._ts_meta_min_1, compress_hyper_2_11_chunk._ts_meta_max_1, compress_hyper_2_11_chunk."time", compress_hyper_2_11_chunk.int_value, compress_hyper_2_11_chunk.float_value - -> Partial HashAggregate - Output: _hyper_1_2_chunk.float_value, PARTIAL sum(_hyper_1_2_chunk.segment_by_value) - Group Key: _hyper_1_2_chunk.float_value + -> Custom Scan (VectorAgg) + Output: _hyper_1_2_chunk.float_value, (PARTIAL sum(_hyper_1_2_chunk.segment_by_value)) + Grouping Policy: hashed with single 8-byte key -> Custom Scan (DecompressChunk) on _timescaledb_internal._hyper_1_2_chunk Output: _hyper_1_2_chunk.float_value, _hyper_1_2_chunk.segment_by_value -> Parallel Seq Scan on _timescaledb_internal.compress_hyper_2_12_chunk Output: compress_hyper_2_12_chunk._ts_meta_count, compress_hyper_2_12_chunk.segment_by_value, compress_hyper_2_12_chunk._ts_meta_min_1, compress_hyper_2_12_chunk._ts_meta_max_1, compress_hyper_2_12_chunk."time", compress_hyper_2_12_chunk.int_value, compress_hyper_2_12_chunk.float_value - -> Partial HashAggregate - Output: _hyper_1_3_chunk.float_value, PARTIAL sum(_hyper_1_3_chunk.segment_by_value) - Group Key: _hyper_1_3_chunk.float_value + -> Custom Scan (VectorAgg) + Output: _hyper_1_3_chunk.float_value, (PARTIAL sum(_hyper_1_3_chunk.segment_by_value)) + Grouping Policy: hashed with single 8-byte key -> Custom Scan (DecompressChunk) on _timescaledb_internal._hyper_1_3_chunk Output: _hyper_1_3_chunk.float_value, _hyper_1_3_chunk.segment_by_value -> Parallel Seq Scan on _timescaledb_internal.compress_hyper_2_13_chunk @@ -472,23 +472,23 @@ SELECT sum(segment_by_value) FROM testtable GROUP BY int_value; Output: _hyper_1_1_chunk.int_value, (PARTIAL sum(_hyper_1_1_chunk.segment_by_value)) Workers Planned: 2 -> Parallel Append - -> Partial HashAggregate - Output: _hyper_1_1_chunk.int_value, PARTIAL sum(_hyper_1_1_chunk.segment_by_value) - Group Key: _hyper_1_1_chunk.int_value + -> Custom Scan (VectorAgg) + Output: _hyper_1_1_chunk.int_value, (PARTIAL sum(_hyper_1_1_chunk.segment_by_value)) + Grouping Policy: hashed with single 4-byte key -> Custom Scan (DecompressChunk) on _timescaledb_internal._hyper_1_1_chunk Output: _hyper_1_1_chunk.int_value, _hyper_1_1_chunk.segment_by_value -> Parallel Seq Scan on _timescaledb_internal.compress_hyper_2_11_chunk Output: compress_hyper_2_11_chunk._ts_meta_count, compress_hyper_2_11_chunk.segment_by_value, compress_hyper_2_11_chunk._ts_meta_min_1, compress_hyper_2_11_chunk._ts_meta_max_1, compress_hyper_2_11_chunk."time", compress_hyper_2_11_chunk.int_value, compress_hyper_2_11_chunk.float_value - -> Partial HashAggregate - Output: _hyper_1_2_chunk.int_value, PARTIAL sum(_hyper_1_2_chunk.segment_by_value) - Group Key: _hyper_1_2_chunk.int_value + -> Custom Scan (VectorAgg) + Output: _hyper_1_2_chunk.int_value, (PARTIAL sum(_hyper_1_2_chunk.segment_by_value)) + Grouping Policy: hashed with single 4-byte key -> Custom Scan (DecompressChunk) on _timescaledb_internal._hyper_1_2_chunk Output: _hyper_1_2_chunk.int_value, _hyper_1_2_chunk.segment_by_value -> Parallel Seq Scan on _timescaledb_internal.compress_hyper_2_12_chunk Output: compress_hyper_2_12_chunk._ts_meta_count, compress_hyper_2_12_chunk.segment_by_value, compress_hyper_2_12_chunk._ts_meta_min_1, compress_hyper_2_12_chunk._ts_meta_max_1, compress_hyper_2_12_chunk."time", compress_hyper_2_12_chunk.int_value, compress_hyper_2_12_chunk.float_value - -> Partial HashAggregate - Output: _hyper_1_3_chunk.int_value, PARTIAL sum(_hyper_1_3_chunk.segment_by_value) - Group Key: _hyper_1_3_chunk.int_value + -> Custom Scan (VectorAgg) + Output: _hyper_1_3_chunk.int_value, (PARTIAL sum(_hyper_1_3_chunk.segment_by_value)) + Grouping Policy: hashed with single 4-byte key -> Custom Scan (DecompressChunk) on _timescaledb_internal._hyper_1_3_chunk Output: _hyper_1_3_chunk.int_value, _hyper_1_3_chunk.segment_by_value -> Parallel Seq Scan on _timescaledb_internal.compress_hyper_2_13_chunk @@ -2863,67 +2863,77 @@ SELECT sum(segment_by_value) FILTER (WHERE segment_by_value > 99999) FROM testta Output: (PARTIAL sum(_hyper_1_81_chunk.segment_by_value) FILTER (WHERE (_hyper_1_81_chunk.segment_by_value > 99999))) Workers Planned: 2 -> Parallel Append - -> Partial Aggregate - Output: PARTIAL sum(_hyper_1_81_chunk.segment_by_value) FILTER (WHERE (_hyper_1_81_chunk.segment_by_value > 99999)) + -> Custom Scan (VectorAgg) + Output: (PARTIAL sum(_hyper_1_81_chunk.segment_by_value) FILTER (WHERE (_hyper_1_81_chunk.segment_by_value > 99999))) + Grouping Policy: all compressed batches -> Custom Scan (DecompressChunk) on _timescaledb_internal._hyper_1_81_chunk Output: _hyper_1_81_chunk.segment_by_value -> Parallel Seq Scan on _timescaledb_internal.compress_hyper_2_91_chunk Output: compress_hyper_2_91_chunk._ts_meta_count, compress_hyper_2_91_chunk.segment_by_value, compress_hyper_2_91_chunk._ts_meta_min_1, compress_hyper_2_91_chunk._ts_meta_max_1, compress_hyper_2_91_chunk."time", compress_hyper_2_91_chunk.int_value, compress_hyper_2_91_chunk.float_value - -> Partial Aggregate - Output: PARTIAL sum(_hyper_1_82_chunk.segment_by_value) FILTER (WHERE (_hyper_1_82_chunk.segment_by_value > 99999)) + -> Custom Scan (VectorAgg) + Output: (PARTIAL sum(_hyper_1_82_chunk.segment_by_value) FILTER (WHERE (_hyper_1_82_chunk.segment_by_value > 99999))) + Grouping Policy: all compressed batches -> Custom Scan (DecompressChunk) on _timescaledb_internal._hyper_1_82_chunk Output: _hyper_1_82_chunk.segment_by_value -> Parallel Seq Scan on _timescaledb_internal.compress_hyper_2_92_chunk Output: compress_hyper_2_92_chunk._ts_meta_count, compress_hyper_2_92_chunk.segment_by_value, compress_hyper_2_92_chunk._ts_meta_min_1, compress_hyper_2_92_chunk._ts_meta_max_1, compress_hyper_2_92_chunk."time", compress_hyper_2_92_chunk.int_value, compress_hyper_2_92_chunk.float_value - -> Partial Aggregate - Output: PARTIAL sum(_hyper_1_83_chunk.segment_by_value) FILTER (WHERE (_hyper_1_83_chunk.segment_by_value > 99999)) + -> Custom Scan (VectorAgg) + Output: (PARTIAL sum(_hyper_1_83_chunk.segment_by_value) FILTER (WHERE (_hyper_1_83_chunk.segment_by_value > 99999))) + Grouping Policy: all compressed batches -> Custom Scan (DecompressChunk) on _timescaledb_internal._hyper_1_83_chunk Output: _hyper_1_83_chunk.segment_by_value -> Parallel Seq Scan on _timescaledb_internal.compress_hyper_2_93_chunk Output: compress_hyper_2_93_chunk._ts_meta_count, compress_hyper_2_93_chunk.segment_by_value, compress_hyper_2_93_chunk._ts_meta_min_1, compress_hyper_2_93_chunk._ts_meta_max_1, compress_hyper_2_93_chunk."time", compress_hyper_2_93_chunk.int_value, compress_hyper_2_93_chunk.float_value - -> Partial Aggregate - Output: PARTIAL sum(_hyper_1_84_chunk.segment_by_value) FILTER (WHERE (_hyper_1_84_chunk.segment_by_value > 99999)) + -> Custom Scan (VectorAgg) + Output: (PARTIAL sum(_hyper_1_84_chunk.segment_by_value) FILTER (WHERE (_hyper_1_84_chunk.segment_by_value > 99999))) + Grouping Policy: all compressed batches -> Custom Scan (DecompressChunk) on _timescaledb_internal._hyper_1_84_chunk Output: _hyper_1_84_chunk.segment_by_value -> Parallel Seq Scan on _timescaledb_internal.compress_hyper_2_94_chunk Output: compress_hyper_2_94_chunk._ts_meta_count, compress_hyper_2_94_chunk.segment_by_value, compress_hyper_2_94_chunk._ts_meta_min_1, compress_hyper_2_94_chunk._ts_meta_max_1, compress_hyper_2_94_chunk."time", compress_hyper_2_94_chunk.int_value, compress_hyper_2_94_chunk.float_value - -> Partial Aggregate - Output: PARTIAL sum(_hyper_1_85_chunk.segment_by_value) FILTER (WHERE (_hyper_1_85_chunk.segment_by_value > 99999)) + -> Custom Scan (VectorAgg) + Output: (PARTIAL sum(_hyper_1_85_chunk.segment_by_value) FILTER (WHERE (_hyper_1_85_chunk.segment_by_value > 99999))) + Grouping Policy: all compressed batches -> Custom Scan (DecompressChunk) on _timescaledb_internal._hyper_1_85_chunk Output: _hyper_1_85_chunk.segment_by_value -> Parallel Seq Scan on _timescaledb_internal.compress_hyper_2_95_chunk Output: compress_hyper_2_95_chunk._ts_meta_count, compress_hyper_2_95_chunk.segment_by_value, compress_hyper_2_95_chunk._ts_meta_min_1, compress_hyper_2_95_chunk._ts_meta_max_1, compress_hyper_2_95_chunk."time", compress_hyper_2_95_chunk.int_value, compress_hyper_2_95_chunk.float_value - -> Partial Aggregate - Output: PARTIAL sum(_hyper_1_86_chunk.segment_by_value) FILTER (WHERE (_hyper_1_86_chunk.segment_by_value > 99999)) + -> Custom Scan (VectorAgg) + Output: (PARTIAL sum(_hyper_1_86_chunk.segment_by_value) FILTER (WHERE (_hyper_1_86_chunk.segment_by_value > 99999))) + Grouping Policy: all compressed batches -> Custom Scan (DecompressChunk) on _timescaledb_internal._hyper_1_86_chunk Output: _hyper_1_86_chunk.segment_by_value -> Parallel Seq Scan on _timescaledb_internal.compress_hyper_2_96_chunk Output: compress_hyper_2_96_chunk._ts_meta_count, compress_hyper_2_96_chunk.segment_by_value, compress_hyper_2_96_chunk._ts_meta_min_1, compress_hyper_2_96_chunk._ts_meta_max_1, compress_hyper_2_96_chunk."time", compress_hyper_2_96_chunk.int_value, compress_hyper_2_96_chunk.float_value - -> Partial Aggregate - Output: PARTIAL sum(_hyper_1_87_chunk.segment_by_value) FILTER (WHERE (_hyper_1_87_chunk.segment_by_value > 99999)) + -> Custom Scan (VectorAgg) + Output: (PARTIAL sum(_hyper_1_87_chunk.segment_by_value) FILTER (WHERE (_hyper_1_87_chunk.segment_by_value > 99999))) + Grouping Policy: all compressed batches -> Custom Scan (DecompressChunk) on _timescaledb_internal._hyper_1_87_chunk Output: _hyper_1_87_chunk.segment_by_value -> Parallel Seq Scan on _timescaledb_internal.compress_hyper_2_97_chunk Output: compress_hyper_2_97_chunk._ts_meta_count, compress_hyper_2_97_chunk.segment_by_value, compress_hyper_2_97_chunk._ts_meta_min_1, compress_hyper_2_97_chunk._ts_meta_max_1, compress_hyper_2_97_chunk."time", compress_hyper_2_97_chunk.int_value, compress_hyper_2_97_chunk.float_value - -> Partial Aggregate - Output: PARTIAL sum(_hyper_1_88_chunk.segment_by_value) FILTER (WHERE (_hyper_1_88_chunk.segment_by_value > 99999)) + -> Custom Scan (VectorAgg) + Output: (PARTIAL sum(_hyper_1_88_chunk.segment_by_value) FILTER (WHERE (_hyper_1_88_chunk.segment_by_value > 99999))) + Grouping Policy: all compressed batches -> Custom Scan (DecompressChunk) on _timescaledb_internal._hyper_1_88_chunk Output: _hyper_1_88_chunk.segment_by_value -> Parallel Seq Scan on _timescaledb_internal.compress_hyper_2_98_chunk Output: compress_hyper_2_98_chunk._ts_meta_count, compress_hyper_2_98_chunk.segment_by_value, compress_hyper_2_98_chunk._ts_meta_min_1, compress_hyper_2_98_chunk._ts_meta_max_1, compress_hyper_2_98_chunk."time", compress_hyper_2_98_chunk.int_value, compress_hyper_2_98_chunk.float_value - -> Partial Aggregate - Output: PARTIAL sum(_hyper_1_89_chunk.segment_by_value) FILTER (WHERE (_hyper_1_89_chunk.segment_by_value > 99999)) + -> Custom Scan (VectorAgg) + Output: (PARTIAL sum(_hyper_1_89_chunk.segment_by_value) FILTER (WHERE (_hyper_1_89_chunk.segment_by_value > 99999))) + Grouping Policy: all compressed batches -> Custom Scan (DecompressChunk) on _timescaledb_internal._hyper_1_89_chunk Output: _hyper_1_89_chunk.segment_by_value -> Parallel Seq Scan on _timescaledb_internal.compress_hyper_2_99_chunk Output: compress_hyper_2_99_chunk._ts_meta_count, compress_hyper_2_99_chunk.segment_by_value, compress_hyper_2_99_chunk._ts_meta_min_1, compress_hyper_2_99_chunk._ts_meta_max_1, compress_hyper_2_99_chunk."time", compress_hyper_2_99_chunk.int_value, compress_hyper_2_99_chunk.float_value - -> Partial Aggregate - Output: PARTIAL sum(_hyper_1_90_chunk.segment_by_value) FILTER (WHERE (_hyper_1_90_chunk.segment_by_value > 99999)) + -> Custom Scan (VectorAgg) + Output: (PARTIAL sum(_hyper_1_90_chunk.segment_by_value) FILTER (WHERE (_hyper_1_90_chunk.segment_by_value > 99999))) + Grouping Policy: all compressed batches -> Custom Scan (DecompressChunk) on _timescaledb_internal._hyper_1_90_chunk Output: _hyper_1_90_chunk.segment_by_value -> Parallel Seq Scan on _timescaledb_internal.compress_hyper_2_100_chunk Output: compress_hyper_2_100_chunk._ts_meta_count, compress_hyper_2_100_chunk.segment_by_value, compress_hyper_2_100_chunk._ts_meta_min_1, compress_hyper_2_100_chunk._ts_meta_max_1, compress_hyper_2_100_chunk."time", compress_hyper_2_100_chunk.int_value, compress_hyper_2_100_chunk.float_value -(66 rows) +(76 rows) SET timescaledb.enable_vectorized_aggregation = OFF; SELECT sum(segment_by_value) FILTER (WHERE segment_by_value > 99999) FROM testtable; diff --git a/tsl/test/sql/CMakeLists.txt b/tsl/test/sql/CMakeLists.txt index bae570319dc..b6a7e9eea28 100644 --- a/tsl/test/sql/CMakeLists.txt +++ b/tsl/test/sql/CMakeLists.txt @@ -114,6 +114,8 @@ if(CMAKE_BUILD_TYPE MATCHES Debug) recompress_chunk_segmentwise.sql feature_flags.sql vector_agg_default.sql + vector_agg_filter.sql + vector_agg_grouping.sql vector_agg_memory.sql vector_agg_segmentby.sql) diff --git a/tsl/test/sql/vector_agg_filter.sql b/tsl/test/sql/vector_agg_filter.sql new file mode 100644 index 00000000000..4080675de50 --- /dev/null +++ b/tsl/test/sql/vector_agg_filter.sql @@ -0,0 +1,122 @@ +-- This file and its contents are licensed under the Timescale License. +-- Please see the included NOTICE for copyright information and +-- LICENSE-TIMESCALE for a copy of the license. + +\c :TEST_DBNAME :ROLE_SUPERUSER +-- helper function: float -> pseudorandom float [-0.5..0.5] +CREATE OR REPLACE FUNCTION mix(x anyelement) RETURNS float8 AS $$ + SELECT hashfloat8(x::float8) / pow(2, 32) +$$ LANGUAGE SQL; +-- non-vectorizable equality operator +create operator === (function = 'int4eq', rightarg = int4, leftarg = int4); +-- an abs() function that is stable not immutable +create function stable_abs(x int4) returns int4 as 'int4abs' language internal stable; + +\set CHUNKS 2::int +\set CHUNK_ROWS 100000::int +\set GROUPING_CARDINALITY 10::int + +create table aggfilter(t int, s int, + cint2 int2, dropped int4, cint4 int4); +select create_hypertable('aggfilter', 's', chunk_time_interval => :GROUPING_CARDINALITY / :CHUNKS); + +create view source as +select s * 10000 + t as t, + s, + case when t % 1051 = 0 then null + else (mix(s + t * 1019) * 32767)::int2 end as cint2, + 1 as dropped, + (mix(s + t * 1021) * 32767)::int4 as cint4 +from + generate_series(1::int, :CHUNK_ROWS * :CHUNKS / :GROUPING_CARDINALITY) t, + generate_series(0::int, :GROUPING_CARDINALITY - 1::int) s(s) +; + +insert into aggfilter select * from source where s = 1; + +alter table aggfilter set (timescaledb.compress, timescaledb.compress_orderby = 't', + timescaledb.compress_segmentby = 's'); + +select count(compress_chunk(x)) from show_chunks('aggfilter') x; + +alter table aggfilter add column ss int default 11; +alter table aggfilter drop column dropped; + +insert into aggfilter +select t, s, cint2, cint4, + case + -- null in entire batch + when s = 2 then null + -- null for some rows + when s = 3 and t % 1053 = 0 then null + -- for some rows same as default + when s = 4 and t % 1057 = 0 then 11 + -- not null for entire batch + else s + end as ss +from source where s != 1 +; +select count(compress_chunk(x)) from show_chunks('aggfilter') x; +vacuum freeze analyze aggfilter; + + + +set timescaledb.debug_require_vector_agg = 'require'; +---- Uncomment to generate reference. +--set timescaledb.enable_vectorized_aggregation to off; set timescaledb.debug_require_vector_agg = 'allow'; + +select + format('%sselect %s%s(%s)%s from aggfilter%s%s%s;', + explain, + grouping || ', ', + function, variable, + ' filter (where ' || agg_filter || ')', + ' where ' || condition, + ' group by ' || grouping, + format(' order by %s(%s), ', function, variable) || grouping || ' limit 10', + function, variable) +from + unnest(array[ + 'explain (costs off) ', + null]) explain, + unnest(array[ + 's', + 'ss', + 'cint2', + 'cint4', + '*']) variable, + unnest(array[ + 'min', + 'count']) function, + unnest(array[ + null, + 'cint2 > 0', + 'cint2 is null']) with ordinality as condition(condition, n), + unnest(array[ + null, + 's', + 'ss']) with ordinality as grouping(grouping, n), + unnest(array[ + null, + 'cint2 < 0', + 'ss > 1000', + 'cint4 > 0', + 's != 5']) with ordinality as agg_filter(agg_filter, n) +where + true + and (explain is null /* or condition is null and grouping = 's' */) + and (variable != '*' or function = 'count') +order by explain, condition.n, variable, function, grouping.n, agg_filter.n +\gexec + +reset timescaledb.debug_require_vector_agg; + +-- FILTER that is not vectorizable +set timescaledb.debug_require_vector_agg = 'forbid'; +select count(*) filter (where cint2 === 0) from aggfilter; +-- FILTER with stable function +set timescaledb.debug_require_vector_agg = 'require'; +select count(*) filter (where cint2 = stable_abs(0)) from aggfilter; + +reset timescaledb.debug_require_vector_agg; + diff --git a/tsl/test/sql/vector_agg_functions.sql b/tsl/test/sql/vector_agg_functions.sql index 0e6a0d0860f..2876a303fba 100644 --- a/tsl/test/sql/vector_agg_functions.sql +++ b/tsl/test/sql/vector_agg_functions.sql @@ -98,7 +98,7 @@ limit 1 set timescaledb.debug_require_vector_agg = :'guc_value'; ---- Uncomment to generate reference. Note that there are minor discrepancies ---- on float4 due to different numeric stability in our and PG implementations. --- set timescaledb.enable_vectorized_aggregation to off; set timescaledb.debug_require_vector_agg = 'allow'; +--set timescaledb.enable_vectorized_aggregation to off; set timescaledb.debug_require_vector_agg = 'forbid'; select format('%sselect %s%s(%s) from aggfns%s%s%s;', @@ -142,7 +142,8 @@ from 'cint2 is null']) with ordinality as condition(condition, n), unnest(array[ null, - 's']) with ordinality as grouping(grouping, n) + 's', + 'ss']) with ordinality as grouping(grouping, n) where true and (explain is null /* or condition is null and grouping = 's' */) @@ -156,6 +157,11 @@ order by explain, condition.n, variable, function, grouping.n \gexec +-- Test multiple aggregate functions as well. +select count(*), count(cint2), min(cfloat4), cint2 from aggfns group by cint2 +order by count(*) desc, cint2 limit 10 +; + -- Test edge cases for various batch sizes and the filter matching around batch -- end. select count(*) from edges; @@ -164,3 +170,7 @@ select s, count(*) from edges group by 1 order by 1; select s, count(*), min(f1) from edges where f1 = 63 group by 1 order by 1; select s, count(*), min(f1) from edges where f1 = 64 group by 1 order by 1; select s, count(*), min(f1) from edges where f1 = 65 group by 1 order by 1; + +select ss, count(*), min(f1) from edges where f1 = 63 group by 1 order by 1; +select ss, count(*), min(f1) from edges where f1 = 64 group by 1 order by 1; +select ss, count(*), min(f1) from edges where f1 = 65 group by 1 order by 1; diff --git a/tsl/test/sql/vector_agg_grouping.sql b/tsl/test/sql/vector_agg_grouping.sql new file mode 100644 index 00000000000..e087e54c48e --- /dev/null +++ b/tsl/test/sql/vector_agg_grouping.sql @@ -0,0 +1,126 @@ +-- This file and its contents are licensed under the Timescale License. +-- Please see the included NOTICE for copyright information and +-- LICENSE-TIMESCALE for a copy of the license. + +\c :TEST_DBNAME :ROLE_SUPERUSER +-- helper function: float -> pseudorandom float [-0.5..0.5] +CREATE OR REPLACE FUNCTION mix(x anyelement) RETURNS float8 AS $$ + SELECT hashfloat8(x::float8) / pow(2, 32) +$$ LANGUAGE SQL; + +\set CHUNKS 2::int +\set CHUNK_ROWS 100000::int +\set GROUPING_CARDINALITY 10::int + +create table agggroup(t int, s int, + cint2 int2, cint4 int4, cint8 int8); +select create_hypertable('agggroup', 's', chunk_time_interval => :GROUPING_CARDINALITY / :CHUNKS); + +create view source as +select s * 10000 + t as t, + s, + case when t % 1051 = 0 then null + else (mix(s + t * 1019) * 32767)::int2 end as cint2, + (mix(s + t * 1021) * 32767)::int4 as cint4, + (mix(s + t * 1031) * 32767)::int8 as cint8 +from + generate_series(1::int, :CHUNK_ROWS * :CHUNKS / :GROUPING_CARDINALITY) t, + generate_series(0::int, :GROUPING_CARDINALITY - 1::int) s(s) +; + +insert into agggroup select * from source where s = 1; + +alter table agggroup set (timescaledb.compress, timescaledb.compress_orderby = 't', + timescaledb.compress_segmentby = 's'); + +select count(compress_chunk(x)) from show_chunks('agggroup') x; + +alter table agggroup add column ss int default 11; +alter table agggroup add column x text default '11'; + +insert into agggroup +select *, ss::text as x from ( + select *, + case + -- null in entire batch + when s = 2 then null + -- null for some rows + when s = 3 and t % 1051 = 0 then null + -- for some rows same as default + when s = 4 and t % 1057 = 0 then 11 + -- not null for entire batch + else s + end as ss + from source where s != 1 +) t +; +select count(compress_chunk(x)) from show_chunks('agggroup') x; +vacuum freeze analyze agggroup; + + +set timescaledb.debug_require_vector_agg = 'require'; +---- Uncomment to generate reference. Note that there are minor discrepancies +---- on float4 due to different numeric stability in our and PG implementations. +--set timescaledb.enable_vectorized_aggregation to off; set timescaledb.debug_require_vector_agg = 'allow'; + +select + format('%sselect %s%s(%s) from agggroup%s%s%s;', + explain, + grouping || ', ', + function, variable, + ' where ' || condition, + ' group by ' || grouping, + format(' order by %s(%s), ', function, variable) || grouping || ' limit 10', + function, variable) +from + unnest(array[ + 'explain (costs off) ', + null]) explain, + unnest(array[ + 'cint2', + '*']) variable, + unnest(array[ + 'min', + 'count']) function, + unnest(array[ + null, + 'cint2 > 0', + 'cint2 is null', + 'cint2 is null and x is null']) with ordinality as condition(condition, n), + unnest(array[ + null, + 'cint2', + 'cint4', + 'cint4, cint8', + 'cint8', + 's, cint2', + 's, ss', + 's, x', + 'ss, cint2, x', + 'ss, s', + 'ss, x, cint2', + 't, s, ss, x, cint4, cint8, cint2', + 'x']) with ordinality as grouping(grouping, n) +where + true + and (explain is null /* or condition is null and grouping = 's' */) + and (variable != '*' or function = 'count') +order by explain, condition.n, variable, function, grouping.n +\gexec + +reset timescaledb.debug_require_vector_agg; + + +create table long(t int, a text, b text, c text, d text); +select create_hypertable('long', 't'); +insert into long select n, x, x, x, x from ( + select n, repeat('1', 100 * 4 + n) x + from generate_series(1, 4) n) t +; +insert into long values (-1, 'a', 'b', 'c', 'd'); +alter table long set (timescaledb.compress); +select count(compress_chunk(x)) from show_chunks('long') x; + +set timescaledb.debug_require_vector_agg = 'require'; +select count(*) from long group by a, b, c, d order by 1 limit 10; +reset timescaledb.debug_require_vector_agg;