• Stars
    star
    429
  • Rank 101,271 (Top 2 %)
  • Language PLpgSQL
  • License
    Other
  • Created over 7 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Postgresql temporal_tables extension in PL/pgSQL, without the need for external c extension.

Temporal Tables

This is an attempt to rewrite the postgresql temporal_tables extension in PL/pgSQL, without the need for external c extension.

The goal is to be able to use it on AWS RDS and other hosted solutions, where using custom extensions or c functions is not an option.

The version provided in versioning_function.sql is a drop-in replacement.

It works exactly the same way, but lacks the set_system_time function to work with the current time.

The version in versioning_function_nochecks.sql is similar to the previous one, but all validation checks have been removed. This version is 2x faster than the normal one, but more dangerous and prone to errors.

With time, added some new functionality diverging from the original implementations. New functionalities are however still retro-compatible:

Usage

Create a database and the versioning function:

createdb temporal_test
psql temporal_test < versioning_function.sql

Connect to the db:

psql temporal_test

Create the table to version, in this example it will be a "subscription" table:

CREATE TABLE subscriptions
(
  name text NOT NULL,
  state text NOT NULL
);

Add the system period column:

ALTER TABLE subscriptions
  ADD COLUMN sys_period tstzrange NOT NULL DEFAULT tstzrange(current_timestamp, null);

Create the history table:

CREATE TABLE subscriptions_history (LIKE subscriptions);

Finally, create the trigger:

CREATE TRIGGER versioning_trigger
BEFORE INSERT OR UPDATE OR DELETE ON subscriptions
FOR EACH ROW EXECUTE PROCEDURE versioning(
  'sys_period', 'subscriptions_history', true
);

A note on the history table name. Previous versions of this extension quoted and escaped it before usage. Starting version 0.4.0 we are not escaping it anymore and users need to provide the escaped version as a parameter to the trigger.

This is consistent with the c version, simplifies the extension code and fixes an issue with upper case names that weren't properly supported.

Now test with some data:

INSERT INTO subscriptions (name, state) VALUES ('test1', 'inserted');
UPDATE subscriptions SET state = 'updated' WHERE name = 'test1';
UPDATE subscriptions SET state = 'updated twice' WHERE name = 'test1';
DELETE FROM subscriptions WHERE name = 'test1';

Take some time between a query and the following, otherwise the difference in the time periods won't be noticeable.

After all the query are completed, you should check the tables content.

SELECT * FROM subscriptions;

Should return 0 rows

SELECT * FROM subscriptions_history

Should return something similar to:

name state sys_period
test1 inserted ["2017-08-01 16:09:45.542983+02","2017-08-01 16:09:54.984179+02")
test1 updated ["2017-08-01 16:09:54.984179+02","2017-08-01 16:10:08.880571+02")
test1 updated twice ["2017-08-01 16:10:08.880571+02","2017-08-01 16:10:17.33659+02")

Additional features

Ignore updates without actual change

NOTE: This feature does not work for tables with columns with types that does not support equality operator (e.g. PostGIS types, JSON types, etc.).

By default this extension creates a record in the history table for every update that occurs in the versioned table, regardless of any change actually happening.

We added a fourth paramater to the trigger to change this behaviour and only record updates that result in an actual change.

It is worth mentioning that before making the change, a check is performed on the source table against the history table, in such a way that if the history table has only a subset of the columns of the source table, and you are performing an update in a column that is not present in this subset (this means the column does not exist in the history table), this extension will NOT add a new record to the history. Then you can have columns in the source table that create no new versions if modified by not including those columns in the history table.

The paramater is set by default to false, set it to true to stop tracking updates without actual changes:

CREATE TRIGGER versioning_trigger
BEFORE INSERT OR UPDATE OR DELETE ON subscriptions
FOR EACH ROW EXECUTE PROCEDURE versioning(
  'sys_period', 'subscriptions_history', true, true
);

Migrations

