diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 0000000..418432d --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,86 @@ +name: Redis FDW test + +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + - main +jobs: + detect-pgversion: + runs-on: ubuntu-22.04 + outputs: + pgversion: ${{ steps.detect-pgversion.outputs.targets }} + steps: + - uses: actions/checkout@v4 + + - name: detect-pgversion + id: detect-pgversion + run: | + targets=`bash GitHubActions/detect_targets.sh` + echo "targets=$targets" >> $GITHUB_OUTPUT + + test: + needs: detect-pgversion + env: + POSTGIS_VERSION : "3.4.2" + HTTP_PROXY: "" + HTTPS_PROXY: "" + HIREDIS_FOR_TESTING_DIR: "/opt/hiredis_testing" + strategy: + fail-fast: false + matrix: + pg: ${{ fromJSON(needs.detect-pgversion.outputs.pgversion) }} + config: ["default", "postgis"] + + name: Test on PostgreSQL ${{ matrix.pg }}, ${{ matrix.config }} mode + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + + - name: tar + run: tar zcvf redis_fdw.tar.gz ./* + + - name: set_proxy + run: bash GitHubActions/env.sh + + - name: download PostGIS, ${{ matrix.config }} mode + run: | + if [[ "${{ matrix.config }}" == "postgis" ]]; then + bash GitHubActions/download_postgis.sh ${{ env.POSTGIS_VERSION }} + fi + + - name: install locales + run: bash GitHubActions/install_locales.sh + + - name: build PostgreSQL ${{ matrix.pg }} + run: bash GitHubActions/build_postgres.sh ${{ matrix.pg }} + + - name: install Redis, ${{ matrix.config }} mode + run: bash GitHubActions/install_redis.sh ${{ matrix.config }} ${{ env.HIREDIS_FOR_TESTING_DIR }} + + - name: build PostGIS ${{ env.POSTGIS_VERSION }} for PostgreSQL ${{ matrix.pg }}, ${{ matrix.config }} mode + run: | + if [[ "${{ matrix.config }}" == "postgis" ]]; then + bash GitHubActions/build_postgis.sh ${{ matrix.pg }} ${{ env.POSTGIS_VERSION }} + fi + + - name: build redis_fdw, ${{ matrix.config }} mode + run: | + bash GitHubActions/build_redis_fdw.sh ${{ matrix.pg }} ${{ matrix.config }} ${{ env.HIREDIS_FOR_TESTING_DIR }} + + - name: execute redis_fdw test + run: bash GitHubActions/execute_test.sh ${{ matrix.pg }} ${{ matrix.config }} ${{ env.HIREDIS_FOR_TESTING_DIR }} + + - name: download output files (regression.diffs) + if: failure() + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.pg }}-${{ matrix.config }}-test-results + path: | + workdir/postgresql-${{ matrix.pg }}/contrib/redis_fdw/test/regression.diffs + workdir/postgresql-${{ matrix.pg }}/contrib/redis_fdw/test/regression.out + workdir/postgresql-${{ matrix.pg }}/contrib/redis_fdw/test/results + retention-days: 7 + diff --git a/GitHubActions/README.md b/GitHubActions/README.md new file mode 100644 index 0000000..641cb90 --- /dev/null +++ b/GitHubActions/README.md @@ -0,0 +1,13 @@ +# CI environment of redis_fdw. + +Tests will be executed automatically when commited to main/master branch and when a pull request was opened/updated. +It is realized by using GitHub actions. + +The CI process is defined in .github/workflows/CI.yml file. +Scripts in this directory (GitHubActions/*.sh) are referred by CI.yml. + +The regression test will be executed for multi-versions of PostgreSQL. +Target versions are determined automatically based on directory names in "expected" directory. + +If the regression test failed, test result files (result directory, regression.diff amd regression.out) are uploaded as artifacts. +7 days later, artifact files will be deleted. diff --git a/GitHubActions/build_postgis.sh b/GitHubActions/build_postgis.sh new file mode 100644 index 0000000..348646b --- /dev/null +++ b/GitHubActions/build_postgis.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +################################################################################ +# +# This script downloads PostGIS from the official web site into ./workdir +# then builds it. +# +# Usage: ./build_postgis.sh pg_version postgis_version +# pg_version is a PostgreSQL version to be installed like 16.0. +# postgis_version is a PostGIS version to be installed. +# +# Requirements +# - be able to connect to the PostGIS official web site by wget. +# +################################################################################ + +POSTGRESQL_VERSION=$1 +POSTGIS_VERSION=$2 + +# Install necessary dependencies +sudo apt update +sudo apt install -y build-essential libxml2-dev libgeos-dev libproj-dev libgdal-dev libjson-c-dev libprotobuf-c-dev protobuf-c-compiler + +cd ./workdir +# Download and compile PostGIS +cp -vr postgis "postgresql-${POSTGRESQL_VERSION}/contrib" +( +cd "postgresql-${POSTGRESQL_VERSION}/contrib/postgis" +echo " - PostGIS directory" +GEOS_CONFIG_PATH=$(which geos-config) +export LD_LIBRARY_PATH="/usr/local/lib/:$LD_LIBRARY_PATH" +./configure --with-pgconfig=/usr/local/pgsql/bin/pg_config --with-geosconfig=$GEOS_CONFIG_PATH +make +sudo make install +) + +( +cd "postgresql-${POSTGRESQL_VERSION}/contrib/hstore" +make +sudo make install +) diff --git a/GitHubActions/build_postgres.sh b/GitHubActions/build_postgres.sh new file mode 100644 index 0000000..fca424d --- /dev/null +++ b/GitHubActions/build_postgres.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +################################################################################ +# +# This script downloads PostgreSQL from the official web site into ./workdir +# then builds it. +# +# Usage: ./build_postgres.sh pg_version [configure_options] +# pg_version is a PostgreSQL version to be installed like 17.0. +# configure_options are a list of option for postgres server. +# +# Requirements +# - be able to connect to the PostgreSQL official web site by curl. +# +################################################################################ + +POSTGRESQL_VERSION=$1 +CONFIGURE_OPTIONS="" + +while (( "$#" )); do + CONFIGURE_OPTIONS="$CONFIGURE_OPTIONS $2" + shift +done + +mkdir -p ./workdir +cd ./workdir +adr="https://ftp.postgresql.org/pub/source/v${POSTGRESQL_VERSION}/postgresql-${POSTGRESQL_VERSION}.tar.bz2"; +echo "PG version URL: + $adr" +curl -O "$adr" +tar xjf postgresql-${POSTGRESQL_VERSION}.tar.bz2 +cd postgresql-${POSTGRESQL_VERSION} + +if [ -z "$CONFIGURE_OPTIONS" ]; then + ./configure +else + ./configure $CONFIGURE_OPTIONS +fi + +make +sudo make install +sudo chown -R $USER /usr/local/pgsql diff --git a/GitHubActions/build_redis_fdw.sh b/GitHubActions/build_redis_fdw.sh new file mode 100644 index 0000000..bcc34b8 --- /dev/null +++ b/GitHubActions/build_redis_fdw.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +################################################################################ +# +# This script builds redis_fdw in PostgreSQL source tree. +# +# Usage: ./build_redis_fdw.sh pg_version mode hiredis_for_testing_dir +# pg_version is a PostgreSQL version like 17.0 to be built in. +# mode is flag for redis_fdw compiler. +# hiredis_for_testing_dir: path to install directory of hiredis version for testing +# +# Requirements +# - the source code of redis_fdw is available by git clone. +# - the source code of PostgreSQL is located in ~/workdir/postgresql-{pg_version}. +# - Hiredis development package is installed in a system. +################################################################################ + +VERSION="$1" +MODE="$2" +HIREDIS_FOR_TESTING_DIR="$3" + +mkdir -p ./workdir/postgresql-${VERSION}/contrib/redis_fdw +tar zxf ./redis_fdw.tar.gz -C ./workdir/postgresql-${VERSION}/contrib/redis_fdw/ +cd ./workdir/postgresql-${VERSION}/contrib/redis_fdw + +# show locally compiled hiredis library +ls -la /usr/local/lib + +if [ "$MODE" == "postgis" ]; then + make ENABLE_GIS=1 HIREDIS_FOR_TESTING_DIR="$3" +else + make HIREDIS_FOR_TESTING_DIR="$3" +fi + +sudo make install diff --git a/GitHubActions/detect_targets.sh b/GitHubActions/detect_targets.sh new file mode 100644 index 0000000..95808e8 --- /dev/null +++ b/GitHubActions/detect_targets.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +################################################################################ +# +# This script detects target PostgreSQL versions for redis_fdw testing from +# directory names in ./sql directory. Detected versions will be outputed to +# the standard output as an array of string like ["16.3","17.0"]. +# +# Usage: ./detect_targets.sh +# +# Requirements +# - there is a directory named "sql" in a curent directory. +# +################################################################################ + +dirs="./test/expected/*" +pattern="[0-9]+(\.|rc)[0-9]+" +targets="[" +for pathname in $dirs; do + if [[ "$pathname" =~ $pattern ]]; then + target=`basename $pathname` + if [ "$targets" != "[" ]; then + targets+="," + fi + targets+="\"$target\"" + fi +done +targets+="]" + +echo "$targets" diff --git a/GitHubActions/download_postgis.sh b/GitHubActions/download_postgis.sh new file mode 100644 index 0000000..bc72a20 --- /dev/null +++ b/GitHubActions/download_postgis.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +################################################################################ +# +# This script downloads PostGIS from the official web site into ./workdir +# then builds it. +# +# Usage: ./download_postgis.sh postgis_version +# postgis_version is a PostGIS version to be installed. +# +# Requirements +# - be able to connect to the PostGIS official web site by wget. +# +################################################################################ + +POSTGIS_VERSION=$1 + +mkdir -p ./workdir +cd ./workdir +pgisfile="postgis-${POSTGIS_VERSION}.tar.gz" +if [ ! -f "$pgisfile" ]; then + wget -nv "http://download.osgeo.org/postgis/source/$pgisfile" + tar -xzf "$pgisfile" + mv postgis-${POSTGIS_VERSION} postgis -v + echo "PostGIS source code directory " $(dirname $(readlink -f postgis)) +else + echo "PostGIS downloaded" +fi diff --git a/GitHubActions/env.sh b/GitHubActions/env.sh new file mode 100644 index 0000000..f607376 --- /dev/null +++ b/GitHubActions/env.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +################################################################################ +# +# This script configures apt.conf to set a proxy if an environment variable +# HTTP_PROXY or HTTPS_PROXY is set. +# +# Usage: ./env.sh +# +# Requirements +# - having superuser privileges +# +################################################################################ + +if [ -z $HTTP_PROXY ] && [ "$HTTP_PROXY" != "" ]; then + echo 'Acquire::http::proxy "$HTTP_PROXY";' | sudo tee /etc/apt/apt.conf +fi +if [ -z $HTTPS_PROXY ] && [ "$HTTPS_PROXY" != "" ]; then + echo 'Acquire::https::proxy "$HTTPS_PROXY";' | sudo tee -a /etc/apt/apt.conf +fi diff --git a/GitHubActions/execute_test.sh b/GitHubActions/execute_test.sh new file mode 100644 index 0000000..98e5684 --- /dev/null +++ b/GitHubActions/execute_test.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +################################################################################ +# +# This script executes a regression test pf redis_fdw by calling test.sh in +# redis_fdw. If all tests are passed, this script will exit successfully. +# Otherwise, it will exit with failure. + +# Usage: ./execute_test.sh pg_version mode redis_for_testing_dir +# pg_version is a PostgreSQL version to be tested like 17.0. +# mode is flag for redis_fdw compiler. +# hiredis_for_testing_dir: path to install directory of hiredis version for testing +# +# Requiremets +# - the source code of PostgreSQL is located in ./workdir/postgresql-{pg_version}. +# - the source code of redis_fdw is loacted in ./workdir/postgresql-{pg_version}/contrib/redis_fdw. +# - PostgreSQL and redis_fdw were built. +# - this script assumes that tests are passed if this file (created by executing +# the test) contains " ALL {number} tests passed" at the last or the 3rd line +# from the end. +# +################################################################################ + +VERSION=$1 +MODE="$2" +HIREDIS_FOR_TESTING_DIR="$3" + +cd ./workdir/postgresql-${VERSION}/contrib/redis_fdw + +if [ "$MODE" == "postgis" ]; then + export ENABLE_GIS=1 + + # Start postgres server + POSTGRES_HOME=/usr/local/pgsql + ${POSTGRES_HOME}/bin/initdb ${POSTGRES_HOME}/databases + ${POSTGRES_HOME}/bin/pg_ctl -D ${POSTGRES_HOME}/databases -l logfile start + + # Change the testing method + sed -i 's/make check/make installcheck/' test.sh +fi + +# Execute test script +chmod +x ./test.sh +./test.sh $MAKEFILE_OPT + +last_line=$(tail -n 1 make_check.out) +third_line_from_the_last=$(tail -n 3 make_check.out | head -n 1) + +pattern=" All [0-9]+ tests passed.+" + +if [[ "$last_line" =~ $pattern ]]; then + echo "last_line" + +elif [[ "$third_line_from_the_last" =~ $pattern ]]; then + echo "$third_line_from_the_last" +else + echo "Error : not All the tests passed" + echo "last line : '$last_line'" + echo "thierd_line_from_the_last : '$third_line_from_the_last'" + exit 1 +fi diff --git a/GitHubActions/install_locales.sh b/GitHubActions/install_locales.sh new file mode 100644 index 0000000..1d5f606 --- /dev/null +++ b/GitHubActions/install_locales.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +################################################################################ +# +# This script installs some locales and language packs used by redis_fdw +# tests in Ubuntu. +# +# Usage: ./install_locales.sh +# +# Requirements: +# - having superuser privileges +# +################################################################################ + +sudo apt-get update +sudo apt-get install locales language-pack-ja +sudo locale-gen ja_JP.EUC-JP +sudo apt-get install language-pack-ko-base language-pack-ko +sudo locale-gen ko_KR.EUC-KR +sudo apt-get install language-pack-bg-base language-pack-bg +sudo locale-gen bg_BG +sudo apt-get install libreadline8 libreadline-dev diff --git a/GitHubActions/install_redis.sh b/GitHubActions/install_redis.sh new file mode 100644 index 0000000..3e49d5a --- /dev/null +++ b/GitHubActions/install_redis.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +################################################################################ +# +# This sript installs Redis environment for Redis FDW testing +# +# Usage: ./install_redis.sh version year testing_mode hiredis_for_testing_dir [configure_options] +# testing_mode: 'default' or 'postgis' value. +# hiredis_for_testing_dir: path to install directory of the specified hiredis version +# +# Ex) ./install_redis.sh postgis /opt/redis_testing +# +# Requirements +# - be able to connect to official repository of Ununtu +# - having superuser privileges +# +################################################################################ + +TESTING_MODE="$1" +HIREDIS_FOR_TESTING_DIR="$2" + +# libhiredis*** is a dependency of hiredis-dev +sudo apt-get install redis libhiredis-dev -y diff --git a/License b/License new file mode 100644 index 0000000..39d44e3 --- /dev/null +++ b/License @@ -0,0 +1,19 @@ +PostgreSQL license + +Copyright (c) 2011-2025, Dave Page and Andrew Dunstan + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose, without fee, and without a written agreement is +hereby granted, provided that the above copyright notice and this paragraph and +the following two paragraphs appear in all copies. + +IN NO EVENT SHALL Dave or Andrew BE LIABLE TO ANY PARTY FOR +DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST +PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF +TOSHIBA CORPORATION HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Dave and Andrew SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND +Dave and Andrew HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, +UPDATES, ENHANCEMENTS, OR MODIFICATIONS. diff --git a/Makefile b/Makefile index 7b7d934..246eb89 100644 --- a/Makefile +++ b/Makefile @@ -18,23 +18,42 @@ MODULE_big = redis_fdw OBJS = redis_fdw.o EXTENSION = redis_fdw -DATA = redis_fdw--1.0.sql +DATA = redis_fdw--1.0.sql # here can be additional future file # redis_fdw--1.0--1.1.sql -REGRESS = redis_fdw -REGRESS_OPTS = --inputdir=test --outputdir=test \ - --load-extension=hstore \ - --load-extension=$(EXTENSION) +ifdef ENABLE_GIS +override PG_CFLAGS += -DREDIS_FDW_GIS_ENABLE +GISTEST=postgis +else +GISTEST=nogis +endif + +ifndef REGRESS +REGRESS = redis_fdw $(GISTEST) +#encodings # future test modules +endif -EXTRA_CLEAN = sql/redis_fdw.sql expected/redis_fdw.out +REGRESS_OPTS = --encoding=utf8 --inputdir=test --outputdir=test -SHLIB_LINK += -lhiredis +UNAME = uname +OS := $(shell $(UNAME)) +ifeq ($(OS), Darwin) +DLSUFFIX = .dylib +else +DLSUFFIX = .so +endif -USE_PGXS = 1 +SHLIB_LINK := -lhiredis -ifeq ($(USE_PGXS),1) +ifdef USE_PGXS PG_CONFIG = pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) include $(PGXS) +ifndef MAJORVERSION +MAJORVERSION := $(basename $(VERSION)) +endif +ifeq (,$(findstring $(MAJORVERSION), 10 11 12 13 14 15 16 17 18)) +$(error PostgreSQL 10 11 12 13, 14, 15, 16, 17 or 18 is required to compile this extension) +endif else subdir = contrib/redis_fdw top_builddir = ../.. @@ -42,5 +61,24 @@ include $(top_builddir)/src/Makefile.global include $(top_srcdir)/contrib/contrib-global.mk endif +ifdef REGRESS_PREFIX +REGRESS_PREFIX_SUB = $(REGRESS_PREFIX) +else +REGRESS_PREFIX_SUB = $(VERSION) +endif + +REGRESS := $(addprefix $(REGRESS_PREFIX_SUB)/,$(REGRESS)) +$(shell mkdir -p test) +$(shell mkdir -p test/results) +$(shell mkdir -p test/results/$(REGRESS_PREFIX_SUB)) + +EXTRA_INSTALL+=contrib/hstore + +ifdef ENABLE_GIS +check: temp-install +temp-install: EXTRA_INSTALL+=contrib/postgis +checkprep: EXTRA_INSTALL+=contrib/postgis +endif + # we put all the tests in a test subdir, but pgxs expects us not to, darn it override pg_regress_clean_files = test/results/ test/regression.diffs test/regression.out tmp_check/ log/ diff --git a/README.md b/README.md index 08b48e4..72a6ed9 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,9 @@ It has now been extended for production use by [Andrew](#license-and-authors). **By all means use it, but do so entirely at your own risk!** You have been warned! +Current CI status. +[![CI Status](https://github.com/pg-redis-fdw/redis_fdw/actions/workflows/CI.yml/badge.svg)](https://github.com/pg-redis-fdw/redis_fdw/actions/workflows/CI.yml) + Contents -------- @@ -404,3 +407,6 @@ License and authors ------- * Dave Page dpage@pgadmin.org * Andrew Dunstan andrew@dunslane.net + +Redis FDW is licensed under PostgreSQL license, see the [`License`](License) file for full details. +Provided license based on https://opensource.org/license/postgresql diff --git a/redis_fdw--1.0.sql b/redis_fdw--1.0.sql index f502b6f..b42c5c6 100644 --- a/redis_fdw--1.0.sql +++ b/redis_fdw--1.0.sql @@ -27,3 +27,19 @@ LANGUAGE C STRICT; CREATE FOREIGN DATA WRAPPER redis_fdw HANDLER redis_fdw_handler VALIDATOR redis_fdw_validator; + +CREATE OR REPLACE FUNCTION redis_fdw_version() +RETURNS int +AS 'MODULE_PATHNAME' +LANGUAGE C STRICT VOLATILE PARALLEL SAFE; + +COMMENT ON FUNCTION redis_fdw_version() +IS 'Returns Redis FDW code version'; + +CREATE OR REPLACE FUNCTION redis_fdw_hiredis_version() +RETURNS int +AS 'MODULE_PATHNAME' +LANGUAGE C STRICT VOLATILE PARALLEL SAFE; + +COMMENT ON FUNCTION redis_fdw_hiredis_version() +IS 'Returns hiredis library code version'; diff --git a/redis_fdw.c b/redis_fdw.c index 54195da..f43047b 100644 --- a/redis_fdw.c +++ b/redis_fdw.c @@ -1,4 +1,3 @@ - /*------------------------------------------------------------------------- * * foreign-data wrapper for Redis @@ -20,18 +19,17 @@ /* #define DEBUG */ #include "postgres.h" +#include /* check that we are compiling for the right postgres version */ -#if PG_VERSION_NUM < 190000 -#error wrong Postgresql version this branch is only for 19. +#if PG_VERSION_NUM < 140000 +#error Selected Postgresql version is very old for this branch, try to use some older branch. #endif - #include #include #include -#include #include "funcapi.h" #include "access/reloptions.h" @@ -42,8 +40,12 @@ #include "catalog/pg_user_mapping.h" #include "catalog/pg_type.h" #include "commands/defrem.h" +#if PG_VERSION_NUM >= 180000 #include "commands/explain_format.h" #include "commands/explain_state.h" +#else +#include "commands/explain.h" +#endif #include "foreign/fdwapi.h" #include "foreign/foreign.h" #include "miscadmin.h" @@ -52,7 +54,9 @@ #include "nodes/makefuncs.h" #include "nodes/parsenodes.h" #include "optimizer/appendinfo.h" +#if PG_VERSION_NUM >= 160000 #include "optimizer/inherit.h" +#endif #include "optimizer/optimizer.h" #include "optimizer/pathnode.h" #include "optimizer/planmain.h" @@ -66,6 +70,12 @@ PG_MODULE_MAGIC; +/* + * Code version is updated at new release. + * Older branches are equal to minor + */ +#define REDIS_FDW_CODE_VERSION 1901 + #define PROCID_TEXTEQ 67 /* @@ -83,7 +93,6 @@ struct RedisFdwOption */ static struct RedisFdwOption valid_options[] = { - /* Connection options */ {"address", ForeignServerRelationId}, {"port", ForeignServerRelationId}, @@ -184,9 +193,13 @@ typedef struct RedisFdwModifyState */ extern Datum redis_fdw_handler(PG_FUNCTION_ARGS); extern Datum redis_fdw_validator(PG_FUNCTION_ARGS); +extern Datum redis_fdw_version(PG_FUNCTION_ARGS); +extern Datum redis_fdw_hiredis_version(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(redis_fdw_handler); PG_FUNCTION_INFO_V1(redis_fdw_validator); +PG_FUNCTION_INFO_V1(redis_fdw_version); +PG_FUNCTION_INFO_V1(redis_fdw_hiredis_version); /* * FDW callback routines @@ -229,16 +242,20 @@ static TupleTableSlot *redisExecForeignInsert(EState *estate, ResultRelInfo *rinfo, TupleTableSlot *slot, TupleTableSlot *planSlot); + static void redisEndForeignModify(EState *estate, - ResultRelInfo *rinfo); + ResultRelInfo *rinfo); + static void redisAddForeignUpdateTargets(PlannerInfo *root, Index rtindex, RangeTblEntry *target_rte, Relation target_relation); + static TupleTableSlot *redisExecForeignDelete(EState *estate, ResultRelInfo *rinfo, TupleTableSlot *slot, TupleTableSlot *planSlot); + static TupleTableSlot *redisExecForeignUpdate(EState *estate, ResultRelInfo *rinfo, TupleTableSlot *slot, @@ -802,15 +819,18 @@ redisGetForeignPaths(PlannerInfo *root, create_foreignscan_path(root, baserel, NULL, /* default pathtarget */ baserel->rows, +#if PG_VERSION_NUM >= 180000 0, /* no disabled nodes */ +#endif startup_cost, total_cost, NIL, /* no pathkeys */ NULL, /* no outer rel either */ NULL, /* no extra plan */ +#if PG_VERSION_NUM >= 170000 NIL, /* no fdw_restrictinfo list */ +#endif NIL)); /* no fdw_private data */ - } /* @@ -1739,7 +1759,6 @@ redisAddForeignUpdateTargets(PlannerInfo *root, attr->atttypmod, InvalidOid, 0); - /* register it as a row-identity column needed by this target rel */ add_row_identity_var(root, var, rtindex, REDISMODKEYNAME); } @@ -1800,16 +1819,27 @@ redisPlanForeignModify(PlannerInfo *root, } else if (operation == CMD_UPDATE) { - +#if PG_VERSION_NUM >= 160000 /* code borrowed from mysql fdw */ - RelOptInfo *rrel = find_base_rel(root, resultRelation); Bitmapset *tmpset = get_rel_all_updated_cols(root, rrel); int colidx = -1; - +#else + /* modifiedCols in pg < 9.5 */ + Bitmapset *tmpset = bms_copy(rte->updatedCols); + AttrNumber col; +#endif +#if PG_VERSION_NUM >= 160000 while ((colidx = bms_next_member(tmpset, colidx)) >= 0) +#else + while ((col = bms_first_member(tmpset)) >= 0) +#endif { +#if PG_VERSION_NUM >= 160000 AttrNumber col = colidx + FirstLowInvalidHeapAttributeNumber; +#else + col += FirstLowInvalidHeapAttributeNumber; +#endif if (col <= InvalidAttrNumber) /* shouldn't happen */ elog(ERROR, "system-column update is not supported"); @@ -2939,3 +2969,23 @@ redisEndForeignModify(EState *estate, redisFree(fmstate->context); } } + +/* + * redis_fdw_version + * Gets source code version of this FDW + */ +Datum +redis_fdw_version(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT32(REDIS_FDW_CODE_VERSION); +} + +/* + * redis_fdw_hiredis_version + * Gets used hiredis source code version + */ +Datum +redis_fdw_hiredis_version(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT32(HIREDIS_MAJOR * 10000 + HIREDIS_MINOR * 100 + HIREDIS_PATCH); +} diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..87f9c64 --- /dev/null +++ b/test.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# Usage: +# ./test.sh -- test without GIS support +# ./test.sh ENABLE_GIS=1 -- test with GIS support + +# full test sequence, +# you can put your own test sequence here by following example +# undefined REGRESS environment variable will cause full test sequence from Makefile +#export REGRESS="redis_fdw extra/test2 test3 types/test4 .... "; + +make clean $@; +make $@; +make check $@ | tee make_check.out; diff --git a/test/.gitignore b/test/.gitignore deleted file mode 100644 index 6628455..0000000 --- a/test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/results/ diff --git a/test/expected/14.12/nogis.out b/test/expected/14.12/nogis.out new file mode 100644 index 0000000..cf309cd --- /dev/null +++ b/test/expected/14.12/nogis.out @@ -0,0 +1,23 @@ +-- Testcase 001 +CREATE EXTENSION hstore; +-- Testcase 002 +CREATE EXTENSION redis_fdw; +-- Testcase 003 +create server localredis foreign data wrapper redis_fdw; +-- Testcase 004 +create user mapping for public server localredis; +-- Testcase 005 +-- \! redis-cli < test/redis_gis_ini +-- REDIS SPATIAL VALUE TESTS WILL BE HERE +-- Testcase 098 +-- all done, so now blow everything in the db away again +\! redis-cli < test/redis_clean +OK +OK +-- Testcase 099 +DROP EXTENSION redis_fdw CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to server localredis +drop cascades to user mapping for public on server localredis +-- Testcase 100 +DROP EXTENSION hstore CASCADE; diff --git a/test/expected/14.12/postgis.out b/test/expected/14.12/postgis.out new file mode 100644 index 0000000..0b315ca --- /dev/null +++ b/test/expected/14.12/postgis.out @@ -0,0 +1,26 @@ +-- Testcase 001 +CREATE EXTENSION postgis; +-- Testcase 002 +CREATE EXTENSION hstore; +-- Testcase 003 +CREATE EXTENSION redis_fdw; +-- Testcase 004 +create server localredis foreign data wrapper redis_fdw; +-- Testcase 005 +create user mapping for public server localredis; +-- Testcase 006 +-- \! redis-cli < test/redis_gis_ini +-- Testcase 098 +-- all done, so now blow everything in the db away again +\! redis-cli < test/redis_clean +OK +OK +-- Testcase 099 +DROP EXTENSION redis_fdw CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to server localredis +drop cascades to user mapping for public on server localredis +-- Testcase 100 +DROP EXTENSION hstore CASCADE; +-- Testcase 101 +DROP EXTENSION postgis CASCADE; diff --git a/test/expected/redis_fdw.out b/test/expected/14.12/redis_fdw.out similarity index 93% rename from test/expected/redis_fdw.out rename to test/expected/14.12/redis_fdw.out index 7c2841b..7b5789d 100644 --- a/test/expected/redis_fdw.out +++ b/test/expected/14.12/redis_fdw.out @@ -1,11 +1,29 @@ +-- Testcase 001: +CREATE EXTENSION hstore; +-- Testcase 002: +CREATE EXTENSION redis_fdw; +-- Testcase 003: +select redis_fdw_version(); + redis_fdw_version +------------------- + 1901 +(1 row) + +-- Testcase 004: +select redis_fdw_hiredis_version(); + redis_fdw_hiredis_version +--------------------------- + 1401 +(1 row) + +-- Testcase 005: CREATE OR REPLACE FUNCTION atsort( a text[]) RETURNS text[] LANGUAGE sql IMMUTABLE STRICT AS $function$ select array(select unnest($1) order by 1) -$function$ -; +$function$; create server localredis foreign data wrapper redis_fdw; create user mapping for public server localredis; -- tables for all 5 data types (4 structured plus scalar) @@ -44,7 +62,7 @@ do $$ $$; \unset ON_ERROR_STOP -- ok, empty, so now run the setup script -\! redis-cli < test/sql/redis_setup +\! redis-cli < test/redis_setup OK OK OK @@ -378,7 +396,7 @@ select * from db15_1key_zset_scores order by score desc; -- insert delete update -- first clean the database again -\! redis-cli < test/sql/redis_clean +\! redis-cli < test/redis_clean OK OK -- singleton scalar table @@ -1342,7 +1360,7 @@ select * from db15_w_hash_kset; (0 rows) -- now clean up for the cursor tests -\! redis-cli < test/sql/redis_clean +\! redis-cli < test/redis_clean OK OK -- cursor tests @@ -1395,6 +1413,54 @@ select count(*) from db15bigkeysetscalar; (1 row) -- all done, so now blow everything in the db away again -\! redis-cli < test/sql/redis_clean +\! redis-cli < test/redis_clean OK OK +DROP EXTENSION redis_fdw CASCADE; +NOTICE: drop cascades to 45 other objects +DETAIL: drop cascades to server localredis +drop cascades to user mapping for public on server localredis +drop cascades to foreign table db15 +drop cascades to foreign table db15_hash +drop cascades to foreign table db15_set +drop cascades to foreign table db15_list +drop cascades to foreign table db15_zset +drop cascades to foreign table db15_hash_prefix +drop cascades to foreign table db15_hash_prefix_array +drop cascades to foreign table db15_hash_keyset_array +drop cascades to foreign table db15_set_prefix +drop cascades to foreign table db15_set_prefix_array +drop cascades to foreign table db15_set_keyset_array +drop cascades to foreign table db15_list_prefix +drop cascades to foreign table db15_list_prefix_array +drop cascades to foreign table db15_list_keyset_array +drop cascades to foreign table db15_zset_prefix +drop cascades to foreign table db15_zset_prefix_array +drop cascades to foreign table db15_zset_keyset_array +drop cascades to foreign table db15_1key +drop cascades to foreign table db15_1key_hash +drop cascades to foreign table db15_1key_set +drop cascades to foreign table db15_1key_list +drop cascades to foreign table db15_1key_zset +drop cascades to foreign table db15_1key_zset_scores +drop cascades to foreign table db15_w_1key_scalar +drop cascades to foreign table db15_w_1key_hash +drop cascades to foreign table db15_w_1key_list +drop cascades to foreign table db15_w_1key_set +drop cascades to foreign table db15_w_1key_zset +drop cascades to foreign table db15_w_1key_zsetx +drop cascades to foreign table db15_w_scalar +drop cascades to foreign table db15_w_scalar_pfx +drop cascades to foreign table db15_w_scalar_kset +drop cascades to foreign table db15_w_set_nonarr +drop cascades to foreign table db15_w_set_pfx +drop cascades to foreign table db15_w_set_kset +drop cascades to foreign table db15_w_list_pfx +drop cascades to foreign table db15_w_list_kset +drop cascades to foreign table db15_w_zset_pfx +drop cascades to foreign table db15_w_zset_kset +drop cascades to foreign table db15_w_hash_pfx +drop cascades to foreign table db15_w_hash_kset +drop cascades to foreign table db15bigprefixscalar +drop cascades to foreign table db15bigkeysetscalar +DROP EXTENSION hstore; diff --git a/test/expected/15.7/nogis.out b/test/expected/15.7/nogis.out new file mode 100644 index 0000000..cf309cd --- /dev/null +++ b/test/expected/15.7/nogis.out @@ -0,0 +1,23 @@ +-- Testcase 001 +CREATE EXTENSION hstore; +-- Testcase 002 +CREATE EXTENSION redis_fdw; +-- Testcase 003 +create server localredis foreign data wrapper redis_fdw; +-- Testcase 004 +create user mapping for public server localredis; +-- Testcase 005 +-- \! redis-cli < test/redis_gis_ini +-- REDIS SPATIAL VALUE TESTS WILL BE HERE +-- Testcase 098 +-- all done, so now blow everything in the db away again +\! redis-cli < test/redis_clean +OK +OK +-- Testcase 099 +DROP EXTENSION redis_fdw CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to server localredis +drop cascades to user mapping for public on server localredis +-- Testcase 100 +DROP EXTENSION hstore CASCADE; diff --git a/test/expected/15.7/postgis.out b/test/expected/15.7/postgis.out new file mode 100644 index 0000000..0b315ca --- /dev/null +++ b/test/expected/15.7/postgis.out @@ -0,0 +1,26 @@ +-- Testcase 001 +CREATE EXTENSION postgis; +-- Testcase 002 +CREATE EXTENSION hstore; +-- Testcase 003 +CREATE EXTENSION redis_fdw; +-- Testcase 004 +create server localredis foreign data wrapper redis_fdw; +-- Testcase 005 +create user mapping for public server localredis; +-- Testcase 006 +-- \! redis-cli < test/redis_gis_ini +-- Testcase 098 +-- all done, so now blow everything in the db away again +\! redis-cli < test/redis_clean +OK +OK +-- Testcase 099 +DROP EXTENSION redis_fdw CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to server localredis +drop cascades to user mapping for public on server localredis +-- Testcase 100 +DROP EXTENSION hstore CASCADE; +-- Testcase 101 +DROP EXTENSION postgis CASCADE; diff --git a/test/expected/15.7/redis_fdw.out b/test/expected/15.7/redis_fdw.out new file mode 100644 index 0000000..7b5789d --- /dev/null +++ b/test/expected/15.7/redis_fdw.out @@ -0,0 +1,1466 @@ +-- Testcase 001: +CREATE EXTENSION hstore; +-- Testcase 002: +CREATE EXTENSION redis_fdw; +-- Testcase 003: +select redis_fdw_version(); + redis_fdw_version +------------------- + 1901 +(1 row) + +-- Testcase 004: +select redis_fdw_hiredis_version(); + redis_fdw_hiredis_version +--------------------------- + 1401 +(1 row) + +-- Testcase 005: +CREATE OR REPLACE FUNCTION atsort( a text[]) + RETURNS text[] + LANGUAGE sql + IMMUTABLE STRICT +AS $function$ + select array(select unnest($1) order by 1) +$function$; +create server localredis foreign data wrapper redis_fdw; +create user mapping for public server localredis; +-- tables for all 5 data types (4 structured plus scalar) +create foreign table db15(key text, value text) + server localredis + options (database '15'); +create foreign table db15_hash(key text, value text) + server localredis + options (database '15', tabletype 'hash'); +create foreign table db15_set(key text, value text) + server localredis + options (database '15', tabletype 'set'); +create foreign table db15_list(key text, value text) + server localredis + options (database '15', tabletype 'list'); +create foreign table db15_zset(key text, value text) + server localredis + options (database '15', tabletype 'zset'); +-- make sure they are all empty - if any are not stop the script right now +\set ON_ERROR_STOP +do $$ + declare + rows bigint; + begin + select into rows + (select count(*) from db15) + + (select count(*) from db15_hash) + + (select count(*) from db15_set) + + (select count(*) from db15_list) + + (select count(*) from db15_zset); + if rows > 0 + then + raise EXCEPTION 'db 15 not empty'; + end if; + end; +$$; +\unset ON_ERROR_STOP +-- ok, empty, so now run the setup script +\! redis-cli < test/redis_setup +OK +OK +OK +8 +5 +6 +4 +OK +OK +6 +6 +2 +2 +2 +2 +select * from db15 order by key; + key | value +-----+-------- + baz | blurfl + foo | bar +(2 rows) + +select * from db15 where key = 'foo'; + key | value +-----+------- + foo | bar +(1 row) + +-- hash +create foreign table db15_hash_prefix(key text, value text) + server localredis + options (tabletype 'hash', tablekeyprefix 'hash', database '15'); +create foreign table db15_hash_prefix_array(key text, value text[]) + server localredis + options (tabletype 'hash', tablekeyprefix 'hash', database '15'); +create foreign table db15_hash_keyset_array(key text, value text[]) + server localredis + options (tabletype 'hash', tablekeyset 'hkeys', database '15'); +select * from db15_hash_prefix order by key; + key | value +-------+------------------------------------------- + hash1 | {"k1","v1","k2","v2","k3","v3","k4","v4"} + hash2 | {"k1","v5","k2","v6","k3","v7","k4","v8"} +(2 rows) + +select * from db15_hash_prefix where key = 'hash1'; + key | value +-------+------------------------------------------- + hash1 | {"k1","v1","k2","v2","k3","v3","k4","v4"} +(1 row) + +select * from db15_hash_prefix_array order by key; + key | value +-------+--------------------------- + hash1 | {k1,v1,k2,v2,k3,v3,k4,v4} + hash2 | {k1,v5,k2,v6,k3,v7,k4,v8} +(2 rows) + +select * from db15_hash_prefix_array where key = 'hash1'; + key | value +-------+--------------------------- + hash1 | {k1,v1,k2,v2,k3,v3,k4,v4} +(1 row) + +select * from db15_hash_keyset_array order by key; + key | value +-------+--------------------------- + hash1 | {k1,v1,k2,v2,k3,v3,k4,v4} + hash2 | {k1,v5,k2,v6,k3,v7,k4,v8} +(2 rows) + +select * from db15_hash_keyset_array where key = 'hash1'; + key | value +-------+--------------------------- + hash1 | {k1,v1,k2,v2,k3,v3,k4,v4} +(1 row) + +-- a couple of nifty things we an do with hash tables +select key, hstore(value) from db15_hash_prefix_array order by key; + key | hstore +-------+------------------------------------------------ + hash1 | "k1"=>"v1", "k2"=>"v2", "k3"=>"v3", "k4"=>"v4" + hash2 | "k1"=>"v5", "k2"=>"v6", "k3"=>"v7", "k4"=>"v8" +(2 rows) + +create type atab as (k1 text, k2 text, k3 text); +select key, (populate_record(null::atab, hstore(value))).* +from db15_hash_prefix_array +order by key; + key | k1 | k2 | k3 +-------+----+----+---- + hash1 | v1 | v2 | v3 + hash2 | v5 | v6 | v7 +(2 rows) + +-- set +create foreign table db15_set_prefix(key text, value text) + server localredis + options (tabletype 'set', tablekeyprefix 'set', database '15'); +create foreign table db15_set_prefix_array(key text, value text[]) + server localredis + options (tabletype 'set', tablekeyprefix 'set', database '15'); +create foreign table db15_set_keyset_array(key text, value text[]) + server localredis + options (tabletype 'set', tablekeyset 'skeys', database '15'); +-- need to use atsort() on set results to get predicable output +-- since redis will give them back in arbitrary order +-- means we can't show the actual value for db15_set_prefix which has it as a +-- single text field +select key, atsort(value::text[]) as value from db15_set_prefix order by key; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} + set2 | {m10,m11,m12,m8,m9} +(2 rows) + +select key, atsort(value::text[]) as value from db15_set_prefix where key = 'set1'; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} +(1 row) + +select key, atsort(value) as value from db15_set_prefix_array order by key; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} + set2 | {m10,m11,m12,m8,m9} +(2 rows) + +select key, atsort(value) as value from db15_set_prefix_array where key = 'set1'; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} +(1 row) + +select key, atsort(value) as value from db15_set_keyset_array order by key; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} + set2 | {m10,m11,m12,m8,m9} +(2 rows) + +select key, atsort(value) as value from db15_set_keyset_array where key = 'set1'; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} +(1 row) + +-- list +create foreign table db15_list_prefix(key text, value text) + server localredis + options (tabletype 'list', tablekeyprefix 'list', database '15'); +create foreign table db15_list_prefix_array(key text, value text[]) + server localredis + options (tabletype 'list', tablekeyprefix 'list', database '15'); +create foreign table db15_list_keyset_array(key text, value text[]) + server localredis + options (tabletype 'list', tablekeyset 'lkeys', database '15'); +select * from db15_list_prefix order by key; + key | value +-------+--------------------------------- + list1 | {"e6","e5","e4","e3","e2","e1"} + list2 | {"e10","e9","e8","e7"} +(2 rows) + +select * from db15_list_prefix where key = 'list1'; + key | value +-------+--------------------------------- + list1 | {"e6","e5","e4","e3","e2","e1"} +(1 row) + +select * from db15_list_prefix_array order by key; + key | value +-------+--------------------- + list1 | {e6,e5,e4,e3,e2,e1} + list2 | {e10,e9,e8,e7} +(2 rows) + +select * from db15_list_prefix_array where key = 'list1'; + key | value +-------+--------------------- + list1 | {e6,e5,e4,e3,e2,e1} +(1 row) + +select * from db15_list_keyset_array order by key; + key | value +-------+--------------------- + list1 | {e6,e5,e4,e3,e2,e1} + list2 | {e10,e9,e8,e7} +(2 rows) + +select * from db15_list_keyset_array where key = 'list1'; + key | value +-------+--------------------- + list1 | {e6,e5,e4,e3,e2,e1} +(1 row) + +-- zset +create foreign table db15_zset_prefix(key text, value text) + server localredis + options (tabletype 'zset', tablekeyprefix 'zset', database '15'); +create foreign table db15_zset_prefix_array(key text, value text[]) + server localredis + options (tabletype 'zset', tablekeyprefix 'zset', database '15'); +create foreign table db15_zset_keyset_array(key text, value text[]) + server localredis + options (tabletype 'zset', tablekeyset 'zkeys', database '15'); +select * from db15_zset_prefix order by key; + key | value +-------+------------------------------------ + zset1 | {"z1","z2","z3","z4","z5","z6"} + zset2 | {"z7","z8","z9","z10","z11","z12"} +(2 rows) + +select * from db15_zset_prefix where key = 'zset1'; + key | value +-------+--------------------------------- + zset1 | {"z1","z2","z3","z4","z5","z6"} +(1 row) + +select * from db15_zset_prefix_array order by key; + key | value +-------+------------------------ + zset1 | {z1,z2,z3,z4,z5,z6} + zset2 | {z7,z8,z9,z10,z11,z12} +(2 rows) + +select * from db15_zset_prefix_array where key = 'zset1'; + key | value +-------+--------------------- + zset1 | {z1,z2,z3,z4,z5,z6} +(1 row) + +select * from db15_zset_keyset_array order by key; + key | value +-------+------------------------ + zset1 | {z1,z2,z3,z4,z5,z6} + zset2 | {z7,z8,z9,z10,z11,z12} +(2 rows) + +select * from db15_zset_keyset_array where key = 'zset1'; + key | value +-------+--------------------- + zset1 | {z1,z2,z3,z4,z5,z6} +(1 row) + +-- singleton scalar +create foreign table db15_1key(value text) + server localredis + options (singleton_key 'foo', database '15'); +select * from db15_1key; + value +------- + bar +(1 row) + +-- singleton hash +create foreign table db15_1key_hash(key text, value text) + server localredis + options (tabletype 'hash', singleton_key 'hash1', database '15'); +select * from db15_1key_hash order by key; + key | value +-----+------- + k1 | v1 + k2 | v2 + k3 | v3 + k4 | v4 +(4 rows) + +-- singleton set +create foreign table db15_1key_set(value text) + server localredis + options (tabletype 'set', singleton_key 'set1', database '15'); +select * from db15_1key_set order by value; + value +------- + m1 + m2 + m3 + m4 + m5 + m6 + m7 + m8 +(8 rows) + +-- singleton list +create foreign table db15_1key_list(value text) + server localredis + options (tabletype 'list', singleton_key 'list1', database '15'); +select * from db15_1key_list order by value; + value +------- + e1 + e2 + e3 + e4 + e5 + e6 +(6 rows) + +-- singleton zset +create foreign table db15_1key_zset(value text) + server localredis + options (tabletype 'zset', singleton_key 'zset1', database '15'); +select * from db15_1key_zset order by value; + value +------- + z1 + z2 + z3 + z4 + z5 + z6 +(6 rows) + +-- singleton zset with scores +create foreign table db15_1key_zset_scores(value text, score numeric) + server localredis + options (tabletype 'zset', singleton_key 'zset1', database '15'); +select * from db15_1key_zset_scores order by score desc; + value | score +-------+------- + z6 | 6 + z5 | 5 + z4 | 4 + z3 | 3 + z2 | 2 + z1 | 1 +(6 rows) + +-- insert delete update +-- first clean the database again +\! redis-cli < test/redis_clean +OK +OK +-- singleton scalar table +create foreign table db15_w_1key_scalar(val text) + server localredis + options (singleton_key 'w_1key_scalar', database '15'); +select * from db15_w_1key_scalar; + val +----- +(0 rows) + +insert into db15_w_1key_scalar values ('only row'); +select * from db15_w_1key_scalar; + val +---------- + only row +(1 row) + +insert into db15_w_1key_scalar values ('only row'); +ERROR: key already exists: w_1key_scalar +delete from db15_w_1key_scalar where val = 'not only row'; +select * from db15_w_1key_scalar; + val +---------- + only row +(1 row) + +update db15_w_1key_scalar set val = 'new scalar val'; +select * from db15_w_1key_scalar; + val +---------------- + new scalar val +(1 row) + +delete from db15_w_1key_scalar; +select * from db15_w_1key_scalar; + val +----- +(0 rows) + +-- singleton hash +create foreign table db15_w_1key_hash(key text, val text) + server localredis + options (singleton_key 'w_1key_hash', tabletype 'hash', database '15'); +select * from db15_w_1key_hash; + key | val +-----+----- +(0 rows) + +insert into db15_w_1key_hash values ('a','b'), ('c','d'),('e','f'); +select * from db15_w_1key_hash order by key; + key | val +-----+----- + a | b + c | d + e | f +(3 rows) + +insert into db15_w_1key_hash values ('a','b'); +ERROR: key already exists: a +delete from db15_w_1key_hash where key = 'a'; +delete from db15_w_1key_hash where key = 'a'; +select * from db15_w_1key_hash order by key; + key | val +-----+----- + c | d + e | f +(2 rows) + +update db15_w_1key_hash set key = 'x', val = 'y' where key = 'c'; +select * from db15_w_1key_hash order by key; + key | val +-----+----- + e | f + x | y +(2 rows) + +update db15_w_1key_hash set val = 'z' where key = 'e'; +select * from db15_w_1key_hash order by key; + key | val +-----+----- + e | z + x | y +(2 rows) + +update db15_w_1key_hash set key = 'w' where key = 'e'; +select * from db15_w_1key_hash order by key; + key | val +-----+----- + w | z + x | y +(2 rows) + +-- singleton list +create foreign table db15_w_1key_list(val text) + server localredis + options (singleton_key 'w_1key_list', tabletype 'list', database '15'); +select * from db15_w_1key_list; + val +----- +(0 rows) + +insert into db15_w_1key_list values ('a'), ('c'),('e'); +-- for lists the order should (must) be determinate +select * from db15_w_1key_list /* order by val */ ; + val +----- + a + c + e +(3 rows) + +delete from db15_w_1key_list where val = 'a'; +ERROR: delete not supported for this type of table +delete from db15_w_1key_list where val = 'z'; +ERROR: delete not supported for this type of table +insert into db15_w_1key_list values ('b'), ('d'),('f'),('a'); -- dups allowed here +select * from db15_w_1key_list /* order by val */; + val +----- + a + c + e + b + d + f + a +(7 rows) + +update db15_w_1key_list set val = 'y'; +ERROR: update not supported for this type of table +-- singleton set +create foreign table db15_w_1key_set(key text) + server localredis + options (singleton_key 'w_1key_set', tabletype 'set', database '15'); +select * from db15_w_1key_set; + key +----- +(0 rows) + +insert into db15_w_1key_set values ('a'), ('c'),('e'); +select * from db15_w_1key_set order by key; + key +----- + a + c + e +(3 rows) + +insert into db15_w_1key_set values ('a'); -- error - dup +ERROR: key already exists: a +delete from db15_w_1key_set where key = 'c'; +select * from db15_w_1key_set order by key; + key +----- + a + e +(2 rows) + +update db15_w_1key_set set key = 'x' where key = 'e'; +select * from db15_w_1key_set order by key; + key +----- + a + x +(2 rows) + +-- singleton zset with scores +create foreign table db15_w_1key_zset(key text, priority numeric) + server localredis + options (singleton_key 'w_1key_zset', tabletype 'zset', database '15'); +select * from db15_w_1key_zset; + key | priority +-----+---------- +(0 rows) + +insert into db15_w_1key_zset values ('a',1), ('c',5),('e',-5), ('h',10); +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + e | -5 + a | 1 + c | 5 + h | 10 +(4 rows) + +insert into db15_w_1key_zset values ('a',99); +ERROR: key already exists: a +delete from db15_w_1key_zset where key = 'a'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + e | -5 + c | 5 + h | 10 +(3 rows) + +delete from db15_w_1key_zset where priority = '5'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + e | -5 + h | 10 +(2 rows) + +update db15_w_1key_zset set key = 'x', priority = 99 where priority = '-5'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + h | 10 + x | 99 +(2 rows) + +update db15_w_1key_zset set key = 'y' where key = 'h'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + y | 10 + x | 99 +(2 rows) + +update db15_w_1key_zset set priority = 20 where key = 'y'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + y | 20 + x | 99 +(2 rows) + +-- singleton zset no scores +-- use set from last step +delete from db15_w_1key_zset; +insert into db15_w_1key_zset values ('e',-5); +create foreign table db15_w_1key_zsetx(key text) + server localredis + options (singleton_key 'w_1key_zset', tabletype 'zset', database '15'); +select * from db15_w_1key_zsetx; + key +----- + e +(1 row) + +insert into db15_w_1key_zsetx values ('a'), ('c'),('e'); -- can't insert +ERROR: operation not supported for singleton zset table without priorities column +update db15_w_1key_zsetx set key = 'z' where key = 'e'; +select * from db15_w_1key_zsetx order by key; + key +----- + z +(1 row) + +delete from db15_w_1key_zsetx where key = 'z'; +select * from db15_w_1key_zsetx order by key; + key +----- +(0 rows) + +-- non-singleton scalar table no prefix no keyset +create foreign table db15_w_scalar(key text, val text) + server localredis + options (database '15'); +select * from db15_w_scalar; + key | val +-----+----- +(0 rows) + +insert into db15_w_scalar values ('a_ws','b'), ('c_ws','d'),('e_ws','f'); +select * from db15_w_scalar order by key; + key | val +------+----- + a_ws | b + c_ws | d + e_ws | f +(3 rows) + +delete from db15_w_scalar where key = 'a_ws'; +select * from db15_w_scalar order by key; + key | val +------+----- + c_ws | d + e_ws | f +(2 rows) + +update db15_w_scalar set key = 'x_ws', val='y' where key = 'e_ws'; +select * from db15_w_scalar order by key; + key | val +------+----- + c_ws | d + x_ws | y +(2 rows) + +update db15_w_scalar set key = 'z_ws' where key = 'c_ws'; +select * from db15_w_scalar order by key; + key | val +------+----- + x_ws | y + z_ws | d +(2 rows) + +update db15_w_scalar set val = 'z' where key = 'z_ws'; +select * from db15_w_scalar order by key; + key | val +------+----- + x_ws | y + z_ws | z +(2 rows) + +/* +-- don't delete the whole namespace + delete from db15_w_scalar; + +select * from db15_w_scalar; +*/ +-- non-singleton scalar table keyprefix +create foreign table db15_w_scalar_pfx(key text, val text) + server localredis + options (database '15', tablekeyprefix 'w_scalar_'); +select * from db15_w_scalar_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_scalar_pfx values ('w_scalar_a','b'), ('w_scalar_c','d'),('w_scalar_e','f'); +insert into db15_w_scalar_pfx values ('x','y'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_scalar_' +insert into db15_w_scalar_pfx values ('w_scalar_a','x'); -- dup error +ERROR: key already exists: w_scalar_a +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_a | b + w_scalar_c | d + w_scalar_e | f +(3 rows) + +delete from db15_w_scalar_pfx where key = 'w_scalar_a'; +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_c | d + w_scalar_e | f +(2 rows) + +update db15_w_scalar_pfx set key = 'x', val = 'y' where key = 'w_scalar_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_scalar_pfx set key = 'x' where key = 'w_scalar_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_scalar_pfx set key = 'w_scalar_x', val = 'y' where key = 'w_scalar_c'; +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_e | f + w_scalar_x | y +(2 rows) + +update db15_w_scalar_pfx set key = 'w_scalar_z' where key = 'w_scalar_x'; +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_e | f + w_scalar_z | y +(2 rows) + +update db15_w_scalar_pfx set val = 'w' where key = 'w_scalar_e'; +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_e | w + w_scalar_z | y +(2 rows) + +delete from db15_w_scalar_pfx; +select * from db15_w_scalar_pfx order by key; + key | val +-----+----- +(0 rows) + +-- non-singleton scalar table keyset +create foreign table db15_w_scalar_kset(key text, val text) + server localredis + options (database '15', tablekeyset 'w_scalar_kset'); +select * from db15_w_scalar_kset order by key; + key | val +-----+----- +(0 rows) + +insert into db15_w_scalar_kset values ('a_wsks','b'), ('c_wsks','d'),('e_wsks','f'); +insert into db15_w_scalar_kset values ('a_wsks','x'); -- dup error +ERROR: key already exists: a_wsks +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + a_wsks | b + c_wsks | d + e_wsks | f +(3 rows) + +delete from db15_w_scalar_kset where key = 'a_wsks'; +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + c_wsks | d + e_wsks | f +(2 rows) + +update db15_w_scalar_kset set key = 'x_wsks', val = 'y' where key = 'c_wsks'; +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + e_wsks | f + x_wsks | y +(2 rows) + +update db15_w_scalar_kset set key = 'z_wsks' where key = 'x_wsks'; +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + e_wsks | f + z_wsks | y +(2 rows) + +update db15_w_scalar_kset set val = 'w' where key = 'e_wsks'; +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + e_wsks | w + z_wsks | y +(2 rows) + +delete from db15_w_scalar_kset; +select * from db15_w_scalar_kset order by key; + key | val +-----+----- +(0 rows) + +-- non-singleton set table no prefix no keyset +-- non-array case -- fails +create foreign table db15_w_set_nonarr(key text, val text) + server localredis + options (database '15', tabletype 'set'); +insert into db15_w_set_nonarr values ('nkseta','{b,c,d}'), ('nksetc','{d,e,f}'),('nksete','{f,g,h}'); +ERROR: cannot insert into this type of Redis table - needs an array +/* +-- namespace too polluted for this case +create foreign table db15_w_set(key text, val text[]) + server localredis + options (database '15', tabletype 'set'); + +select * from db15_w_set; + +insert into db15_w_set values ('nkseta','{b,c,d}'), ('nksetc','{d,e,f}'),('nksete','{f,g,h}'); + +select * from db15_w_set; + +delete from db15_w_set where key = 'nkseta'; + +select * from db15_w_set; + +delete from db15_w_set; + +select * from db15_w_set; + +*/ +-- non-singleton set table keyprefix +create foreign table db15_w_set_pfx(key text, val text[]) + server localredis + options (database '15', tabletype 'set', tablekeyprefix 'w_set_'); +select * from db15_w_set_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_set_pfx values ('w_set_a','{b,c,d}'), ('w_set_c','{d,e,f}'),('w_set_e','{f,g,h}'); +insert into db15_w_set_pfx values ('x','{y}'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_set_' +insert into db15_w_set_pfx values ('w_set_a','{x,y,z}'); -- dup error +ERROR: key already exists: w_set_a +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_a | {b,c,d} + w_set_c | {d,e,f} + w_set_e | {f,g,h} +(3 rows) + +delete from db15_w_set_pfx where key = 'w_set_a'; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_c | {d,e,f} + w_set_e | {f,g,h} +(2 rows) + +update db15_w_set_pfx set key = 'x' where key = 'w_set_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_set_pfx set key = 'x', val = '{y}' where key = 'w_set_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_set_pfx set key = 'w_set_x', val = '{x,y,z}' where key = 'w_set_c'; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_e | {f,g,h} + w_set_x | {x,y,z} +(2 rows) + +update db15_w_set_pfx set key = 'w_set_z' where key = 'w_set_x'; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_e | {f,g,h} + w_set_z | {x,y,z} +(2 rows) + +update db15_w_set_pfx set val = '{q,r,s}' where key = 'w_set_e'; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_e | {q,r,s} + w_set_z | {x,y,z} +(2 rows) + +delete from db15_w_set_pfx; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +-----+----- +(0 rows) + +-- non-singleton set table keyset +create foreign table db15_w_set_kset(key text, val text[]) + server localredis + options (database '15', tabletype 'set', tablekeyset 'w_set_kset'); +select * from db15_w_set_kset; + key | val +-----+----- +(0 rows) + +insert into db15_w_set_kset values ('a_wsk','{b,c,d}'), ('c_wsk','{d,e,f}'),('e_wsk','{f,g,h}'); +insert into db15_w_set_kset values ('a_wsk','{x}'); -- dup error +ERROR: key already exists: a_wsk +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + a_wsk | {b,c,d} + c_wsk | {d,e,f} + e_wsk | {f,g,h} +(3 rows) + +delete from db15_w_set_kset where key = 'a_wsk'; +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + c_wsk | {d,e,f} + e_wsk | {f,g,h} +(2 rows) + +update db15_w_set_kset set key = 'x_wsk', val = '{x,y,z}' where key = 'c_wsk'; +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + e_wsk | {f,g,h} + x_wsk | {x,y,z} +(2 rows) + +update db15_w_set_kset set key = 'z_wsk' where key = 'x_wsk'; +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + e_wsk | {f,g,h} + z_wsk | {x,y,z} +(2 rows) + +update db15_w_set_kset set val = '{q,r,s}' where key = 'e_wsk'; +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + e_wsk | {q,r,s} + z_wsk | {x,y,z} +(2 rows) + +delete from db15_w_set_kset; +select * from db15_w_set_kset; + key | val +-----+----- +(0 rows) + +-- non-singleton list table keyprefix +create foreign table db15_w_list_pfx(key text, val text[]) + server localredis + options (database '15', tabletype 'list', tablekeyprefix 'w_list_'); +select * from db15_w_list_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_list_pfx values ('w_list_a','{b,c,d}'), ('w_list_c','{d,e,f}'),('w_list_e','{f,g,h}'); +insert into db15_w_list_pfx values ('x','{y}'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_list_' +insert into db15_w_list_pfx values ('w_list_a','{x,y,z}'); -- dup error +ERROR: key already exists: w_list_a +select * from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_a | {b,c,d} + w_list_c | {d,e,f} + w_list_e | {f,g,h} +(3 rows) + +delete from db15_w_list_pfx where key = 'w_list_a'; +select * from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_c | {d,e,f} + w_list_e | {f,g,h} +(2 rows) + +update db15_w_list_pfx set key = 'x' where key = 'w_list_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_list_pfx set key = 'x', val = '{y}' where key = 'w_list_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_list_pfx set key = 'w_list_x', val = '{x,y,z}' where key = 'w_list_c'; +select key, atsort(val) as val from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_e | {f,g,h} + w_list_x | {x,y,z} +(2 rows) + +update db15_w_list_pfx set key = 'w_list_z' where key = 'w_list_x'; +select key, atsort(val) as val from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_e | {f,g,h} + w_list_z | {x,y,z} +(2 rows) + +update db15_w_list_pfx set val = '{q,r,s}' where key = 'w_list_e'; +select key, atsort(val) as val from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_e | {q,r,s} + w_list_z | {x,y,z} +(2 rows) + +delete from db15_w_list_pfx; +select * from db15_w_list_pfx; + key | val +-----+----- +(0 rows) + +-- non-singleton list table keyset +create foreign table db15_w_list_kset(key text, val text[]) + server localredis + options (database '15', tabletype 'list', tablekeyset 'w_list_kset'); +select * from db15_w_list_kset; + key | val +-----+----- +(0 rows) + +insert into db15_w_list_kset values ('a_wlk','{b,c,d}'), ('c_wlk','{d,e,f}'),('e_wlk','{f,g,h}'); +insert into db15_w_list_kset values ('a_wlk','{x}'); -- dup error +ERROR: key already exists: a_wlk +select * from db15_w_list_kset order by key; + key | val +-------+--------- + a_wlk | {b,c,d} + c_wlk | {d,e,f} + e_wlk | {f,g,h} +(3 rows) + +delete from db15_w_list_kset where key = 'a_wlk'; +select * from db15_w_list_kset order by key; + key | val +-------+--------- + c_wlk | {d,e,f} + e_wlk | {f,g,h} +(2 rows) + +update db15_w_list_kset set key = 'x_wlk', val = '{x,y,z}' where key = 'c_wlk'; +select key, atsort(val) as val from db15_w_list_kset order by key; + key | val +-------+--------- + e_wlk | {f,g,h} + x_wlk | {x,y,z} +(2 rows) + +update db15_w_list_kset set key = 'z_wlk' where key = 'x_wlk'; +select key, atsort(val) as val from db15_w_list_kset order by key; + key | val +-------+--------- + e_wlk | {f,g,h} + z_wlk | {x,y,z} +(2 rows) + +update db15_w_list_kset set val = '{q,r,s}' where key = 'e_wlk'; +select key, atsort(val) as val from db15_w_list_kset order by key; + key | val +-------+--------- + e_wlk | {q,r,s} + z_wlk | {x,y,z} +(2 rows) + +delete from db15_w_list_kset; +select * from db15_w_list_kset; + key | val +-----+----- +(0 rows) + +-- non-singleton zset table keyprefix +create foreign table db15_w_zset_pfx(key text, val text[]) + server localredis + options (database '15', tabletype 'zset', tablekeyprefix 'w_zset_'); +select * from db15_w_zset_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_zset_pfx values ('w_zset_a','{b,c,d}'), ('w_zset_c','{d,e,f}'),('w_zset_e','{f,g,h}'); +insert into db15_w_zset_pfx values ('x','{y}'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_zset_' +insert into db15_w_zset_pfx values ('w_zset_a','{x,y,z}'); -- dup error +ERROR: key already exists: w_zset_a +select * from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_a | {b,c,d} + w_zset_c | {d,e,f} + w_zset_e | {f,g,h} +(3 rows) + +delete from db15_w_zset_pfx where key = 'w_zset_a'; +select * from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_c | {d,e,f} + w_zset_e | {f,g,h} +(2 rows) + +update db15_w_zset_pfx set key = 'x' where key = 'w_zset_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_zset_pfx set key = 'x', val = '{y}' where key = 'w_zset_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_zset_pfx set key = 'w_zset_x', val = '{x,y,z}' where key = 'w_zset_c'; +select key, atsort(val) as val from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_e | {f,g,h} + w_zset_x | {x,y,z} +(2 rows) + +update db15_w_zset_pfx set key = 'w_zset_z' where key = 'w_zset_x'; +select key, atsort(val) as val from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_e | {f,g,h} + w_zset_z | {x,y,z} +(2 rows) + +update db15_w_zset_pfx set val = '{q,r,s}' where key = 'w_zset_e'; +select key, atsort(val) as val from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_e | {q,r,s} + w_zset_z | {x,y,z} +(2 rows) + +delete from db15_w_zset_pfx; +select * from db15_w_zset_pfx; + key | val +-----+----- +(0 rows) + +-- non-singleton zset table keyset +create foreign table db15_w_zset_kset(key text, val text[]) + server localredis + options (database '15', tabletype 'zset', tablekeyset 'w_zset_kset'); +select * from db15_w_zset_kset; + key | val +-----+----- +(0 rows) + +insert into db15_w_zset_kset values ('a_wzk','{b,c,d}'), ('c_wzk','{d,e,f}'),('e_wzk','{f,g,h}'); +insert into db15_w_zset_kset values ('a_wzk','{x}'); -- dup error +ERROR: key already exists: a_wzk +select * from db15_w_zset_kset order by key; + key | val +-------+--------- + a_wzk | {b,c,d} + c_wzk | {d,e,f} + e_wzk | {f,g,h} +(3 rows) + +delete from db15_w_zset_kset where key = 'a_wzk'; +select * from db15_w_zset_kset order by key; + key | val +-------+--------- + c_wzk | {d,e,f} + e_wzk | {f,g,h} +(2 rows) + +update db15_w_zset_kset set key = 'x_wlk', val = '{x,y,z}' where key = 'c_wzk'; +select key, atsort(val) as val from db15_w_zset_kset order by key; + key | val +-------+--------- + e_wzk | {f,g,h} + x_wlk | {x,y,z} +(2 rows) + +update db15_w_zset_kset set key = 'z_wzk' where key = 'x_wzk'; +select key, atsort(val) as val from db15_w_zset_kset order by key; + key | val +-------+--------- + e_wzk | {f,g,h} + x_wlk | {x,y,z} +(2 rows) + +update db15_w_zset_kset set val = '{q,r,s}' where key = 'e_wzk'; +select key, atsort(val) as val from db15_w_zset_kset order by key; + key | val +-------+--------- + e_wzk | {q,r,s} + x_wlk | {x,y,z} +(2 rows) + +delete from db15_w_zset_kset; +select * from db15_w_zset_kset; + key | val +-----+----- +(0 rows) + +-- non-singleton hash table prefix +create foreign table db15_w_hash_pfx(key text, val text[]) + server localredis + options (database '15', tabletype 'hash', tablekeyprefix 'w_hash_'); +select * from db15_w_hash_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_hash_pfx values ('w_hash_e','{f,g,h}'); -- error +ERROR: cannot decompose odd number of items into a Redis hash +insert into db15_w_hash_pfx values ('w_hash_e','{}'); -- error +ERROR: cannot store empty list in a Redis table +insert into db15_w_hash_pfx values ('w_hash_a','{b,c,d,e}'), ('w_hash_c','{f,g,h,i}'),('w_hash_e','{j,k}'); +insert into db15_w_hash_pfx values ('x','{y,z}'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_hash_' +insert into db15_w_hash_pfx values ('w_hash_a','{y,z}'); -- dup error +ERROR: key already exists: w_hash_a +select * from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_a | {b,c,d,e} + w_hash_c | {f,g,h,i} + w_hash_e | {j,k} +(3 rows) + +delete from db15_w_hash_pfx where key = 'w_hash_a'; +select * from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_c | {f,g,h,i} + w_hash_e | {j,k} +(2 rows) + +update db15_w_hash_pfx set key = 'x' where key = 'w_hash_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_hash_pfx set key = 'x', val = '{y,z}' where key = 'w_hash_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_hash_pfx set key = 'w_hash_x', val = '{x,y,z}' where key = 'w_hash_c'; -- err +ERROR: cannot decompose odd number of items into a Redis hash +update db15_w_hash_pfx set key = 'w_hash_x', val = '{w,x,y,z}' where key = 'w_hash_c'; +select key, val from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_e | {j,k} + w_hash_x | {w,x,y,z} +(2 rows) + +update db15_w_hash_pfx set key = 'w_hash_z' where key = 'w_hash_x'; +select key, val from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_e | {j,k} + w_hash_z | {w,x,y,z} +(2 rows) + +update db15_w_hash_pfx set val = '{q,r,s}' where key = 'w_hash_e'; +ERROR: cannot decompose odd number of items into a Redis hash +select key, val from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_e | {j,k} + w_hash_z | {w,x,y,z} +(2 rows) + +delete from db15_w_hash_pfx; +select * from db15_w_hash_pfx; + key | val +-----+----- +(0 rows) + +--non-singleton hash table keyset +create foreign table db15_w_hash_kset(key text, val text[]) + server localredis + options (database '15', tabletype 'hash', tablekeyset 'w_hash_kset'); +select * from db15_w_hash_kset; + key | val +-----+----- +(0 rows) + +insert into db15_w_hash_pfx values ('e_whk','{f,g,h}'); -- error +ERROR: key 'e_whk' does not match table key prefix 'w_hash_' +insert into db15_w_hash_pfx values ('e_whk','{}'); -- error +ERROR: key 'e_whk' does not match table key prefix 'w_hash_' +insert into db15_w_hash_kset values ('a_whk','{b,c,d,e}'), ('c_whk','{f,g,h,i}'),('e_whk','{j,k}'); +insert into db15_w_hash_kset values ('a_whk','{x,y}'); -- dup error +ERROR: key already exists: a_whk +select * from db15_w_hash_kset order by key; + key | val +-------+----------- + a_whk | {b,c,d,e} + c_whk | {f,g,h,i} + e_whk | {j,k} +(3 rows) + +delete from db15_w_hash_kset where key = 'a_whk'; +select * from db15_w_hash_kset order by key; + key | val +-------+----------- + c_whk | {f,g,h,i} + e_whk | {j,k} +(2 rows) + +update db15_w_hash_kset set key = 'x_whk', val = '{w,x,y,z}' where key = 'c_whk'; +select key, val from db15_w_hash_kset order by key; + key | val +-------+----------- + e_whk | {j,k} + x_whk | {w,x,y,z} +(2 rows) + +update db15_w_hash_kset set key = 'z_whk' where key = 'x_whk'; +select key, val from db15_w_hash_kset order by key; + key | val +-------+----------- + e_whk | {j,k} + z_whk | {w,x,y,z} +(2 rows) + +update db15_w_hash_kset set val = '{q,r}' where key = 'e_whk'; +select key, val from db15_w_hash_kset order by key; + key | val +-------+----------- + e_whk | {q,r} + z_whk | {w,x,y,z} +(2 rows) + +delete from db15_w_hash_kset; +select * from db15_w_hash_kset; + key | val +-----+----- +(0 rows) + +-- now clean up for the cursor tests +\! redis-cli < test/redis_clean +OK +OK +-- cursor tests +create foreign table db15bigprefixscalar ( + key text not null, + val text +) +server localredis +options (database '15', tablekeyprefix 'w_scalar_'); +create foreign table db15bigkeysetscalar ( + key text not null, + val text +) +server localredis +options (database '15', tablekeyset 'w_kset'); +insert into db15 +select 'junk' || x, 'junk' +from generate_series(1,10000) as x; +insert into db15bigprefixscalar +select 'w_scalar_' || x::text, 'val ' || x::text +from generate_series (1,10000) as x; +insert into db15bigkeysetscalar +select 'key_' || x::text, 'val ' || x::text +from generate_series (1,10000) as x; +insert into db15 +select 'junk' || x, 'junk' +from generate_series(10001, 20000) as x; +insert into db15bigprefixscalar +select 'w_scalar_' || x::text, 'val ' || x::text +from generate_series (10001, 20000) as x; +insert into db15bigkeysetscalar +select 'key_' || x::text, 'val ' || x::text +from generate_series (10001, 20000) as x; +select count(*) from db15; + count +------- + 60000 +(1 row) + +select count(*) from db15bigprefixscalar; + count +------- + 20000 +(1 row) + +select count(*) from db15bigkeysetscalar; + count +------- + 20000 +(1 row) + +-- all done, so now blow everything in the db away again +\! redis-cli < test/redis_clean +OK +OK +DROP EXTENSION redis_fdw CASCADE; +NOTICE: drop cascades to 45 other objects +DETAIL: drop cascades to server localredis +drop cascades to user mapping for public on server localredis +drop cascades to foreign table db15 +drop cascades to foreign table db15_hash +drop cascades to foreign table db15_set +drop cascades to foreign table db15_list +drop cascades to foreign table db15_zset +drop cascades to foreign table db15_hash_prefix +drop cascades to foreign table db15_hash_prefix_array +drop cascades to foreign table db15_hash_keyset_array +drop cascades to foreign table db15_set_prefix +drop cascades to foreign table db15_set_prefix_array +drop cascades to foreign table db15_set_keyset_array +drop cascades to foreign table db15_list_prefix +drop cascades to foreign table db15_list_prefix_array +drop cascades to foreign table db15_list_keyset_array +drop cascades to foreign table db15_zset_prefix +drop cascades to foreign table db15_zset_prefix_array +drop cascades to foreign table db15_zset_keyset_array +drop cascades to foreign table db15_1key +drop cascades to foreign table db15_1key_hash +drop cascades to foreign table db15_1key_set +drop cascades to foreign table db15_1key_list +drop cascades to foreign table db15_1key_zset +drop cascades to foreign table db15_1key_zset_scores +drop cascades to foreign table db15_w_1key_scalar +drop cascades to foreign table db15_w_1key_hash +drop cascades to foreign table db15_w_1key_list +drop cascades to foreign table db15_w_1key_set +drop cascades to foreign table db15_w_1key_zset +drop cascades to foreign table db15_w_1key_zsetx +drop cascades to foreign table db15_w_scalar +drop cascades to foreign table db15_w_scalar_pfx +drop cascades to foreign table db15_w_scalar_kset +drop cascades to foreign table db15_w_set_nonarr +drop cascades to foreign table db15_w_set_pfx +drop cascades to foreign table db15_w_set_kset +drop cascades to foreign table db15_w_list_pfx +drop cascades to foreign table db15_w_list_kset +drop cascades to foreign table db15_w_zset_pfx +drop cascades to foreign table db15_w_zset_kset +drop cascades to foreign table db15_w_hash_pfx +drop cascades to foreign table db15_w_hash_kset +drop cascades to foreign table db15bigprefixscalar +drop cascades to foreign table db15bigkeysetscalar +DROP EXTENSION hstore; diff --git a/test/expected/16.3/nogis.out b/test/expected/16.3/nogis.out new file mode 100644 index 0000000..cf309cd --- /dev/null +++ b/test/expected/16.3/nogis.out @@ -0,0 +1,23 @@ +-- Testcase 001 +CREATE EXTENSION hstore; +-- Testcase 002 +CREATE EXTENSION redis_fdw; +-- Testcase 003 +create server localredis foreign data wrapper redis_fdw; +-- Testcase 004 +create user mapping for public server localredis; +-- Testcase 005 +-- \! redis-cli < test/redis_gis_ini +-- REDIS SPATIAL VALUE TESTS WILL BE HERE +-- Testcase 098 +-- all done, so now blow everything in the db away again +\! redis-cli < test/redis_clean +OK +OK +-- Testcase 099 +DROP EXTENSION redis_fdw CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to server localredis +drop cascades to user mapping for public on server localredis +-- Testcase 100 +DROP EXTENSION hstore CASCADE; diff --git a/test/expected/16.3/postgis.out b/test/expected/16.3/postgis.out new file mode 100644 index 0000000..0b315ca --- /dev/null +++ b/test/expected/16.3/postgis.out @@ -0,0 +1,26 @@ +-- Testcase 001 +CREATE EXTENSION postgis; +-- Testcase 002 +CREATE EXTENSION hstore; +-- Testcase 003 +CREATE EXTENSION redis_fdw; +-- Testcase 004 +create server localredis foreign data wrapper redis_fdw; +-- Testcase 005 +create user mapping for public server localredis; +-- Testcase 006 +-- \! redis-cli < test/redis_gis_ini +-- Testcase 098 +-- all done, so now blow everything in the db away again +\! redis-cli < test/redis_clean +OK +OK +-- Testcase 099 +DROP EXTENSION redis_fdw CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to server localredis +drop cascades to user mapping for public on server localredis +-- Testcase 100 +DROP EXTENSION hstore CASCADE; +-- Testcase 101 +DROP EXTENSION postgis CASCADE; diff --git a/test/expected/16.3/redis_fdw.out b/test/expected/16.3/redis_fdw.out new file mode 100644 index 0000000..7b5789d --- /dev/null +++ b/test/expected/16.3/redis_fdw.out @@ -0,0 +1,1466 @@ +-- Testcase 001: +CREATE EXTENSION hstore; +-- Testcase 002: +CREATE EXTENSION redis_fdw; +-- Testcase 003: +select redis_fdw_version(); + redis_fdw_version +------------------- + 1901 +(1 row) + +-- Testcase 004: +select redis_fdw_hiredis_version(); + redis_fdw_hiredis_version +--------------------------- + 1401 +(1 row) + +-- Testcase 005: +CREATE OR REPLACE FUNCTION atsort( a text[]) + RETURNS text[] + LANGUAGE sql + IMMUTABLE STRICT +AS $function$ + select array(select unnest($1) order by 1) +$function$; +create server localredis foreign data wrapper redis_fdw; +create user mapping for public server localredis; +-- tables for all 5 data types (4 structured plus scalar) +create foreign table db15(key text, value text) + server localredis + options (database '15'); +create foreign table db15_hash(key text, value text) + server localredis + options (database '15', tabletype 'hash'); +create foreign table db15_set(key text, value text) + server localredis + options (database '15', tabletype 'set'); +create foreign table db15_list(key text, value text) + server localredis + options (database '15', tabletype 'list'); +create foreign table db15_zset(key text, value text) + server localredis + options (database '15', tabletype 'zset'); +-- make sure they are all empty - if any are not stop the script right now +\set ON_ERROR_STOP +do $$ + declare + rows bigint; + begin + select into rows + (select count(*) from db15) + + (select count(*) from db15_hash) + + (select count(*) from db15_set) + + (select count(*) from db15_list) + + (select count(*) from db15_zset); + if rows > 0 + then + raise EXCEPTION 'db 15 not empty'; + end if; + end; +$$; +\unset ON_ERROR_STOP +-- ok, empty, so now run the setup script +\! redis-cli < test/redis_setup +OK +OK +OK +8 +5 +6 +4 +OK +OK +6 +6 +2 +2 +2 +2 +select * from db15 order by key; + key | value +-----+-------- + baz | blurfl + foo | bar +(2 rows) + +select * from db15 where key = 'foo'; + key | value +-----+------- + foo | bar +(1 row) + +-- hash +create foreign table db15_hash_prefix(key text, value text) + server localredis + options (tabletype 'hash', tablekeyprefix 'hash', database '15'); +create foreign table db15_hash_prefix_array(key text, value text[]) + server localredis + options (tabletype 'hash', tablekeyprefix 'hash', database '15'); +create foreign table db15_hash_keyset_array(key text, value text[]) + server localredis + options (tabletype 'hash', tablekeyset 'hkeys', database '15'); +select * from db15_hash_prefix order by key; + key | value +-------+------------------------------------------- + hash1 | {"k1","v1","k2","v2","k3","v3","k4","v4"} + hash2 | {"k1","v5","k2","v6","k3","v7","k4","v8"} +(2 rows) + +select * from db15_hash_prefix where key = 'hash1'; + key | value +-------+------------------------------------------- + hash1 | {"k1","v1","k2","v2","k3","v3","k4","v4"} +(1 row) + +select * from db15_hash_prefix_array order by key; + key | value +-------+--------------------------- + hash1 | {k1,v1,k2,v2,k3,v3,k4,v4} + hash2 | {k1,v5,k2,v6,k3,v7,k4,v8} +(2 rows) + +select * from db15_hash_prefix_array where key = 'hash1'; + key | value +-------+--------------------------- + hash1 | {k1,v1,k2,v2,k3,v3,k4,v4} +(1 row) + +select * from db15_hash_keyset_array order by key; + key | value +-------+--------------------------- + hash1 | {k1,v1,k2,v2,k3,v3,k4,v4} + hash2 | {k1,v5,k2,v6,k3,v7,k4,v8} +(2 rows) + +select * from db15_hash_keyset_array where key = 'hash1'; + key | value +-------+--------------------------- + hash1 | {k1,v1,k2,v2,k3,v3,k4,v4} +(1 row) + +-- a couple of nifty things we an do with hash tables +select key, hstore(value) from db15_hash_prefix_array order by key; + key | hstore +-------+------------------------------------------------ + hash1 | "k1"=>"v1", "k2"=>"v2", "k3"=>"v3", "k4"=>"v4" + hash2 | "k1"=>"v5", "k2"=>"v6", "k3"=>"v7", "k4"=>"v8" +(2 rows) + +create type atab as (k1 text, k2 text, k3 text); +select key, (populate_record(null::atab, hstore(value))).* +from db15_hash_prefix_array +order by key; + key | k1 | k2 | k3 +-------+----+----+---- + hash1 | v1 | v2 | v3 + hash2 | v5 | v6 | v7 +(2 rows) + +-- set +create foreign table db15_set_prefix(key text, value text) + server localredis + options (tabletype 'set', tablekeyprefix 'set', database '15'); +create foreign table db15_set_prefix_array(key text, value text[]) + server localredis + options (tabletype 'set', tablekeyprefix 'set', database '15'); +create foreign table db15_set_keyset_array(key text, value text[]) + server localredis + options (tabletype 'set', tablekeyset 'skeys', database '15'); +-- need to use atsort() on set results to get predicable output +-- since redis will give them back in arbitrary order +-- means we can't show the actual value for db15_set_prefix which has it as a +-- single text field +select key, atsort(value::text[]) as value from db15_set_prefix order by key; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} + set2 | {m10,m11,m12,m8,m9} +(2 rows) + +select key, atsort(value::text[]) as value from db15_set_prefix where key = 'set1'; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} +(1 row) + +select key, atsort(value) as value from db15_set_prefix_array order by key; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} + set2 | {m10,m11,m12,m8,m9} +(2 rows) + +select key, atsort(value) as value from db15_set_prefix_array where key = 'set1'; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} +(1 row) + +select key, atsort(value) as value from db15_set_keyset_array order by key; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} + set2 | {m10,m11,m12,m8,m9} +(2 rows) + +select key, atsort(value) as value from db15_set_keyset_array where key = 'set1'; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} +(1 row) + +-- list +create foreign table db15_list_prefix(key text, value text) + server localredis + options (tabletype 'list', tablekeyprefix 'list', database '15'); +create foreign table db15_list_prefix_array(key text, value text[]) + server localredis + options (tabletype 'list', tablekeyprefix 'list', database '15'); +create foreign table db15_list_keyset_array(key text, value text[]) + server localredis + options (tabletype 'list', tablekeyset 'lkeys', database '15'); +select * from db15_list_prefix order by key; + key | value +-------+--------------------------------- + list1 | {"e6","e5","e4","e3","e2","e1"} + list2 | {"e10","e9","e8","e7"} +(2 rows) + +select * from db15_list_prefix where key = 'list1'; + key | value +-------+--------------------------------- + list1 | {"e6","e5","e4","e3","e2","e1"} +(1 row) + +select * from db15_list_prefix_array order by key; + key | value +-------+--------------------- + list1 | {e6,e5,e4,e3,e2,e1} + list2 | {e10,e9,e8,e7} +(2 rows) + +select * from db15_list_prefix_array where key = 'list1'; + key | value +-------+--------------------- + list1 | {e6,e5,e4,e3,e2,e1} +(1 row) + +select * from db15_list_keyset_array order by key; + key | value +-------+--------------------- + list1 | {e6,e5,e4,e3,e2,e1} + list2 | {e10,e9,e8,e7} +(2 rows) + +select * from db15_list_keyset_array where key = 'list1'; + key | value +-------+--------------------- + list1 | {e6,e5,e4,e3,e2,e1} +(1 row) + +-- zset +create foreign table db15_zset_prefix(key text, value text) + server localredis + options (tabletype 'zset', tablekeyprefix 'zset', database '15'); +create foreign table db15_zset_prefix_array(key text, value text[]) + server localredis + options (tabletype 'zset', tablekeyprefix 'zset', database '15'); +create foreign table db15_zset_keyset_array(key text, value text[]) + server localredis + options (tabletype 'zset', tablekeyset 'zkeys', database '15'); +select * from db15_zset_prefix order by key; + key | value +-------+------------------------------------ + zset1 | {"z1","z2","z3","z4","z5","z6"} + zset2 | {"z7","z8","z9","z10","z11","z12"} +(2 rows) + +select * from db15_zset_prefix where key = 'zset1'; + key | value +-------+--------------------------------- + zset1 | {"z1","z2","z3","z4","z5","z6"} +(1 row) + +select * from db15_zset_prefix_array order by key; + key | value +-------+------------------------ + zset1 | {z1,z2,z3,z4,z5,z6} + zset2 | {z7,z8,z9,z10,z11,z12} +(2 rows) + +select * from db15_zset_prefix_array where key = 'zset1'; + key | value +-------+--------------------- + zset1 | {z1,z2,z3,z4,z5,z6} +(1 row) + +select * from db15_zset_keyset_array order by key; + key | value +-------+------------------------ + zset1 | {z1,z2,z3,z4,z5,z6} + zset2 | {z7,z8,z9,z10,z11,z12} +(2 rows) + +select * from db15_zset_keyset_array where key = 'zset1'; + key | value +-------+--------------------- + zset1 | {z1,z2,z3,z4,z5,z6} +(1 row) + +-- singleton scalar +create foreign table db15_1key(value text) + server localredis + options (singleton_key 'foo', database '15'); +select * from db15_1key; + value +------- + bar +(1 row) + +-- singleton hash +create foreign table db15_1key_hash(key text, value text) + server localredis + options (tabletype 'hash', singleton_key 'hash1', database '15'); +select * from db15_1key_hash order by key; + key | value +-----+------- + k1 | v1 + k2 | v2 + k3 | v3 + k4 | v4 +(4 rows) + +-- singleton set +create foreign table db15_1key_set(value text) + server localredis + options (tabletype 'set', singleton_key 'set1', database '15'); +select * from db15_1key_set order by value; + value +------- + m1 + m2 + m3 + m4 + m5 + m6 + m7 + m8 +(8 rows) + +-- singleton list +create foreign table db15_1key_list(value text) + server localredis + options (tabletype 'list', singleton_key 'list1', database '15'); +select * from db15_1key_list order by value; + value +------- + e1 + e2 + e3 + e4 + e5 + e6 +(6 rows) + +-- singleton zset +create foreign table db15_1key_zset(value text) + server localredis + options (tabletype 'zset', singleton_key 'zset1', database '15'); +select * from db15_1key_zset order by value; + value +------- + z1 + z2 + z3 + z4 + z5 + z6 +(6 rows) + +-- singleton zset with scores +create foreign table db15_1key_zset_scores(value text, score numeric) + server localredis + options (tabletype 'zset', singleton_key 'zset1', database '15'); +select * from db15_1key_zset_scores order by score desc; + value | score +-------+------- + z6 | 6 + z5 | 5 + z4 | 4 + z3 | 3 + z2 | 2 + z1 | 1 +(6 rows) + +-- insert delete update +-- first clean the database again +\! redis-cli < test/redis_clean +OK +OK +-- singleton scalar table +create foreign table db15_w_1key_scalar(val text) + server localredis + options (singleton_key 'w_1key_scalar', database '15'); +select * from db15_w_1key_scalar; + val +----- +(0 rows) + +insert into db15_w_1key_scalar values ('only row'); +select * from db15_w_1key_scalar; + val +---------- + only row +(1 row) + +insert into db15_w_1key_scalar values ('only row'); +ERROR: key already exists: w_1key_scalar +delete from db15_w_1key_scalar where val = 'not only row'; +select * from db15_w_1key_scalar; + val +---------- + only row +(1 row) + +update db15_w_1key_scalar set val = 'new scalar val'; +select * from db15_w_1key_scalar; + val +---------------- + new scalar val +(1 row) + +delete from db15_w_1key_scalar; +select * from db15_w_1key_scalar; + val +----- +(0 rows) + +-- singleton hash +create foreign table db15_w_1key_hash(key text, val text) + server localredis + options (singleton_key 'w_1key_hash', tabletype 'hash', database '15'); +select * from db15_w_1key_hash; + key | val +-----+----- +(0 rows) + +insert into db15_w_1key_hash values ('a','b'), ('c','d'),('e','f'); +select * from db15_w_1key_hash order by key; + key | val +-----+----- + a | b + c | d + e | f +(3 rows) + +insert into db15_w_1key_hash values ('a','b'); +ERROR: key already exists: a +delete from db15_w_1key_hash where key = 'a'; +delete from db15_w_1key_hash where key = 'a'; +select * from db15_w_1key_hash order by key; + key | val +-----+----- + c | d + e | f +(2 rows) + +update db15_w_1key_hash set key = 'x', val = 'y' where key = 'c'; +select * from db15_w_1key_hash order by key; + key | val +-----+----- + e | f + x | y +(2 rows) + +update db15_w_1key_hash set val = 'z' where key = 'e'; +select * from db15_w_1key_hash order by key; + key | val +-----+----- + e | z + x | y +(2 rows) + +update db15_w_1key_hash set key = 'w' where key = 'e'; +select * from db15_w_1key_hash order by key; + key | val +-----+----- + w | z + x | y +(2 rows) + +-- singleton list +create foreign table db15_w_1key_list(val text) + server localredis + options (singleton_key 'w_1key_list', tabletype 'list', database '15'); +select * from db15_w_1key_list; + val +----- +(0 rows) + +insert into db15_w_1key_list values ('a'), ('c'),('e'); +-- for lists the order should (must) be determinate +select * from db15_w_1key_list /* order by val */ ; + val +----- + a + c + e +(3 rows) + +delete from db15_w_1key_list where val = 'a'; +ERROR: delete not supported for this type of table +delete from db15_w_1key_list where val = 'z'; +ERROR: delete not supported for this type of table +insert into db15_w_1key_list values ('b'), ('d'),('f'),('a'); -- dups allowed here +select * from db15_w_1key_list /* order by val */; + val +----- + a + c + e + b + d + f + a +(7 rows) + +update db15_w_1key_list set val = 'y'; +ERROR: update not supported for this type of table +-- singleton set +create foreign table db15_w_1key_set(key text) + server localredis + options (singleton_key 'w_1key_set', tabletype 'set', database '15'); +select * from db15_w_1key_set; + key +----- +(0 rows) + +insert into db15_w_1key_set values ('a'), ('c'),('e'); +select * from db15_w_1key_set order by key; + key +----- + a + c + e +(3 rows) + +insert into db15_w_1key_set values ('a'); -- error - dup +ERROR: key already exists: a +delete from db15_w_1key_set where key = 'c'; +select * from db15_w_1key_set order by key; + key +----- + a + e +(2 rows) + +update db15_w_1key_set set key = 'x' where key = 'e'; +select * from db15_w_1key_set order by key; + key +----- + a + x +(2 rows) + +-- singleton zset with scores +create foreign table db15_w_1key_zset(key text, priority numeric) + server localredis + options (singleton_key 'w_1key_zset', tabletype 'zset', database '15'); +select * from db15_w_1key_zset; + key | priority +-----+---------- +(0 rows) + +insert into db15_w_1key_zset values ('a',1), ('c',5),('e',-5), ('h',10); +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + e | -5 + a | 1 + c | 5 + h | 10 +(4 rows) + +insert into db15_w_1key_zset values ('a',99); +ERROR: key already exists: a +delete from db15_w_1key_zset where key = 'a'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + e | -5 + c | 5 + h | 10 +(3 rows) + +delete from db15_w_1key_zset where priority = '5'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + e | -5 + h | 10 +(2 rows) + +update db15_w_1key_zset set key = 'x', priority = 99 where priority = '-5'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + h | 10 + x | 99 +(2 rows) + +update db15_w_1key_zset set key = 'y' where key = 'h'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + y | 10 + x | 99 +(2 rows) + +update db15_w_1key_zset set priority = 20 where key = 'y'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + y | 20 + x | 99 +(2 rows) + +-- singleton zset no scores +-- use set from last step +delete from db15_w_1key_zset; +insert into db15_w_1key_zset values ('e',-5); +create foreign table db15_w_1key_zsetx(key text) + server localredis + options (singleton_key 'w_1key_zset', tabletype 'zset', database '15'); +select * from db15_w_1key_zsetx; + key +----- + e +(1 row) + +insert into db15_w_1key_zsetx values ('a'), ('c'),('e'); -- can't insert +ERROR: operation not supported for singleton zset table without priorities column +update db15_w_1key_zsetx set key = 'z' where key = 'e'; +select * from db15_w_1key_zsetx order by key; + key +----- + z +(1 row) + +delete from db15_w_1key_zsetx where key = 'z'; +select * from db15_w_1key_zsetx order by key; + key +----- +(0 rows) + +-- non-singleton scalar table no prefix no keyset +create foreign table db15_w_scalar(key text, val text) + server localredis + options (database '15'); +select * from db15_w_scalar; + key | val +-----+----- +(0 rows) + +insert into db15_w_scalar values ('a_ws','b'), ('c_ws','d'),('e_ws','f'); +select * from db15_w_scalar order by key; + key | val +------+----- + a_ws | b + c_ws | d + e_ws | f +(3 rows) + +delete from db15_w_scalar where key = 'a_ws'; +select * from db15_w_scalar order by key; + key | val +------+----- + c_ws | d + e_ws | f +(2 rows) + +update db15_w_scalar set key = 'x_ws', val='y' where key = 'e_ws'; +select * from db15_w_scalar order by key; + key | val +------+----- + c_ws | d + x_ws | y +(2 rows) + +update db15_w_scalar set key = 'z_ws' where key = 'c_ws'; +select * from db15_w_scalar order by key; + key | val +------+----- + x_ws | y + z_ws | d +(2 rows) + +update db15_w_scalar set val = 'z' where key = 'z_ws'; +select * from db15_w_scalar order by key; + key | val +------+----- + x_ws | y + z_ws | z +(2 rows) + +/* +-- don't delete the whole namespace + delete from db15_w_scalar; + +select * from db15_w_scalar; +*/ +-- non-singleton scalar table keyprefix +create foreign table db15_w_scalar_pfx(key text, val text) + server localredis + options (database '15', tablekeyprefix 'w_scalar_'); +select * from db15_w_scalar_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_scalar_pfx values ('w_scalar_a','b'), ('w_scalar_c','d'),('w_scalar_e','f'); +insert into db15_w_scalar_pfx values ('x','y'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_scalar_' +insert into db15_w_scalar_pfx values ('w_scalar_a','x'); -- dup error +ERROR: key already exists: w_scalar_a +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_a | b + w_scalar_c | d + w_scalar_e | f +(3 rows) + +delete from db15_w_scalar_pfx where key = 'w_scalar_a'; +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_c | d + w_scalar_e | f +(2 rows) + +update db15_w_scalar_pfx set key = 'x', val = 'y' where key = 'w_scalar_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_scalar_pfx set key = 'x' where key = 'w_scalar_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_scalar_pfx set key = 'w_scalar_x', val = 'y' where key = 'w_scalar_c'; +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_e | f + w_scalar_x | y +(2 rows) + +update db15_w_scalar_pfx set key = 'w_scalar_z' where key = 'w_scalar_x'; +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_e | f + w_scalar_z | y +(2 rows) + +update db15_w_scalar_pfx set val = 'w' where key = 'w_scalar_e'; +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_e | w + w_scalar_z | y +(2 rows) + +delete from db15_w_scalar_pfx; +select * from db15_w_scalar_pfx order by key; + key | val +-----+----- +(0 rows) + +-- non-singleton scalar table keyset +create foreign table db15_w_scalar_kset(key text, val text) + server localredis + options (database '15', tablekeyset 'w_scalar_kset'); +select * from db15_w_scalar_kset order by key; + key | val +-----+----- +(0 rows) + +insert into db15_w_scalar_kset values ('a_wsks','b'), ('c_wsks','d'),('e_wsks','f'); +insert into db15_w_scalar_kset values ('a_wsks','x'); -- dup error +ERROR: key already exists: a_wsks +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + a_wsks | b + c_wsks | d + e_wsks | f +(3 rows) + +delete from db15_w_scalar_kset where key = 'a_wsks'; +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + c_wsks | d + e_wsks | f +(2 rows) + +update db15_w_scalar_kset set key = 'x_wsks', val = 'y' where key = 'c_wsks'; +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + e_wsks | f + x_wsks | y +(2 rows) + +update db15_w_scalar_kset set key = 'z_wsks' where key = 'x_wsks'; +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + e_wsks | f + z_wsks | y +(2 rows) + +update db15_w_scalar_kset set val = 'w' where key = 'e_wsks'; +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + e_wsks | w + z_wsks | y +(2 rows) + +delete from db15_w_scalar_kset; +select * from db15_w_scalar_kset order by key; + key | val +-----+----- +(0 rows) + +-- non-singleton set table no prefix no keyset +-- non-array case -- fails +create foreign table db15_w_set_nonarr(key text, val text) + server localredis + options (database '15', tabletype 'set'); +insert into db15_w_set_nonarr values ('nkseta','{b,c,d}'), ('nksetc','{d,e,f}'),('nksete','{f,g,h}'); +ERROR: cannot insert into this type of Redis table - needs an array +/* +-- namespace too polluted for this case +create foreign table db15_w_set(key text, val text[]) + server localredis + options (database '15', tabletype 'set'); + +select * from db15_w_set; + +insert into db15_w_set values ('nkseta','{b,c,d}'), ('nksetc','{d,e,f}'),('nksete','{f,g,h}'); + +select * from db15_w_set; + +delete from db15_w_set where key = 'nkseta'; + +select * from db15_w_set; + +delete from db15_w_set; + +select * from db15_w_set; + +*/ +-- non-singleton set table keyprefix +create foreign table db15_w_set_pfx(key text, val text[]) + server localredis + options (database '15', tabletype 'set', tablekeyprefix 'w_set_'); +select * from db15_w_set_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_set_pfx values ('w_set_a','{b,c,d}'), ('w_set_c','{d,e,f}'),('w_set_e','{f,g,h}'); +insert into db15_w_set_pfx values ('x','{y}'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_set_' +insert into db15_w_set_pfx values ('w_set_a','{x,y,z}'); -- dup error +ERROR: key already exists: w_set_a +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_a | {b,c,d} + w_set_c | {d,e,f} + w_set_e | {f,g,h} +(3 rows) + +delete from db15_w_set_pfx where key = 'w_set_a'; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_c | {d,e,f} + w_set_e | {f,g,h} +(2 rows) + +update db15_w_set_pfx set key = 'x' where key = 'w_set_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_set_pfx set key = 'x', val = '{y}' where key = 'w_set_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_set_pfx set key = 'w_set_x', val = '{x,y,z}' where key = 'w_set_c'; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_e | {f,g,h} + w_set_x | {x,y,z} +(2 rows) + +update db15_w_set_pfx set key = 'w_set_z' where key = 'w_set_x'; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_e | {f,g,h} + w_set_z | {x,y,z} +(2 rows) + +update db15_w_set_pfx set val = '{q,r,s}' where key = 'w_set_e'; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_e | {q,r,s} + w_set_z | {x,y,z} +(2 rows) + +delete from db15_w_set_pfx; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +-----+----- +(0 rows) + +-- non-singleton set table keyset +create foreign table db15_w_set_kset(key text, val text[]) + server localredis + options (database '15', tabletype 'set', tablekeyset 'w_set_kset'); +select * from db15_w_set_kset; + key | val +-----+----- +(0 rows) + +insert into db15_w_set_kset values ('a_wsk','{b,c,d}'), ('c_wsk','{d,e,f}'),('e_wsk','{f,g,h}'); +insert into db15_w_set_kset values ('a_wsk','{x}'); -- dup error +ERROR: key already exists: a_wsk +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + a_wsk | {b,c,d} + c_wsk | {d,e,f} + e_wsk | {f,g,h} +(3 rows) + +delete from db15_w_set_kset where key = 'a_wsk'; +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + c_wsk | {d,e,f} + e_wsk | {f,g,h} +(2 rows) + +update db15_w_set_kset set key = 'x_wsk', val = '{x,y,z}' where key = 'c_wsk'; +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + e_wsk | {f,g,h} + x_wsk | {x,y,z} +(2 rows) + +update db15_w_set_kset set key = 'z_wsk' where key = 'x_wsk'; +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + e_wsk | {f,g,h} + z_wsk | {x,y,z} +(2 rows) + +update db15_w_set_kset set val = '{q,r,s}' where key = 'e_wsk'; +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + e_wsk | {q,r,s} + z_wsk | {x,y,z} +(2 rows) + +delete from db15_w_set_kset; +select * from db15_w_set_kset; + key | val +-----+----- +(0 rows) + +-- non-singleton list table keyprefix +create foreign table db15_w_list_pfx(key text, val text[]) + server localredis + options (database '15', tabletype 'list', tablekeyprefix 'w_list_'); +select * from db15_w_list_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_list_pfx values ('w_list_a','{b,c,d}'), ('w_list_c','{d,e,f}'),('w_list_e','{f,g,h}'); +insert into db15_w_list_pfx values ('x','{y}'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_list_' +insert into db15_w_list_pfx values ('w_list_a','{x,y,z}'); -- dup error +ERROR: key already exists: w_list_a +select * from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_a | {b,c,d} + w_list_c | {d,e,f} + w_list_e | {f,g,h} +(3 rows) + +delete from db15_w_list_pfx where key = 'w_list_a'; +select * from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_c | {d,e,f} + w_list_e | {f,g,h} +(2 rows) + +update db15_w_list_pfx set key = 'x' where key = 'w_list_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_list_pfx set key = 'x', val = '{y}' where key = 'w_list_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_list_pfx set key = 'w_list_x', val = '{x,y,z}' where key = 'w_list_c'; +select key, atsort(val) as val from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_e | {f,g,h} + w_list_x | {x,y,z} +(2 rows) + +update db15_w_list_pfx set key = 'w_list_z' where key = 'w_list_x'; +select key, atsort(val) as val from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_e | {f,g,h} + w_list_z | {x,y,z} +(2 rows) + +update db15_w_list_pfx set val = '{q,r,s}' where key = 'w_list_e'; +select key, atsort(val) as val from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_e | {q,r,s} + w_list_z | {x,y,z} +(2 rows) + +delete from db15_w_list_pfx; +select * from db15_w_list_pfx; + key | val +-----+----- +(0 rows) + +-- non-singleton list table keyset +create foreign table db15_w_list_kset(key text, val text[]) + server localredis + options (database '15', tabletype 'list', tablekeyset 'w_list_kset'); +select * from db15_w_list_kset; + key | val +-----+----- +(0 rows) + +insert into db15_w_list_kset values ('a_wlk','{b,c,d}'), ('c_wlk','{d,e,f}'),('e_wlk','{f,g,h}'); +insert into db15_w_list_kset values ('a_wlk','{x}'); -- dup error +ERROR: key already exists: a_wlk +select * from db15_w_list_kset order by key; + key | val +-------+--------- + a_wlk | {b,c,d} + c_wlk | {d,e,f} + e_wlk | {f,g,h} +(3 rows) + +delete from db15_w_list_kset where key = 'a_wlk'; +select * from db15_w_list_kset order by key; + key | val +-------+--------- + c_wlk | {d,e,f} + e_wlk | {f,g,h} +(2 rows) + +update db15_w_list_kset set key = 'x_wlk', val = '{x,y,z}' where key = 'c_wlk'; +select key, atsort(val) as val from db15_w_list_kset order by key; + key | val +-------+--------- + e_wlk | {f,g,h} + x_wlk | {x,y,z} +(2 rows) + +update db15_w_list_kset set key = 'z_wlk' where key = 'x_wlk'; +select key, atsort(val) as val from db15_w_list_kset order by key; + key | val +-------+--------- + e_wlk | {f,g,h} + z_wlk | {x,y,z} +(2 rows) + +update db15_w_list_kset set val = '{q,r,s}' where key = 'e_wlk'; +select key, atsort(val) as val from db15_w_list_kset order by key; + key | val +-------+--------- + e_wlk | {q,r,s} + z_wlk | {x,y,z} +(2 rows) + +delete from db15_w_list_kset; +select * from db15_w_list_kset; + key | val +-----+----- +(0 rows) + +-- non-singleton zset table keyprefix +create foreign table db15_w_zset_pfx(key text, val text[]) + server localredis + options (database '15', tabletype 'zset', tablekeyprefix 'w_zset_'); +select * from db15_w_zset_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_zset_pfx values ('w_zset_a','{b,c,d}'), ('w_zset_c','{d,e,f}'),('w_zset_e','{f,g,h}'); +insert into db15_w_zset_pfx values ('x','{y}'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_zset_' +insert into db15_w_zset_pfx values ('w_zset_a','{x,y,z}'); -- dup error +ERROR: key already exists: w_zset_a +select * from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_a | {b,c,d} + w_zset_c | {d,e,f} + w_zset_e | {f,g,h} +(3 rows) + +delete from db15_w_zset_pfx where key = 'w_zset_a'; +select * from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_c | {d,e,f} + w_zset_e | {f,g,h} +(2 rows) + +update db15_w_zset_pfx set key = 'x' where key = 'w_zset_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_zset_pfx set key = 'x', val = '{y}' where key = 'w_zset_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_zset_pfx set key = 'w_zset_x', val = '{x,y,z}' where key = 'w_zset_c'; +select key, atsort(val) as val from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_e | {f,g,h} + w_zset_x | {x,y,z} +(2 rows) + +update db15_w_zset_pfx set key = 'w_zset_z' where key = 'w_zset_x'; +select key, atsort(val) as val from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_e | {f,g,h} + w_zset_z | {x,y,z} +(2 rows) + +update db15_w_zset_pfx set val = '{q,r,s}' where key = 'w_zset_e'; +select key, atsort(val) as val from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_e | {q,r,s} + w_zset_z | {x,y,z} +(2 rows) + +delete from db15_w_zset_pfx; +select * from db15_w_zset_pfx; + key | val +-----+----- +(0 rows) + +-- non-singleton zset table keyset +create foreign table db15_w_zset_kset(key text, val text[]) + server localredis + options (database '15', tabletype 'zset', tablekeyset 'w_zset_kset'); +select * from db15_w_zset_kset; + key | val +-----+----- +(0 rows) + +insert into db15_w_zset_kset values ('a_wzk','{b,c,d}'), ('c_wzk','{d,e,f}'),('e_wzk','{f,g,h}'); +insert into db15_w_zset_kset values ('a_wzk','{x}'); -- dup error +ERROR: key already exists: a_wzk +select * from db15_w_zset_kset order by key; + key | val +-------+--------- + a_wzk | {b,c,d} + c_wzk | {d,e,f} + e_wzk | {f,g,h} +(3 rows) + +delete from db15_w_zset_kset where key = 'a_wzk'; +select * from db15_w_zset_kset order by key; + key | val +-------+--------- + c_wzk | {d,e,f} + e_wzk | {f,g,h} +(2 rows) + +update db15_w_zset_kset set key = 'x_wlk', val = '{x,y,z}' where key = 'c_wzk'; +select key, atsort(val) as val from db15_w_zset_kset order by key; + key | val +-------+--------- + e_wzk | {f,g,h} + x_wlk | {x,y,z} +(2 rows) + +update db15_w_zset_kset set key = 'z_wzk' where key = 'x_wzk'; +select key, atsort(val) as val from db15_w_zset_kset order by key; + key | val +-------+--------- + e_wzk | {f,g,h} + x_wlk | {x,y,z} +(2 rows) + +update db15_w_zset_kset set val = '{q,r,s}' where key = 'e_wzk'; +select key, atsort(val) as val from db15_w_zset_kset order by key; + key | val +-------+--------- + e_wzk | {q,r,s} + x_wlk | {x,y,z} +(2 rows) + +delete from db15_w_zset_kset; +select * from db15_w_zset_kset; + key | val +-----+----- +(0 rows) + +-- non-singleton hash table prefix +create foreign table db15_w_hash_pfx(key text, val text[]) + server localredis + options (database '15', tabletype 'hash', tablekeyprefix 'w_hash_'); +select * from db15_w_hash_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_hash_pfx values ('w_hash_e','{f,g,h}'); -- error +ERROR: cannot decompose odd number of items into a Redis hash +insert into db15_w_hash_pfx values ('w_hash_e','{}'); -- error +ERROR: cannot store empty list in a Redis table +insert into db15_w_hash_pfx values ('w_hash_a','{b,c,d,e}'), ('w_hash_c','{f,g,h,i}'),('w_hash_e','{j,k}'); +insert into db15_w_hash_pfx values ('x','{y,z}'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_hash_' +insert into db15_w_hash_pfx values ('w_hash_a','{y,z}'); -- dup error +ERROR: key already exists: w_hash_a +select * from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_a | {b,c,d,e} + w_hash_c | {f,g,h,i} + w_hash_e | {j,k} +(3 rows) + +delete from db15_w_hash_pfx where key = 'w_hash_a'; +select * from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_c | {f,g,h,i} + w_hash_e | {j,k} +(2 rows) + +update db15_w_hash_pfx set key = 'x' where key = 'w_hash_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_hash_pfx set key = 'x', val = '{y,z}' where key = 'w_hash_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_hash_pfx set key = 'w_hash_x', val = '{x,y,z}' where key = 'w_hash_c'; -- err +ERROR: cannot decompose odd number of items into a Redis hash +update db15_w_hash_pfx set key = 'w_hash_x', val = '{w,x,y,z}' where key = 'w_hash_c'; +select key, val from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_e | {j,k} + w_hash_x | {w,x,y,z} +(2 rows) + +update db15_w_hash_pfx set key = 'w_hash_z' where key = 'w_hash_x'; +select key, val from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_e | {j,k} + w_hash_z | {w,x,y,z} +(2 rows) + +update db15_w_hash_pfx set val = '{q,r,s}' where key = 'w_hash_e'; +ERROR: cannot decompose odd number of items into a Redis hash +select key, val from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_e | {j,k} + w_hash_z | {w,x,y,z} +(2 rows) + +delete from db15_w_hash_pfx; +select * from db15_w_hash_pfx; + key | val +-----+----- +(0 rows) + +--non-singleton hash table keyset +create foreign table db15_w_hash_kset(key text, val text[]) + server localredis + options (database '15', tabletype 'hash', tablekeyset 'w_hash_kset'); +select * from db15_w_hash_kset; + key | val +-----+----- +(0 rows) + +insert into db15_w_hash_pfx values ('e_whk','{f,g,h}'); -- error +ERROR: key 'e_whk' does not match table key prefix 'w_hash_' +insert into db15_w_hash_pfx values ('e_whk','{}'); -- error +ERROR: key 'e_whk' does not match table key prefix 'w_hash_' +insert into db15_w_hash_kset values ('a_whk','{b,c,d,e}'), ('c_whk','{f,g,h,i}'),('e_whk','{j,k}'); +insert into db15_w_hash_kset values ('a_whk','{x,y}'); -- dup error +ERROR: key already exists: a_whk +select * from db15_w_hash_kset order by key; + key | val +-------+----------- + a_whk | {b,c,d,e} + c_whk | {f,g,h,i} + e_whk | {j,k} +(3 rows) + +delete from db15_w_hash_kset where key = 'a_whk'; +select * from db15_w_hash_kset order by key; + key | val +-------+----------- + c_whk | {f,g,h,i} + e_whk | {j,k} +(2 rows) + +update db15_w_hash_kset set key = 'x_whk', val = '{w,x,y,z}' where key = 'c_whk'; +select key, val from db15_w_hash_kset order by key; + key | val +-------+----------- + e_whk | {j,k} + x_whk | {w,x,y,z} +(2 rows) + +update db15_w_hash_kset set key = 'z_whk' where key = 'x_whk'; +select key, val from db15_w_hash_kset order by key; + key | val +-------+----------- + e_whk | {j,k} + z_whk | {w,x,y,z} +(2 rows) + +update db15_w_hash_kset set val = '{q,r}' where key = 'e_whk'; +select key, val from db15_w_hash_kset order by key; + key | val +-------+----------- + e_whk | {q,r} + z_whk | {w,x,y,z} +(2 rows) + +delete from db15_w_hash_kset; +select * from db15_w_hash_kset; + key | val +-----+----- +(0 rows) + +-- now clean up for the cursor tests +\! redis-cli < test/redis_clean +OK +OK +-- cursor tests +create foreign table db15bigprefixscalar ( + key text not null, + val text +) +server localredis +options (database '15', tablekeyprefix 'w_scalar_'); +create foreign table db15bigkeysetscalar ( + key text not null, + val text +) +server localredis +options (database '15', tablekeyset 'w_kset'); +insert into db15 +select 'junk' || x, 'junk' +from generate_series(1,10000) as x; +insert into db15bigprefixscalar +select 'w_scalar_' || x::text, 'val ' || x::text +from generate_series (1,10000) as x; +insert into db15bigkeysetscalar +select 'key_' || x::text, 'val ' || x::text +from generate_series (1,10000) as x; +insert into db15 +select 'junk' || x, 'junk' +from generate_series(10001, 20000) as x; +insert into db15bigprefixscalar +select 'w_scalar_' || x::text, 'val ' || x::text +from generate_series (10001, 20000) as x; +insert into db15bigkeysetscalar +select 'key_' || x::text, 'val ' || x::text +from generate_series (10001, 20000) as x; +select count(*) from db15; + count +------- + 60000 +(1 row) + +select count(*) from db15bigprefixscalar; + count +------- + 20000 +(1 row) + +select count(*) from db15bigkeysetscalar; + count +------- + 20000 +(1 row) + +-- all done, so now blow everything in the db away again +\! redis-cli < test/redis_clean +OK +OK +DROP EXTENSION redis_fdw CASCADE; +NOTICE: drop cascades to 45 other objects +DETAIL: drop cascades to server localredis +drop cascades to user mapping for public on server localredis +drop cascades to foreign table db15 +drop cascades to foreign table db15_hash +drop cascades to foreign table db15_set +drop cascades to foreign table db15_list +drop cascades to foreign table db15_zset +drop cascades to foreign table db15_hash_prefix +drop cascades to foreign table db15_hash_prefix_array +drop cascades to foreign table db15_hash_keyset_array +drop cascades to foreign table db15_set_prefix +drop cascades to foreign table db15_set_prefix_array +drop cascades to foreign table db15_set_keyset_array +drop cascades to foreign table db15_list_prefix +drop cascades to foreign table db15_list_prefix_array +drop cascades to foreign table db15_list_keyset_array +drop cascades to foreign table db15_zset_prefix +drop cascades to foreign table db15_zset_prefix_array +drop cascades to foreign table db15_zset_keyset_array +drop cascades to foreign table db15_1key +drop cascades to foreign table db15_1key_hash +drop cascades to foreign table db15_1key_set +drop cascades to foreign table db15_1key_list +drop cascades to foreign table db15_1key_zset +drop cascades to foreign table db15_1key_zset_scores +drop cascades to foreign table db15_w_1key_scalar +drop cascades to foreign table db15_w_1key_hash +drop cascades to foreign table db15_w_1key_list +drop cascades to foreign table db15_w_1key_set +drop cascades to foreign table db15_w_1key_zset +drop cascades to foreign table db15_w_1key_zsetx +drop cascades to foreign table db15_w_scalar +drop cascades to foreign table db15_w_scalar_pfx +drop cascades to foreign table db15_w_scalar_kset +drop cascades to foreign table db15_w_set_nonarr +drop cascades to foreign table db15_w_set_pfx +drop cascades to foreign table db15_w_set_kset +drop cascades to foreign table db15_w_list_pfx +drop cascades to foreign table db15_w_list_kset +drop cascades to foreign table db15_w_zset_pfx +drop cascades to foreign table db15_w_zset_kset +drop cascades to foreign table db15_w_hash_pfx +drop cascades to foreign table db15_w_hash_kset +drop cascades to foreign table db15bigprefixscalar +drop cascades to foreign table db15bigkeysetscalar +DROP EXTENSION hstore; diff --git a/test/expected/17.0/nogis.out b/test/expected/17.0/nogis.out new file mode 100644 index 0000000..cf309cd --- /dev/null +++ b/test/expected/17.0/nogis.out @@ -0,0 +1,23 @@ +-- Testcase 001 +CREATE EXTENSION hstore; +-- Testcase 002 +CREATE EXTENSION redis_fdw; +-- Testcase 003 +create server localredis foreign data wrapper redis_fdw; +-- Testcase 004 +create user mapping for public server localredis; +-- Testcase 005 +-- \! redis-cli < test/redis_gis_ini +-- REDIS SPATIAL VALUE TESTS WILL BE HERE +-- Testcase 098 +-- all done, so now blow everything in the db away again +\! redis-cli < test/redis_clean +OK +OK +-- Testcase 099 +DROP EXTENSION redis_fdw CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to server localredis +drop cascades to user mapping for public on server localredis +-- Testcase 100 +DROP EXTENSION hstore CASCADE; diff --git a/test/expected/17.0/postgis.out b/test/expected/17.0/postgis.out new file mode 100644 index 0000000..0b315ca --- /dev/null +++ b/test/expected/17.0/postgis.out @@ -0,0 +1,26 @@ +-- Testcase 001 +CREATE EXTENSION postgis; +-- Testcase 002 +CREATE EXTENSION hstore; +-- Testcase 003 +CREATE EXTENSION redis_fdw; +-- Testcase 004 +create server localredis foreign data wrapper redis_fdw; +-- Testcase 005 +create user mapping for public server localredis; +-- Testcase 006 +-- \! redis-cli < test/redis_gis_ini +-- Testcase 098 +-- all done, so now blow everything in the db away again +\! redis-cli < test/redis_clean +OK +OK +-- Testcase 099 +DROP EXTENSION redis_fdw CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to server localredis +drop cascades to user mapping for public on server localredis +-- Testcase 100 +DROP EXTENSION hstore CASCADE; +-- Testcase 101 +DROP EXTENSION postgis CASCADE; diff --git a/test/expected/17.0/redis_fdw.out b/test/expected/17.0/redis_fdw.out new file mode 100644 index 0000000..7b5789d --- /dev/null +++ b/test/expected/17.0/redis_fdw.out @@ -0,0 +1,1466 @@ +-- Testcase 001: +CREATE EXTENSION hstore; +-- Testcase 002: +CREATE EXTENSION redis_fdw; +-- Testcase 003: +select redis_fdw_version(); + redis_fdw_version +------------------- + 1901 +(1 row) + +-- Testcase 004: +select redis_fdw_hiredis_version(); + redis_fdw_hiredis_version +--------------------------- + 1401 +(1 row) + +-- Testcase 005: +CREATE OR REPLACE FUNCTION atsort( a text[]) + RETURNS text[] + LANGUAGE sql + IMMUTABLE STRICT +AS $function$ + select array(select unnest($1) order by 1) +$function$; +create server localredis foreign data wrapper redis_fdw; +create user mapping for public server localredis; +-- tables for all 5 data types (4 structured plus scalar) +create foreign table db15(key text, value text) + server localredis + options (database '15'); +create foreign table db15_hash(key text, value text) + server localredis + options (database '15', tabletype 'hash'); +create foreign table db15_set(key text, value text) + server localredis + options (database '15', tabletype 'set'); +create foreign table db15_list(key text, value text) + server localredis + options (database '15', tabletype 'list'); +create foreign table db15_zset(key text, value text) + server localredis + options (database '15', tabletype 'zset'); +-- make sure they are all empty - if any are not stop the script right now +\set ON_ERROR_STOP +do $$ + declare + rows bigint; + begin + select into rows + (select count(*) from db15) + + (select count(*) from db15_hash) + + (select count(*) from db15_set) + + (select count(*) from db15_list) + + (select count(*) from db15_zset); + if rows > 0 + then + raise EXCEPTION 'db 15 not empty'; + end if; + end; +$$; +\unset ON_ERROR_STOP +-- ok, empty, so now run the setup script +\! redis-cli < test/redis_setup +OK +OK +OK +8 +5 +6 +4 +OK +OK +6 +6 +2 +2 +2 +2 +select * from db15 order by key; + key | value +-----+-------- + baz | blurfl + foo | bar +(2 rows) + +select * from db15 where key = 'foo'; + key | value +-----+------- + foo | bar +(1 row) + +-- hash +create foreign table db15_hash_prefix(key text, value text) + server localredis + options (tabletype 'hash', tablekeyprefix 'hash', database '15'); +create foreign table db15_hash_prefix_array(key text, value text[]) + server localredis + options (tabletype 'hash', tablekeyprefix 'hash', database '15'); +create foreign table db15_hash_keyset_array(key text, value text[]) + server localredis + options (tabletype 'hash', tablekeyset 'hkeys', database '15'); +select * from db15_hash_prefix order by key; + key | value +-------+------------------------------------------- + hash1 | {"k1","v1","k2","v2","k3","v3","k4","v4"} + hash2 | {"k1","v5","k2","v6","k3","v7","k4","v8"} +(2 rows) + +select * from db15_hash_prefix where key = 'hash1'; + key | value +-------+------------------------------------------- + hash1 | {"k1","v1","k2","v2","k3","v3","k4","v4"} +(1 row) + +select * from db15_hash_prefix_array order by key; + key | value +-------+--------------------------- + hash1 | {k1,v1,k2,v2,k3,v3,k4,v4} + hash2 | {k1,v5,k2,v6,k3,v7,k4,v8} +(2 rows) + +select * from db15_hash_prefix_array where key = 'hash1'; + key | value +-------+--------------------------- + hash1 | {k1,v1,k2,v2,k3,v3,k4,v4} +(1 row) + +select * from db15_hash_keyset_array order by key; + key | value +-------+--------------------------- + hash1 | {k1,v1,k2,v2,k3,v3,k4,v4} + hash2 | {k1,v5,k2,v6,k3,v7,k4,v8} +(2 rows) + +select * from db15_hash_keyset_array where key = 'hash1'; + key | value +-------+--------------------------- + hash1 | {k1,v1,k2,v2,k3,v3,k4,v4} +(1 row) + +-- a couple of nifty things we an do with hash tables +select key, hstore(value) from db15_hash_prefix_array order by key; + key | hstore +-------+------------------------------------------------ + hash1 | "k1"=>"v1", "k2"=>"v2", "k3"=>"v3", "k4"=>"v4" + hash2 | "k1"=>"v5", "k2"=>"v6", "k3"=>"v7", "k4"=>"v8" +(2 rows) + +create type atab as (k1 text, k2 text, k3 text); +select key, (populate_record(null::atab, hstore(value))).* +from db15_hash_prefix_array +order by key; + key | k1 | k2 | k3 +-------+----+----+---- + hash1 | v1 | v2 | v3 + hash2 | v5 | v6 | v7 +(2 rows) + +-- set +create foreign table db15_set_prefix(key text, value text) + server localredis + options (tabletype 'set', tablekeyprefix 'set', database '15'); +create foreign table db15_set_prefix_array(key text, value text[]) + server localredis + options (tabletype 'set', tablekeyprefix 'set', database '15'); +create foreign table db15_set_keyset_array(key text, value text[]) + server localredis + options (tabletype 'set', tablekeyset 'skeys', database '15'); +-- need to use atsort() on set results to get predicable output +-- since redis will give them back in arbitrary order +-- means we can't show the actual value for db15_set_prefix which has it as a +-- single text field +select key, atsort(value::text[]) as value from db15_set_prefix order by key; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} + set2 | {m10,m11,m12,m8,m9} +(2 rows) + +select key, atsort(value::text[]) as value from db15_set_prefix where key = 'set1'; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} +(1 row) + +select key, atsort(value) as value from db15_set_prefix_array order by key; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} + set2 | {m10,m11,m12,m8,m9} +(2 rows) + +select key, atsort(value) as value from db15_set_prefix_array where key = 'set1'; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} +(1 row) + +select key, atsort(value) as value from db15_set_keyset_array order by key; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} + set2 | {m10,m11,m12,m8,m9} +(2 rows) + +select key, atsort(value) as value from db15_set_keyset_array where key = 'set1'; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} +(1 row) + +-- list +create foreign table db15_list_prefix(key text, value text) + server localredis + options (tabletype 'list', tablekeyprefix 'list', database '15'); +create foreign table db15_list_prefix_array(key text, value text[]) + server localredis + options (tabletype 'list', tablekeyprefix 'list', database '15'); +create foreign table db15_list_keyset_array(key text, value text[]) + server localredis + options (tabletype 'list', tablekeyset 'lkeys', database '15'); +select * from db15_list_prefix order by key; + key | value +-------+--------------------------------- + list1 | {"e6","e5","e4","e3","e2","e1"} + list2 | {"e10","e9","e8","e7"} +(2 rows) + +select * from db15_list_prefix where key = 'list1'; + key | value +-------+--------------------------------- + list1 | {"e6","e5","e4","e3","e2","e1"} +(1 row) + +select * from db15_list_prefix_array order by key; + key | value +-------+--------------------- + list1 | {e6,e5,e4,e3,e2,e1} + list2 | {e10,e9,e8,e7} +(2 rows) + +select * from db15_list_prefix_array where key = 'list1'; + key | value +-------+--------------------- + list1 | {e6,e5,e4,e3,e2,e1} +(1 row) + +select * from db15_list_keyset_array order by key; + key | value +-------+--------------------- + list1 | {e6,e5,e4,e3,e2,e1} + list2 | {e10,e9,e8,e7} +(2 rows) + +select * from db15_list_keyset_array where key = 'list1'; + key | value +-------+--------------------- + list1 | {e6,e5,e4,e3,e2,e1} +(1 row) + +-- zset +create foreign table db15_zset_prefix(key text, value text) + server localredis + options (tabletype 'zset', tablekeyprefix 'zset', database '15'); +create foreign table db15_zset_prefix_array(key text, value text[]) + server localredis + options (tabletype 'zset', tablekeyprefix 'zset', database '15'); +create foreign table db15_zset_keyset_array(key text, value text[]) + server localredis + options (tabletype 'zset', tablekeyset 'zkeys', database '15'); +select * from db15_zset_prefix order by key; + key | value +-------+------------------------------------ + zset1 | {"z1","z2","z3","z4","z5","z6"} + zset2 | {"z7","z8","z9","z10","z11","z12"} +(2 rows) + +select * from db15_zset_prefix where key = 'zset1'; + key | value +-------+--------------------------------- + zset1 | {"z1","z2","z3","z4","z5","z6"} +(1 row) + +select * from db15_zset_prefix_array order by key; + key | value +-------+------------------------ + zset1 | {z1,z2,z3,z4,z5,z6} + zset2 | {z7,z8,z9,z10,z11,z12} +(2 rows) + +select * from db15_zset_prefix_array where key = 'zset1'; + key | value +-------+--------------------- + zset1 | {z1,z2,z3,z4,z5,z6} +(1 row) + +select * from db15_zset_keyset_array order by key; + key | value +-------+------------------------ + zset1 | {z1,z2,z3,z4,z5,z6} + zset2 | {z7,z8,z9,z10,z11,z12} +(2 rows) + +select * from db15_zset_keyset_array where key = 'zset1'; + key | value +-------+--------------------- + zset1 | {z1,z2,z3,z4,z5,z6} +(1 row) + +-- singleton scalar +create foreign table db15_1key(value text) + server localredis + options (singleton_key 'foo', database '15'); +select * from db15_1key; + value +------- + bar +(1 row) + +-- singleton hash +create foreign table db15_1key_hash(key text, value text) + server localredis + options (tabletype 'hash', singleton_key 'hash1', database '15'); +select * from db15_1key_hash order by key; + key | value +-----+------- + k1 | v1 + k2 | v2 + k3 | v3 + k4 | v4 +(4 rows) + +-- singleton set +create foreign table db15_1key_set(value text) + server localredis + options (tabletype 'set', singleton_key 'set1', database '15'); +select * from db15_1key_set order by value; + value +------- + m1 + m2 + m3 + m4 + m5 + m6 + m7 + m8 +(8 rows) + +-- singleton list +create foreign table db15_1key_list(value text) + server localredis + options (tabletype 'list', singleton_key 'list1', database '15'); +select * from db15_1key_list order by value; + value +------- + e1 + e2 + e3 + e4 + e5 + e6 +(6 rows) + +-- singleton zset +create foreign table db15_1key_zset(value text) + server localredis + options (tabletype 'zset', singleton_key 'zset1', database '15'); +select * from db15_1key_zset order by value; + value +------- + z1 + z2 + z3 + z4 + z5 + z6 +(6 rows) + +-- singleton zset with scores +create foreign table db15_1key_zset_scores(value text, score numeric) + server localredis + options (tabletype 'zset', singleton_key 'zset1', database '15'); +select * from db15_1key_zset_scores order by score desc; + value | score +-------+------- + z6 | 6 + z5 | 5 + z4 | 4 + z3 | 3 + z2 | 2 + z1 | 1 +(6 rows) + +-- insert delete update +-- first clean the database again +\! redis-cli < test/redis_clean +OK +OK +-- singleton scalar table +create foreign table db15_w_1key_scalar(val text) + server localredis + options (singleton_key 'w_1key_scalar', database '15'); +select * from db15_w_1key_scalar; + val +----- +(0 rows) + +insert into db15_w_1key_scalar values ('only row'); +select * from db15_w_1key_scalar; + val +---------- + only row +(1 row) + +insert into db15_w_1key_scalar values ('only row'); +ERROR: key already exists: w_1key_scalar +delete from db15_w_1key_scalar where val = 'not only row'; +select * from db15_w_1key_scalar; + val +---------- + only row +(1 row) + +update db15_w_1key_scalar set val = 'new scalar val'; +select * from db15_w_1key_scalar; + val +---------------- + new scalar val +(1 row) + +delete from db15_w_1key_scalar; +select * from db15_w_1key_scalar; + val +----- +(0 rows) + +-- singleton hash +create foreign table db15_w_1key_hash(key text, val text) + server localredis + options (singleton_key 'w_1key_hash', tabletype 'hash', database '15'); +select * from db15_w_1key_hash; + key | val +-----+----- +(0 rows) + +insert into db15_w_1key_hash values ('a','b'), ('c','d'),('e','f'); +select * from db15_w_1key_hash order by key; + key | val +-----+----- + a | b + c | d + e | f +(3 rows) + +insert into db15_w_1key_hash values ('a','b'); +ERROR: key already exists: a +delete from db15_w_1key_hash where key = 'a'; +delete from db15_w_1key_hash where key = 'a'; +select * from db15_w_1key_hash order by key; + key | val +-----+----- + c | d + e | f +(2 rows) + +update db15_w_1key_hash set key = 'x', val = 'y' where key = 'c'; +select * from db15_w_1key_hash order by key; + key | val +-----+----- + e | f + x | y +(2 rows) + +update db15_w_1key_hash set val = 'z' where key = 'e'; +select * from db15_w_1key_hash order by key; + key | val +-----+----- + e | z + x | y +(2 rows) + +update db15_w_1key_hash set key = 'w' where key = 'e'; +select * from db15_w_1key_hash order by key; + key | val +-----+----- + w | z + x | y +(2 rows) + +-- singleton list +create foreign table db15_w_1key_list(val text) + server localredis + options (singleton_key 'w_1key_list', tabletype 'list', database '15'); +select * from db15_w_1key_list; + val +----- +(0 rows) + +insert into db15_w_1key_list values ('a'), ('c'),('e'); +-- for lists the order should (must) be determinate +select * from db15_w_1key_list /* order by val */ ; + val +----- + a + c + e +(3 rows) + +delete from db15_w_1key_list where val = 'a'; +ERROR: delete not supported for this type of table +delete from db15_w_1key_list where val = 'z'; +ERROR: delete not supported for this type of table +insert into db15_w_1key_list values ('b'), ('d'),('f'),('a'); -- dups allowed here +select * from db15_w_1key_list /* order by val */; + val +----- + a + c + e + b + d + f + a +(7 rows) + +update db15_w_1key_list set val = 'y'; +ERROR: update not supported for this type of table +-- singleton set +create foreign table db15_w_1key_set(key text) + server localredis + options (singleton_key 'w_1key_set', tabletype 'set', database '15'); +select * from db15_w_1key_set; + key +----- +(0 rows) + +insert into db15_w_1key_set values ('a'), ('c'),('e'); +select * from db15_w_1key_set order by key; + key +----- + a + c + e +(3 rows) + +insert into db15_w_1key_set values ('a'); -- error - dup +ERROR: key already exists: a +delete from db15_w_1key_set where key = 'c'; +select * from db15_w_1key_set order by key; + key +----- + a + e +(2 rows) + +update db15_w_1key_set set key = 'x' where key = 'e'; +select * from db15_w_1key_set order by key; + key +----- + a + x +(2 rows) + +-- singleton zset with scores +create foreign table db15_w_1key_zset(key text, priority numeric) + server localredis + options (singleton_key 'w_1key_zset', tabletype 'zset', database '15'); +select * from db15_w_1key_zset; + key | priority +-----+---------- +(0 rows) + +insert into db15_w_1key_zset values ('a',1), ('c',5),('e',-5), ('h',10); +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + e | -5 + a | 1 + c | 5 + h | 10 +(4 rows) + +insert into db15_w_1key_zset values ('a',99); +ERROR: key already exists: a +delete from db15_w_1key_zset where key = 'a'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + e | -5 + c | 5 + h | 10 +(3 rows) + +delete from db15_w_1key_zset where priority = '5'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + e | -5 + h | 10 +(2 rows) + +update db15_w_1key_zset set key = 'x', priority = 99 where priority = '-5'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + h | 10 + x | 99 +(2 rows) + +update db15_w_1key_zset set key = 'y' where key = 'h'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + y | 10 + x | 99 +(2 rows) + +update db15_w_1key_zset set priority = 20 where key = 'y'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + y | 20 + x | 99 +(2 rows) + +-- singleton zset no scores +-- use set from last step +delete from db15_w_1key_zset; +insert into db15_w_1key_zset values ('e',-5); +create foreign table db15_w_1key_zsetx(key text) + server localredis + options (singleton_key 'w_1key_zset', tabletype 'zset', database '15'); +select * from db15_w_1key_zsetx; + key +----- + e +(1 row) + +insert into db15_w_1key_zsetx values ('a'), ('c'),('e'); -- can't insert +ERROR: operation not supported for singleton zset table without priorities column +update db15_w_1key_zsetx set key = 'z' where key = 'e'; +select * from db15_w_1key_zsetx order by key; + key +----- + z +(1 row) + +delete from db15_w_1key_zsetx where key = 'z'; +select * from db15_w_1key_zsetx order by key; + key +----- +(0 rows) + +-- non-singleton scalar table no prefix no keyset +create foreign table db15_w_scalar(key text, val text) + server localredis + options (database '15'); +select * from db15_w_scalar; + key | val +-----+----- +(0 rows) + +insert into db15_w_scalar values ('a_ws','b'), ('c_ws','d'),('e_ws','f'); +select * from db15_w_scalar order by key; + key | val +------+----- + a_ws | b + c_ws | d + e_ws | f +(3 rows) + +delete from db15_w_scalar where key = 'a_ws'; +select * from db15_w_scalar order by key; + key | val +------+----- + c_ws | d + e_ws | f +(2 rows) + +update db15_w_scalar set key = 'x_ws', val='y' where key = 'e_ws'; +select * from db15_w_scalar order by key; + key | val +------+----- + c_ws | d + x_ws | y +(2 rows) + +update db15_w_scalar set key = 'z_ws' where key = 'c_ws'; +select * from db15_w_scalar order by key; + key | val +------+----- + x_ws | y + z_ws | d +(2 rows) + +update db15_w_scalar set val = 'z' where key = 'z_ws'; +select * from db15_w_scalar order by key; + key | val +------+----- + x_ws | y + z_ws | z +(2 rows) + +/* +-- don't delete the whole namespace + delete from db15_w_scalar; + +select * from db15_w_scalar; +*/ +-- non-singleton scalar table keyprefix +create foreign table db15_w_scalar_pfx(key text, val text) + server localredis + options (database '15', tablekeyprefix 'w_scalar_'); +select * from db15_w_scalar_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_scalar_pfx values ('w_scalar_a','b'), ('w_scalar_c','d'),('w_scalar_e','f'); +insert into db15_w_scalar_pfx values ('x','y'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_scalar_' +insert into db15_w_scalar_pfx values ('w_scalar_a','x'); -- dup error +ERROR: key already exists: w_scalar_a +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_a | b + w_scalar_c | d + w_scalar_e | f +(3 rows) + +delete from db15_w_scalar_pfx where key = 'w_scalar_a'; +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_c | d + w_scalar_e | f +(2 rows) + +update db15_w_scalar_pfx set key = 'x', val = 'y' where key = 'w_scalar_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_scalar_pfx set key = 'x' where key = 'w_scalar_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_scalar_pfx set key = 'w_scalar_x', val = 'y' where key = 'w_scalar_c'; +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_e | f + w_scalar_x | y +(2 rows) + +update db15_w_scalar_pfx set key = 'w_scalar_z' where key = 'w_scalar_x'; +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_e | f + w_scalar_z | y +(2 rows) + +update db15_w_scalar_pfx set val = 'w' where key = 'w_scalar_e'; +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_e | w + w_scalar_z | y +(2 rows) + +delete from db15_w_scalar_pfx; +select * from db15_w_scalar_pfx order by key; + key | val +-----+----- +(0 rows) + +-- non-singleton scalar table keyset +create foreign table db15_w_scalar_kset(key text, val text) + server localredis + options (database '15', tablekeyset 'w_scalar_kset'); +select * from db15_w_scalar_kset order by key; + key | val +-----+----- +(0 rows) + +insert into db15_w_scalar_kset values ('a_wsks','b'), ('c_wsks','d'),('e_wsks','f'); +insert into db15_w_scalar_kset values ('a_wsks','x'); -- dup error +ERROR: key already exists: a_wsks +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + a_wsks | b + c_wsks | d + e_wsks | f +(3 rows) + +delete from db15_w_scalar_kset where key = 'a_wsks'; +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + c_wsks | d + e_wsks | f +(2 rows) + +update db15_w_scalar_kset set key = 'x_wsks', val = 'y' where key = 'c_wsks'; +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + e_wsks | f + x_wsks | y +(2 rows) + +update db15_w_scalar_kset set key = 'z_wsks' where key = 'x_wsks'; +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + e_wsks | f + z_wsks | y +(2 rows) + +update db15_w_scalar_kset set val = 'w' where key = 'e_wsks'; +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + e_wsks | w + z_wsks | y +(2 rows) + +delete from db15_w_scalar_kset; +select * from db15_w_scalar_kset order by key; + key | val +-----+----- +(0 rows) + +-- non-singleton set table no prefix no keyset +-- non-array case -- fails +create foreign table db15_w_set_nonarr(key text, val text) + server localredis + options (database '15', tabletype 'set'); +insert into db15_w_set_nonarr values ('nkseta','{b,c,d}'), ('nksetc','{d,e,f}'),('nksete','{f,g,h}'); +ERROR: cannot insert into this type of Redis table - needs an array +/* +-- namespace too polluted for this case +create foreign table db15_w_set(key text, val text[]) + server localredis + options (database '15', tabletype 'set'); + +select * from db15_w_set; + +insert into db15_w_set values ('nkseta','{b,c,d}'), ('nksetc','{d,e,f}'),('nksete','{f,g,h}'); + +select * from db15_w_set; + +delete from db15_w_set where key = 'nkseta'; + +select * from db15_w_set; + +delete from db15_w_set; + +select * from db15_w_set; + +*/ +-- non-singleton set table keyprefix +create foreign table db15_w_set_pfx(key text, val text[]) + server localredis + options (database '15', tabletype 'set', tablekeyprefix 'w_set_'); +select * from db15_w_set_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_set_pfx values ('w_set_a','{b,c,d}'), ('w_set_c','{d,e,f}'),('w_set_e','{f,g,h}'); +insert into db15_w_set_pfx values ('x','{y}'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_set_' +insert into db15_w_set_pfx values ('w_set_a','{x,y,z}'); -- dup error +ERROR: key already exists: w_set_a +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_a | {b,c,d} + w_set_c | {d,e,f} + w_set_e | {f,g,h} +(3 rows) + +delete from db15_w_set_pfx where key = 'w_set_a'; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_c | {d,e,f} + w_set_e | {f,g,h} +(2 rows) + +update db15_w_set_pfx set key = 'x' where key = 'w_set_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_set_pfx set key = 'x', val = '{y}' where key = 'w_set_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_set_pfx set key = 'w_set_x', val = '{x,y,z}' where key = 'w_set_c'; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_e | {f,g,h} + w_set_x | {x,y,z} +(2 rows) + +update db15_w_set_pfx set key = 'w_set_z' where key = 'w_set_x'; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_e | {f,g,h} + w_set_z | {x,y,z} +(2 rows) + +update db15_w_set_pfx set val = '{q,r,s}' where key = 'w_set_e'; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_e | {q,r,s} + w_set_z | {x,y,z} +(2 rows) + +delete from db15_w_set_pfx; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +-----+----- +(0 rows) + +-- non-singleton set table keyset +create foreign table db15_w_set_kset(key text, val text[]) + server localredis + options (database '15', tabletype 'set', tablekeyset 'w_set_kset'); +select * from db15_w_set_kset; + key | val +-----+----- +(0 rows) + +insert into db15_w_set_kset values ('a_wsk','{b,c,d}'), ('c_wsk','{d,e,f}'),('e_wsk','{f,g,h}'); +insert into db15_w_set_kset values ('a_wsk','{x}'); -- dup error +ERROR: key already exists: a_wsk +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + a_wsk | {b,c,d} + c_wsk | {d,e,f} + e_wsk | {f,g,h} +(3 rows) + +delete from db15_w_set_kset where key = 'a_wsk'; +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + c_wsk | {d,e,f} + e_wsk | {f,g,h} +(2 rows) + +update db15_w_set_kset set key = 'x_wsk', val = '{x,y,z}' where key = 'c_wsk'; +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + e_wsk | {f,g,h} + x_wsk | {x,y,z} +(2 rows) + +update db15_w_set_kset set key = 'z_wsk' where key = 'x_wsk'; +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + e_wsk | {f,g,h} + z_wsk | {x,y,z} +(2 rows) + +update db15_w_set_kset set val = '{q,r,s}' where key = 'e_wsk'; +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + e_wsk | {q,r,s} + z_wsk | {x,y,z} +(2 rows) + +delete from db15_w_set_kset; +select * from db15_w_set_kset; + key | val +-----+----- +(0 rows) + +-- non-singleton list table keyprefix +create foreign table db15_w_list_pfx(key text, val text[]) + server localredis + options (database '15', tabletype 'list', tablekeyprefix 'w_list_'); +select * from db15_w_list_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_list_pfx values ('w_list_a','{b,c,d}'), ('w_list_c','{d,e,f}'),('w_list_e','{f,g,h}'); +insert into db15_w_list_pfx values ('x','{y}'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_list_' +insert into db15_w_list_pfx values ('w_list_a','{x,y,z}'); -- dup error +ERROR: key already exists: w_list_a +select * from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_a | {b,c,d} + w_list_c | {d,e,f} + w_list_e | {f,g,h} +(3 rows) + +delete from db15_w_list_pfx where key = 'w_list_a'; +select * from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_c | {d,e,f} + w_list_e | {f,g,h} +(2 rows) + +update db15_w_list_pfx set key = 'x' where key = 'w_list_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_list_pfx set key = 'x', val = '{y}' where key = 'w_list_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_list_pfx set key = 'w_list_x', val = '{x,y,z}' where key = 'w_list_c'; +select key, atsort(val) as val from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_e | {f,g,h} + w_list_x | {x,y,z} +(2 rows) + +update db15_w_list_pfx set key = 'w_list_z' where key = 'w_list_x'; +select key, atsort(val) as val from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_e | {f,g,h} + w_list_z | {x,y,z} +(2 rows) + +update db15_w_list_pfx set val = '{q,r,s}' where key = 'w_list_e'; +select key, atsort(val) as val from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_e | {q,r,s} + w_list_z | {x,y,z} +(2 rows) + +delete from db15_w_list_pfx; +select * from db15_w_list_pfx; + key | val +-----+----- +(0 rows) + +-- non-singleton list table keyset +create foreign table db15_w_list_kset(key text, val text[]) + server localredis + options (database '15', tabletype 'list', tablekeyset 'w_list_kset'); +select * from db15_w_list_kset; + key | val +-----+----- +(0 rows) + +insert into db15_w_list_kset values ('a_wlk','{b,c,d}'), ('c_wlk','{d,e,f}'),('e_wlk','{f,g,h}'); +insert into db15_w_list_kset values ('a_wlk','{x}'); -- dup error +ERROR: key already exists: a_wlk +select * from db15_w_list_kset order by key; + key | val +-------+--------- + a_wlk | {b,c,d} + c_wlk | {d,e,f} + e_wlk | {f,g,h} +(3 rows) + +delete from db15_w_list_kset where key = 'a_wlk'; +select * from db15_w_list_kset order by key; + key | val +-------+--------- + c_wlk | {d,e,f} + e_wlk | {f,g,h} +(2 rows) + +update db15_w_list_kset set key = 'x_wlk', val = '{x,y,z}' where key = 'c_wlk'; +select key, atsort(val) as val from db15_w_list_kset order by key; + key | val +-------+--------- + e_wlk | {f,g,h} + x_wlk | {x,y,z} +(2 rows) + +update db15_w_list_kset set key = 'z_wlk' where key = 'x_wlk'; +select key, atsort(val) as val from db15_w_list_kset order by key; + key | val +-------+--------- + e_wlk | {f,g,h} + z_wlk | {x,y,z} +(2 rows) + +update db15_w_list_kset set val = '{q,r,s}' where key = 'e_wlk'; +select key, atsort(val) as val from db15_w_list_kset order by key; + key | val +-------+--------- + e_wlk | {q,r,s} + z_wlk | {x,y,z} +(2 rows) + +delete from db15_w_list_kset; +select * from db15_w_list_kset; + key | val +-----+----- +(0 rows) + +-- non-singleton zset table keyprefix +create foreign table db15_w_zset_pfx(key text, val text[]) + server localredis + options (database '15', tabletype 'zset', tablekeyprefix 'w_zset_'); +select * from db15_w_zset_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_zset_pfx values ('w_zset_a','{b,c,d}'), ('w_zset_c','{d,e,f}'),('w_zset_e','{f,g,h}'); +insert into db15_w_zset_pfx values ('x','{y}'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_zset_' +insert into db15_w_zset_pfx values ('w_zset_a','{x,y,z}'); -- dup error +ERROR: key already exists: w_zset_a +select * from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_a | {b,c,d} + w_zset_c | {d,e,f} + w_zset_e | {f,g,h} +(3 rows) + +delete from db15_w_zset_pfx where key = 'w_zset_a'; +select * from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_c | {d,e,f} + w_zset_e | {f,g,h} +(2 rows) + +update db15_w_zset_pfx set key = 'x' where key = 'w_zset_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_zset_pfx set key = 'x', val = '{y}' where key = 'w_zset_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_zset_pfx set key = 'w_zset_x', val = '{x,y,z}' where key = 'w_zset_c'; +select key, atsort(val) as val from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_e | {f,g,h} + w_zset_x | {x,y,z} +(2 rows) + +update db15_w_zset_pfx set key = 'w_zset_z' where key = 'w_zset_x'; +select key, atsort(val) as val from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_e | {f,g,h} + w_zset_z | {x,y,z} +(2 rows) + +update db15_w_zset_pfx set val = '{q,r,s}' where key = 'w_zset_e'; +select key, atsort(val) as val from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_e | {q,r,s} + w_zset_z | {x,y,z} +(2 rows) + +delete from db15_w_zset_pfx; +select * from db15_w_zset_pfx; + key | val +-----+----- +(0 rows) + +-- non-singleton zset table keyset +create foreign table db15_w_zset_kset(key text, val text[]) + server localredis + options (database '15', tabletype 'zset', tablekeyset 'w_zset_kset'); +select * from db15_w_zset_kset; + key | val +-----+----- +(0 rows) + +insert into db15_w_zset_kset values ('a_wzk','{b,c,d}'), ('c_wzk','{d,e,f}'),('e_wzk','{f,g,h}'); +insert into db15_w_zset_kset values ('a_wzk','{x}'); -- dup error +ERROR: key already exists: a_wzk +select * from db15_w_zset_kset order by key; + key | val +-------+--------- + a_wzk | {b,c,d} + c_wzk | {d,e,f} + e_wzk | {f,g,h} +(3 rows) + +delete from db15_w_zset_kset where key = 'a_wzk'; +select * from db15_w_zset_kset order by key; + key | val +-------+--------- + c_wzk | {d,e,f} + e_wzk | {f,g,h} +(2 rows) + +update db15_w_zset_kset set key = 'x_wlk', val = '{x,y,z}' where key = 'c_wzk'; +select key, atsort(val) as val from db15_w_zset_kset order by key; + key | val +-------+--------- + e_wzk | {f,g,h} + x_wlk | {x,y,z} +(2 rows) + +update db15_w_zset_kset set key = 'z_wzk' where key = 'x_wzk'; +select key, atsort(val) as val from db15_w_zset_kset order by key; + key | val +-------+--------- + e_wzk | {f,g,h} + x_wlk | {x,y,z} +(2 rows) + +update db15_w_zset_kset set val = '{q,r,s}' where key = 'e_wzk'; +select key, atsort(val) as val from db15_w_zset_kset order by key; + key | val +-------+--------- + e_wzk | {q,r,s} + x_wlk | {x,y,z} +(2 rows) + +delete from db15_w_zset_kset; +select * from db15_w_zset_kset; + key | val +-----+----- +(0 rows) + +-- non-singleton hash table prefix +create foreign table db15_w_hash_pfx(key text, val text[]) + server localredis + options (database '15', tabletype 'hash', tablekeyprefix 'w_hash_'); +select * from db15_w_hash_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_hash_pfx values ('w_hash_e','{f,g,h}'); -- error +ERROR: cannot decompose odd number of items into a Redis hash +insert into db15_w_hash_pfx values ('w_hash_e','{}'); -- error +ERROR: cannot store empty list in a Redis table +insert into db15_w_hash_pfx values ('w_hash_a','{b,c,d,e}'), ('w_hash_c','{f,g,h,i}'),('w_hash_e','{j,k}'); +insert into db15_w_hash_pfx values ('x','{y,z}'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_hash_' +insert into db15_w_hash_pfx values ('w_hash_a','{y,z}'); -- dup error +ERROR: key already exists: w_hash_a +select * from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_a | {b,c,d,e} + w_hash_c | {f,g,h,i} + w_hash_e | {j,k} +(3 rows) + +delete from db15_w_hash_pfx where key = 'w_hash_a'; +select * from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_c | {f,g,h,i} + w_hash_e | {j,k} +(2 rows) + +update db15_w_hash_pfx set key = 'x' where key = 'w_hash_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_hash_pfx set key = 'x', val = '{y,z}' where key = 'w_hash_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_hash_pfx set key = 'w_hash_x', val = '{x,y,z}' where key = 'w_hash_c'; -- err +ERROR: cannot decompose odd number of items into a Redis hash +update db15_w_hash_pfx set key = 'w_hash_x', val = '{w,x,y,z}' where key = 'w_hash_c'; +select key, val from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_e | {j,k} + w_hash_x | {w,x,y,z} +(2 rows) + +update db15_w_hash_pfx set key = 'w_hash_z' where key = 'w_hash_x'; +select key, val from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_e | {j,k} + w_hash_z | {w,x,y,z} +(2 rows) + +update db15_w_hash_pfx set val = '{q,r,s}' where key = 'w_hash_e'; +ERROR: cannot decompose odd number of items into a Redis hash +select key, val from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_e | {j,k} + w_hash_z | {w,x,y,z} +(2 rows) + +delete from db15_w_hash_pfx; +select * from db15_w_hash_pfx; + key | val +-----+----- +(0 rows) + +--non-singleton hash table keyset +create foreign table db15_w_hash_kset(key text, val text[]) + server localredis + options (database '15', tabletype 'hash', tablekeyset 'w_hash_kset'); +select * from db15_w_hash_kset; + key | val +-----+----- +(0 rows) + +insert into db15_w_hash_pfx values ('e_whk','{f,g,h}'); -- error +ERROR: key 'e_whk' does not match table key prefix 'w_hash_' +insert into db15_w_hash_pfx values ('e_whk','{}'); -- error +ERROR: key 'e_whk' does not match table key prefix 'w_hash_' +insert into db15_w_hash_kset values ('a_whk','{b,c,d,e}'), ('c_whk','{f,g,h,i}'),('e_whk','{j,k}'); +insert into db15_w_hash_kset values ('a_whk','{x,y}'); -- dup error +ERROR: key already exists: a_whk +select * from db15_w_hash_kset order by key; + key | val +-------+----------- + a_whk | {b,c,d,e} + c_whk | {f,g,h,i} + e_whk | {j,k} +(3 rows) + +delete from db15_w_hash_kset where key = 'a_whk'; +select * from db15_w_hash_kset order by key; + key | val +-------+----------- + c_whk | {f,g,h,i} + e_whk | {j,k} +(2 rows) + +update db15_w_hash_kset set key = 'x_whk', val = '{w,x,y,z}' where key = 'c_whk'; +select key, val from db15_w_hash_kset order by key; + key | val +-------+----------- + e_whk | {j,k} + x_whk | {w,x,y,z} +(2 rows) + +update db15_w_hash_kset set key = 'z_whk' where key = 'x_whk'; +select key, val from db15_w_hash_kset order by key; + key | val +-------+----------- + e_whk | {j,k} + z_whk | {w,x,y,z} +(2 rows) + +update db15_w_hash_kset set val = '{q,r}' where key = 'e_whk'; +select key, val from db15_w_hash_kset order by key; + key | val +-------+----------- + e_whk | {q,r} + z_whk | {w,x,y,z} +(2 rows) + +delete from db15_w_hash_kset; +select * from db15_w_hash_kset; + key | val +-----+----- +(0 rows) + +-- now clean up for the cursor tests +\! redis-cli < test/redis_clean +OK +OK +-- cursor tests +create foreign table db15bigprefixscalar ( + key text not null, + val text +) +server localredis +options (database '15', tablekeyprefix 'w_scalar_'); +create foreign table db15bigkeysetscalar ( + key text not null, + val text +) +server localredis +options (database '15', tablekeyset 'w_kset'); +insert into db15 +select 'junk' || x, 'junk' +from generate_series(1,10000) as x; +insert into db15bigprefixscalar +select 'w_scalar_' || x::text, 'val ' || x::text +from generate_series (1,10000) as x; +insert into db15bigkeysetscalar +select 'key_' || x::text, 'val ' || x::text +from generate_series (1,10000) as x; +insert into db15 +select 'junk' || x, 'junk' +from generate_series(10001, 20000) as x; +insert into db15bigprefixscalar +select 'w_scalar_' || x::text, 'val ' || x::text +from generate_series (10001, 20000) as x; +insert into db15bigkeysetscalar +select 'key_' || x::text, 'val ' || x::text +from generate_series (10001, 20000) as x; +select count(*) from db15; + count +------- + 60000 +(1 row) + +select count(*) from db15bigprefixscalar; + count +------- + 20000 +(1 row) + +select count(*) from db15bigkeysetscalar; + count +------- + 20000 +(1 row) + +-- all done, so now blow everything in the db away again +\! redis-cli < test/redis_clean +OK +OK +DROP EXTENSION redis_fdw CASCADE; +NOTICE: drop cascades to 45 other objects +DETAIL: drop cascades to server localredis +drop cascades to user mapping for public on server localredis +drop cascades to foreign table db15 +drop cascades to foreign table db15_hash +drop cascades to foreign table db15_set +drop cascades to foreign table db15_list +drop cascades to foreign table db15_zset +drop cascades to foreign table db15_hash_prefix +drop cascades to foreign table db15_hash_prefix_array +drop cascades to foreign table db15_hash_keyset_array +drop cascades to foreign table db15_set_prefix +drop cascades to foreign table db15_set_prefix_array +drop cascades to foreign table db15_set_keyset_array +drop cascades to foreign table db15_list_prefix +drop cascades to foreign table db15_list_prefix_array +drop cascades to foreign table db15_list_keyset_array +drop cascades to foreign table db15_zset_prefix +drop cascades to foreign table db15_zset_prefix_array +drop cascades to foreign table db15_zset_keyset_array +drop cascades to foreign table db15_1key +drop cascades to foreign table db15_1key_hash +drop cascades to foreign table db15_1key_set +drop cascades to foreign table db15_1key_list +drop cascades to foreign table db15_1key_zset +drop cascades to foreign table db15_1key_zset_scores +drop cascades to foreign table db15_w_1key_scalar +drop cascades to foreign table db15_w_1key_hash +drop cascades to foreign table db15_w_1key_list +drop cascades to foreign table db15_w_1key_set +drop cascades to foreign table db15_w_1key_zset +drop cascades to foreign table db15_w_1key_zsetx +drop cascades to foreign table db15_w_scalar +drop cascades to foreign table db15_w_scalar_pfx +drop cascades to foreign table db15_w_scalar_kset +drop cascades to foreign table db15_w_set_nonarr +drop cascades to foreign table db15_w_set_pfx +drop cascades to foreign table db15_w_set_kset +drop cascades to foreign table db15_w_list_pfx +drop cascades to foreign table db15_w_list_kset +drop cascades to foreign table db15_w_zset_pfx +drop cascades to foreign table db15_w_zset_kset +drop cascades to foreign table db15_w_hash_pfx +drop cascades to foreign table db15_w_hash_kset +drop cascades to foreign table db15bigprefixscalar +drop cascades to foreign table db15bigkeysetscalar +DROP EXTENSION hstore; diff --git a/test/expected/18rc1/nogis.out b/test/expected/18rc1/nogis.out new file mode 100644 index 0000000..cf309cd --- /dev/null +++ b/test/expected/18rc1/nogis.out @@ -0,0 +1,23 @@ +-- Testcase 001 +CREATE EXTENSION hstore; +-- Testcase 002 +CREATE EXTENSION redis_fdw; +-- Testcase 003 +create server localredis foreign data wrapper redis_fdw; +-- Testcase 004 +create user mapping for public server localredis; +-- Testcase 005 +-- \! redis-cli < test/redis_gis_ini +-- REDIS SPATIAL VALUE TESTS WILL BE HERE +-- Testcase 098 +-- all done, so now blow everything in the db away again +\! redis-cli < test/redis_clean +OK +OK +-- Testcase 099 +DROP EXTENSION redis_fdw CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to server localredis +drop cascades to user mapping for public on server localredis +-- Testcase 100 +DROP EXTENSION hstore CASCADE; diff --git a/test/expected/18rc1/postgis.out b/test/expected/18rc1/postgis.out new file mode 100644 index 0000000..b84d7cb --- /dev/null +++ b/test/expected/18rc1/postgis.out @@ -0,0 +1,29 @@ +-- Testcase 001 +CREATE EXTENSION postgis; +ERROR: extension "postgis" is not available +HINT: The extension must first be installed on the system where PostgreSQL is running. +-- Testcase 002 +CREATE EXTENSION hstore; +-- Testcase 003 +CREATE EXTENSION redis_fdw; +-- Testcase 004 +create server localredis foreign data wrapper redis_fdw; +-- Testcase 005 +create user mapping for public server localredis; +-- Testcase 006 +-- \! redis-cli < test/redis_gis_ini +-- Testcase 098 +-- all done, so now blow everything in the db away again +\! redis-cli < test/redis_clean +OK +OK +-- Testcase 099 +DROP EXTENSION redis_fdw CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to server localredis +drop cascades to user mapping for public on server localredis +-- Testcase 100 +DROP EXTENSION hstore CASCADE; +-- Testcase 101 +DROP EXTENSION postgis CASCADE; +ERROR: extension "postgis" does not exist diff --git a/test/expected/18rc1/redis_fdw.out b/test/expected/18rc1/redis_fdw.out new file mode 100644 index 0000000..7b5789d --- /dev/null +++ b/test/expected/18rc1/redis_fdw.out @@ -0,0 +1,1466 @@ +-- Testcase 001: +CREATE EXTENSION hstore; +-- Testcase 002: +CREATE EXTENSION redis_fdw; +-- Testcase 003: +select redis_fdw_version(); + redis_fdw_version +------------------- + 1901 +(1 row) + +-- Testcase 004: +select redis_fdw_hiredis_version(); + redis_fdw_hiredis_version +--------------------------- + 1401 +(1 row) + +-- Testcase 005: +CREATE OR REPLACE FUNCTION atsort( a text[]) + RETURNS text[] + LANGUAGE sql + IMMUTABLE STRICT +AS $function$ + select array(select unnest($1) order by 1) +$function$; +create server localredis foreign data wrapper redis_fdw; +create user mapping for public server localredis; +-- tables for all 5 data types (4 structured plus scalar) +create foreign table db15(key text, value text) + server localredis + options (database '15'); +create foreign table db15_hash(key text, value text) + server localredis + options (database '15', tabletype 'hash'); +create foreign table db15_set(key text, value text) + server localredis + options (database '15', tabletype 'set'); +create foreign table db15_list(key text, value text) + server localredis + options (database '15', tabletype 'list'); +create foreign table db15_zset(key text, value text) + server localredis + options (database '15', tabletype 'zset'); +-- make sure they are all empty - if any are not stop the script right now +\set ON_ERROR_STOP +do $$ + declare + rows bigint; + begin + select into rows + (select count(*) from db15) + + (select count(*) from db15_hash) + + (select count(*) from db15_set) + + (select count(*) from db15_list) + + (select count(*) from db15_zset); + if rows > 0 + then + raise EXCEPTION 'db 15 not empty'; + end if; + end; +$$; +\unset ON_ERROR_STOP +-- ok, empty, so now run the setup script +\! redis-cli < test/redis_setup +OK +OK +OK +8 +5 +6 +4 +OK +OK +6 +6 +2 +2 +2 +2 +select * from db15 order by key; + key | value +-----+-------- + baz | blurfl + foo | bar +(2 rows) + +select * from db15 where key = 'foo'; + key | value +-----+------- + foo | bar +(1 row) + +-- hash +create foreign table db15_hash_prefix(key text, value text) + server localredis + options (tabletype 'hash', tablekeyprefix 'hash', database '15'); +create foreign table db15_hash_prefix_array(key text, value text[]) + server localredis + options (tabletype 'hash', tablekeyprefix 'hash', database '15'); +create foreign table db15_hash_keyset_array(key text, value text[]) + server localredis + options (tabletype 'hash', tablekeyset 'hkeys', database '15'); +select * from db15_hash_prefix order by key; + key | value +-------+------------------------------------------- + hash1 | {"k1","v1","k2","v2","k3","v3","k4","v4"} + hash2 | {"k1","v5","k2","v6","k3","v7","k4","v8"} +(2 rows) + +select * from db15_hash_prefix where key = 'hash1'; + key | value +-------+------------------------------------------- + hash1 | {"k1","v1","k2","v2","k3","v3","k4","v4"} +(1 row) + +select * from db15_hash_prefix_array order by key; + key | value +-------+--------------------------- + hash1 | {k1,v1,k2,v2,k3,v3,k4,v4} + hash2 | {k1,v5,k2,v6,k3,v7,k4,v8} +(2 rows) + +select * from db15_hash_prefix_array where key = 'hash1'; + key | value +-------+--------------------------- + hash1 | {k1,v1,k2,v2,k3,v3,k4,v4} +(1 row) + +select * from db15_hash_keyset_array order by key; + key | value +-------+--------------------------- + hash1 | {k1,v1,k2,v2,k3,v3,k4,v4} + hash2 | {k1,v5,k2,v6,k3,v7,k4,v8} +(2 rows) + +select * from db15_hash_keyset_array where key = 'hash1'; + key | value +-------+--------------------------- + hash1 | {k1,v1,k2,v2,k3,v3,k4,v4} +(1 row) + +-- a couple of nifty things we an do with hash tables +select key, hstore(value) from db15_hash_prefix_array order by key; + key | hstore +-------+------------------------------------------------ + hash1 | "k1"=>"v1", "k2"=>"v2", "k3"=>"v3", "k4"=>"v4" + hash2 | "k1"=>"v5", "k2"=>"v6", "k3"=>"v7", "k4"=>"v8" +(2 rows) + +create type atab as (k1 text, k2 text, k3 text); +select key, (populate_record(null::atab, hstore(value))).* +from db15_hash_prefix_array +order by key; + key | k1 | k2 | k3 +-------+----+----+---- + hash1 | v1 | v2 | v3 + hash2 | v5 | v6 | v7 +(2 rows) + +-- set +create foreign table db15_set_prefix(key text, value text) + server localredis + options (tabletype 'set', tablekeyprefix 'set', database '15'); +create foreign table db15_set_prefix_array(key text, value text[]) + server localredis + options (tabletype 'set', tablekeyprefix 'set', database '15'); +create foreign table db15_set_keyset_array(key text, value text[]) + server localredis + options (tabletype 'set', tablekeyset 'skeys', database '15'); +-- need to use atsort() on set results to get predicable output +-- since redis will give them back in arbitrary order +-- means we can't show the actual value for db15_set_prefix which has it as a +-- single text field +select key, atsort(value::text[]) as value from db15_set_prefix order by key; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} + set2 | {m10,m11,m12,m8,m9} +(2 rows) + +select key, atsort(value::text[]) as value from db15_set_prefix where key = 'set1'; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} +(1 row) + +select key, atsort(value) as value from db15_set_prefix_array order by key; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} + set2 | {m10,m11,m12,m8,m9} +(2 rows) + +select key, atsort(value) as value from db15_set_prefix_array where key = 'set1'; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} +(1 row) + +select key, atsort(value) as value from db15_set_keyset_array order by key; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} + set2 | {m10,m11,m12,m8,m9} +(2 rows) + +select key, atsort(value) as value from db15_set_keyset_array where key = 'set1'; + key | value +------+--------------------------- + set1 | {m1,m2,m3,m4,m5,m6,m7,m8} +(1 row) + +-- list +create foreign table db15_list_prefix(key text, value text) + server localredis + options (tabletype 'list', tablekeyprefix 'list', database '15'); +create foreign table db15_list_prefix_array(key text, value text[]) + server localredis + options (tabletype 'list', tablekeyprefix 'list', database '15'); +create foreign table db15_list_keyset_array(key text, value text[]) + server localredis + options (tabletype 'list', tablekeyset 'lkeys', database '15'); +select * from db15_list_prefix order by key; + key | value +-------+--------------------------------- + list1 | {"e6","e5","e4","e3","e2","e1"} + list2 | {"e10","e9","e8","e7"} +(2 rows) + +select * from db15_list_prefix where key = 'list1'; + key | value +-------+--------------------------------- + list1 | {"e6","e5","e4","e3","e2","e1"} +(1 row) + +select * from db15_list_prefix_array order by key; + key | value +-------+--------------------- + list1 | {e6,e5,e4,e3,e2,e1} + list2 | {e10,e9,e8,e7} +(2 rows) + +select * from db15_list_prefix_array where key = 'list1'; + key | value +-------+--------------------- + list1 | {e6,e5,e4,e3,e2,e1} +(1 row) + +select * from db15_list_keyset_array order by key; + key | value +-------+--------------------- + list1 | {e6,e5,e4,e3,e2,e1} + list2 | {e10,e9,e8,e7} +(2 rows) + +select * from db15_list_keyset_array where key = 'list1'; + key | value +-------+--------------------- + list1 | {e6,e5,e4,e3,e2,e1} +(1 row) + +-- zset +create foreign table db15_zset_prefix(key text, value text) + server localredis + options (tabletype 'zset', tablekeyprefix 'zset', database '15'); +create foreign table db15_zset_prefix_array(key text, value text[]) + server localredis + options (tabletype 'zset', tablekeyprefix 'zset', database '15'); +create foreign table db15_zset_keyset_array(key text, value text[]) + server localredis + options (tabletype 'zset', tablekeyset 'zkeys', database '15'); +select * from db15_zset_prefix order by key; + key | value +-------+------------------------------------ + zset1 | {"z1","z2","z3","z4","z5","z6"} + zset2 | {"z7","z8","z9","z10","z11","z12"} +(2 rows) + +select * from db15_zset_prefix where key = 'zset1'; + key | value +-------+--------------------------------- + zset1 | {"z1","z2","z3","z4","z5","z6"} +(1 row) + +select * from db15_zset_prefix_array order by key; + key | value +-------+------------------------ + zset1 | {z1,z2,z3,z4,z5,z6} + zset2 | {z7,z8,z9,z10,z11,z12} +(2 rows) + +select * from db15_zset_prefix_array where key = 'zset1'; + key | value +-------+--------------------- + zset1 | {z1,z2,z3,z4,z5,z6} +(1 row) + +select * from db15_zset_keyset_array order by key; + key | value +-------+------------------------ + zset1 | {z1,z2,z3,z4,z5,z6} + zset2 | {z7,z8,z9,z10,z11,z12} +(2 rows) + +select * from db15_zset_keyset_array where key = 'zset1'; + key | value +-------+--------------------- + zset1 | {z1,z2,z3,z4,z5,z6} +(1 row) + +-- singleton scalar +create foreign table db15_1key(value text) + server localredis + options (singleton_key 'foo', database '15'); +select * from db15_1key; + value +------- + bar +(1 row) + +-- singleton hash +create foreign table db15_1key_hash(key text, value text) + server localredis + options (tabletype 'hash', singleton_key 'hash1', database '15'); +select * from db15_1key_hash order by key; + key | value +-----+------- + k1 | v1 + k2 | v2 + k3 | v3 + k4 | v4 +(4 rows) + +-- singleton set +create foreign table db15_1key_set(value text) + server localredis + options (tabletype 'set', singleton_key 'set1', database '15'); +select * from db15_1key_set order by value; + value +------- + m1 + m2 + m3 + m4 + m5 + m6 + m7 + m8 +(8 rows) + +-- singleton list +create foreign table db15_1key_list(value text) + server localredis + options (tabletype 'list', singleton_key 'list1', database '15'); +select * from db15_1key_list order by value; + value +------- + e1 + e2 + e3 + e4 + e5 + e6 +(6 rows) + +-- singleton zset +create foreign table db15_1key_zset(value text) + server localredis + options (tabletype 'zset', singleton_key 'zset1', database '15'); +select * from db15_1key_zset order by value; + value +------- + z1 + z2 + z3 + z4 + z5 + z6 +(6 rows) + +-- singleton zset with scores +create foreign table db15_1key_zset_scores(value text, score numeric) + server localredis + options (tabletype 'zset', singleton_key 'zset1', database '15'); +select * from db15_1key_zset_scores order by score desc; + value | score +-------+------- + z6 | 6 + z5 | 5 + z4 | 4 + z3 | 3 + z2 | 2 + z1 | 1 +(6 rows) + +-- insert delete update +-- first clean the database again +\! redis-cli < test/redis_clean +OK +OK +-- singleton scalar table +create foreign table db15_w_1key_scalar(val text) + server localredis + options (singleton_key 'w_1key_scalar', database '15'); +select * from db15_w_1key_scalar; + val +----- +(0 rows) + +insert into db15_w_1key_scalar values ('only row'); +select * from db15_w_1key_scalar; + val +---------- + only row +(1 row) + +insert into db15_w_1key_scalar values ('only row'); +ERROR: key already exists: w_1key_scalar +delete from db15_w_1key_scalar where val = 'not only row'; +select * from db15_w_1key_scalar; + val +---------- + only row +(1 row) + +update db15_w_1key_scalar set val = 'new scalar val'; +select * from db15_w_1key_scalar; + val +---------------- + new scalar val +(1 row) + +delete from db15_w_1key_scalar; +select * from db15_w_1key_scalar; + val +----- +(0 rows) + +-- singleton hash +create foreign table db15_w_1key_hash(key text, val text) + server localredis + options (singleton_key 'w_1key_hash', tabletype 'hash', database '15'); +select * from db15_w_1key_hash; + key | val +-----+----- +(0 rows) + +insert into db15_w_1key_hash values ('a','b'), ('c','d'),('e','f'); +select * from db15_w_1key_hash order by key; + key | val +-----+----- + a | b + c | d + e | f +(3 rows) + +insert into db15_w_1key_hash values ('a','b'); +ERROR: key already exists: a +delete from db15_w_1key_hash where key = 'a'; +delete from db15_w_1key_hash where key = 'a'; +select * from db15_w_1key_hash order by key; + key | val +-----+----- + c | d + e | f +(2 rows) + +update db15_w_1key_hash set key = 'x', val = 'y' where key = 'c'; +select * from db15_w_1key_hash order by key; + key | val +-----+----- + e | f + x | y +(2 rows) + +update db15_w_1key_hash set val = 'z' where key = 'e'; +select * from db15_w_1key_hash order by key; + key | val +-----+----- + e | z + x | y +(2 rows) + +update db15_w_1key_hash set key = 'w' where key = 'e'; +select * from db15_w_1key_hash order by key; + key | val +-----+----- + w | z + x | y +(2 rows) + +-- singleton list +create foreign table db15_w_1key_list(val text) + server localredis + options (singleton_key 'w_1key_list', tabletype 'list', database '15'); +select * from db15_w_1key_list; + val +----- +(0 rows) + +insert into db15_w_1key_list values ('a'), ('c'),('e'); +-- for lists the order should (must) be determinate +select * from db15_w_1key_list /* order by val */ ; + val +----- + a + c + e +(3 rows) + +delete from db15_w_1key_list where val = 'a'; +ERROR: delete not supported for this type of table +delete from db15_w_1key_list where val = 'z'; +ERROR: delete not supported for this type of table +insert into db15_w_1key_list values ('b'), ('d'),('f'),('a'); -- dups allowed here +select * from db15_w_1key_list /* order by val */; + val +----- + a + c + e + b + d + f + a +(7 rows) + +update db15_w_1key_list set val = 'y'; +ERROR: update not supported for this type of table +-- singleton set +create foreign table db15_w_1key_set(key text) + server localredis + options (singleton_key 'w_1key_set', tabletype 'set', database '15'); +select * from db15_w_1key_set; + key +----- +(0 rows) + +insert into db15_w_1key_set values ('a'), ('c'),('e'); +select * from db15_w_1key_set order by key; + key +----- + a + c + e +(3 rows) + +insert into db15_w_1key_set values ('a'); -- error - dup +ERROR: key already exists: a +delete from db15_w_1key_set where key = 'c'; +select * from db15_w_1key_set order by key; + key +----- + a + e +(2 rows) + +update db15_w_1key_set set key = 'x' where key = 'e'; +select * from db15_w_1key_set order by key; + key +----- + a + x +(2 rows) + +-- singleton zset with scores +create foreign table db15_w_1key_zset(key text, priority numeric) + server localredis + options (singleton_key 'w_1key_zset', tabletype 'zset', database '15'); +select * from db15_w_1key_zset; + key | priority +-----+---------- +(0 rows) + +insert into db15_w_1key_zset values ('a',1), ('c',5),('e',-5), ('h',10); +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + e | -5 + a | 1 + c | 5 + h | 10 +(4 rows) + +insert into db15_w_1key_zset values ('a',99); +ERROR: key already exists: a +delete from db15_w_1key_zset where key = 'a'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + e | -5 + c | 5 + h | 10 +(3 rows) + +delete from db15_w_1key_zset where priority = '5'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + e | -5 + h | 10 +(2 rows) + +update db15_w_1key_zset set key = 'x', priority = 99 where priority = '-5'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + h | 10 + x | 99 +(2 rows) + +update db15_w_1key_zset set key = 'y' where key = 'h'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + y | 10 + x | 99 +(2 rows) + +update db15_w_1key_zset set priority = 20 where key = 'y'; +select * from db15_w_1key_zset order by priority; + key | priority +-----+---------- + y | 20 + x | 99 +(2 rows) + +-- singleton zset no scores +-- use set from last step +delete from db15_w_1key_zset; +insert into db15_w_1key_zset values ('e',-5); +create foreign table db15_w_1key_zsetx(key text) + server localredis + options (singleton_key 'w_1key_zset', tabletype 'zset', database '15'); +select * from db15_w_1key_zsetx; + key +----- + e +(1 row) + +insert into db15_w_1key_zsetx values ('a'), ('c'),('e'); -- can't insert +ERROR: operation not supported for singleton zset table without priorities column +update db15_w_1key_zsetx set key = 'z' where key = 'e'; +select * from db15_w_1key_zsetx order by key; + key +----- + z +(1 row) + +delete from db15_w_1key_zsetx where key = 'z'; +select * from db15_w_1key_zsetx order by key; + key +----- +(0 rows) + +-- non-singleton scalar table no prefix no keyset +create foreign table db15_w_scalar(key text, val text) + server localredis + options (database '15'); +select * from db15_w_scalar; + key | val +-----+----- +(0 rows) + +insert into db15_w_scalar values ('a_ws','b'), ('c_ws','d'),('e_ws','f'); +select * from db15_w_scalar order by key; + key | val +------+----- + a_ws | b + c_ws | d + e_ws | f +(3 rows) + +delete from db15_w_scalar where key = 'a_ws'; +select * from db15_w_scalar order by key; + key | val +------+----- + c_ws | d + e_ws | f +(2 rows) + +update db15_w_scalar set key = 'x_ws', val='y' where key = 'e_ws'; +select * from db15_w_scalar order by key; + key | val +------+----- + c_ws | d + x_ws | y +(2 rows) + +update db15_w_scalar set key = 'z_ws' where key = 'c_ws'; +select * from db15_w_scalar order by key; + key | val +------+----- + x_ws | y + z_ws | d +(2 rows) + +update db15_w_scalar set val = 'z' where key = 'z_ws'; +select * from db15_w_scalar order by key; + key | val +------+----- + x_ws | y + z_ws | z +(2 rows) + +/* +-- don't delete the whole namespace + delete from db15_w_scalar; + +select * from db15_w_scalar; +*/ +-- non-singleton scalar table keyprefix +create foreign table db15_w_scalar_pfx(key text, val text) + server localredis + options (database '15', tablekeyprefix 'w_scalar_'); +select * from db15_w_scalar_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_scalar_pfx values ('w_scalar_a','b'), ('w_scalar_c','d'),('w_scalar_e','f'); +insert into db15_w_scalar_pfx values ('x','y'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_scalar_' +insert into db15_w_scalar_pfx values ('w_scalar_a','x'); -- dup error +ERROR: key already exists: w_scalar_a +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_a | b + w_scalar_c | d + w_scalar_e | f +(3 rows) + +delete from db15_w_scalar_pfx where key = 'w_scalar_a'; +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_c | d + w_scalar_e | f +(2 rows) + +update db15_w_scalar_pfx set key = 'x', val = 'y' where key = 'w_scalar_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_scalar_pfx set key = 'x' where key = 'w_scalar_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_scalar_pfx set key = 'w_scalar_x', val = 'y' where key = 'w_scalar_c'; +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_e | f + w_scalar_x | y +(2 rows) + +update db15_w_scalar_pfx set key = 'w_scalar_z' where key = 'w_scalar_x'; +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_e | f + w_scalar_z | y +(2 rows) + +update db15_w_scalar_pfx set val = 'w' where key = 'w_scalar_e'; +select * from db15_w_scalar_pfx order by key; + key | val +------------+----- + w_scalar_e | w + w_scalar_z | y +(2 rows) + +delete from db15_w_scalar_pfx; +select * from db15_w_scalar_pfx order by key; + key | val +-----+----- +(0 rows) + +-- non-singleton scalar table keyset +create foreign table db15_w_scalar_kset(key text, val text) + server localredis + options (database '15', tablekeyset 'w_scalar_kset'); +select * from db15_w_scalar_kset order by key; + key | val +-----+----- +(0 rows) + +insert into db15_w_scalar_kset values ('a_wsks','b'), ('c_wsks','d'),('e_wsks','f'); +insert into db15_w_scalar_kset values ('a_wsks','x'); -- dup error +ERROR: key already exists: a_wsks +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + a_wsks | b + c_wsks | d + e_wsks | f +(3 rows) + +delete from db15_w_scalar_kset where key = 'a_wsks'; +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + c_wsks | d + e_wsks | f +(2 rows) + +update db15_w_scalar_kset set key = 'x_wsks', val = 'y' where key = 'c_wsks'; +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + e_wsks | f + x_wsks | y +(2 rows) + +update db15_w_scalar_kset set key = 'z_wsks' where key = 'x_wsks'; +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + e_wsks | f + z_wsks | y +(2 rows) + +update db15_w_scalar_kset set val = 'w' where key = 'e_wsks'; +select * from db15_w_scalar_kset order by key; + key | val +--------+----- + e_wsks | w + z_wsks | y +(2 rows) + +delete from db15_w_scalar_kset; +select * from db15_w_scalar_kset order by key; + key | val +-----+----- +(0 rows) + +-- non-singleton set table no prefix no keyset +-- non-array case -- fails +create foreign table db15_w_set_nonarr(key text, val text) + server localredis + options (database '15', tabletype 'set'); +insert into db15_w_set_nonarr values ('nkseta','{b,c,d}'), ('nksetc','{d,e,f}'),('nksete','{f,g,h}'); +ERROR: cannot insert into this type of Redis table - needs an array +/* +-- namespace too polluted for this case +create foreign table db15_w_set(key text, val text[]) + server localredis + options (database '15', tabletype 'set'); + +select * from db15_w_set; + +insert into db15_w_set values ('nkseta','{b,c,d}'), ('nksetc','{d,e,f}'),('nksete','{f,g,h}'); + +select * from db15_w_set; + +delete from db15_w_set where key = 'nkseta'; + +select * from db15_w_set; + +delete from db15_w_set; + +select * from db15_w_set; + +*/ +-- non-singleton set table keyprefix +create foreign table db15_w_set_pfx(key text, val text[]) + server localredis + options (database '15', tabletype 'set', tablekeyprefix 'w_set_'); +select * from db15_w_set_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_set_pfx values ('w_set_a','{b,c,d}'), ('w_set_c','{d,e,f}'),('w_set_e','{f,g,h}'); +insert into db15_w_set_pfx values ('x','{y}'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_set_' +insert into db15_w_set_pfx values ('w_set_a','{x,y,z}'); -- dup error +ERROR: key already exists: w_set_a +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_a | {b,c,d} + w_set_c | {d,e,f} + w_set_e | {f,g,h} +(3 rows) + +delete from db15_w_set_pfx where key = 'w_set_a'; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_c | {d,e,f} + w_set_e | {f,g,h} +(2 rows) + +update db15_w_set_pfx set key = 'x' where key = 'w_set_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_set_pfx set key = 'x', val = '{y}' where key = 'w_set_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_set_pfx set key = 'w_set_x', val = '{x,y,z}' where key = 'w_set_c'; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_e | {f,g,h} + w_set_x | {x,y,z} +(2 rows) + +update db15_w_set_pfx set key = 'w_set_z' where key = 'w_set_x'; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_e | {f,g,h} + w_set_z | {x,y,z} +(2 rows) + +update db15_w_set_pfx set val = '{q,r,s}' where key = 'w_set_e'; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +---------+--------- + w_set_e | {q,r,s} + w_set_z | {x,y,z} +(2 rows) + +delete from db15_w_set_pfx; +select key, atsort(val) as val from db15_w_set_pfx order by key; + key | val +-----+----- +(0 rows) + +-- non-singleton set table keyset +create foreign table db15_w_set_kset(key text, val text[]) + server localredis + options (database '15', tabletype 'set', tablekeyset 'w_set_kset'); +select * from db15_w_set_kset; + key | val +-----+----- +(0 rows) + +insert into db15_w_set_kset values ('a_wsk','{b,c,d}'), ('c_wsk','{d,e,f}'),('e_wsk','{f,g,h}'); +insert into db15_w_set_kset values ('a_wsk','{x}'); -- dup error +ERROR: key already exists: a_wsk +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + a_wsk | {b,c,d} + c_wsk | {d,e,f} + e_wsk | {f,g,h} +(3 rows) + +delete from db15_w_set_kset where key = 'a_wsk'; +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + c_wsk | {d,e,f} + e_wsk | {f,g,h} +(2 rows) + +update db15_w_set_kset set key = 'x_wsk', val = '{x,y,z}' where key = 'c_wsk'; +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + e_wsk | {f,g,h} + x_wsk | {x,y,z} +(2 rows) + +update db15_w_set_kset set key = 'z_wsk' where key = 'x_wsk'; +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + e_wsk | {f,g,h} + z_wsk | {x,y,z} +(2 rows) + +update db15_w_set_kset set val = '{q,r,s}' where key = 'e_wsk'; +select key, atsort(val) as val from db15_w_set_kset order by key; + key | val +-------+--------- + e_wsk | {q,r,s} + z_wsk | {x,y,z} +(2 rows) + +delete from db15_w_set_kset; +select * from db15_w_set_kset; + key | val +-----+----- +(0 rows) + +-- non-singleton list table keyprefix +create foreign table db15_w_list_pfx(key text, val text[]) + server localredis + options (database '15', tabletype 'list', tablekeyprefix 'w_list_'); +select * from db15_w_list_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_list_pfx values ('w_list_a','{b,c,d}'), ('w_list_c','{d,e,f}'),('w_list_e','{f,g,h}'); +insert into db15_w_list_pfx values ('x','{y}'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_list_' +insert into db15_w_list_pfx values ('w_list_a','{x,y,z}'); -- dup error +ERROR: key already exists: w_list_a +select * from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_a | {b,c,d} + w_list_c | {d,e,f} + w_list_e | {f,g,h} +(3 rows) + +delete from db15_w_list_pfx where key = 'w_list_a'; +select * from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_c | {d,e,f} + w_list_e | {f,g,h} +(2 rows) + +update db15_w_list_pfx set key = 'x' where key = 'w_list_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_list_pfx set key = 'x', val = '{y}' where key = 'w_list_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_list_pfx set key = 'w_list_x', val = '{x,y,z}' where key = 'w_list_c'; +select key, atsort(val) as val from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_e | {f,g,h} + w_list_x | {x,y,z} +(2 rows) + +update db15_w_list_pfx set key = 'w_list_z' where key = 'w_list_x'; +select key, atsort(val) as val from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_e | {f,g,h} + w_list_z | {x,y,z} +(2 rows) + +update db15_w_list_pfx set val = '{q,r,s}' where key = 'w_list_e'; +select key, atsort(val) as val from db15_w_list_pfx order by key; + key | val +----------+--------- + w_list_e | {q,r,s} + w_list_z | {x,y,z} +(2 rows) + +delete from db15_w_list_pfx; +select * from db15_w_list_pfx; + key | val +-----+----- +(0 rows) + +-- non-singleton list table keyset +create foreign table db15_w_list_kset(key text, val text[]) + server localredis + options (database '15', tabletype 'list', tablekeyset 'w_list_kset'); +select * from db15_w_list_kset; + key | val +-----+----- +(0 rows) + +insert into db15_w_list_kset values ('a_wlk','{b,c,d}'), ('c_wlk','{d,e,f}'),('e_wlk','{f,g,h}'); +insert into db15_w_list_kset values ('a_wlk','{x}'); -- dup error +ERROR: key already exists: a_wlk +select * from db15_w_list_kset order by key; + key | val +-------+--------- + a_wlk | {b,c,d} + c_wlk | {d,e,f} + e_wlk | {f,g,h} +(3 rows) + +delete from db15_w_list_kset where key = 'a_wlk'; +select * from db15_w_list_kset order by key; + key | val +-------+--------- + c_wlk | {d,e,f} + e_wlk | {f,g,h} +(2 rows) + +update db15_w_list_kset set key = 'x_wlk', val = '{x,y,z}' where key = 'c_wlk'; +select key, atsort(val) as val from db15_w_list_kset order by key; + key | val +-------+--------- + e_wlk | {f,g,h} + x_wlk | {x,y,z} +(2 rows) + +update db15_w_list_kset set key = 'z_wlk' where key = 'x_wlk'; +select key, atsort(val) as val from db15_w_list_kset order by key; + key | val +-------+--------- + e_wlk | {f,g,h} + z_wlk | {x,y,z} +(2 rows) + +update db15_w_list_kset set val = '{q,r,s}' where key = 'e_wlk'; +select key, atsort(val) as val from db15_w_list_kset order by key; + key | val +-------+--------- + e_wlk | {q,r,s} + z_wlk | {x,y,z} +(2 rows) + +delete from db15_w_list_kset; +select * from db15_w_list_kset; + key | val +-----+----- +(0 rows) + +-- non-singleton zset table keyprefix +create foreign table db15_w_zset_pfx(key text, val text[]) + server localredis + options (database '15', tabletype 'zset', tablekeyprefix 'w_zset_'); +select * from db15_w_zset_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_zset_pfx values ('w_zset_a','{b,c,d}'), ('w_zset_c','{d,e,f}'),('w_zset_e','{f,g,h}'); +insert into db15_w_zset_pfx values ('x','{y}'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_zset_' +insert into db15_w_zset_pfx values ('w_zset_a','{x,y,z}'); -- dup error +ERROR: key already exists: w_zset_a +select * from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_a | {b,c,d} + w_zset_c | {d,e,f} + w_zset_e | {f,g,h} +(3 rows) + +delete from db15_w_zset_pfx where key = 'w_zset_a'; +select * from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_c | {d,e,f} + w_zset_e | {f,g,h} +(2 rows) + +update db15_w_zset_pfx set key = 'x' where key = 'w_zset_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_zset_pfx set key = 'x', val = '{y}' where key = 'w_zset_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_zset_pfx set key = 'w_zset_x', val = '{x,y,z}' where key = 'w_zset_c'; +select key, atsort(val) as val from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_e | {f,g,h} + w_zset_x | {x,y,z} +(2 rows) + +update db15_w_zset_pfx set key = 'w_zset_z' where key = 'w_zset_x'; +select key, atsort(val) as val from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_e | {f,g,h} + w_zset_z | {x,y,z} +(2 rows) + +update db15_w_zset_pfx set val = '{q,r,s}' where key = 'w_zset_e'; +select key, atsort(val) as val from db15_w_zset_pfx order by key; + key | val +----------+--------- + w_zset_e | {q,r,s} + w_zset_z | {x,y,z} +(2 rows) + +delete from db15_w_zset_pfx; +select * from db15_w_zset_pfx; + key | val +-----+----- +(0 rows) + +-- non-singleton zset table keyset +create foreign table db15_w_zset_kset(key text, val text[]) + server localredis + options (database '15', tabletype 'zset', tablekeyset 'w_zset_kset'); +select * from db15_w_zset_kset; + key | val +-----+----- +(0 rows) + +insert into db15_w_zset_kset values ('a_wzk','{b,c,d}'), ('c_wzk','{d,e,f}'),('e_wzk','{f,g,h}'); +insert into db15_w_zset_kset values ('a_wzk','{x}'); -- dup error +ERROR: key already exists: a_wzk +select * from db15_w_zset_kset order by key; + key | val +-------+--------- + a_wzk | {b,c,d} + c_wzk | {d,e,f} + e_wzk | {f,g,h} +(3 rows) + +delete from db15_w_zset_kset where key = 'a_wzk'; +select * from db15_w_zset_kset order by key; + key | val +-------+--------- + c_wzk | {d,e,f} + e_wzk | {f,g,h} +(2 rows) + +update db15_w_zset_kset set key = 'x_wlk', val = '{x,y,z}' where key = 'c_wzk'; +select key, atsort(val) as val from db15_w_zset_kset order by key; + key | val +-------+--------- + e_wzk | {f,g,h} + x_wlk | {x,y,z} +(2 rows) + +update db15_w_zset_kset set key = 'z_wzk' where key = 'x_wzk'; +select key, atsort(val) as val from db15_w_zset_kset order by key; + key | val +-------+--------- + e_wzk | {f,g,h} + x_wlk | {x,y,z} +(2 rows) + +update db15_w_zset_kset set val = '{q,r,s}' where key = 'e_wzk'; +select key, atsort(val) as val from db15_w_zset_kset order by key; + key | val +-------+--------- + e_wzk | {q,r,s} + x_wlk | {x,y,z} +(2 rows) + +delete from db15_w_zset_kset; +select * from db15_w_zset_kset; + key | val +-----+----- +(0 rows) + +-- non-singleton hash table prefix +create foreign table db15_w_hash_pfx(key text, val text[]) + server localredis + options (database '15', tabletype 'hash', tablekeyprefix 'w_hash_'); +select * from db15_w_hash_pfx; + key | val +-----+----- +(0 rows) + +insert into db15_w_hash_pfx values ('w_hash_e','{f,g,h}'); -- error +ERROR: cannot decompose odd number of items into a Redis hash +insert into db15_w_hash_pfx values ('w_hash_e','{}'); -- error +ERROR: cannot store empty list in a Redis table +insert into db15_w_hash_pfx values ('w_hash_a','{b,c,d,e}'), ('w_hash_c','{f,g,h,i}'),('w_hash_e','{j,k}'); +insert into db15_w_hash_pfx values ('x','{y,z}'); -- prefix error +ERROR: key 'x' does not match table key prefix 'w_hash_' +insert into db15_w_hash_pfx values ('w_hash_a','{y,z}'); -- dup error +ERROR: key already exists: w_hash_a +select * from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_a | {b,c,d,e} + w_hash_c | {f,g,h,i} + w_hash_e | {j,k} +(3 rows) + +delete from db15_w_hash_pfx where key = 'w_hash_a'; +select * from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_c | {f,g,h,i} + w_hash_e | {j,k} +(2 rows) + +update db15_w_hash_pfx set key = 'x' where key = 'w_hash_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_hash_pfx set key = 'x', val = '{y,z}' where key = 'w_hash_c'; -- prefix err +ERROR: key prefix condition violation: x +update db15_w_hash_pfx set key = 'w_hash_x', val = '{x,y,z}' where key = 'w_hash_c'; -- err +ERROR: cannot decompose odd number of items into a Redis hash +update db15_w_hash_pfx set key = 'w_hash_x', val = '{w,x,y,z}' where key = 'w_hash_c'; +select key, val from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_e | {j,k} + w_hash_x | {w,x,y,z} +(2 rows) + +update db15_w_hash_pfx set key = 'w_hash_z' where key = 'w_hash_x'; +select key, val from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_e | {j,k} + w_hash_z | {w,x,y,z} +(2 rows) + +update db15_w_hash_pfx set val = '{q,r,s}' where key = 'w_hash_e'; +ERROR: cannot decompose odd number of items into a Redis hash +select key, val from db15_w_hash_pfx order by key; + key | val +----------+----------- + w_hash_e | {j,k} + w_hash_z | {w,x,y,z} +(2 rows) + +delete from db15_w_hash_pfx; +select * from db15_w_hash_pfx; + key | val +-----+----- +(0 rows) + +--non-singleton hash table keyset +create foreign table db15_w_hash_kset(key text, val text[]) + server localredis + options (database '15', tabletype 'hash', tablekeyset 'w_hash_kset'); +select * from db15_w_hash_kset; + key | val +-----+----- +(0 rows) + +insert into db15_w_hash_pfx values ('e_whk','{f,g,h}'); -- error +ERROR: key 'e_whk' does not match table key prefix 'w_hash_' +insert into db15_w_hash_pfx values ('e_whk','{}'); -- error +ERROR: key 'e_whk' does not match table key prefix 'w_hash_' +insert into db15_w_hash_kset values ('a_whk','{b,c,d,e}'), ('c_whk','{f,g,h,i}'),('e_whk','{j,k}'); +insert into db15_w_hash_kset values ('a_whk','{x,y}'); -- dup error +ERROR: key already exists: a_whk +select * from db15_w_hash_kset order by key; + key | val +-------+----------- + a_whk | {b,c,d,e} + c_whk | {f,g,h,i} + e_whk | {j,k} +(3 rows) + +delete from db15_w_hash_kset where key = 'a_whk'; +select * from db15_w_hash_kset order by key; + key | val +-------+----------- + c_whk | {f,g,h,i} + e_whk | {j,k} +(2 rows) + +update db15_w_hash_kset set key = 'x_whk', val = '{w,x,y,z}' where key = 'c_whk'; +select key, val from db15_w_hash_kset order by key; + key | val +-------+----------- + e_whk | {j,k} + x_whk | {w,x,y,z} +(2 rows) + +update db15_w_hash_kset set key = 'z_whk' where key = 'x_whk'; +select key, val from db15_w_hash_kset order by key; + key | val +-------+----------- + e_whk | {j,k} + z_whk | {w,x,y,z} +(2 rows) + +update db15_w_hash_kset set val = '{q,r}' where key = 'e_whk'; +select key, val from db15_w_hash_kset order by key; + key | val +-------+----------- + e_whk | {q,r} + z_whk | {w,x,y,z} +(2 rows) + +delete from db15_w_hash_kset; +select * from db15_w_hash_kset; + key | val +-----+----- +(0 rows) + +-- now clean up for the cursor tests +\! redis-cli < test/redis_clean +OK +OK +-- cursor tests +create foreign table db15bigprefixscalar ( + key text not null, + val text +) +server localredis +options (database '15', tablekeyprefix 'w_scalar_'); +create foreign table db15bigkeysetscalar ( + key text not null, + val text +) +server localredis +options (database '15', tablekeyset 'w_kset'); +insert into db15 +select 'junk' || x, 'junk' +from generate_series(1,10000) as x; +insert into db15bigprefixscalar +select 'w_scalar_' || x::text, 'val ' || x::text +from generate_series (1,10000) as x; +insert into db15bigkeysetscalar +select 'key_' || x::text, 'val ' || x::text +from generate_series (1,10000) as x; +insert into db15 +select 'junk' || x, 'junk' +from generate_series(10001, 20000) as x; +insert into db15bigprefixscalar +select 'w_scalar_' || x::text, 'val ' || x::text +from generate_series (10001, 20000) as x; +insert into db15bigkeysetscalar +select 'key_' || x::text, 'val ' || x::text +from generate_series (10001, 20000) as x; +select count(*) from db15; + count +------- + 60000 +(1 row) + +select count(*) from db15bigprefixscalar; + count +------- + 20000 +(1 row) + +select count(*) from db15bigkeysetscalar; + count +------- + 20000 +(1 row) + +-- all done, so now blow everything in the db away again +\! redis-cli < test/redis_clean +OK +OK +DROP EXTENSION redis_fdw CASCADE; +NOTICE: drop cascades to 45 other objects +DETAIL: drop cascades to server localredis +drop cascades to user mapping for public on server localredis +drop cascades to foreign table db15 +drop cascades to foreign table db15_hash +drop cascades to foreign table db15_set +drop cascades to foreign table db15_list +drop cascades to foreign table db15_zset +drop cascades to foreign table db15_hash_prefix +drop cascades to foreign table db15_hash_prefix_array +drop cascades to foreign table db15_hash_keyset_array +drop cascades to foreign table db15_set_prefix +drop cascades to foreign table db15_set_prefix_array +drop cascades to foreign table db15_set_keyset_array +drop cascades to foreign table db15_list_prefix +drop cascades to foreign table db15_list_prefix_array +drop cascades to foreign table db15_list_keyset_array +drop cascades to foreign table db15_zset_prefix +drop cascades to foreign table db15_zset_prefix_array +drop cascades to foreign table db15_zset_keyset_array +drop cascades to foreign table db15_1key +drop cascades to foreign table db15_1key_hash +drop cascades to foreign table db15_1key_set +drop cascades to foreign table db15_1key_list +drop cascades to foreign table db15_1key_zset +drop cascades to foreign table db15_1key_zset_scores +drop cascades to foreign table db15_w_1key_scalar +drop cascades to foreign table db15_w_1key_hash +drop cascades to foreign table db15_w_1key_list +drop cascades to foreign table db15_w_1key_set +drop cascades to foreign table db15_w_1key_zset +drop cascades to foreign table db15_w_1key_zsetx +drop cascades to foreign table db15_w_scalar +drop cascades to foreign table db15_w_scalar_pfx +drop cascades to foreign table db15_w_scalar_kset +drop cascades to foreign table db15_w_set_nonarr +drop cascades to foreign table db15_w_set_pfx +drop cascades to foreign table db15_w_set_kset +drop cascades to foreign table db15_w_list_pfx +drop cascades to foreign table db15_w_list_kset +drop cascades to foreign table db15_w_zset_pfx +drop cascades to foreign table db15_w_zset_kset +drop cascades to foreign table db15_w_hash_pfx +drop cascades to foreign table db15_w_hash_kset +drop cascades to foreign table db15bigprefixscalar +drop cascades to foreign table db15bigkeysetscalar +DROP EXTENSION hstore; diff --git a/test/local multiversional tests/README.md b/test/local multiversional tests/README.md new file mode 100644 index 0000000..b89d6c5 --- /dev/null +++ b/test/local multiversional tests/README.md @@ -0,0 +1,28 @@ +### Multiversional local tests in PostgreSQL source code file tree + +1. Move this files to parent directory of redis_fdw +2. `mkdir "PostgreSQL source"` +3. copy `redis_fdw` main directory as `redis_fdw_base` to `PostgreSQL source` directory +4. cd to redis_fdw directory +5. Run the following command to get all PostgreSQL source codes for testing versions: +`../getmvpgenv.sh redis_fdw PostgreSQL\ source/` + + Multiversional testing environment will be + - downloaded from official PostgreSQL git URLs, + - compiled, + - tested against internal regress tests + + This need + - 1.2+ Gb of disk space, + - not less than 30 minutes and + - 1+ Gb of network traffic. + + * Please ensure your OS have needed packages for PostgreSQL source code compilation + See https://wiki.postgresql.org/wiki/Compile_and_Install_from_source_code + +6. Full code change tests can be called by following command +`reset; ../new_mulver_cycle.sh redis_fdw 'PostgreSQL\ source';` + Change tests for a PostgreSQL version be called by following command with some version number +`reset; ../new_mulver_cycle.sh redis_fdw 'PostgreSQL source' 17.0;` + +Have a good tests! diff --git a/test/local multiversional tests/getmvpgenv.sh b/test/local multiversional tests/getmvpgenv.sh new file mode 100755 index 0000000..c98f138 --- /dev/null +++ b/test/local multiversional tests/getmvpgenv.sh @@ -0,0 +1,72 @@ +#!/bin/bash +[ "$1" == "" ] && exit; +fdwname="$1"; +[ "$2" == "" ] && pg_multver_src_dir='PostgreSQL source' || pg_multver_src_dir="$2"; +baseadr=$(readlink -f "$0"); +baseadr=$(dirname "$baseadr"); +pg_multver_src_dir0="$pg_multver_src_dir" +pg_multver_src_dir="$baseadr/$pg_multver_src_dir"; +[ ! -d "$pg_multver_src_dir" ] && (mkdir "$pg_multver_src_dir"); + +d0=$(date); +echo "$d0"; + +cd "$pg_multver_src_dir"; +# Clone original $fdwname. +#[ ! -d "${fdwname}_base" ] && git clone "https://github.com/pgspider/$fdwname" "${fdwname}_base" || (cd "${fdwname}_base"; git pull; cd ..;); + +# Get and read list of PostgreSQL versions. +ver=$(ls -1 "../$fdwname/test/expected/" | tr '.' '_'); +echo "$ver"; + +# Get or pull (update) individual PostgreSQL source trees for different versions. +echo "$ver" | while read ver_curs; do + [ ! -d "REL_$ver_curs" ] && mkdir "REL_$ver_curs"; + ( + cd "REL_$ver_curs"; + git clone https://git.postgresql.org/git/postgresql.git -b "REL_$ver_curs" || ( cd postgresql; git pull https://git.postgresql.org/git/postgresql.git "REL_$ver_curs"; cd ..;); + ) +done; + +# Configure PostgreSQL sources +echo "$ver" | while read ver_curs; do + ( + cd "REL_$ver_curs/postgresql"; + ./configure; + ) +done; + +# Make PostgreSQL sources +echo "$ver" | while read ver_curs; do + ( + cd "REL_$ver_curs/postgresql"; + make; + ) +done; + +# Run internal checks for PostgreSQL. +echo "$ver" | while read ver_curs; do + ( + cd "REL_$ver_curs/postgresql"; + make check; + ) +done; + +echo "Beginned at $d0"; +echo -n "PostgreSQL compiled and tested at"; +date; + +# Copy generic $fdwname to contrib directory of all PostgreSQL versions. +echo "$ver" | while read ver_curs; do + basedir="REL_$ver_curs/postgresql/contrib/$fdwname"; + [ -d "$basedir" ] && rm -r -f "$basedir"; + cp -r "${fdwname}_base" "$basedir"; +done; + +cd ..; + +"$baseadr/mulver_test.sh" "$fdwname" "$pg_multver_src_dir0"; + +echo "Beginned at $d0"; +echo -n "Multiversional testing environment for $fdwname and mainstream $fdwname compiled and tested at "; +date; diff --git a/test/local multiversional tests/lint.sh b/test/local multiversional tests/lint.sh new file mode 100755 index 0000000..9c95d3e --- /dev/null +++ b/test/local multiversional tests/lint.sh @@ -0,0 +1 @@ +sed -i -e's/[ \t]*$//' ./*.c ./*.md ./*.h ./*.sh ./sql/init_data/*.sql; diff --git a/test/local multiversional tests/mulver_test.sh b/test/local multiversional tests/mulver_test.sh new file mode 100755 index 0000000..65f807d --- /dev/null +++ b/test/local multiversional tests/mulver_test.sh @@ -0,0 +1,31 @@ +#!/bin/bash +[ "$1" == "" ] && exit; +fdwname="$1"; +[ "$2" == "" ] && pg_multver_src_dir='PostgreSQL source' || pg_multver_src_dir="$2"; +baseadr=$(readlink -f "$0"); +baseadr=$(dirname "$baseadr"); +pg_multver_src_dir="$baseadr/$pg_multver_src_dir"; +[ ! -d "$pg_multver_src_dir" ] && (echo "No PostgreSQL source code directory +Press any key"; read x; exit;); + +one_ver=$(echo "$3"| tr '.' '_'); +ver=$(ls -1 "$baseadr/$fdwname/test/expected/" | tr '.' '_'); +echo "$ver"; + +cd "$pg_multver_src_dir"; +# Run $fdwname regression tests for tested version. +echo "$ver" | while read ver_curs; do + [ "$one_ver" != "" ] && [ "$one_ver" != "$ver_curs" ] && continue; + basedir="REL_$ver_curs/postgresql/contrib/$fdwname"; + ( + cd "$basedir"; + ./test.sh; + ) + # "Copy" diff files from regression tests from different PostgreSQL version source code trees. + rm "rel_$ver_curs regression.diff" "$fdwname_${ver_curs}_results" 2> /dev/null; + ln -s -r "$basedir/test/regression.diffs" "$fdwname_${ver_curs}_regr.diff"; + ver0=$(echo "$ver_curs" | tr '_' '.'); + ln -s -r "$basedir/test/results/$ver0" "$fdwname_${ver_curs}_results" ; +done; + +cd ..; diff --git a/test/local multiversional tests/new_mulver_cycle.sh b/test/local multiversional tests/new_mulver_cycle.sh new file mode 100755 index 0000000..ff54259 --- /dev/null +++ b/test/local multiversional tests/new_mulver_cycle.sh @@ -0,0 +1,30 @@ +#!/bin/bash +[ "$1" == "" ] && exit; +fdwname="$1"; +[ "$2" == "" ] && pg_multver_src_dir='PostgreSQL source' || pg_multver_src_dir="$2"; +baseadr=$(readlink -f "$0"); +baseadr=$(dirname "$baseadr"); +pg_multver_src_dir0="$pg_multver_src_dir" +pg_multver_src_dir="$baseadr/$pg_multver_src_dir"; +[ ! -d "$pg_multver_src_dir" ] && (echo "No PostgreSQL source code directory +Press any key"; read x; exit;); + +one_ver="$3"; +ver=$(ls -1 "$baseadr/$fdwname/test/expected/" | tr '.' '_'); + +echo "$ver" | while read ver_curs; do + [ "$one_ver" != "" ] && [ "$one_ver" != "$ver_curs" ] && continue; + rm -v "$pg_multver_src_dir/$fdwname_${ver_curs}_regr.diff"; + rm -v "$pg_multver_src_dir/$fdwname_${ver_curs}_results"; +done; + +# Run $fdwname regression tests for tested version. +echo "$ver" | while read ver_curs; do + rm -r -f "$pg_multver_src_dir/REL_$ver_curs/postgresql/contrib/$fdwname"; + cp -r "$baseadr/$fdwname" "$pg_multver_src_dir/REL_$ver_curs/postgresql/contrib"; +done; + +dir=$(readlink -f "$0"); +dir=$(dirname "$dir"); +"$dir/mulver_test.sh" "$fdwname" "$pg_multver_src_dir0" "$3" "$4"; +echo "TESTING CYCLE IS ENDED, PLEASE READ THE RESULTS!"; diff --git a/test/sql/redis_clean b/test/redis_clean similarity index 95% rename from test/sql/redis_clean rename to test/redis_clean index 4a96e9e..fd2a8ec 100644 --- a/test/sql/redis_clean +++ b/test/redis_clean @@ -1,4 +1,3 @@ select 15 flushdb - diff --git a/test/sql/redis_setup b/test/redis_setup similarity index 99% rename from test/sql/redis_setup rename to test/redis_setup index 3c6f2c9..a3b157c 100644 --- a/test/sql/redis_setup +++ b/test/redis_setup @@ -19,7 +19,3 @@ sadd hkeys hash1 hash2 sadd lkeys list1 list2 sadd skeys set1 set2 sadd zkeys zset1 zset2 - - - - diff --git a/test/sql/14.12 b/test/sql/14.12 new file mode 120000 index 0000000..7f83a84 --- /dev/null +++ b/test/sql/14.12 @@ -0,0 +1 @@ +17.0 \ No newline at end of file diff --git a/test/sql/15.7 b/test/sql/15.7 new file mode 120000 index 0000000..7f83a84 --- /dev/null +++ b/test/sql/15.7 @@ -0,0 +1 @@ +17.0 \ No newline at end of file diff --git a/test/sql/16.3 b/test/sql/16.3 new file mode 120000 index 0000000..7f83a84 --- /dev/null +++ b/test/sql/16.3 @@ -0,0 +1 @@ +17.0 \ No newline at end of file diff --git a/test/sql/17.0/nogis.sql b/test/sql/17.0/nogis.sql new file mode 100644 index 0000000..f766e69 --- /dev/null +++ b/test/sql/17.0/nogis.sql @@ -0,0 +1,23 @@ +-- Testcase 001 +CREATE EXTENSION hstore; +-- Testcase 002 +CREATE EXTENSION redis_fdw; + +-- Testcase 003 +create server localredis foreign data wrapper redis_fdw; +-- Testcase 004 +create user mapping for public server localredis; + +-- Testcase 005 +-- \! redis-cli < test/redis_gis_ini + +-- REDIS SPATIAL VALUE TESTS WILL BE HERE + +-- Testcase 098 +-- all done, so now blow everything in the db away again +\! redis-cli < test/redis_clean + +-- Testcase 099 +DROP EXTENSION redis_fdw CASCADE; +-- Testcase 100 +DROP EXTENSION hstore CASCADE; diff --git a/test/sql/17.0/postgis.sql b/test/sql/17.0/postgis.sql new file mode 100644 index 0000000..e166f99 --- /dev/null +++ b/test/sql/17.0/postgis.sql @@ -0,0 +1,26 @@ +-- Testcase 001 +CREATE EXTENSION postgis; +-- Testcase 002 +CREATE EXTENSION hstore; +-- Testcase 003 +CREATE EXTENSION redis_fdw; + +-- Testcase 004 +create server localredis foreign data wrapper redis_fdw; +-- Testcase 005 +create user mapping for public server localredis; + +-- Testcase 006 +-- \! redis-cli < test/redis_gis_ini + + +-- Testcase 098 +-- all done, so now blow everything in the db away again +\! redis-cli < test/redis_clean + +-- Testcase 099 +DROP EXTENSION redis_fdw CASCADE; +-- Testcase 100 +DROP EXTENSION hstore CASCADE; +-- Testcase 101 +DROP EXTENSION postgis CASCADE; diff --git a/test/sql/redis_fdw.sql b/test/sql/17.0/redis_fdw.sql similarity index 98% rename from test/sql/redis_fdw.sql rename to test/sql/17.0/redis_fdw.sql index b74e0f0..ee832d2 100644 --- a/test/sql/redis_fdw.sql +++ b/test/sql/17.0/redis_fdw.sql @@ -1,15 +1,21 @@ +-- Testcase 001: +CREATE EXTENSION hstore; +-- Testcase 002: +CREATE EXTENSION redis_fdw; +-- Testcase 003: +select redis_fdw_version(); +-- Testcase 004: +select redis_fdw_hiredis_version(); + +-- Testcase 005: CREATE OR REPLACE FUNCTION atsort( a text[]) RETURNS text[] LANGUAGE sql IMMUTABLE STRICT AS $function$ select array(select unnest($1) order by 1) -$function$ - -; - - +$function$; create server localredis foreign data wrapper redis_fdw; @@ -61,7 +67,7 @@ $$; -- ok, empty, so now run the setup script -\! redis-cli < test/sql/redis_setup +\! redis-cli < test/redis_setup select * from db15 order by key; @@ -231,7 +237,7 @@ select * from db15_1key_zset_scores order by score desc; -- first clean the database again -\! redis-cli < test/sql/redis_clean +\! redis-cli < test/redis_clean -- singleton scalar table @@ -841,7 +847,7 @@ select * from db15_w_hash_kset; -- now clean up for the cursor tests -\! redis-cli < test/sql/redis_clean +\! redis-cli < test/redis_clean -- cursor tests @@ -891,5 +897,7 @@ select count(*) from db15bigkeysetscalar; -- all done, so now blow everything in the db away again -\! redis-cli < test/sql/redis_clean +\! redis-cli < test/redis_clean +DROP EXTENSION redis_fdw CASCADE; +DROP EXTENSION hstore; diff --git a/test/sql/18rc1 b/test/sql/18rc1 new file mode 120000 index 0000000..7f83a84 --- /dev/null +++ b/test/sql/18rc1 @@ -0,0 +1 @@ +17.0 \ No newline at end of file