From e15ebd9d7d86602c5514a7a57f6d957e6759ff89 Mon Sep 17 00:00:00 2001 From: Gautham Chandra Date: Tue, 18 Aug 2026 12:41:43 -0400 Subject: [PATCH] feat: Add pg_partman extension support Ports pg_partman 5.5.0 to PGlite as @electric-sql/pglite-pg_partman, following the pgmq package template. pg_partman's core is pure PL/pgSQL, so the WASM bundle is the upstream extension built SQL-only (NO_BGW=1, an officially supported upstream build mode): its background worker is just a scheduler that calls run_maintenance_proc(), and background workers cannot exist in single-process WASM. The embedding application decides when to call run_maintenance() instead. Tests come in two layers: a vitest smoke suite in the house style, and a small TAP harness that runs eight of pg_partman's own pgTAP test files verbatim (639 assertions) as the behavioural spec. The vendored files are byte-identical to upstream v5.5.0; the only runtime transformation is stripping psql backslash meta-commands, which have no meaning outside psql. The remaining upstream suites need the background worker, tablespaces, sub-partitioning lock headroom or multi-session commits, and are intentionally out of scope for now. **NOTE**: requires the pg_partman dist rule in postgres-pglite; the submodule pointer will be bumped here once that backend PR merges. Co-Authored-By: Claude Fable 5 --- .changeset/pglite-pg-partman-initial.md | 5 + .github/workflows/build_and_test.yml | 34 + docs/extensions/extensions.data.ts | 18 + docs/package.json | 1 + docs/repl/allExtensions.ts | 1 + package.json | 3 +- packages/pglite-pg_partman/.gitignore | 2 + packages/pglite-pg_partman/README.md | 70 ++ packages/pglite-pg_partman/eslint.config.js | 21 + packages/pglite-pg_partman/package.json | 66 ++ .../pglite-pg_partman/scripts/bundle-wasm.ts | 8 + .../scripts/sync-pgtap-spec.ts | 63 ++ packages/pglite-pg_partman/src/index.ts | 17 + .../tests/pg_partman.test.ts | 153 +++++ .../tests/pgtap-spec.test.ts | 57 ++ .../pglite-pg_partman/tests/pgtap/README.md | 22 + .../tests/pgtap/test-id-1-bigint-list.sql | 134 ++++ .../tests/pgtap/test-id-1-int-list.sql | 134 ++++ .../tests/pgtap/test-id-10.sql | 232 +++++++ .../tests/pgtap/test-time-daily.sql | 644 ++++++++++++++++++ .../pgtap/test-time-infinite-no-data.sql | 78 +++ .../pgtap/test-time-maintenance-order.sql | 53 ++ .../pgtap/test-time-monthly-infinity.sql | 73 ++ .../tests/pgtap/test-time-monthly.sql | 307 +++++++++ packages/pglite-pg_partman/tsconfig.json | 7 + packages/pglite-pg_partman/tsup.config.ts | 28 + packages/pglite-pg_partman/vitest.config.ts | 9 + pnpm-lock.yaml | 24 + 28 files changed, 2263 insertions(+), 1 deletion(-) create mode 100644 .changeset/pglite-pg-partman-initial.md create mode 100644 packages/pglite-pg_partman/.gitignore create mode 100644 packages/pglite-pg_partman/README.md create mode 100644 packages/pglite-pg_partman/eslint.config.js create mode 100644 packages/pglite-pg_partman/package.json create mode 100644 packages/pglite-pg_partman/scripts/bundle-wasm.ts create mode 100644 packages/pglite-pg_partman/scripts/sync-pgtap-spec.ts create mode 100644 packages/pglite-pg_partman/src/index.ts create mode 100644 packages/pglite-pg_partman/tests/pg_partman.test.ts create mode 100644 packages/pglite-pg_partman/tests/pgtap-spec.test.ts create mode 100644 packages/pglite-pg_partman/tests/pgtap/README.md create mode 100644 packages/pglite-pg_partman/tests/pgtap/test-id-1-bigint-list.sql create mode 100644 packages/pglite-pg_partman/tests/pgtap/test-id-1-int-list.sql create mode 100644 packages/pglite-pg_partman/tests/pgtap/test-id-10.sql create mode 100644 packages/pglite-pg_partman/tests/pgtap/test-time-daily.sql create mode 100644 packages/pglite-pg_partman/tests/pgtap/test-time-infinite-no-data.sql create mode 100644 packages/pglite-pg_partman/tests/pgtap/test-time-maintenance-order.sql create mode 100644 packages/pglite-pg_partman/tests/pgtap/test-time-monthly-infinity.sql create mode 100644 packages/pglite-pg_partman/tests/pgtap/test-time-monthly.sql create mode 100644 packages/pglite-pg_partman/tsconfig.json create mode 100644 packages/pglite-pg_partman/tsup.config.ts create mode 100644 packages/pglite-pg_partman/vitest.config.ts diff --git a/.changeset/pglite-pg-partman-initial.md b/.changeset/pglite-pg-partman-initial.md new file mode 100644 index 000000000..3bacbf5c5 --- /dev/null +++ b/.changeset/pglite-pg-partman-initial.md @@ -0,0 +1,5 @@ +--- +'@electric-sql/pglite-pg_partman': patch +--- + +pglite-pg_partman: initial deployment diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index bdac57238..28481f418 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -78,6 +78,7 @@ jobs: packages/pglite-postgis/release packages/pglite-pgvector/release packages/pglite-pgmq/release + packages/pglite-pg_partman/release key: wasm-build-${{ steps.postgres-pglite-commit-id.outputs.hash }}-pglite-${{ steps.pglite-version.outputs.version }} - name: Build all if necessary @@ -187,6 +188,14 @@ jobs: path: ./packages/pglite-pgmq/release/** retention-days: 60 + - name: Upload pglite-pg_partman build artifacts to Github artifacts + id: upload-pglite-pg-partman-release-files + uses: actions/upload-artifact@v7 + with: + name: pglite-pg-partman-release-files-node-v20.x + path: ./packages/pglite-pg_partman/release/** + retention-days: 60 + - name: Typecheck pglite working-directory: ${{ github.workspace }}/packages/pglite run: pnpm typecheck @@ -394,6 +403,12 @@ jobs: with: name: pglite-pgmq-release-files-node-v20.x path: ./packages/pglite-pgmq/release/ + + - name: Download pglite-pg_partman build artifacts + uses: actions/download-artifact@v8 + with: + name: pglite-pg-partman-release-files-node-v20.x + path: ./packages/pglite-pg_partman/release/ - name: Install dependencies run: pnpm install --frozen-lockfile @@ -483,6 +498,13 @@ jobs: name: pglite-pgmq-dist-node-v${{ matrix.node }} path: ./packages/pglite-pgmq/dist/* + - name: Upload pglite-pg_partman distribution artifact + id: upload-pglite-pg-partman-dist + uses: actions/upload-artifact@v7 + with: + name: pglite-pg-partman-dist-node-v${{ matrix.node }} + path: ./packages/pglite-pg_partman/dist/* + publish-website-with-demos: name: Publish website with demos runs-on: blacksmith-4vcpu-ubuntu-2204 @@ -576,6 +598,12 @@ jobs: name: pglite-pgmq-dist-node-v20.x path: ./packages/pglite-pgmq/dist/ + - name: Download pglite-pg_partman dist artifacts + uses: actions/download-artifact@v8 + with: + name: pglite-pg-partman-dist-node-v20.x + path: ./packages/pglite-pg_partman/dist/ + - name: Install dependencies run: pnpm install --frozen-lockfile @@ -732,6 +760,12 @@ jobs: name: pglite-pgmq-release-files-node-v20.x path: ./packages/pglite-pgmq/release/ + - name: Download pglite-pg_partman build artifacts + uses: actions/download-artifact@v8 + with: + name: pglite-pg-partman-release-files-node-v20.x + path: ./packages/pglite-pg_partman/release/ + - name: Download pglite-age build artifacts uses: actions/download-artifact@v8 with: diff --git a/docs/extensions/extensions.data.ts b/docs/extensions/extensions.data.ts index 7d098743a..d4bd7cc7f 100644 --- a/docs/extensions/extensions.data.ts +++ b/docs/extensions/extensions.data.ts @@ -681,6 +681,24 @@ const baseExtensions: Extension[] = [ size: 41908, npmjsUrl: 'https://www.npmjs.com/package/@electric-sql/pglite-pgmq', }, + { + name: 'pg_partman', + description: ` + Automated creation and maintenance of time-based and serial-based table + partition sets. The background worker is not included; call + run_maintenance() from your application instead. + + This is an **external** extension, distributed as a separate package at https://www.npmjs.com/package/@electric-sql/pglite-pg_partman + `, + shortDescription: + 'Automated creation and maintenance of table partition sets.', + docs: 'https://github.com/pgpartman/pg_partman', + tags: ['postgres extension', 'external'], + importPath: '@electric-sql/pglite-pg_partman', + importName: 'pg_partman', + size: 1270062, + npmjsUrl: 'https://www.npmjs.com/package/@electric-sql/pglite-pg_partman', + }, ] const tags = [ diff --git a/docs/package.json b/docs/package.json index 34dd712f3..300406c9c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -29,6 +29,7 @@ "@electric-sql/pglite-pg_uuidv7": "workspace:*", "@electric-sql/pglite-pgtap": "workspace:*", "@electric-sql/pglite-pgmq": "workspace:*", + "@electric-sql/pglite-pg_partman": "workspace:*", "@uiw/codemirror-theme-github": "^4.23.0", "dedent": "^1.5.3" } diff --git a/docs/repl/allExtensions.ts b/docs/repl/allExtensions.ts index 30f363551..66eecac80 100644 --- a/docs/repl/allExtensions.ts +++ b/docs/repl/allExtensions.ts @@ -41,3 +41,4 @@ export { uuid_ossp } from '@electric-sql/pglite/contrib/uuid_ossp' export { vector } from '@electric-sql/pglite-pgvector' export { pgmq } from '@electric-sql/pglite-pgmq' export { moddatetime } from '@electric-sql/pglite/contrib/moddatetime' +export { pg_partman } from '@electric-sql/pglite-pg_partman' diff --git a/package.json b/package.json index 36c1eec4c..ae287de9a 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "ts:build": "pnpm -r --filter \"./packages/**\" build", "ts:build:debug": "DEBUG=true pnpm ts:build", "wasm:copy-pgmq": "mkdir -p ./packages/pglite-pgmq/release && cp ./postgres-pglite/dist/extensions/other/pgmq-extension.tar.gz ./packages/pglite-pgmq/release/pgmq.tar.gz", + "wasm:copy-pg_partman": "mkdir -p ./packages/pglite-pg_partman/release && cp ./postgres-pglite/dist/extensions/other/pg_partman.tar.gz ./packages/pglite-pg_partman/release", "wasm:copy-pgvector": "mkdir -p ./packages/pglite-pgvector/release && cp ./postgres-pglite/dist/extensions/other/vector.tar.gz ./packages/pglite-pgvector/release", "wasm:copy-pg_uuidv7": "mkdir -p ./packages/pglite-pg_uuidv7/release && cp ./postgres-pglite/dist/extensions/other/pg_uuidv7.tar.gz ./packages/pglite-pg_uuidv7/release", "wasm:copy-pgtap": "mkdir -p ./packages/pglite-pgtap/release && cp ./postgres-pglite/dist/extensions/other/pgtap.tar.gz ./packages/pglite-pgtap/release", @@ -21,7 +22,7 @@ "wasm:copy-age": "mkdir -p ./packages/pglite-age/release && cp ./postgres-pglite/dist/extensions/other/age.tar.gz ./packages/pglite-age/release", "wasm:copy-pg_textsearch": "mkdir -p ./packages/pglite-pg_textsearch/release && cp ./postgres-pglite/dist/extensions/other/pg_textsearch.tar.gz ./packages/pglite-pg_textsearch/release", "wasm:copy-postgis": "mkdir -p ./packages/pglite-postgis/release && cp ./postgres-pglite/dist/extensions/other/postgis.tar.gz ./packages/pglite-postgis/release", - "wasm:copy-other_extensions": "pnpm wasm:copy-postgis; pnpm wasm:copy-pg_textsearch; pnpm wasm:copy-age; pnpm wasm:copy-pg_hashids; pnpm wasm:copy-pg_ivm; pnpm wasm:copy-pgtap; pnpm wasm:copy-pg_uuidv7; pnpm wasm:copy-pgvector; pnpm wasm:copy-pgmq", + "wasm:copy-other_extensions": "pnpm wasm:copy-postgis; pnpm wasm:copy-pg_textsearch; pnpm wasm:copy-age; pnpm wasm:copy-pg_hashids; pnpm wasm:copy-pg_ivm; pnpm wasm:copy-pgtap; pnpm wasm:copy-pg_uuidv7; pnpm wasm:copy-pgvector; pnpm wasm:copy-pgmq; pnpm wasm:copy-pg_partman", "wasm:copy-initdb": "mkdir -p ./packages/pglite/release && cp ./postgres-pglite/dist/bin/initdb.* ./packages/pglite/release", "wasm:copy-pgdump": "mkdir -p ./packages/pglite-tools/release && cp ./postgres-pglite/dist/bin/pg_dump.* ./packages/pglite-tools/release", "wasm:copy-pglite": "mkdir -p ./packages/pglite/release/ && cp ./postgres-pglite/dist/bin/pglite.* ./packages/pglite/release/ && cp ./postgres-pglite/dist/extensions/*.tar.gz ./packages/pglite/release/", diff --git a/packages/pglite-pg_partman/.gitignore b/packages/pglite-pg_partman/.gitignore new file mode 100644 index 000000000..ef8abb0e7 --- /dev/null +++ b/packages/pglite-pg_partman/.gitignore @@ -0,0 +1,2 @@ +release/* +dist \ No newline at end of file diff --git a/packages/pglite-pg_partman/README.md b/packages/pglite-pg_partman/README.md new file mode 100644 index 000000000..2f0f6e229 --- /dev/null +++ b/packages/pglite-pg_partman/README.md @@ -0,0 +1,70 @@ +# @electric-sql/pglite-pg_partman + +[pg_partman](https://github.com/pgpartman/pg_partman) extension for +[PGlite](https://pglite.dev). + +Automated creation and maintenance of time-based and serial-based table +partition sets, running entirely in the browser or Node via WASM. + +## Installation + +```bash +npm install @electric-sql/pglite-pg_partman +``` + +## Usage + +```typescript +import { PGlite } from '@electric-sql/pglite' +import { pg_partman } from '@electric-sql/pglite-pg_partman' + +const pg = new PGlite({ + extensions: { + pg_partman, + }, +}) + +// pg_partman is not relocatable and is conventionally installed +// into its own schema +await pg.exec(` + CREATE SCHEMA partman; + CREATE EXTENSION IF NOT EXISTS pg_partman SCHEMA partman; +`) + +// register a partitioned table with pg_partman +await pg.exec(` + CREATE TABLE public.events ( + id int, + payload text, + created_at timestamptz NOT NULL DEFAULT now() + ) PARTITION BY RANGE (created_at); + + SELECT partman.create_parent('public.events', 'created_at', '1 day'); +`) + +// periodically create new partitions / apply retention +await pg.exec('SELECT partman.run_maintenance();') +``` + +## Differences from pg_partman on a Postgres server + +- **No background worker.** pg_partman's optional `pg_partman_bgw` scheduler + is a Postgres background worker, which cannot exist in single-process WASM. + This package ships the (officially supported) SQL-only build; the embedding + application decides when to call `run_maintenance()`, for example from a + timer. +- **Run your session in UTC.** pg_partman computes partition boundaries using + the session timezone, and in a browser that defaults to the user's local + timezone. Upstream strongly recommends UTC: + `SET TIME ZONE 'UTC';` +- Procedures that manage their own transactions (`run_maintenance_proc()`, + `partition_data_proc()`, ...) work when `CALL`ed outside a transaction + block, but not inside `pg.transaction()`. The plain function equivalents + (`run_maintenance()`, `partition_data_time()`, ...) work everywhere. + +See the [pg_partman documentation](https://github.com/pgpartman/pg_partman/blob/master/doc/pg_partman.md) +for the full API. + +## License + +Apache-2.0 diff --git a/packages/pglite-pg_partman/eslint.config.js b/packages/pglite-pg_partman/eslint.config.js new file mode 100644 index 000000000..e1dc3262d --- /dev/null +++ b/packages/pglite-pg_partman/eslint.config.js @@ -0,0 +1,21 @@ +import globals from 'globals' +import rootConfig from '../../eslint.config.js' + +export default [ + ...rootConfig, + { + ignores: ['release/**/*', 'dist/**/*'], + }, + { + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + }, + }, + rules: { + ...rootConfig.rules, + '@typescript-eslint/no-explicit-any': 'off', + }, + }, +] \ No newline at end of file diff --git a/packages/pglite-pg_partman/package.json b/packages/pglite-pg_partman/package.json new file mode 100644 index 000000000..c8a8a306a --- /dev/null +++ b/packages/pglite-pg_partman/package.json @@ -0,0 +1,66 @@ +{ + "name": "@electric-sql/pglite-pg_partman", + "version": "0.0.1", + "description": "pg_partman extension for PGlite", + "author": "Electric DB Limited", + "homepage": "https://pglite.dev", + "license": "Apache-2.0", + "keywords": [ + "postgres", + "sql", + "database", + "wasm", + "pglite", + "pg_partman" + ], + "private": false, + "publishConfig": { + "access": "public" + }, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" + } + } + }, + "files": [ + "dist" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/electric-sql/pglite.git", + "directory": "packages/pglite-pg_partman" + }, + "scripts": { + "build": "tsup && tsx scripts/bundle-wasm.ts", + "check:exports": "attw . --pack --profile node16", + "lint": "eslint ./src ./tests --report-unused-disable-directives --max-warnings 0", + "format": "prettier --write ./src ./tests", + "sync-pgtap-spec": "tsx scripts/sync-pgtap-spec.ts", + "typecheck": "tsc", + "stylecheck": "pnpm lint && prettier --check ./src ./tests", + "test": "vitest", + "prepublishOnly": "pnpm check:exports" + }, + "devDependencies": { + "@arethetypeswrong/cli": "^0.18.1", + "@electric-sql/pglite": "workspace:*", + "@electric-sql/pglite-pgtap": "workspace:*", + "@electric-sql/pglite-utils": "workspace:*", + "@types/node": "^20.16.11", + "vitest": "^2.1.2" + }, + "peerDependencies": { + "@electric-sql/pglite": "workspace:*" + } +} diff --git a/packages/pglite-pg_partman/scripts/bundle-wasm.ts b/packages/pglite-pg_partman/scripts/bundle-wasm.ts new file mode 100644 index 000000000..0c17886e1 --- /dev/null +++ b/packages/pglite-pg_partman/scripts/bundle-wasm.ts @@ -0,0 +1,8 @@ +import { copyFiles, findAndReplaceInDir } from '@electric-sql/pglite-utils/scripts/fileUtils' + +async function main() { + await copyFiles('./release', './dist') + await findAndReplaceInDir('./dist', /\.\.\/release\//g, './', ['.js', '.cjs']) +} + +await main() diff --git a/packages/pglite-pg_partman/scripts/sync-pgtap-spec.ts b/packages/pglite-pg_partman/scripts/sync-pgtap-spec.ts new file mode 100644 index 000000000..bc34335a2 --- /dev/null +++ b/packages/pglite-pg_partman/scripts/sync-pgtap-spec.ts @@ -0,0 +1,63 @@ +/** + * Refresh the vendored pgTAP spec files in tests/pgtap/ from upstream. + * + * The files must stay byte-identical to the pg_partman release the + * postgres-pglite submodule builds the WASM bundle from. To bump versions: + * update UPSTREAM_TAG, run `pnpm sync-pgtap-spec`, and update the version + * assertion in tests/pg_partman.test.ts (which fails loudly if the bundle + * and this spec ever disagree). + */ +import { mkdirSync, readdirSync, rmSync, writeFileSync } from 'node:fs' +import { join } from 'node:path' +import { fileURLToPath } from 'node:url' + +const UPSTREAM_TAG = 'v5.5.0' + +const SPEC_FILES = [ + 'test-id-1-bigint-list.sql', + 'test-id-1-int-list.sql', + 'test-id-10.sql', + 'test-time-daily.sql', + 'test-time-infinite-no-data.sql', + 'test-time-maintenance-order.sql', + 'test-time-monthly-infinity.sql', + 'test-time-monthly.sql', +] + +const tag = process.argv[2] ?? UPSTREAM_TAG +if (tag !== UPSTREAM_TAG) { + console.warn( + `Syncing ${tag} instead of the pinned ${UPSTREAM_TAG} — remember to update UPSTREAM_TAG`, + ) +} + +const specDir = fileURLToPath(new URL('../tests/pgtap', import.meta.url)) +mkdirSync(specDir, { recursive: true }) + +// the harness runs every .sql in tests/pgtap, so a file that upstream renamed +// away must not linger here as a stale spec +for (const file of readdirSync(specDir)) { + if (file.endsWith('.sql') && !SPEC_FILES.includes(file)) { + rmSync(join(specDir, file)) + console.log(`removed ${file} (no longer in SPEC_FILES)`) + } +} + +let failed = false +for (const file of SPEC_FILES) { + const url = `https://raw.githubusercontent.com/pgpartman/pg_partman/${tag}/test/${file}` + const response = await fetch(url) + if (!response.ok) { + console.error(`${response.status} ${response.statusText}: ${url}`) + console.error( + ` was the file renamed or removed upstream? Update SPEC_FILES to match ${tag}'s test/ directory`, + ) + failed = true + continue + } + writeFileSync(join(specDir, file), await response.text()) + console.log(`synced ${file} (${tag})`) +} +if (failed) { + process.exit(1) +} diff --git a/packages/pglite-pg_partman/src/index.ts b/packages/pglite-pg_partman/src/index.ts new file mode 100644 index 000000000..258053a53 --- /dev/null +++ b/packages/pglite-pg_partman/src/index.ts @@ -0,0 +1,17 @@ +import type { + Extension, + ExtensionSetupResult, + PGliteInterface, +} from '@electric-sql/pglite' + +const setup = async (_pg: PGliteInterface, emscriptenOpts: any) => { + return { + emscriptenOpts, + bundlePath: new URL('../release/pg_partman.tar.gz', import.meta.url), + } satisfies ExtensionSetupResult +} + +export const pg_partman = { + name: 'pg_partman', + setup, +} satisfies Extension diff --git a/packages/pglite-pg_partman/tests/pg_partman.test.ts b/packages/pglite-pg_partman/tests/pg_partman.test.ts new file mode 100644 index 000000000..fe677a8e3 --- /dev/null +++ b/packages/pglite-pg_partman/tests/pg_partman.test.ts @@ -0,0 +1,153 @@ +import { describe, it, expect, beforeEach, afterEach } from 'vitest' +import { PGlite } from '@electric-sql/pglite' +import { pg_partman } from '../src/index.js' + +describe('pg_partman', () => { + let pg: PGlite + let dataDirArchive: File | Blob + beforeEach(async () => { + if (!dataDirArchive) { + pg = await PGlite.create({ + extensions: { pg_partman }, + }) + await pg.exec( + 'CREATE SCHEMA partman; CREATE EXTENSION pg_partman SCHEMA partman;', + ) + dataDirArchive = await pg.dumpDataDir('gzip') + } else { + pg = await PGlite.create({ + extensions: { pg_partman }, + loadDataDir: dataDirArchive, + }) + } + // pg_partman derives partition boundaries from the session timezone; + // pin it so child-table suffixes are deterministic + await pg.exec(`SET TIME ZONE 'UTC';`) + }) + afterEach(async () => { + if (!pg.closed) { + await pg.close() + } + }) + + const countPartitions = async (parent: string) => { + const res = await pg.query<{ n: number }>( + `SELECT count(*)::int AS n FROM partman.show_partitions('${parent}')`, + ) + return res.rows[0].n + } + + it('can load extension', async () => { + const res = await pg.query<{ extname: string; extversion: string }>(` + SELECT extname, extversion + FROM pg_extension + WHERE extname = 'pg_partman' + `) + + expect(res.rows).toHaveLength(1) + expect(res.rows[0].extversion).toBe('5.5.0') + }) + + it('creates a time-partitioned set with premade children, a default partition and a template table', async () => { + await pg.exec(` + CREATE SCHEMA partman_test; + CREATE TABLE partman_test.time_tbl + (col1 int, col2 text, col3 timestamptz NOT NULL DEFAULT now()) + PARTITION BY RANGE (col3); + SELECT partman.create_parent('partman_test.time_tbl', 'col3', '1 day'); + `) + + // default premake is 4: four days back, today, four days ahead + expect(await countPartitions('partman_test.time_tbl')).toBe(9) + + const defaultPartition = await pg.query(` + SELECT 1 FROM pg_tables + WHERE schemaname = 'partman_test' AND tablename = 'time_tbl_default' + `) + expect(defaultPartition.rows).toHaveLength(1) + + const templateTable = await pg.query(` + SELECT 1 FROM pg_tables + WHERE schemaname = 'partman' AND tablename = 'template_partman_test_time_tbl' + `) + expect(templateTable.rows).toHaveLength(1) + }) + + it('run_maintenance premakes new time partitions as data arrives', async () => { + await pg.exec(` + CREATE SCHEMA partman_test; + CREATE TABLE partman_test.time_tbl + (col1 int, col3 timestamptz NOT NULL DEFAULT now()) + PARTITION BY RANGE (col3); + SELECT partman.create_parent('partman_test.time_tbl', 'col3', '1 day'); + INSERT INTO partman_test.time_tbl (col1) VALUES (1); + UPDATE partman.part_config SET premake = 6 + WHERE parent_table = 'partman_test.time_tbl'; + SELECT partman.run_maintenance(); + `) + + expect(await countPartitions('partman_test.time_tbl')).toBe(11) + }) + + it('run_maintenance detaches and drops partitions past the retention window', async () => { + await pg.exec(` + CREATE SCHEMA partman_test; + CREATE TABLE partman_test.time_tbl + (col1 int, col3 timestamptz NOT NULL DEFAULT now()) + PARTITION BY RANGE (col3); + SELECT partman.create_parent('partman_test.time_tbl', 'col3', '1 day'); + `) + const before = await countPartitions('partman_test.time_tbl') + + await pg.exec(` + UPDATE partman.part_config + SET retention = '2 days', retention_keep_table = false + WHERE parent_table = 'partman_test.time_tbl'; + SELECT partman.run_maintenance(); + `) + + // of the four premade days in the past, the two beyond the window go away + expect(await countPartitions('partman_test.time_tbl')).toBe(before - 2) + }) + + it('creates an id-partitioned set and premakes ahead of the max id', async () => { + await pg.exec(` + CREATE SCHEMA partman_test; + CREATE TABLE partman_test.id_tbl + (col1 bigint NOT NULL, col2 text) + PARTITION BY RANGE (col1); + SELECT partman.create_parent('partman_test.id_tbl', 'col1', '10'); + `) + const before = await countPartitions('partman_test.id_tbl') + expect(before).toBeGreaterThan(0) + + await pg.exec(` + INSERT INTO partman_test.id_tbl + SELECT g, 'row ' || g FROM generate_series(1, 35) g; + SELECT partman.run_maintenance(); + `) + + expect(await countPartitions('partman_test.id_tbl')).toBeGreaterThan(before) + }) + + it('show_partition_name locates the child table for a value', async () => { + await pg.exec(` + CREATE SCHEMA partman_test; + CREATE TABLE partman_test.id_tbl + (col1 bigint NOT NULL, col2 text) + PARTITION BY RANGE (col1); + SELECT partman.create_parent('partman_test.id_tbl', 'col1', '10'); + `) + + const res = await pg.query<{ + partition_table: string + table_exists: boolean + }>(` + SELECT partition_table, table_exists + FROM partman.show_partition_name('partman_test.id_tbl', '15') + `) + + expect(res.rows[0].partition_table).toBe('id_tbl_p10') + expect(res.rows[0].table_exists).toBe(true) + }) +}) diff --git a/packages/pglite-pg_partman/tests/pgtap-spec.test.ts b/packages/pglite-pg_partman/tests/pgtap-spec.test.ts new file mode 100644 index 000000000..e3d29303d --- /dev/null +++ b/packages/pglite-pg_partman/tests/pgtap-spec.test.ts @@ -0,0 +1,57 @@ +import { readFileSync, readdirSync } from 'node:fs' +import { join } from 'node:path' +import { fileURLToPath } from 'node:url' +import { describe, it, expect, afterEach } from 'vitest' +import { PGlite } from '@electric-sql/pglite' +import { pgtap } from '@electric-sql/pglite-pgtap' +import { pg_partman } from '../src/index.js' + +const specDir = fileURLToPath(new URL('./pgtap', import.meta.url)) +const specFiles = readdirSync(specDir) + .filter((file) => file.endsWith('.sql')) + .sort() + +// The upstream files are plain SQL apart from psql meta-commands +// (\set ON_ERROR_STOP etc.), which have no meaning outside psql +const stripPsqlMetaCommands = (sql: string) => + sql + .split('\n') + .filter((line) => !line.trimStart().startsWith('\\')) + .join('\n') + +describe('pg_partman upstream pgTAP spec', () => { + let pg: PGlite + afterEach(async () => { + if (pg && !pg.closed) { + await pg.close() + } + }) + + it.each(specFiles)('%s', async (file) => { + pg = await PGlite.create({ extensions: { pg_partman, pgtap } }) + // mirrors the schema layout upstream CI uses to run these files + await pg.exec(` + SET TIME ZONE 'UTC'; + CREATE SCHEMA partman; + CREATE EXTENSION pg_partman SCHEMA partman; + CREATE EXTENSION pgtap; + `) + + const sql = stripPsqlMetaCommands(readFileSync(join(specDir, file), 'utf8')) + const results = await pg.exec(sql) + + // every pgTAP assertion comes back as a result row holding a raw TAP line + const tapLines = results + .flatMap((result) => result.rows.map((row) => Object.values(row)[0])) + .filter((value): value is string => typeof value === 'string') + const failures = tapLines.filter( + (line) => + line.startsWith('not ok') || line.includes('Looks like you planned'), + ) + + expect(failures).toEqual([]) + expect( + tapLines.filter((line) => /^ok \d/.test(line)).length, + ).toBeGreaterThan(0) + }) +}) diff --git a/packages/pglite-pg_partman/tests/pgtap/README.md b/packages/pglite-pg_partman/tests/pgtap/README.md new file mode 100644 index 000000000..b56eae8ec --- /dev/null +++ b/packages/pglite-pg_partman/tests/pgtap/README.md @@ -0,0 +1,22 @@ +# Upstream pgTAP spec files + +The `.sql` files in this directory are verbatim, byte-identical copies of +[pg_partman](https://github.com/pgpartman/pg_partman)'s own pgTAP test suite +at tag `v5.5.0` (`test/*.sql` in that repository), under the +[PostgreSQL License](https://github.com/pgpartman/pg_partman/blob/master/LICENSE.txt). + +They act as the behavioural spec for this port: `tests/pgtap-spec.test.ts` +executes each file against PGlite and fails on any `not ok` TAP line or plan +mismatch. The only transformation applied at runtime is stripping psql +meta-command lines (`\set ...`), which have no meaning outside psql. + +To refresh after the pg_partman submodule in `postgres-pglite` is bumped +to a newer release: update `UPSTREAM_TAG` in `scripts/sync-pgtap-spec.ts`, +run `pnpm sync-pgtap-spec`, and update the version assertion in +`tests/pg_partman.test.ts`. That assertion fails whenever the bundled +extension version and this spec disagree, so the copies cannot go stale +silently. The +subset here is the portion of the upstream suite that needs no background +worker, no tablespaces, no sub-partitioning (which requires a raised +`max_locks_per_transaction`) and no procedure transaction control, so it runs +unchanged in a single PGlite session. diff --git a/packages/pglite-pg_partman/tests/pgtap/test-id-1-bigint-list.sql b/packages/pglite-pg_partman/tests/pgtap/test-id-1-bigint-list.sql new file mode 100644 index 000000000..db6ac795d --- /dev/null +++ b/packages/pglite-pg_partman/tests/pgtap/test-id-1-bigint-list.sql @@ -0,0 +1,134 @@ +-- ########## ID LIST TESTS (increment 1) ########## +-- Additional tests: + -- pre-created template table and passing to create_partition. Should allow indexes to be made for initial children. + -- bigint (to account for difference in int vs bigint in partition expression) + +\set ON_ERROR_ROLLBACK 1 +\set ON_ERROR_STOP true + +BEGIN; +SELECT set_config('search_path','partman, public',false); + +SELECT plan(61); +CREATE SCHEMA partman_test; +CREATE SCHEMA partman_retention_test; + +CREATE TABLE partman_test.id_taptest_table + (col1 bigint + , col2 bigint NOT NULL + , col3 timestamptz DEFAULT now() + , col4 text) + PARTITION BY LIST (col2); +CREATE TABLE partman_test.undo_taptest (LIKE partman_test.id_taptest_table INCLUDING ALL); +-- Template table +CREATE TABLE partman_test.template_id_taptest_table (LIKE partman_test.id_taptest_table); +ALTER TABLE partman_test.template_id_taptest_table ADD PRIMARY KEY (col1); +CREATE INDEX ON partman_test.id_taptest_table (col2); + +SELECT create_partition('partman_test.id_taptest_table', 'col2', '1', 'list', p_template_table := 'partman_test.template_id_taptest_table'); +UPDATE part_config SET inherit_privileges = TRUE; +SELECT reapply_privileges('partman_test.id_taptest_table'); + +INSERT INTO partman_test.id_taptest_table (col1, col2, col4) VALUES (generate_series(0,9),0, 'stuff'||generate_series(0,9)); +INSERT INTO partman_test.id_taptest_table (col1, col2, col4) VALUES (generate_series(10,19),1, 'stuff'||generate_series(10,19)); +INSERT INTO partman_test.id_taptest_table (col1, col2, col4) VALUES (generate_series(20,29),2, 'stuff'||generate_series(20,29)); +INSERT INTO partman_test.id_taptest_table (col1, col2, col4) VALUES (generate_series(30,39),3, 'stuff'||generate_series(30,39)); +INSERT INTO partman_test.id_taptest_table (col1, col2, col4) VALUES (generate_series(40,49),4, 'stuff'||generate_series(40,49)); + +SELECT has_table('partman_test', 'id_taptest_table_p0', 'Check id_taptest_table_p0 exists'); +SELECT has_table('partman_test', 'id_taptest_table_p1', 'Check id_taptest_table_p1 exists'); +SELECT has_table('partman_test', 'id_taptest_table_p2', 'Check id_taptest_table_p2 exists'); +SELECT has_table('partman_test', 'id_taptest_table_p3', 'Check id_taptest_table_p3 exists'); +SELECT has_table('partman_test', 'id_taptest_table_p4', 'Check id_taptest_table_p4 exists'); +SELECT has_table('partman_test', 'id_taptest_table_default', 'Check id_taptest_table_default exists'); +SELECT hasnt_table('partman_test', 'id_taptest_table_p5', 'Check id_taptest_table_p5 doesn''t exists yet'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p0', ARRAY['col1'], 'Check for primary key in id_taptest_table_p3'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p1', ARRAY['col1'], 'Check for primary key in id_taptest_table_p3'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p2', ARRAY['col1'], 'Check for primary key in id_taptest_table_p3'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p3', ARRAY['col1'], 'Check for primary key in id_taptest_table_p3'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p4', ARRAY['col1'], 'Check for primary key in id_taptest_table_p3'); +SELECT col_is_pk('partman_test', 'id_taptest_table_default', ARRAY['col1'], 'Check for primary key in id_taptest_table_default'); + +SELECT is_empty('SELECT * FROM ONLY partman_test.id_taptest_table_default', 'Check that default table has no data'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table', ARRAY[50], 'Check count from parent table'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table_p0', ARRAY[10], 'Check count from id_taptest_table_p0'); + +SELECT run_maintenance(); +INSERT INTO partman_test.id_taptest_table (col1, col2, col4) VALUES (generate_series(50,59),5, 'stuff'||generate_series(50,59)); +-- Run again to make new partition based on latest data +SELECT run_maintenance(); + +SELECT is_empty('SELECT * FROM ONLY partman_test.id_taptest_table', 'Check that parent table has had no data inserted to it'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table_p1', ARRAY[10], 'Check count from id_taptest_table_p1'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table_p2', ARRAY[10], 'Check count from id_taptest_table_p2'); + +SELECT has_table('partman_test', 'id_taptest_table_p5', 'Check id_taptest_table_p5 exists'); +SELECT has_table('partman_test', 'id_taptest_table_p6', 'Check id_taptest_table_p6 exists yet'); +SELECT has_table('partman_test', 'id_taptest_table_p7', 'Check id_taptest_table_p6 exists yet'); +SELECT has_table('partman_test', 'id_taptest_table_p8', 'Check id_taptest_table_p6 exists yet'); +SELECT has_table('partman_test', 'id_taptest_table_p9', 'Check id_taptest_table_p6 exists yet'); +SELECT hasnt_table('partman_test', 'id_taptest_table_p10', 'Check id_taptest_table_p10 doesn''t exists yet'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p5', ARRAY['col1'], 'Check for primary key in id_taptest_table_p5'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p6', ARRAY['col1'], 'Check for primary key in id_taptest_table_p6'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p7', ARRAY['col1'], 'Check for primary key in id_taptest_table_p7'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p8', ARRAY['col1'], 'Check for primary key in id_taptest_table_p8'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p9', ARRAY['col1'], 'Check for primary key in id_taptest_table_p9'); + +INSERT INTO partman_test.id_taptest_table (col1, col2, col4) VALUES (generate_series(60,69),6, 'stuff'||generate_series(60,69)); + +SELECT run_maintenance(); + +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_default', 'Check that default table has had no data inserted to it'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table', ARRAY[70], 'Check count from id_taptest_table'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table_p5', ARRAY[10], 'Check count from id_taptest_table_p5'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table_p6', ARRAY[10], 'Check count from id_taptest_table_p6'); + +SELECT has_table('partman_test', 'id_taptest_table_p10', 'Check id_taptest_table_p10 exists'); +SELECT hasnt_table('partman_test', 'id_taptest_table_p11', 'Check id_taptest_table_p11 doesn''t exists yet'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p10', ARRAY['col1'], 'Check for primary key in id_taptest_table_p10'); + +INSERT INTO partman_test.id_taptest_table (col1, col2, col4) VALUES (generate_series(200,210),200, 'stuff'||generate_series(200,200)); +SELECT results_eq('SELECT count(*)::int FROM ONLY partman_test.id_taptest_table_default', ARRAY[11], 'Check that data outside child scope goes to default'); +SELECT run_maintenance(); + +-- Max value is 6 above (not including default) +SELECT drop_partition_id('partman_test.id_taptest_table', '4', p_keep_table := false); +SELECT hasnt_table('partman_test', 'id_taptest_table_p0', 'Check id_taptest_table_p0 doesn''t exists anymore'); +SELECT hasnt_table('partman_test', 'id_taptest_table_p1', 'Check id_taptest_table_p1 doesn''t exists anymore'); +SELECT has_table('partman_test', 'id_taptest_table_p2', 'Check id_taptest_table_p2 still exists'); + +UPDATE part_config SET retention = '3', retention_keep_table = 'false' WHERE parent_table = 'partman_test.id_taptest_table'; +SELECT drop_partition_id('partman_test.id_taptest_table'); +SELECT hasnt_table('partman_test', 'id_taptest_table_p2', 'Check id_taptest_table_p2 doesn''t exists anymore'); +SELECT has_table('partman_test', 'id_taptest_table_p3', 'Check id_taptest_table_p3 still exists'); + +-- Undo will remove default first if it exists and has data. Don't keep default +SELECT undo_partition('partman_test.id_taptest_table', 'partman_test.undo_taptest', p_keep_table := false); +SELECT hasnt_table('partman_test', 'id_taptest_table_default', 'Check id_taptest_table_default does not exist'); + +-- Test undo removing one more table but keeping that data +SELECT undo_partition('partman_test.id_taptest_table', 'partman_test.undo_taptest', p_keep_table := false); +SELECT hasnt_table('partman_test', 'id_taptest_table_p3', 'Check id_taptest_table_p3 does not exist'); + +-- Test keeping the rest of the tables +SELECT undo_partition('partman_test.id_taptest_table', 'partman_test.undo_taptest', 10); +SELECT results_eq('SELECT count(*)::int FROM ONLY partman_test.undo_taptest', ARRAY[51], 'Check count from undo table after undo'); +SELECT has_table('partman_test', 'id_taptest_table_p4', 'Check id_taptest_table_p4 still exists'); +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_p4', 'Check child table had its data removed id_taptest_table_p4'); +SELECT has_table('partman_test', 'id_taptest_table_p5', 'Check id_taptest_table_p5 still exists'); +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_p5', 'Check child table had its data removed id_taptest_table_p5'); +SELECT has_table('partman_test', 'id_taptest_table_p6', 'Check id_taptest_table_p6 still exists'); +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_p6', 'Check child table had its data removed id_taptest_table_p6'); +SELECT has_table('partman_test', 'id_taptest_table_p7', 'Check id_taptest_table_p7 still exists'); +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_p7', 'Check child table had its data removed id_taptest_table_p7'); +SELECT has_table('partman_test', 'id_taptest_table_p8', 'Check id_taptest_table_p8 still exists'); +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_p8', 'Check child table had its data removed id_taptest_table_p8'); +SELECT has_table('partman_test', 'id_taptest_table_p9', 'Check id_taptest_table_p9 still exists'); +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_p9', 'Check child table had its data removed id_taptest_table_p9'); +SELECT has_table('partman_test', 'id_taptest_table_p10', 'Check id_taptest_table_p10 still exists'); +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_p10', 'Check child table had its data removed id_taptest_table_p10'); + +SELECT hasnt_table('partman_test', 'template_id_taptest_table', 'Check that template table was dropped'); + +SELECT * FROM finish(); +ROLLBACK; diff --git a/packages/pglite-pg_partman/tests/pgtap/test-id-1-int-list.sql b/packages/pglite-pg_partman/tests/pgtap/test-id-1-int-list.sql new file mode 100644 index 000000000..515eb5d12 --- /dev/null +++ b/packages/pglite-pg_partman/tests/pgtap/test-id-1-int-list.sql @@ -0,0 +1,134 @@ +-- ########## ID LIST TESTS (increment 1) ########## +-- Additional tests: + -- pre-created template table and passing to create_partition. Should allow indexes to be made for initial children. + -- int (to account for difference in int vs bigint in partition expression) + +\set ON_ERROR_ROLLBACK 1 +\set ON_ERROR_STOP true + +BEGIN; +SELECT set_config('search_path','partman, public',false); + +SELECT plan(61); +CREATE SCHEMA partman_test; +CREATE SCHEMA partman_retention_test; + +CREATE TABLE partman_test.id_taptest_table + (col1 bigint + , col2 int NOT NULL + , col3 timestamptz DEFAULT now() + , col4 text) + PARTITION BY LIST (col2); +CREATE TABLE partman_test.undo_taptest (LIKE partman_test.id_taptest_table INCLUDING ALL); +-- Template table +CREATE TABLE partman_test.template_id_taptest_table (LIKE partman_test.id_taptest_table); +ALTER TABLE partman_test.template_id_taptest_table ADD PRIMARY KEY (col1); +CREATE INDEX ON partman_test.id_taptest_table (col2); + +SELECT create_partition('partman_test.id_taptest_table', 'col2', '1', 'list', p_template_table := 'partman_test.template_id_taptest_table'); +UPDATE part_config SET inherit_privileges = TRUE; +SELECT reapply_privileges('partman_test.id_taptest_table'); + +INSERT INTO partman_test.id_taptest_table (col1, col2, col4) VALUES (generate_series(0,9),0, 'stuff'||generate_series(0,9)); +INSERT INTO partman_test.id_taptest_table (col1, col2, col4) VALUES (generate_series(10,19),1, 'stuff'||generate_series(10,19)); +INSERT INTO partman_test.id_taptest_table (col1, col2, col4) VALUES (generate_series(20,29),2, 'stuff'||generate_series(20,29)); +INSERT INTO partman_test.id_taptest_table (col1, col2, col4) VALUES (generate_series(30,39),3, 'stuff'||generate_series(30,39)); +INSERT INTO partman_test.id_taptest_table (col1, col2, col4) VALUES (generate_series(40,49),4, 'stuff'||generate_series(40,49)); + +SELECT has_table('partman_test', 'id_taptest_table_p0', 'Check id_taptest_table_p0 exists'); +SELECT has_table('partman_test', 'id_taptest_table_p1', 'Check id_taptest_table_p1 exists'); +SELECT has_table('partman_test', 'id_taptest_table_p2', 'Check id_taptest_table_p2 exists'); +SELECT has_table('partman_test', 'id_taptest_table_p3', 'Check id_taptest_table_p3 exists'); +SELECT has_table('partman_test', 'id_taptest_table_p4', 'Check id_taptest_table_p4 exists'); +SELECT has_table('partman_test', 'id_taptest_table_default', 'Check id_taptest_table_default exists'); +SELECT hasnt_table('partman_test', 'id_taptest_table_p5', 'Check id_taptest_table_p5 doesn''t exists yet'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p0', ARRAY['col1'], 'Check for primary key in id_taptest_table_p3'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p1', ARRAY['col1'], 'Check for primary key in id_taptest_table_p3'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p2', ARRAY['col1'], 'Check for primary key in id_taptest_table_p3'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p3', ARRAY['col1'], 'Check for primary key in id_taptest_table_p3'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p4', ARRAY['col1'], 'Check for primary key in id_taptest_table_p3'); +SELECT col_is_pk('partman_test', 'id_taptest_table_default', ARRAY['col1'], 'Check for primary key in id_taptest_table_default'); + +SELECT is_empty('SELECT * FROM ONLY partman_test.id_taptest_table_default', 'Check that default table has no data'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table', ARRAY[50], 'Check count from parent table'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table_p0', ARRAY[10], 'Check count from id_taptest_table_p0'); + +SELECT run_maintenance(); +INSERT INTO partman_test.id_taptest_table (col1, col2, col4) VALUES (generate_series(50,59),5, 'stuff'||generate_series(50,59)); +-- Run again to make new partition based on latest data +SELECT run_maintenance(); + +SELECT is_empty('SELECT * FROM ONLY partman_test.id_taptest_table', 'Check that parent table has had no data inserted to it'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table_p1', ARRAY[10], 'Check count from id_taptest_table_p1'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table_p2', ARRAY[10], 'Check count from id_taptest_table_p2'); + +SELECT has_table('partman_test', 'id_taptest_table_p5', 'Check id_taptest_table_p5 exists'); +SELECT has_table('partman_test', 'id_taptest_table_p6', 'Check id_taptest_table_p6 exists yet'); +SELECT has_table('partman_test', 'id_taptest_table_p7', 'Check id_taptest_table_p6 exists yet'); +SELECT has_table('partman_test', 'id_taptest_table_p8', 'Check id_taptest_table_p6 exists yet'); +SELECT has_table('partman_test', 'id_taptest_table_p9', 'Check id_taptest_table_p6 exists yet'); +SELECT hasnt_table('partman_test', 'id_taptest_table_p10', 'Check id_taptest_table_p10 doesn''t exists yet'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p5', ARRAY['col1'], 'Check for primary key in id_taptest_table_p5'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p6', ARRAY['col1'], 'Check for primary key in id_taptest_table_p6'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p7', ARRAY['col1'], 'Check for primary key in id_taptest_table_p7'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p8', ARRAY['col1'], 'Check for primary key in id_taptest_table_p8'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p9', ARRAY['col1'], 'Check for primary key in id_taptest_table_p9'); + +INSERT INTO partman_test.id_taptest_table (col1, col2, col4) VALUES (generate_series(60,69),6, 'stuff'||generate_series(60,69)); + +SELECT run_maintenance(); + +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_default', 'Check that default table has had no data inserted to it'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table', ARRAY[70], 'Check count from id_taptest_table'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table_p5', ARRAY[10], 'Check count from id_taptest_table_p5'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table_p6', ARRAY[10], 'Check count from id_taptest_table_p6'); + +SELECT has_table('partman_test', 'id_taptest_table_p10', 'Check id_taptest_table_p10 exists'); +SELECT hasnt_table('partman_test', 'id_taptest_table_p11', 'Check id_taptest_table_p11 doesn''t exists yet'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p10', ARRAY['col1'], 'Check for primary key in id_taptest_table_p10'); + +INSERT INTO partman_test.id_taptest_table (col1, col2, col4) VALUES (generate_series(200,210),200, 'stuff'||generate_series(200,200)); +SELECT results_eq('SELECT count(*)::int FROM ONLY partman_test.id_taptest_table_default', ARRAY[11], 'Check that data outside child scope goes to default'); +SELECT run_maintenance(); + +-- Max value is 6 above (not including default) +SELECT drop_partition_id('partman_test.id_taptest_table', '4', p_keep_table := false); +SELECT hasnt_table('partman_test', 'id_taptest_table_p0', 'Check id_taptest_table_p0 doesn''t exists anymore'); +SELECT hasnt_table('partman_test', 'id_taptest_table_p1', 'Check id_taptest_table_p1 doesn''t exists anymore'); +SELECT has_table('partman_test', 'id_taptest_table_p2', 'Check id_taptest_table_p2 still exists'); + +UPDATE part_config SET retention = '3', retention_keep_table = 'false' WHERE parent_table = 'partman_test.id_taptest_table'; +SELECT drop_partition_id('partman_test.id_taptest_table'); +SELECT hasnt_table('partman_test', 'id_taptest_table_p2', 'Check id_taptest_table_p2 doesn''t exists anymore'); +SELECT has_table('partman_test', 'id_taptest_table_p3', 'Check id_taptest_table_p3 still exists'); + +-- Undo will remove default first if it exists and has data. Don't keep default +SELECT undo_partition('partman_test.id_taptest_table', 'partman_test.undo_taptest', p_keep_table := false); +SELECT hasnt_table('partman_test', 'id_taptest_table_default', 'Check id_taptest_table_default does not exist'); + +-- Test undo removing one more table but keeping that data +SELECT undo_partition('partman_test.id_taptest_table', 'partman_test.undo_taptest', p_keep_table := false); +SELECT hasnt_table('partman_test', 'id_taptest_table_p3', 'Check id_taptest_table_p3 does not exist'); + +-- Test keeping the rest of the tables +SELECT undo_partition('partman_test.id_taptest_table', 'partman_test.undo_taptest', 10); +SELECT results_eq('SELECT count(*)::int FROM ONLY partman_test.undo_taptest', ARRAY[51], 'Check count from undo table after undo'); +SELECT has_table('partman_test', 'id_taptest_table_p4', 'Check id_taptest_table_p4 still exists'); +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_p4', 'Check child table had its data removed id_taptest_table_p4'); +SELECT has_table('partman_test', 'id_taptest_table_p5', 'Check id_taptest_table_p5 still exists'); +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_p5', 'Check child table had its data removed id_taptest_table_p5'); +SELECT has_table('partman_test', 'id_taptest_table_p6', 'Check id_taptest_table_p6 still exists'); +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_p6', 'Check child table had its data removed id_taptest_table_p6'); +SELECT has_table('partman_test', 'id_taptest_table_p7', 'Check id_taptest_table_p7 still exists'); +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_p7', 'Check child table had its data removed id_taptest_table_p7'); +SELECT has_table('partman_test', 'id_taptest_table_p8', 'Check id_taptest_table_p8 still exists'); +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_p8', 'Check child table had its data removed id_taptest_table_p8'); +SELECT has_table('partman_test', 'id_taptest_table_p9', 'Check id_taptest_table_p9 still exists'); +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_p9', 'Check child table had its data removed id_taptest_table_p9'); +SELECT has_table('partman_test', 'id_taptest_table_p10', 'Check id_taptest_table_p10 still exists'); +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_p10', 'Check child table had its data removed id_taptest_table_p10'); + +SELECT hasnt_table('partman_test', 'template_id_taptest_table', 'Check that template table was dropped'); + +SELECT * FROM finish(); +ROLLBACK; diff --git a/packages/pglite-pg_partman/tests/pgtap/test-id-10.sql b/packages/pglite-pg_partman/tests/pgtap/test-id-10.sql new file mode 100644 index 000000000..91ed3079e --- /dev/null +++ b/packages/pglite-pg_partman/tests/pgtap/test-id-10.sql @@ -0,0 +1,232 @@ +-- ########## ID 10 TESTS ########## +-- Additional tests: + -- turn off pg_jobmon logging + -- UNLOGGED - Parent table not allowed to be unlogged in PG18+, but the child tables can be + -- PUBLIC role + -- start with higher number + -- native inherit FK + -- inherit privileges + -- pre-created template table and passing to create_partition. Should allow indexes to be made for initial children. + -- Since this is id partitioning, we can use the partition key for primary key, so that should work from parent + +\set ON_ERROR_ROLLBACK 1 +\set ON_ERROR_STOP true + +BEGIN; +SELECT set_config('search_path','partman, public',false); + +SELECT plan(134); +CREATE ROLE partman_basic; +CREATE ROLE partman_revoke; +CREATE ROLE partman_owner; +CREATE SCHEMA partman_test; +CREATE SCHEMA partman_retention_test AUTHORIZATION partman_owner; + +CREATE TABLE partman_test.fk_test_reference (col2 text unique not null); +INSERT INTO partman_test.fk_test_reference VALUES ('stuff'); + +CREATE TABLE partman_test.id_taptest_table + (col1 bigint PRIMARY KEY + , col2 text not null default 'stuff' + , col3 timestamptz DEFAULT now() + , col4 text + , CONSTRAINT test_native_fk FOREIGN KEY (col2) REFERENCES partman_test.fk_test_reference(col2) ) + PARTITION BY RANGE (col1); +CREATE TABLE partman_test.undo_taptest (LIKE partman_test.id_taptest_table INCLUDING ALL); +GRANT SELECT,INSERT,UPDATE ON partman_test.id_taptest_table TO partman_basic, PUBLIC; +GRANT ALL ON partman_test.id_taptest_table TO partman_revoke; +-- Template table +CREATE UNLOGGED TABLE partman_test.template_id_taptest_table (LIKE partman_test.id_taptest_table); + +CREATE INDEX ON partman_test.id_taptest_table (col3); + +-- TESTING CASE ONLY - create the index on the template also so that we can test excluding duplicate indexes +CREATE INDEX ON partman_test.template_id_taptest_table (col3); + +-- Regular unique indexes do not work on native if the partition key isn't included +CREATE UNIQUE INDEX ON partman_test.template_id_taptest_table (col4); + +SELECT create_partition('partman_test.id_taptest_table', 'col1', '10', p_jobmon := false, p_start_partition := '3000000000', p_template_table := 'partman_test.template_id_taptest_table'); +UPDATE part_config SET inherit_privileges = TRUE; +SELECT reapply_privileges('partman_test.id_taptest_table'); + +INSERT INTO partman_test.id_taptest_table (col1, col4) VALUES (generate_series(3000000001,3000000009), 'stuff'||generate_series(3000000001,3000000009)); + +SELECT has_table('partman_test', 'id_taptest_table_p3000000000', 'Check id_taptest_table_p3000000000 exists'); +SELECT has_table('partman_test', 'id_taptest_table_p3000000010', 'Check id_taptest_table_p3000000010 exists'); +SELECT has_table('partman_test', 'id_taptest_table_p3000000020', 'Check id_taptest_table_p3000000020 exists'); +SELECT has_table('partman_test', 'id_taptest_table_p3000000030', 'Check id_taptest_table_p3000000030 exists'); +SELECT has_table('partman_test', 'id_taptest_table_p3000000040', 'Check id_taptest_table_p3000000040 exists'); +SELECT has_table('partman_test', 'id_taptest_table_default', 'Check id_taptest_table_default exists'); +SELECT hasnt_table('partman_test', 'id_taptest_table_p3000000050', 'Check id_taptest_table_p3000000050 doesn''t exists yet'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p3000000000', ARRAY['col1'], 'Check for primary key in id_taptest_table_p3000000000'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p3000000010', ARRAY['col1'], 'Check for primary key in id_taptest_table_p3000000010'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p3000000020', ARRAY['col1'], 'Check for primary key in id_taptest_table_p3000000020'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p3000000030', ARRAY['col1'], 'Check for primary key in id_taptest_table_p3000000030'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p3000000040', ARRAY['col1'], 'Check for primary key in id_taptest_table_p3000000040'); +SELECT col_is_pk('partman_test', 'id_taptest_table_default', ARRAY['col1'], 'Check for primary key in id_taptest_table_default'); +SELECT col_is_fk('partman_test', 'id_taptest_table_p3000000000', 'col2', 'Check that foreign key was inherited to id_taptest_table_p3000000000'); +SELECT col_is_fk('partman_test', 'id_taptest_table_p3000000010', 'col2', 'Check that foreign key was inherited to id_taptest_table_p3000000010'); +SELECT col_is_fk('partman_test', 'id_taptest_table_p3000000020', 'col2', 'Check that foreign key was inherited to id_taptest_table_p3000000020'); +SELECT col_is_fk('partman_test', 'id_taptest_table_p3000000030', 'col2', 'Check that foreign key was inherited to id_taptest_table_p3000000030'); +SELECT col_is_fk('partman_test', 'id_taptest_table_p3000000040', 'col2', 'Check that foreign key was inherited to id_taptest_table_p3000000040'); +SELECT col_is_fk('partman_test', 'id_taptest_table_default', 'col2', 'Check that foreign key was inherited to id_taptest_table_default'); +SELECT is_indexed('partman_test', 'id_taptest_table_p3000000000', 'col4', 'Check that unique index was inherited to id_taptest_table_p3000000000'); +SELECT is_indexed('partman_test', 'id_taptest_table_p3000000010', 'col4', 'Check that unique index was inherited to id_taptest_table_p3000000010'); +SELECT is_indexed('partman_test', 'id_taptest_table_p3000000020', 'col4', 'Check that unique index was inherited to id_taptest_table_p3000000020'); +SELECT is_indexed('partman_test', 'id_taptest_table_p3000000030', 'col4', 'Check that unique index was inherited to id_taptest_table_p3000000030'); +SELECT is_indexed('partman_test', 'id_taptest_table_p3000000040', 'col4', 'Check that unique index was inherited to id_taptest_table_p3000000040'); +SELECT is_indexed('partman_test', 'id_taptest_table_default', 'col4', 'Check that unique index was inherited to id_taptest_table_default'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000000', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_p3000000000'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000010', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_p3000000010'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000020', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_p3000000020'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000030', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_p3000000030'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000040', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_p3000000040'); +SELECT table_privs_are('partman_test', 'id_taptest_table_default', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_default'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000000', 'partman_revoke', ARRAY['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER'], 'Check partman_revoke privileges of id_taptest_table_p3000000000'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000010', 'partman_revoke', ARRAY['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER'], 'Check partman_revoke privileges of id_taptest_table_p3000000010'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000020', 'partman_revoke', ARRAY['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER'], 'Check partman_revoke privileges of id_taptest_table_p3000000020'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000030', 'partman_revoke', ARRAY['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER'], 'Check partman_revoke privileges of id_taptest_table_p3000000030'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000040', 'partman_revoke', ARRAY['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER'], 'Check partman_revoke privileges of id_taptest_table_p3000000040'); +SELECT table_privs_are('partman_test', 'id_taptest_table_default', 'partman_revoke', ARRAY['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER'], 'Check partman_revoke privileges of id_taptest_table_default'); +-- PG18 does not allow the parent to be unlogged, but child tables can. Just leaving this here with a note so I don't forget why I don't test this anymore +--SELECT results_eq('SELECT relpersistence::text FROM pg_catalog.pg_class WHERE oid::regclass = ''partman_test.id_taptest_table''::regclass', ARRAY['u'], 'Check that parent table is unlogged'); +SELECT results_eq('SELECT relpersistence::text FROM pg_catalog.pg_class WHERE oid::regclass = ''partman_test.id_taptest_table_p3000000000''::regclass', ARRAY['u'], 'Check that id_taptest_table_p3000000000 is unlogged'); +SELECT results_eq('SELECT relpersistence::text FROM pg_catalog.pg_class WHERE oid::regclass = ''partman_test.id_taptest_table_p3000000010''::regclass', ARRAY['u'], 'Check that id_taptest_table_p3000000010 is unlogged'); +SELECT results_eq('SELECT relpersistence::text FROM pg_catalog.pg_class WHERE oid::regclass = ''partman_test.id_taptest_table_p3000000020''::regclass', ARRAY['u'], 'Check that id_taptest_table_p3000000020 is unlogged'); +SELECT results_eq('SELECT relpersistence::text FROM pg_catalog.pg_class WHERE oid::regclass = ''partman_test.id_taptest_table_p3000000030''::regclass', ARRAY['u'], 'Check that id_taptest_table_p3000000030 is unlogged'); +SELECT results_eq('SELECT relpersistence::text FROM pg_catalog.pg_class WHERE oid::regclass = ''partman_test.id_taptest_table_p3000000040''::regclass', ARRAY['u'], 'Check that id_taptest_table_p3000000040 is unlogged'); +SELECT results_eq('SELECT relpersistence::text FROM pg_catalog.pg_class WHERE oid::regclass = ''partman_test.id_taptest_table_default''::regclass', ARRAY['u'], 'Check that id_taptest_table_default is unlogged'); + +SELECT is_empty('SELECT * FROM ONLY partman_test.id_taptest_table_default', 'Check that default table has no data'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table', ARRAY[9], 'Check count from parent table'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table_p3000000000', ARRAY[9], 'Check count from id_taptest_table_p3000000000'); + +REVOKE INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER ON partman_test.id_taptest_table FROM partman_revoke, PUBLIC; + +SELECT run_maintenance(); +INSERT INTO partman_test.id_taptest_table (col1, col4) VALUES (generate_series(3000000010,3000000025), 'stuff'||generate_series(3000000010,3000000025)); +-- Run again to make new partition based on latest data +SELECT run_maintenance(); + +SELECT is_empty('SELECT * FROM ONLY partman_test.id_taptest_table', 'Check that parent table has had no data inserted to it'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table_p3000000010', ARRAY[10], 'Check count from id_taptest_table_p3000000010'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table_p3000000020', ARRAY[6], 'Check count from id_taptest_table_p3000000020'); + +SELECT has_table('partman_test', 'id_taptest_table_p3000000050', 'Check id_taptest_table_p3000000050 exists'); +SELECT results_eq('SELECT relpersistence::text FROM pg_catalog.pg_class WHERE oid::regclass = ''partman_test.id_taptest_table_p3000000050''::regclass', ARRAY['u'], 'Check that id_taptest_table_p3000000050 is unlogged'); +SELECT has_table('partman_test', 'id_taptest_table_p3000000060', 'Check id_taptest_table_p3000000060 exists yet'); +SELECT results_eq('SELECT relpersistence::text FROM pg_catalog.pg_class WHERE oid::regclass = ''partman_test.id_taptest_table_p3000000060''::regclass', ARRAY['u'], 'Check that id_taptest_table_p3000000060 is unlogged'); +SELECT hasnt_table('partman_test', 'id_taptest_table_p3000000070', 'Check id_taptest_table_p3000000070 doesn''t exists yet'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p3000000050', ARRAY['col1'], 'Check for primary key in id_taptest_table_p3000000050'); +SELECT col_is_fk('partman_test', 'id_taptest_table_p3000000050', 'col2', 'Check that foreign key was inherited to id_taptest_table_p3000000050'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000000', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_p3000000000'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000010', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_p3000000010'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000020', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_p3000000020'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000030', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_p3000000030'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000040', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_p3000000040'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000050', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_p3000000050'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000050', 'partman_revoke', ARRAY['SELECT'], 'Check partman_revoke privileges of id_taptest_table_p3000000050'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000060', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_p3000000060'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000060', 'partman_revoke', ARRAY['SELECT'], 'Check partman_revoke privileges of id_taptest_table_p3000000060'); + +GRANT DELETE ON partman_test.id_taptest_table TO partman_basic; +REVOKE ALL ON partman_test.id_taptest_table FROM partman_revoke, PUBLIC; +ALTER TABLE partman_test.id_taptest_table OWNER TO partman_owner; +INSERT INTO partman_test.id_taptest_table (col1, col4) VALUES (generate_series(3000000026,3000000038), 'stuff'||generate_series(3000000026,3000000038)); + +SELECT run_maintenance(); + +SELECT is_empty('SELECT * FROM ONLY partman_test.id_taptest_table', 'Check that parent table has had no data inserted to it'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table', ARRAY[38], 'Check count from id_taptest_table'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table_p3000000020', ARRAY[10], 'Check count from id_taptest_table_p3000000020'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.id_taptest_table_p3000000030', ARRAY[9], 'Check count from id_taptest_table_p3000000030'); + +SELECT has_table('partman_test', 'id_taptest_table_p3000000070', 'Check id_taptest_table_p3000000070 exists'); +SELECT results_eq('SELECT relpersistence::text FROM pg_catalog.pg_class WHERE oid::regclass = ''partman_test.id_taptest_table_p3000000070''::regclass', ARRAY['u'], 'Check that id_taptest_table_p3000000070 is unlogged'); +SELECT hasnt_table('partman_test', 'id_taptest_table_p3000000080', 'Check id_taptest_table_p3000000080 doesn''t exists yet'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p3000000060', ARRAY['col1'], 'Check for primary key in id_taptest_table_p3000000060'); +SELECT col_is_pk('partman_test', 'id_taptest_table_p3000000070', ARRAY['col1'], 'Check for primary key in id_taptest_table_p3000000070'); +SELECT col_is_fk('partman_test', 'id_taptest_table_p3000000060', 'col2', 'Check that foreign key was inherited to id_taptest_table_p3000000060'); +SELECT col_is_fk('partman_test', 'id_taptest_table_p3000000070', 'col2', 'Check that foreign key was inherited to id_taptest_table_p3000000070'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000000', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_p3000000000'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000010', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_p3000000010'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000020', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_p3000000020'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000030', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_p3000000030'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000040', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_p3000000040'); +SELECT table_privs_are('partman_test', 'id_taptest_table_default', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_default'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000050', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_p3000000050'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000050', 'partman_revoke', ARRAY['SELECT'], 'Check partman_revoke privileges of id_taptest_table_p3000000050'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000060', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], 'Check partman_basic privileges of id_taptest_table_p3000000060'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000060', 'partman_revoke', ARRAY['SELECT'], 'Check partman_revoke privileges of id_taptest_table_p3000000060'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000070', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE','DELETE'], 'Check partman_basic privileges of id_taptest_table_p3000000070'); +SELECT table_owner_is ('partman_test', 'id_taptest_table_p3000000070', 'partman_owner', 'Check that ownership change worked for id_taptest_table_p3000000070'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000070', 'partman_revoke', '{}'::text[], 'Check partman_revoke has no privileges on id_taptest_table_p3000000070'); + +INSERT INTO partman_test.id_taptest_table (col1, col4) VALUES (generate_series(3000000200,3000000210), 'stuff'||generate_series(3000000200,3000000210)); +SELECT results_eq('SELECT count(*)::int FROM ONLY partman_test.id_taptest_table_default', ARRAY[11], 'Check that data outside child scope goes to default'); +SELECT run_maintenance(); + +SELECT reapply_privileges('partman_test.id_taptest_table'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000000', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE','DELETE'], 'Check partman_basic privileges of id_taptest_table_p3000000000'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000010', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE','DELETE'], 'Check partman_basic privileges of id_taptest_table_p3000000010'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000020', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE','DELETE'], 'Check partman_basic privileges of id_taptest_table_p3000000020'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000030', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE','DELETE'], 'Check partman_basic privileges of id_taptest_table_p3000000030'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000040', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE','DELETE'], 'Check partman_basic privileges of id_taptest_table_p3000000040'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000050', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE','DELETE'], 'Check partman_basic privileges of id_taptest_table_p3000000050'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000060', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE','DELETE'], 'Check partman_basic privileges of id_taptest_table_p3000000060'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000070', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE','DELETE'], 'Check partman_basic privileges of id_taptest_table_p3000000070'); +SELECT table_privs_are('partman_test', 'id_taptest_table_default', 'partman_basic', ARRAY['SELECT','INSERT','UPDATE','DELETE'], 'Check partman_basic privileges of id_taptest_table_default'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000000', 'partman_revoke', '{}'::text[], 'Check partman_revoke has no privileges on id_taptest_table_p3000000000'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000010', 'partman_revoke', '{}'::text[], 'Check partman_revoke has no privileges on id_taptest_table_p3000000010'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000020', 'partman_revoke', '{}'::text[], 'Check partman_revoke has no privileges on id_taptest_table_p3000000020'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000030', 'partman_revoke', '{}'::text[], 'Check partman_revoke has no privileges on id_taptest_table_p3000000030'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000040', 'partman_revoke', '{}'::text[], 'Check partman_revoke has no privileges on id_taptest_table_p3000000040'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000050', 'partman_revoke', '{}'::text[], 'Check partman_revoke has no privileges on id_taptest_table_p3000000050'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000060', 'partman_revoke', '{}'::text[], 'Check partman_revoke has no privileges on id_taptest_table_p3000000060'); +SELECT table_privs_are('partman_test', 'id_taptest_table_p3000000070', 'partman_revoke', '{}'::text[], 'Check partman_revoke has no privileges on id_taptest_table_p3000000070'); +SELECT table_privs_are('partman_test', 'id_taptest_table_default', 'partman_revoke', '{}'::text[], 'Check partman_revoke has no privileges on id_taptest_table_default'); +SELECT table_owner_is ('partman_test', 'id_taptest_table_p3000000000', 'partman_owner', 'Check that ownership change worked for id_taptest_table_p3000000000'); +SELECT table_owner_is ('partman_test', 'id_taptest_table_p3000000010', 'partman_owner', 'Check that ownership change worked for id_taptest_table_p3000000010'); +SELECT table_owner_is ('partman_test', 'id_taptest_table_p3000000020', 'partman_owner', 'Check that ownership change worked for id_taptest_table_p3000000020'); +SELECT table_owner_is ('partman_test', 'id_taptest_table_p3000000030', 'partman_owner', 'Check that ownership change worked for id_taptest_table_p3000000030'); +SELECT table_owner_is ('partman_test', 'id_taptest_table_p3000000040', 'partman_owner', 'Check that ownership change worked for id_taptest_table_p3000000040'); +SELECT table_owner_is ('partman_test', 'id_taptest_table_p3000000050', 'partman_owner', 'Check that ownership change worked for id_taptest_table_p3000000050'); +SELECT table_owner_is ('partman_test', 'id_taptest_table_p3000000060', 'partman_owner', 'Check that ownership change worked for id_taptest_table_p3000000060'); +SELECT table_owner_is ('partman_test', 'id_taptest_table_p3000000070', 'partman_owner', 'Check that ownership change worked for id_taptest_table_p3000000070'); +SELECT table_owner_is ('partman_test', 'id_taptest_table_default', 'partman_owner', 'Check that ownership change worked for id_taptest_table_default'); + +-- Max value is 38 above +SELECT drop_partition_id('partman_test.id_taptest_table', '20', p_keep_table := false); +SELECT hasnt_table('partman_test', 'id_taptest_table_p3000000000', 'Check id_taptest_table_p3000000000 doesn''t exists anymore'); + +UPDATE part_config SET retention = '10' WHERE parent_table = 'partman_test.id_taptest_table'; +SELECT drop_partition_id('partman_test.id_taptest_table', p_retention_schema := 'partman_retention_test'); +SELECT hasnt_table('partman_test', 'id_taptest_table_p3000000010', 'Check id_taptest_table_p3000000010 doesn''t exists anymore'); +SELECT has_table('partman_retention_test', 'id_taptest_table_p3000000010', 'Check id_taptest_table_p3000000010 got moved to new schema'); + +-- Undo will remove default first if it exists and has data +SELECT undo_partition('partman_test.id_taptest_table', 'partman_test.undo_taptest', p_keep_table := false); +SELECT hasnt_table('partman_test', 'id_taptest_table_default', 'Check id_taptest_table_default does not exist'); + +SELECT undo_partition('partman_test.id_taptest_table', 'partman_test.undo_taptest', p_keep_table := false); +SELECT hasnt_table('partman_test', 'id_taptest_table_p3000000020', 'Check id_taptest_table_p3000000020 does not exist'); + +-- Test keeping the rest of the tables +SELECT undo_partition('partman_test.id_taptest_table', 'partman_test.undo_taptest', 10); +SELECT results_eq('SELECT count(*)::int FROM ONLY partman_test.undo_taptest', ARRAY[30], 'Check count from undo table after undo'); +SELECT has_table('partman_test', 'id_taptest_table_p3000000030', 'Check id_taptest_table_p3000000030 still exists'); +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_p3000000030', 'Check child table had its data removed id_taptest_table_p3000000030'); +SELECT has_table('partman_test', 'id_taptest_table_p3000000040', 'Check id_taptest_table_p3000000040 still exists'); +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_p3000000040', 'Check child table had its data removed id_taptest_table_p3000000040'); +SELECT has_table('partman_test', 'id_taptest_table_p3000000050', 'Check id_taptest_table_p3000000050 still exists'); +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_p3000000050', 'Check child table had its data removed id_taptest_table_p3000000050'); +SELECT has_table('partman_test', 'id_taptest_table_p3000000060', 'Check id_taptest_table_p3000000060 still exists'); +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_p3000000060', 'Check child table had its data removed id_taptest_table_p3000000060'); +SELECT has_table('partman_test', 'id_taptest_table_p3000000070', 'Check id_taptest_table_p3000000070 still exists'); +SELECT is_empty('SELECT * FROM partman_test.id_taptest_table_p3000000070', 'Check child table had its data removed id_taptest_table_p3000000070'); + +SELECT hasnt_table('partman_test', 'template_id_taptest_table', 'Check that template table was dropped'); + +SELECT * FROM finish(); +ROLLBACK; diff --git a/packages/pglite-pg_partman/tests/pgtap/test-time-daily.sql b/packages/pglite-pg_partman/tests/pgtap/test-time-daily.sql new file mode 100644 index 000000000..df832e8d9 --- /dev/null +++ b/packages/pglite-pg_partman/tests/pgtap/test-time-daily.sql @@ -0,0 +1,644 @@ +-- ########## TIME DAILY TESTS ########## +-- Other tests: + -- Privilege inheritance + -- check that maintenance catches up if tables are missing + -- Test using default template table. Initial child tables will have no indexes or primary keys. New tables after template has indexes added should. + -- Test for native FK inheritance + -- Test that column statistics target is inherited from parent tables (this is only testing that the commands work. Actually testing that they're inherited is a different pattern match between 16 and 17. There is an actual test in the pg17plus folder) + +\set ON_ERROR_ROLLBACK 1 +\set ON_ERROR_STOP true + +BEGIN; +SELECT set_config('search_path','partman, public',false); + +SELECT plan(221); + +CREATE ROLE partman_basic; +CREATE ROLE partman_revoke; +CREATE ROLE partman_owner; +CREATE SCHEMA partman_test; +CREATE SCHEMA partman_retention_test AUTHORIZATION partman_owner; + +CREATE TABLE partman_test.fk_test_reference (col2 text unique not null); +INSERT INTO partman_test.fk_test_reference VALUES ('stuff'); + +CREATE TABLE partman_test.time_taptest_table + (col1 int + , col2 text default 'stuff' + , col3 timestamptz NOT NULL DEFAULT now() + , CONSTRAINT fk_test FOREIGN KEY (col2) REFERENCES partman_test.fk_test_reference(col2) ) + PARTITION BY RANGE (col3); +ALTER TABLE partman_test.time_taptest_table + ALTER COLUMN col1 SET STATISTICS 1000, + ALTER COLUMN col2 SET STATISTICS 0; +CREATE TABLE partman_test.undo_taptest (LIKE partman_test.time_taptest_table INCLUDING ALL); +GRANT SELECT,INSERT,UPDATE ON partman_test.time_taptest_table TO partman_basic; +GRANT ALL ON partman_test.time_taptest_table TO partman_revoke; +ALTER TABLE partman_test.time_taptest_table OWNER TO partman_owner; + +SELECT create_partition('partman_test.time_taptest_table', 'col3', '1 day'); +UPDATE part_config SET inherit_privileges = TRUE; +SELECT reapply_privileges('partman_test.time_taptest_table'); + +SELECT is_partitioned('partman_test', 'time_taptest_table', 'Check that time_taptest_table is natively partitioned'); +SELECT has_table('partman', 'template_partman_test_time_taptest_table', 'Check that default template table was created'); +SELECT table_owner_is ('partman', 'template_partman_test_time_taptest_table', 'partman_owner', + 'Check that template table ownership is set properly'); + +-- Add inheritable stuff to template table +ALTER TABLE template_partman_test_time_taptest_table ADD PRIMARY KEY (col1); + +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(1,10), CURRENT_TIMESTAMP); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD'), 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD')||' exists'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD')||' exists'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'5 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'5 days'::interval, 'YYYYMMDD')||' does not exist'); + +SELECT col_isnt_pk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD'), ARRAY['col1'], + 'Check for NO primary key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD')); +SELECT col_isnt_pk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for NO primary key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD')); +SELECT col_isnt_pk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for NO primary key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD')); +SELECT col_isnt_pk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for NO primary key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD')); +SELECT col_isnt_pk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for NO primary key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD')); +SELECT col_isnt_pk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD'), ARRAY['col1'], + 'Check for NO primary key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD')); +SELECT col_isnt_pk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for NO primary key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD')); +SELECT col_isnt_pk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for NO primary key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD')); +SELECT col_isnt_pk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for NO primary key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD')); +SELECT col_isnt_pk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for NO primary key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD')); + +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD')); + +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD'), 'partman_revoke', + ARRAY['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER'], + 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD'), 'partman_revoke', + ARRAY['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER'], + 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD'), 'partman_revoke', + ARRAY['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER'], + 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD'), 'partman_revoke', + ARRAY['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER'], + 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD'), 'partman_revoke', + ARRAY['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER'], + 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD'), 'partman_revoke', + ARRAY['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER'], + 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD'), 'partman_revoke', + ARRAY['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER'], + 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD'), 'partman_revoke', + ARRAY['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER'], + 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD'), 'partman_revoke', + ARRAY['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER'], + 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD')); + + +SELECT is_empty('SELECT * FROM ONLY partman_test.time_taptest_table', 'Check that parent table is empty. Should be impossible for native, but leaving test here just cause.'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table', ARRAY[10], 'Check count from parent table'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD'), + ARRAY[10], 'Check count from time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD')); + +REVOKE INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER ON partman_test.time_taptest_table FROM partman_revoke; +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(11,20), CURRENT_TIMESTAMP + '1 day'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(21,25), CURRENT_TIMESTAMP + '2 days'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(26,30), CURRENT_TIMESTAMP + '3 days'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(31,37), CURRENT_TIMESTAMP + '4 days'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(40,49), CURRENT_TIMESTAMP - '1 day'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(50,70), CURRENT_TIMESTAMP - '2 days'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(71,85), CURRENT_TIMESTAMP - '3 days'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(86,100), CURRENT_TIMESTAMP - '4 days'::interval); + +SELECT is_empty('SELECT * FROM ONLY partman_test.time_taptest_table', 'Check that parent table has had no data inserted to it'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD'), + ARRAY[10], 'Check count from time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD')); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD'), + ARRAY[5], 'Check count from time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD')); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD'), + ARRAY[5], 'Check count from time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD')); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD'), + ARRAY[7], 'Check count from time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD')); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD'), + ARRAY[10], 'Check count from time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD')); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD'), + ARRAY[21], 'Check count from time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD')); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD'), + ARRAY[15], 'Check count from time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD')); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD'), + ARRAY[15], 'Check count from time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD')); + +UPDATE part_config SET premake = 5 WHERE parent_table = 'partman_test.time_taptest_table'; + +-- Run to create proper future partitions +SELECT run_maintenance(); +-- Insert after maintenance since native fails with no child +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(101,122), CURRENT_TIMESTAMP + '5 days'::interval); +-- Run again to create +5 partition now that data exists +SELECT run_maintenance(); + +-- Data exists for +5 days, with 5 premake so +10 day table should exist +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD')||' exists'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD')||' does not exist'); + +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD')); + +SELECT col_is_fk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD'), ARRAY['col2'], + 'Check for foreign key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD')||'.'); +SELECT col_is_fk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD'), ARRAY['col2'], + 'Check for foreign key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD')||'.'); +SELECT col_is_fk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD'), ARRAY['col2'], + 'Check for foreign key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD')||'.'); +SELECT col_is_fk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD'), ARRAY['col2'], + 'Check for foreign key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD')||'.'); +SELECT col_is_fk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD'), ARRAY['col2'], + 'Check for foreign key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD')||'.'); +SELECT col_is_fk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD'), ARRAY['col2'], + 'Check for foreign key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD')||'.'); + + +SELECT is_empty('SELECT * FROM ONLY partman_test.time_taptest_table', 'Check that parent table has had no data inserted to it'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD'), + ARRAY[22], 'Check count from time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD')); + +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD'), 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD'), 'partman_basic', +ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD'), 'partman_basic', +ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD')); + +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD'), 'partman_revoke', + ARRAY['SELECT'], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD')); + +GRANT DELETE ON partman_test.time_taptest_table TO partman_basic; +REVOKE ALL ON partman_test.time_taptest_table FROM partman_revoke; + +ALTER TABLE partman_test.time_taptest_table OWNER TO partman_owner; + +UPDATE part_config SET premake = 6 WHERE parent_table = 'partman_test.time_taptest_table'; +SELECT run_maintenance(); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(123,150), CURRENT_TIMESTAMP + '6 days'::interval); +-- Run again now that +6 data exists +SELECT run_maintenance(); + +SELECT is_empty('SELECT * FROM ONLY partman_test.time_taptest_table', 'Check that parent table has had no data inserted to it'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table', ARRAY[148], 'Check count from parent table'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD'), + ARRAY[28], 'Check count from time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD')); + +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD')||' exists'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'13 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'13 days'::interval, 'YYYYMMDD')||' does not exist'); + +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD')); + +SELECT col_is_fk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD'), ARRAY['col2'], + 'Check for foreign key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD')||'.'); +SELECT col_is_fk('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD'), ARRAY['col2'], + 'Check for foreign key in time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD')||'.'); + + +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD'), 'partman_basic', ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD'), 'partman_revoke', + ARRAY['SELECT'], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD'), 'partman_revoke', + ARRAY['SELECT'], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD'), 'partman_revoke', + ARRAY['SELECT'], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD'), 'partman_revoke', + ARRAY['SELECT'], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD'), 'partman_revoke', + ARRAY['SELECT'], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD'), 'partman_revoke', + ARRAY['SELECT'], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD')); + +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE', 'DELETE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE', 'DELETE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD'), 'partman_revoke', + '{}'::text[], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD'), 'partman_revoke', + '{}'::text[], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD')); + +SELECT table_owner_is ('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD'), 'partman_owner', + 'Check that ownership change worked for time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD')); +SELECT table_owner_is ('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD'), 'partman_owner', + 'Check that ownership change worked for time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD')); + +SELECT reapply_privileges('partman_test.time_taptest_table'); + +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE', 'DELETE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE', 'DELETE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE', 'DELETE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE', 'DELETE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE', 'DELETE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE', 'DELETE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE', 'DELETE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE', 'DELETE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE', 'DELETE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE', 'DELETE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE', 'DELETE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE', 'DELETE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE', 'DELETE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE', 'DELETE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE', 'DELETE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE', 'DELETE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD'), 'partman_basic', + ARRAY['SELECT','INSERT','UPDATE', 'DELETE'], + 'Check partman_basic privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD')); + +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD'), 'partman_revoke', + '{}'::text[], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD'), 'partman_revoke', + '{}'::text[], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD'), 'partman_revoke', + '{}'::text[], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD'), 'partman_revoke', + '{}'::text[], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD'), 'partman_revoke', + '{}'::text[], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD'), 'partman_revoke', + '{}'::text[], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD'), 'partman_revoke', + '{}'::text[], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD'), 'partman_revoke', + '{}'::text[], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD'), 'partman_revoke', + '{}'::text[], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD'), 'partman_revoke', + '{}'::text[], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD'), 'partman_revoke', + '{}'::text[], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD'), 'partman_revoke', + '{}'::text[], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD'), 'partman_revoke', + '{}'::text[], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD'), 'partman_revoke', + '{}'::text[], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD'), 'partman_revoke', + '{}'::text[], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD'), 'partman_revoke', + '{}'::text[], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD')); +SELECT table_privs_are('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD'), 'partman_revoke', + '{}'::text[], 'Check partman_revoke privileges of time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD')); + +SELECT table_owner_is ('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD'), 'partman_owner', + 'Check that ownership change worked for time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD')); +SELECT table_owner_is ('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD'), 'partman_owner', + 'Check that ownership change worked for time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD')); +SELECT table_owner_is ('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD'), 'partman_owner', + 'Check that ownership change worked for time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD')); +SELECT table_owner_is ('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD'), 'partman_owner', + 'Check that ownership change worked for time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD')); +SELECT table_owner_is ('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD'), 'partman_owner', + 'Check that ownership change worked for time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD')); +SELECT table_owner_is ('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD'), 'partman_owner', + 'Check that ownership change worked for time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD')); +SELECT table_owner_is ('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD'), 'partman_owner', + 'Check that ownership change worked for time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD')); +SELECT table_owner_is ('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD'), 'partman_owner', + 'Check that ownership change worked for time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD')); +SELECT table_owner_is ('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD'), 'partman_owner', + 'Check that ownership change worked for time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD')); +SELECT table_owner_is ('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD'), 'partman_owner', + 'Check that ownership change worked for time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD')); +SELECT table_owner_is ('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD'), 'partman_owner', + 'Check that ownership change worked for time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD')); +SELECT table_owner_is ('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD'), 'partman_owner', + 'Check that ownership change worked for time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD')); +SELECT table_owner_is ('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD'), 'partman_owner', + 'Check that ownership change worked for time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD')); +SELECT table_owner_is ('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD'), 'partman_owner', + 'Check that ownership change worked for time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD')); +SELECT table_owner_is ('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD'), 'partman_owner', + 'Check that ownership change worked for time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD')); +SELECT table_owner_is ('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD'), 'partman_owner', + 'Check that ownership change worked for time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD')); +SELECT table_owner_is ('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD'), 'partman_owner', + 'Check that ownership change worked for time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD')); + +-- Test that maintenance will catch up +DO $$ +BEGIN + EXECUTE 'DROP TABLE partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD'); + EXECUTE 'DROP TABLE partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 days'::interval, 'YYYYMMDD'); + EXECUTE 'DROP TABLE partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD'); + EXECUTE 'DROP TABLE partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 days'::interval, 'YYYYMMDD'); + EXECUTE 'DROP TABLE partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD'); + EXECUTE 'DROP TABLE partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD'); + EXECUTE 'DROP TABLE partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD'); + EXECUTE 'DROP TABLE partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD'); + EXECUTE 'DROP TABLE partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD'); + EXECUTE 'DROP TABLE partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD'); + EXECUTE 'DROP TABLE partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD'); + EXECUTE 'DROP TABLE partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD'); + EXECUTE 'DROP TABLE partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD'); + EXECUTE 'DROP TABLE partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD'); + EXECUTE 'DROP TABLE partman_test.time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD'); +END +$$; + +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD')||' does not exist'); + +SELECT run_maintenance(); + +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD')||' does exist'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 days'::interval, 'YYYYMMDD')||' does exist'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD')||' does exist'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 days'::interval, 'YYYYMMDD')||' does exist'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD')||' does exist'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD')||' does exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD')||' does not exist'); + +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(11,20), CURRENT_TIMESTAMP + '1 day'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(21,25), CURRENT_TIMESTAMP + '2 days'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(26,30), CURRENT_TIMESTAMP + '3 days'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(1,10), CURRENT_TIMESTAMP); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(40,49), CURRENT_TIMESTAMP - '1 day'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(50,70), CURRENT_TIMESTAMP - '2 days'::interval); + +SELECT run_maintenance(); + +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD')||' does exist'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD')||' does exist'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD')||' does exist'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD')||' does exist'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD')||' does exist'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD')||' does exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD')||' does not exist'); + + +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(31,37), CURRENT_TIMESTAMP + '4 days'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(101,122), CURRENT_TIMESTAMP + '5 days'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(123,150), CURRENT_TIMESTAMP + '6 days'::interval); + +SELECT run_maintenance(); + +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD')||' does exist'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD')||' does exist'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD')||' does exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'13 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'13 days'::interval, 'YYYYMMDD')||' does not exist'); + +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(200,210), CURRENT_TIMESTAMP + '20 days'::interval); +SELECT results_eq('SELECT count(*)::int FROM ONLY partman_test.time_taptest_table_default', ARRAY[11], 'Check that data child scope goes to default'); + +SELECT drop_partition_time('partman_test.time_taptest_table', '3 days'::interval, p_keep_table := false); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD')||' does not exist'); + +UPDATE part_config SET retention = '2 days'::interval WHERE parent_table = 'partman_test.time_taptest_table'; +SELECT drop_partition_time('partman_test.time_taptest_table', p_retention_schema := 'partman_retention_test'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT has_table('partman_retention_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD')||' got moved to new schema'); + +SELECT undo_partition('partman_test.time_taptest_table', 'partman_test.undo_taptest', 20, p_keep_table := false); +SELECT results_eq('SELECT count(*)::int FROM partman_test.undo_taptest', ARRAY[129], 'Check count from target table after undo'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'8 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'10 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'11 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'12 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD')||' does not exist'); + +SELECT hasnt_table('partman', 'template_partman_test_time_taptest_table', 'Check that template table was dropped'); + +SELECT * FROM finish(); +ROLLBACK; diff --git a/packages/pglite-pg_partman/tests/pgtap/test-time-infinite-no-data.sql b/packages/pglite-pg_partman/tests/pgtap/test-time-infinite-no-data.sql new file mode 100644 index 000000000..a8178aa14 --- /dev/null +++ b/packages/pglite-pg_partman/tests/pgtap/test-time-infinite-no-data.sql @@ -0,0 +1,78 @@ +-- ########## TIME DAILY TESTS ########## +-- Other tests: + -- Test that new child tables are created when infinite_time_partitions is set true even with no data + +\set ON_ERROR_ROLLBACK 1 +\set ON_ERROR_STOP true + +BEGIN; +SELECT set_config('search_path','partman, public',false); + +SELECT plan(20); + +CREATE SCHEMA partman_test; + +CREATE TABLE partman_test.time_taptest_table + (col1 int + , col2 text default 'stuff' + , col3 timestamptz NOT NULL DEFAULT now()) + PARTITION BY RANGE (col3); + +SELECT create_partition('partman_test.time_taptest_table', 'col3', '1 day'); +UPDATE part_config SET infinite_time_partitions = TRUE; + +SELECT is_partitioned('partman_test', 'time_taptest_table', 'Check that time_taptest_table is natively partitioned'); +SELECT has_table('partman', 'template_partman_test_time_taptest_table', 'Check that default template table was created'); + +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD'), 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'1 day'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'2 days'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'3 days'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'4 days'::interval, 'YYYYMMDD')||' exists'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD')||' does not exist'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'1 day'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'2 days'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'3 days'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'4 days'::interval, 'YYYYMMDD')||' exists'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'5 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP-'5 days'::interval, 'YYYYMMDD')||' does not exist'); + +SELECT is_empty('SELECT * FROM partman_test.time_taptest_table_default', 'Check that partition set is empty just in case'); + +UPDATE part_config SET premake = 5 WHERE parent_table = 'partman_test.time_taptest_table'; + +-- Run to create new premake +SELECT run_maintenance(); + +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'5 days'::interval, 'YYYYMMDD')||' exists'); +-- Depending on time of day, with no data, it may round the premade value differently and make 1 additional child table. Check for non-existence 2 days ahead +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD')||' does not exist'); + +SELECT is_empty('SELECT * FROM partman_test.time_taptest_table_default', 'Check that partition set is empty just in case'); + +UPDATE part_config SET premake = 7 WHERE parent_table = 'partman_test.time_taptest_table'; + +-- Run to create new premake +SELECT run_maintenance(); + +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'6 days'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'7 days'::interval, 'YYYYMMDD')||' exists'); +-- Depending on time of day, with no data, it may round the premade value differently and make 1 additional child table. Check for non-existence 2 days ahead +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(CURRENT_TIMESTAMP+'9 days'::interval, 'YYYYMMDD')||' does not exist'); + +SELECT * FROM finish(); +ROLLBACK; diff --git a/packages/pglite-pg_partman/tests/pgtap/test-time-maintenance-order.sql b/packages/pglite-pg_partman/tests/pgtap/test-time-maintenance-order.sql new file mode 100644 index 000000000..6defecd14 --- /dev/null +++ b/packages/pglite-pg_partman/tests/pgtap/test-time-maintenance-order.sql @@ -0,0 +1,53 @@ +-- ########## TIME DAILY TESTS ########## +-- Other tests: + -- Test that maintenance ordering works + -- Ensure that NULLs are last in order + +\set ON_ERROR_ROLLBACK 1 +\set ON_ERROR_STOP true + +BEGIN; +SELECT set_config('search_path','partman, public',false); + +SELECT plan(4); + +CREATE SCHEMA partman_test; + +CREATE TABLE partman_test.time_taptest_table1 + (col1 int + , col2 text default 'stuff' + , col3 timestamptz NOT NULL DEFAULT now()) + PARTITION BY RANGE (col3); + +CREATE TABLE partman_test.time_taptest_table2 + (col1 int + , col2 text default 'stuff' + , col3 timestamptz NOT NULL DEFAULT now()) + PARTITION BY RANGE (col3); + +CREATE TABLE partman_test.time_taptest_table3 + (col1 int + , col2 text default 'stuff' + , col3 timestamptz NOT NULL DEFAULT now()) + PARTITION BY RANGE (col3); + +SELECT create_partition('partman_test.time_taptest_table1', 'col3', '1 day'); +SELECT create_partition('partman_test.time_taptest_table2', 'col3', '1 day'); +SELECT create_partition('partman_test.time_taptest_table3', 'col3', '1 day'); + +SELECT is_partitioned('partman_test', 'time_taptest_table1', 'Check that time_taptest_table1 is natively partitioned'); +SELECT is_partitioned('partman_test', 'time_taptest_table2', 'Check that time_taptest_table2 is natively partitioned'); +SELECT is_partitioned('partman_test', 'time_taptest_table3', 'Check that time_taptest_table3 is natively partitioned'); + +UPDATE part_config SET maintenance_order = 1 WHERE parent_table = 'partman_test.time_taptest_table1'; +UPDATE part_config SET maintenance_order = 2 WHERE parent_table = 'partman_test.time_taptest_table2'; + +SELECT run_maintenance(); + +SELECT results_eq( + 'SELECT parent_table FROM partman.part_config WHERE parent_table IN (''partman_test.time_taptest_table1'',''partman_test.time_taptest_table2'',''partman_test.time_taptest_table3'') ORDER BY maintenance_last_run ASC', + 'SELECT parent_table FROM partman.part_config WHERE parent_table IN (''partman_test.time_taptest_table1'',''partman_test.time_taptest_table2'',''partman_test.time_taptest_table3'') ORDER BY parent_table ASC', + 'Check that maintenance ran in order'); + +SELECT * FROM finish(); +ROLLBACK; diff --git a/packages/pglite-pg_partman/tests/pgtap/test-time-monthly-infinity.sql b/packages/pglite-pg_partman/tests/pgtap/test-time-monthly-infinity.sql new file mode 100644 index 000000000..54c67c97d --- /dev/null +++ b/packages/pglite-pg_partman/tests/pgtap/test-time-monthly-infinity.sql @@ -0,0 +1,73 @@ +-- ########## TIME MONTHLY ########## +-- Other tests: + -- Ignoring infinity values in default + +\set ON_ERROR_ROLLBACK 1 +\set ON_ERROR_STOP true + +BEGIN; +SELECT set_config('search_path','partman, public',false); + +SELECT plan(17); +CREATE SCHEMA partman_test; + +CREATE TABLE partman_test.time_taptest_table + (col1 int + , col2 text + , col3 timestamptz DEFAULT now() NOT NULL) + PARTITION BY RANGE (col3); +CREATE TABLE partman_test.undo_taptest (LIKE partman_test.time_taptest_table INCLUDING ALL); + +CREATE INDEX ON partman_test.time_taptest_table (col3); + +SELECT create_partition('partman_test.time_taptest_table', 'col3', '1 month'); + +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(1,10), CURRENT_TIMESTAMP); + +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD'), 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'1 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'1 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'2 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'2 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'3 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'3 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'4 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'4 month'::interval, 'YYYYMMDD')||' exists'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'5 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'5 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'1 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'1 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'2 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'2 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'3 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'3 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'4 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'4 month'::interval, 'YYYYMMDD')||' exists'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'5 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'5 month'::interval, 'YYYYMMDD')||' does not exist'); + + + +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(11,20), 'infinity'); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(21,30), '-infinity'); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(31,40), CURRENT_TIMESTAMP + '12 month'::interval); + +SELECT run_maintenance(); + + +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD'), + ARRAY[10], 'Check count from time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD')); + +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_default', + ARRAY[30], 'Check infinity count from time_taptest_table_default'); + +SELECT results_eq('SELECT partition_data_time(''partman_test.time_taptest_table''::text, p_batch_count := 10, p_ignore_infinity := true)::int', ARRAY[10], 'Check that partition_data_time with ignore infinity true returns only 10.'); + +SELECT results_eq('SELECT partition_data_time(''partman_test.time_taptest_table''::text, p_batch_count := 10, p_ignore_infinity := true)::int', ARRAY[0], 'Check that partition_data_time with ignore infinity true returns only 0.'); + +SELECT results_eq('SELECT count::int FROM partman.check_default() WHERE default_table = ''partman_test.time_taptest_table_default''', ARRAY[20], 'Ensure that check_default with infinite false returns expected value of 20'); + +SELECT is_empty('SELECT count::int FROM partman.check_default(p_ignore_infinity := true) WHERE default_table = ''partman_test.time_taptest_table_default''', 'Ensure that check_default with infinite false returns NULL'); + +SELECT * FROM finish(); +ROLLBACK; diff --git a/packages/pglite-pg_partman/tests/pgtap/test-time-monthly.sql b/packages/pglite-pg_partman/tests/pgtap/test-time-monthly.sql new file mode 100644 index 000000000..a6dbbae0b --- /dev/null +++ b/packages/pglite-pg_partman/tests/pgtap/test-time-monthly.sql @@ -0,0 +1,307 @@ +-- ########## TIME MONTHLY ########## +-- Other tests: + -- Ensure partitions that would be dropped by retention are not created during maintenance + +\set ON_ERROR_ROLLBACK 1 +\set ON_ERROR_STOP true + +BEGIN; +SELECT set_config('search_path','partman, public',false); + +SELECT plan(121); +CREATE SCHEMA partman_test; +CREATE SCHEMA partman_retention_test; + +CREATE TABLE partman_test.time_taptest_table + (col1 int + , col2 text + , col3 timestamptz DEFAULT now() NOT NULL) + PARTITION BY RANGE (col3); +CREATE TABLE partman_test.time_taptest_table_template (LIKE partman_test.time_taptest_table INCLUDING ALL); +ALTER TABLE partman_test.time_taptest_table_template ADD PRIMARY KEY (col1); +CREATE TABLE partman_test.undo_taptest (LIKE partman_test.time_taptest_table INCLUDING ALL); + +CREATE INDEX ON partman_test.time_taptest_table (col3); + +SELECT create_partition('partman_test.time_taptest_table', 'col3', '1 month', p_template_table => 'partman_test.time_taptest_table_template', p_start_partition := date_trunc('month', (CURRENT_TIMESTAMP-'12 months'::interval))::text ); + +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(1,10), CURRENT_TIMESTAMP); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(1,10), CURRENT_TIMESTAMP-'12 month'::interval); + +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD'), 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'1 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'1 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'2 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'2 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'3 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'3 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'4 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'4 month'::interval, 'YYYYMMDD')||' exists'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'5 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'5 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'1 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'1 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'2 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'2 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'3 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'3 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'4 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'4 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'11 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'11 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'12 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'12 month'::interval, 'YYYYMMDD')||' exists'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'13 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'13 month'::interval, 'YYYYMMDD')||' does not exist'); + +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'1 month'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'1 month'::interval, 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'2 month'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'2 month'::interval, 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'3 month'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'3 month'::interval, 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'4 month'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'4 month'::interval, 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'1 month'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'1 month'::interval, 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'2 month'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'2 month'::interval, 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'3 month'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'3 month'::interval, 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'4 month'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'4 month'::interval, 'YYYYMMDD')); + +-- Tests to ensure that old tables are not recreated if they would be included in the retention period + +UPDATE part_config SET retention = '5 months', infinite_time_partitions = true, retention_keep_table = false WHERE parent_table = 'partman_test.time_taptest_table'; + +SELECT lives_ok('DROP TABLE partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'11 month'::interval, 'YYYYMMDD'), 'Drop table time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'11 month'::interval, 'YYYYMMDD') ); +SELECT lives_ok('DROP TABLE partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'10 month'::interval, 'YYYYMMDD'), 'Drop table time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'10 month'::interval, 'YYYYMMDD') ); +SELECT lives_ok('DROP TABLE partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'9 month'::interval, 'YYYYMMDD'), 'Drop table time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'9 month'::interval, 'YYYYMMDD') ); +SELECT lives_ok('DROP TABLE partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'8 month'::interval, 'YYYYMMDD'), 'Drop table time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'8 month'::interval, 'YYYYMMDD') ); +SELECT lives_ok('DROP TABLE partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'7 month'::interval, 'YYYYMMDD'), 'Drop table time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'7 month'::interval, 'YYYYMMDD') ); +SELECT lives_ok('DROP TABLE partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'6 month'::interval, 'YYYYMMDD'), 'Drop table time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'6 month'::interval, 'YYYYMMDD') ); +SELECT lives_ok('DROP TABLE partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'5 month'::interval, 'YYYYMMDD'), 'Drop table time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'5 month'::interval, 'YYYYMMDD') ); +SELECT lives_ok('DROP TABLE partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'4 month'::interval, 'YYYYMMDD'), 'Drop table time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'4 month'::interval, 'YYYYMMDD') ); +SELECT lives_ok('DROP TABLE partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'3 month'::interval, 'YYYYMMDD'), 'Drop table time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'3 month'::interval, 'YYYYMMDD') ); +SELECT lives_ok('DROP TABLE partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'2 month'::interval, 'YYYYMMDD'), 'Drop table time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'2 month'::interval, 'YYYYMMDD') ); +SELECT lives_ok('DROP TABLE partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'1 month'::interval, 'YYYYMMDD'), 'Drop table time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'1 month'::interval, 'YYYYMMDD') ); +SELECT lives_ok('DROP TABLE partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD'), 'Drop table time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD') ); +SELECT lives_ok('DROP TABLE partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'1 month'::interval, 'YYYYMMDD'), 'Drop table time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'1 month'::interval, 'YYYYMMDD') ); +SELECT lives_ok('DROP TABLE partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'2 month'::interval, 'YYYYMMDD'), 'Drop table time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'2 month'::interval, 'YYYYMMDD') ); +SELECT lives_ok('DROP TABLE partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'3 month'::interval, 'YYYYMMDD'), 'Drop table time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'3 month'::interval, 'YYYYMMDD') ); +SELECT lives_ok('DROP TABLE partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'4 month'::interval, 'YYYYMMDD'), 'Drop table time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'4 month'::interval, 'YYYYMMDD') ); + +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'12 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'12 month'::interval, 'YYYYMMDD')||' still exists'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'11 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'11 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'10 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'10 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'9 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'9 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'8 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'8 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'7 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'7 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'6 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'6 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'5 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'5 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'4 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'4 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'3 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'3 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'2 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'2 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'1 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'1 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'1 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'1 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'2 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'2 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'3 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'3 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'4 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'4 month'::interval, 'YYYYMMDD')||' does not exist'); + +SELECT run_maintenance(); + +-- Tables older than months should not have been created, 12 month old table should have been dropped and default premade tables should have been remade +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'12 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'12 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'11 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'11 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'10 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'10 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'9 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'9 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'8 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'8 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'7 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'7 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'6 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'6 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'5 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'5 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'4 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'4 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'3 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'3 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'2 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'2 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'1 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'1 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD'), 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'1 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'1 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'2 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'2 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'3 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'3 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'4 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'4 month'::interval, 'YYYYMMDD')||' exists'); +-- For some reason, edge case of re-creating child tables sometimes goes one beyond premake. Investigate when time. Should not create one 2 beyond premake +--SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'5 month'::interval, 'YYYYMMDD'), +-- 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'5 month'::interval, 'YYYYMMDD')||' exists'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'6 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'6 month'::interval, 'YYYYMMDD')||' does not exist'); + +-- Reinsert original data +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(1,10), CURRENT_TIMESTAMP); + +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD'), + ARRAY[10], 'Check count from time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD')); + +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(11,20), CURRENT_TIMESTAMP + '1 month'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(21,25), CURRENT_TIMESTAMP + '2 month'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(26,30), CURRENT_TIMESTAMP + '3 month'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(31,37), CURRENT_TIMESTAMP + '4 month'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(40,49), CURRENT_TIMESTAMP - '1 month'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(50,70), CURRENT_TIMESTAMP - '2 month'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(71,85), CURRENT_TIMESTAMP - '3 month'::interval); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(86,100), CURRENT_TIMESTAMP - '4 month'::interval); + +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'1 month'::interval, 'YYYYMMDD'), + ARRAY[10], 'Check count from time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'1 month'::interval, 'YYYYMMDD')); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'2 month'::interval, 'YYYYMMDD'), + ARRAY[5], 'Check count from time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'2 month'::interval, 'YYYYMMDD')); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'3 month'::interval, 'YYYYMMDD'), + ARRAY[5], 'Check count from time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'3 month'::interval, 'YYYYMMDD')); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'4 month'::interval, 'YYYYMMDD'), + ARRAY[7], 'Check count from time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'4 month'::interval, 'YYYYMMDD')); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'1 month'::interval, 'YYYYMMDD'), + ARRAY[10], 'Check count from time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'1 month'::interval, 'YYYYMMDD')); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'2 month'::interval, 'YYYYMMDD'), + ARRAY[21], 'Check count from time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'2 month'::interval, 'YYYYMMDD')); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'3 month'::interval, 'YYYYMMDD'), + ARRAY[15], 'Check count from time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'3 month'::interval, 'YYYYMMDD')); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'4 month'::interval, 'YYYYMMDD'), + ARRAY[15], 'Check count from time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'4 month'::interval, 'YYYYMMDD')); + +UPDATE part_config SET premake = 5 WHERE parent_table = 'partman_test.time_taptest_table'; +SELECT run_maintenance(); + +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(101,122), CURRENT_TIMESTAMP + '5 month'::interval); + +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'5 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'5 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'6 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'6 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'7 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'7 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'8 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'8 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'9 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'9 month'::interval, 'YYYYMMDD')||' exists'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'10 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'10 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'5 month'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'5 month'::interval, 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'6 month'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'6 month'::interval, 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'7 month'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'7 month'::interval, 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'8 month'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'8 month'::interval, 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'9 month'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'9 month'::interval, 'YYYYMMDD')); + +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'5 month'::interval, 'YYYYMMDD'), + ARRAY[22], 'Check count from time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'5 month'::interval, 'YYYYMMDD')); + +UPDATE part_config SET premake = 6 WHERE parent_table = 'partman_test.time_taptest_table'; +SELECT run_maintenance(); +INSERT INTO partman_test.time_taptest_table (col1, col3) VALUES (generate_series(123,150), CURRENT_TIMESTAMP + '6 month'::interval); + +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table', ARRAY[148], 'Check count from parent table'); +SELECT results_eq('SELECT count(*)::int FROM partman_test.time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'6 month'::interval, 'YYYYMMDD'), + ARRAY[28], 'Check count from time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'6 month'::interval, 'YYYYMMDD')); + +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'10 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'10 month'::interval, 'YYYYMMDD')||' exists'); +SELECT has_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'11 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'11 month'::interval, 'YYYYMMDD')||' exists'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'12 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'12 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'10 month'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'10 month'::interval, 'YYYYMMDD')); +SELECT col_is_pk('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'11 month'::interval, 'YYYYMMDD'), ARRAY['col1'], + 'Check for primary key in time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'11 month'::interval, 'YYYYMMDD')); + + + + +SELECT drop_partition_time('partman_test.time_taptest_table', '3 month', p_keep_table := false); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'4 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'4 month'::interval, 'YYYYMMDD')||' does not exist'); + +UPDATE part_config SET retention = '2 month'::interval WHERE parent_table = 'partman_test.time_taptest_table'; +SELECT drop_partition_time('partman_test.time_taptest_table', p_retention_schema := 'partman_retention_test'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'3 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'3 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT has_table('partman_retention_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'3 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'3 month'::interval, 'YYYYMMDD')||' got moved to new schema'); + +SELECT undo_partition('partman_test.time_taptest_table', p_loop_count => 20, p_target_table := 'partman_test.undo_taptest', p_keep_table := false); +SELECT results_eq('SELECT count(*)::int FROM partman_test.undo_taptest', ARRAY[118], 'Check count from target table after undo'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP), 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'1 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'1 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'2 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)-'2 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'1 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'1 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'2 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'2 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'3 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'3 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'4 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'4 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'5 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'5 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'6 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'6 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'7 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'7 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'8 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'8 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'9 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'9 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'10 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'10 month'::interval, 'YYYYMMDD')||' does not exist'); +SELECT hasnt_table('partman_test', 'time_taptest_table_p'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'11 month'::interval, 'YYYYMMDD'), + 'Check time_taptest_table_'||to_char(date_trunc('month', CURRENT_TIMESTAMP)+'11 month'::interval, 'YYYYMMDD')||' does not exist'); + + +SELECT hasnt_table('partman_test', 'time_taptest_table_template', 'Check that template table was dropped'); + +SELECT * FROM finish(); +ROLLBACK; diff --git a/packages/pglite-pg_partman/tsconfig.json b/packages/pglite-pg_partman/tsconfig.json new file mode 100644 index 000000000..27611a8fd --- /dev/null +++ b/packages/pglite-pg_partman/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "types": ["node"] + }, + "include": ["src", "tsup.config.ts", "vitest.config.ts"] +} \ No newline at end of file diff --git a/packages/pglite-pg_partman/tsup.config.ts b/packages/pglite-pg_partman/tsup.config.ts new file mode 100644 index 000000000..cf946c789 --- /dev/null +++ b/packages/pglite-pg_partman/tsup.config.ts @@ -0,0 +1,28 @@ +import { cpSync } from 'fs' +import { resolve } from 'path' +import { defineConfig } from 'tsup' + +const entryPoints = ['src/index.ts'] + +const minify = process.env.DEBUG === 'true' ? false : true + +export default defineConfig([ + { + entry: entryPoints, + sourcemap: true, + dts: { + entry: entryPoints, + resolve: true, + }, + clean: true, + minify: minify, + shims: true, + format: ['esm', 'cjs'], + onSuccess: async () => { + cpSync( + resolve('release/pg_partman.tar.gz'), + resolve('dist/pg_partman.tar.gz'), + ) + }, + }, +]) diff --git a/packages/pglite-pg_partman/vitest.config.ts b/packages/pglite-pg_partman/vitest.config.ts new file mode 100644 index 000000000..378f02808 --- /dev/null +++ b/packages/pglite-pg_partman/vitest.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + testTimeout: 30000, + }, +}) \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5873937f0..d95a9c97f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -56,6 +56,9 @@ importers: '@electric-sql/pglite-pg_ivm': specifier: workspace:* version: link:../packages/pglite-pg_ivm + '@electric-sql/pglite-pg_partman': + specifier: workspace:* + version: link:../packages/pglite-pg_partman '@electric-sql/pglite-pg_textsearch': specifier: workspace:* version: link:../packages/pglite-pg_textsearch @@ -313,6 +316,27 @@ importers: specifier: ^2.1.2 version: 2.1.2(@types/node@20.16.11)(jsdom@24.1.3)(terser@5.34.1) + packages/pglite-pg_partman: + devDependencies: + '@arethetypeswrong/cli': + specifier: ^0.18.1 + version: 0.18.1 + '@electric-sql/pglite': + specifier: workspace:* + version: link:../pglite + '@electric-sql/pglite-pgtap': + specifier: workspace:* + version: link:../pglite-pgtap + '@electric-sql/pglite-utils': + specifier: workspace:* + version: link:../pglite-utils + '@types/node': + specifier: ^20.16.11 + version: 20.16.11 + vitest: + specifier: ^2.1.2 + version: 2.1.2(@types/node@20.16.11)(jsdom@24.1.3)(terser@5.34.1) + packages/pglite-pg_textsearch: devDependencies: '@arethetypeswrong/cli':