During the life of an application is may be necessary to change the schema of a table. In order for temporal_tables to continue to work properly the same migrations should be applied to the history table as well.

What happens if a column is added to the original table but not to the history table?

The new column will be ignored, meaning that the updated row is transferred to the history table, but without the value of the new column. This means that you will lose that specific data.

There are valid use cases for this, for example when you are not interested in storing the historic values of that column.

Beware that temporal_tables won't raise an error

What should I do if I need to remove a column from the original table but want to keep the historic values for it?

You remove the column in the original table, but keep it in the history table - provided it accepts null values.

From that point on the old column in the history table will be ignored and will get null values.

If the column doesn't accept null values you'll need to modify it to allow for null values, otherwise temporal_tables won't be able to create new rows and all operations on the original table will fail

Test

In order to run tests:

make run_test

The test suite will run the queries in test/sql and store the output in test/result, and will then diff the output from test/result with the prerecorded output in test/expected.

A test suite is also available for the nochecks alternative:

make run_test_nochecks

Obviously, this suite won't run the tests about the error reporting.

Performance tests

For performance tests run:

make performance_test

This will create the temporal_tables_test database, add all necessary tables, run test tests and drop the database.

Is it also possible to test against the nochecks version:

make performance_test_nochecks

or the original c extension run:

make performance_test_original

This required the original extentions to be installed, but will automatically add it to the database.

On the test machine (my laptop) the complete version is 2x slower than the nochecks versions and 16x slower than the original version.

Two comments about those results:

  • original c version makes some use of caching (i.e to share an execution plan), whilst this version doesn't. This is propably accounting for a good chunk of the performance difference. At the moment there's not plan of implementing such caching in this version.
  • The trigger still executes in under 1ms and in production environments the the network latency should be more relevant than the trigger itself.

The team

Paolo Chiodi

https://github.com/paolochiodi

https://twitter.com/paolochiodi

Acknowledgements

This project was kindly sponsored by nearForm.

License

Licensed under MIT.

The test scenarios in test/sql and test/expected have been copied over from the original temporal_tables extension, whose license is BSD 2-clause

More Repositories

1

graphql-hooks

🎣 Minimal hooks-first GraphQL client
TypeScript
1,878
star
2

fast-jwt

Fast JSON Web Token implementation
JavaScript
330
star
3

nscale

Deployment just got easy
JavaScript
325
star
4

react-animation

Animation components and styles for React projects
JavaScript
285
star
5

sql

SQL injection protection module
JavaScript
201
star
6

react-browser-hooks

React Browser Hooks
JavaScript
128
star
7

udaru

Open source Access Manager for node.js
JavaScript
125
star
8

node-cephes

Implementation of special functions and distributions mathematical functions from the cephes library.
C
115
star
9

the-fastify-workshop

A workshop about Fastify
JavaScript
113
star
10

gammaray

Node.js vulnerability scanner
Go
104
star
11

autopsy

dissect your dead node services with mdb via a smart os vm
JavaScript
89
star
12

fastify-auth0-verify

Auth0 verification plugin for Fastify
JavaScript
87
star
13

titus

Deploy useful features in sprint one
JavaScript
61
star
14

micro-services-tutorial-iot

An instructor led microservices workshop
JavaScript
54
star
15

developing-microservices

A workshop on microservices in nodejs
JavaScript
54
star
16

heap-profiler

Heap dump and sample profiler generator for Node.
JavaScript
52
star
17

docker-cloudwatch

Docker Cloudwatch
JavaScript
46
star
18

promises-workshop

Broken Promises Exercises
HTML
45
star
19

polaris

NearForm multi-platform application accelerator
JavaScript
35
star
20

nscale-workshop

Nodeconf.eu nscale workshop
35
star
21

well

well
JavaScript
35
star
22

nceubadge

The NodeConf EU 2017 Badge
HTML
34
star
23

owasp-top-ten-workshop

NearForm OWASP Top Ten Security Vulnerabilities Workshop
JavaScript
34
star
24

graphql-auto-federate

Automatically federate a Mercurius GraphQL service
JavaScript
32
star
25

trail

Audit trail log service
JavaScript
32
star
26

slow-rest-api

A REST API that is slow
HTML
31
star
27

stats

📊 Collect stats about your node.js process 📊
JavaScript
29
star
28

node-hidden-markov-model-tf

A trainable Hidden Markov Model with Gaussian emissions using TensorFlow.js
JavaScript
28
star
29

autocannon-ui

A graphical user interface for autocannon providing the same user experience
JavaScript
28
star
30

react-pwa

Hackernews Progressive Web Application built with React
JavaScript
28
star
31

open-banking-reference-app

NearForm reference application for open banking - https://community.nearform.com/api-banking
TypeScript
27
star
32

react-redux-typescript-saga-immutable

Sample React boilerplate written in TypeScript, including React Router, Redux, Redux Saga, ImmutableJS and Styled Components.
TypeScript
27
star
33

fastify-overview-ui

UI for fastify-overview
JavaScript
26
star
34

minishift-demo

Demo for local development using minishift
Shell
25
star
35

reviewbot

A bot to assist with code reviews via AI
JavaScript
25
star
36

get-jwks

Fetch utils for JWKS keys
JavaScript
23
star
37

sharing-components

JavaScript
23
star
38

tf-modules-example

Code example for the reusable, configurable Terraform modules blog post
HCL
22
star
39

aws-proxy-pattern

Terraform module to create a transparent proxy within AWS
HCL
20
star
40

openapi-transformer-toolkit

Automate design-first API workflows by generating schemas and types from OpenAPI specs.
TypeScript
20
star
41

fastify-casbin

A plugin for Fastify that adds support for Casbin
JavaScript
19
star
42

the-graphql-workshop

A workshop about GraphQL with mercurius
JavaScript
18
star
43

choo-pwa

PWA with Choo
JavaScript
17
star
44

no-gres

A small module to mock pg for testing purposes.
JavaScript
17
star
45

nscale-docs

Documentation for nscale
17
star
46

optic

App for generating OTP tokens for 2FA protected accounts
JavaScript
17
star
47

initium-platform

A set of Kubernetes add-ons with optimal configuration and test coverage to create a day zero platform for your code
Go
16
star
48

optic-release-automation-action

Automate the release process of your npm modules, apps and actions
JavaScript
15
star
49

brokeneck

Admin UI for Auth0, Azure AD and AWS Cognito
JavaScript
15
star
50

node-test-runner-workshop

The Node.js Test Runner Workshop
JavaScript
14
star
51

graphql-hooks-workshop

HTML
14
star
52

react-patterns-workshop

A workshop which covers intermediate and advanced React usage patterns
JavaScript
14
star
53

node-test-github-reporter

A GitHub test reporter for the Node.js test runner
JavaScript
14
star
54

mira

The Mira Accelerator fast-tracks the setup of common Amazon Web Services (AWS) Serverless infrastructure
TypeScript
13
star
55

react-native-apple-wallet-demo

Create Custom Apple Wallet Passes with React Native and Fastify
JavaScript
13
star
56

langchain-google-calendar

A spike project: allows natural language to create actions in Google Calendar
TypeScript
12
star
57

fastify-casbin-rest

A plugin for Fastify that adds support for Casbin's REST model
JavaScript
12
star
58

cloudwatchlogs-stream

Stream interfacet to CloudWatch Logs
JavaScript
11
star
59

mercurius-apollo-registry

A Mercurius plugin for schema reporting to Apollo Studio
JavaScript
11
star
60

leaistic

An ElasticSearch manager
JavaScript
11
star
61

stats-to-elasticsearch

Collect and send stats about your node.js process to elasticsearch. 📊🔌📈
JavaScript
10
star
62

nceubadge2018

NodeConf EU 2018 Badge code and hardware design files
JavaScript
10
star
63

openshift-kafka

Run Apache Kafka in Openshift Origin
Smarty
10
star
64

create-stats-dashboard

📈 A wrapper to create and initialise a stats dashboard on kibana using import-kibana-dashboard, for easy manipulation of stats sent via stats-to-elasticsearch 📉
JavaScript
10
star
65

fastify-mssql

MSSQL Plugin for Fastify
JavaScript
10
star
66

mercurius-explain

A Mercurius plugin that shows the execution time of each resolver in a query
JavaScript
10
star
67

the-micro-frontends-workshop

The Micro Frontends Workshop with Module Federation
JavaScript
9
star
68

commentami

A 'google docs' like commenting system
JavaScript
9
star
69

zoom-shuffle-bot

Zoom Chatbot used to retrieve a randomized list of your current meeting's participants
JavaScript
9
star
70

jsnation-node-workshop

Our workshop at JSNation 2019
JavaScript
9
star
71

optic-expo

Secure 2FA OTP via Mobile Push Notifications
TypeScript
8
star
72

choo-data

Simple data fetching plugin for Choo with server-side rendering support
JavaScript
8
star
73

nodeconfeu-gesture-models

Ongoing attempts at gesture models
C++
8
star
74

slack-knowledgebase-chatgpt-responder

ChatGPT powered slack responder to the questions that are about NearForm knowledge base
JavaScript
8
star
75

initium

Deploy your code on day zero, avoiding vendor lock-in.
7
star
76

playwright-firebase

A plugin to handle Firebase authentication in Playwright tests
TypeScript
7
star
77

docker-container

JavaScript
7
star
78

otlp-blueprint

Open Telemetry + Jaeger + 3-tier application Blueprint
HCL
7
star
79

pwa-poc

PWA for proof of concept for sharing images, qrcode scanning and geolocation from a PWA
JavaScript
7
star
80

slidev-theme-nearform

NearForm theme for sli.dev presentations
CSS
6
star
81

saluki

Utility based CSS-in-JS theming
JavaScript
6
star
82

fastify-secrets-aws

Fastify secrets plugin for AWS Secrets Manager
JavaScript
6
star
83

fastify-cloud-run

Fastify on Google Cloud Run
JavaScript
6
star
84

iot-system

A fuge config for a demo iot system
JavaScript
6
star
85

fastify-slow-down

A slow down plugin for fastify
JavaScript
6
star
86

github-action-check-linked-issues

GitHub action to check if pull requests have their corresponding issues.
JavaScript
6
star
87

github-board-slack-notifications

Send notifications to a Slack channel for any changes that are performed in a GitHub board (Projects v2 / beta)
JavaScript
6
star
88

openshift-ansible

Ansible code for openshift
Python
5
star
89

fastify-jwt-jwks

JSON Web Key Set (JWKS) verification plugin for Fastify
JavaScript
5
star
90

memleak-exercise

JavaScript
5
star
91

github-action-notify-release

GitHub Action that automatically creates an issue with an overview of the commits that are waiting to be released
JavaScript
5
star
92

fastify-ravendb

Fastify RavenDB connection plugin
JavaScript
5
star
93

fastify-secrets-azure

Fastify secrets plugin for Azure Key Vault
JavaScript
5
star
94

anger

pub-sub tester for Nes
JavaScript
5
star
95

choo-bundles

Bundle splitting with HTTP2 push support for Choo with choo-ssr
JavaScript
5
star
96

sentinel

Sentinel - a testing & monitoring application
JavaScript
5
star
97

mercurius-explain-graphiql-plugin

A Graphiql plugin to show the results from mercurius-explain
JavaScript
5
star
98

azure-workshop

Azure Workshop on Kubernetes
JavaScript
5
star
99

webinar-streams

Examples for the streams Webinar
JavaScript
4
star
100

initium-cli

CLI tool for the Initium project
Go
4
star