pax_global_header00006660000000000000000000000064123522676120014520gustar00rootroot0000000000000052 comment=3f1b09248e5729bcde23b7d3ce6f3599410eac89 preprepare-0.7/000077500000000000000000000000001235226761200135335ustar00rootroot00000000000000preprepare-0.7/.gitignore000066400000000000000000000000701235226761200155200ustar00rootroot00000000000000pre_prepare--0.4.sql pre_prepare.o pre_prepare.so .deps preprepare-0.7/Makefile000066400000000000000000000022421235226761200151730ustar00rootroot00000000000000EXTENSION = pre_prepare MODULES = pre_prepare DATA = pre_prepare--0.4.sql pre_prepare--unpackaged--0.4.sql DATA_built = pre_prepare--0.4.sql # use extenstion in 9.1+ SETUPSQL = $(shell $(PG_CONFIG) --version | grep -qE " 8\.| 9\.0" && echo create_module || echo create_extension) REGRESS = $(SETUPSQL) pre_prepare PG_CONFIG = pg_config PGXS = $(shell $(PG_CONFIG) --pgxs) include $(PGXS) SRC = . TARGET = ./build BUILDDIR = /tmp/preprepare ORIG = preprepare.orig DEBIAN = debian PACKAGE = postgresql-?.?-preprepare SOURCE = preprepare README.html: README.asciidoc asciidoc -a toc README.asciidoc pre_prepare--0.4.sql: pre_prepare.sql cp $< $@ unsign-deb: prepare cd $(BUILDDIR)/$(SOURCE) && debuild -us -uc cp $(BUILDDIR)/$(PACKAGE)_* $(TARGET) cp $(BUILDDIR)/$(SOURCE)_* $(TARGET) deb: prepare cd $(BUILDDIR)/$(SOURCE) && debuild cp $(BUILDDIR)/$(PACKAGE)_* $(TARGET) cp $(BUILDDIR)/$(SOURCE)_* $(TARGET) prepare: -test -d $(BUILDDIR) && rm -rf $(BUILDDIR) mkdir -p $(BUILDDIR)/$(SOURCE) rsync -Ca --exclude $(DEBIAN) $(SRC)/* $(BUILDDIR)/$(SOURCE) rsync -Ca $(BUILDDIR)/$(SOURCE)/ $(BUILDDIR)/$(ORIG)/ rsync -Ca $(DEBIAN) $(BUILDDIR)/$(SOURCE) preprepare-0.7/README.asciidoc000066400000000000000000000076251235226761200162020ustar00rootroot00000000000000= pre_prepare == Ideas The +pre_prepare+ module aims to prepare all your statements as soon as possible and in a way that allows client queries not to bother at all and just call +EXECUTE+. == Setup === compile and install The module is using the PG_XS build infrastructure, so just: make make install psql -f `pg_config --sharedir`/contrib/pre_prepare.sql -U user dbname Depending on the way you got PostgreSQL installed in the first place, you may need to use sudo for the +make install+ step. === postgresql.conf Add a custom class then the following settings: custom_variable_classes = 'preprepare' preprepare.relation = 'preprepare.statements' The +pre_prepare.relation+ is the name of the table where you'll put all the statements you want to module to prepare. The following SQL query against the given relation must return the names and SQL statements to be prepared. SELECT name, statement FROM ; The statements won't be edited, so must be the all PREPARE stuff. === pgbouncer When using pgbouncer, which is a good idea, consider setting up +connect_query+ to prepare all the statements at server connection time. [databases] foo = port=5432 connect_query='SELECT prepare_all();' Of course, if using +pre_prepare+, you'll want to avoid using +DISCARD ALL+ as your +reset_query+... === local_preload_libraries ==== If you have +8.3+ It's unfortunately not possible to call +SPI_connect()+ from the module initialization routine (+_PG_init()+) when called via +local_preload_libraries+, it's too much early. So fully transparent preparing of user given statement is not possible with the +pre_prepare+ module, you still have to explicitely call +SELECT prepare_all()+. ==== If running 8.4 or later To call +SPI_connect()+ in fact what's needed is an opened transaction and a current active Snapshot. Both are possible to acquire from within a dynamically loaded module, so +preprepare+ is supporting the case. Update your +postgresql.conf+ to have the following: custom_variable_classes = 'preprepare' preprepare.at_init = on preprepare.relation = 'preprepare.statements' Then +reload+ PostgreSQL and enjoy: any new connection will have already prepared your statements by the time you're able to send queries, so you can forget about +PREPARE+ and directly +EXECUTE+. No need for extra software. Please note that if your statements contain any error, PostgreSQL will handle it as a +FATAL+ error and this will effectively prevent you from connecting to your server. You'll have to turn preprepare.at_init +off+ again then +reload+, or remove +pre_prepare+ from +local_preload_libraries+ then +restart+. == Usage First create a table where to store your statements, e.g.: create table pre_prepare.statements(name text primary key, statement text); The statement stored is the complete statement including the +PREPARE name AS+ part. insert into pre_prepare.statements values ('test', 'prepare test as select 1'); === prepare_all() Then connect to PostgreSQL (via +pgbouncer+ if not using +local_preload_libraries+) and run the +EXECUTE+ command matching with your +PREPARE+ statements, they all are already prepared. If not using +pgbouncer+ nor +preprepare.at_init = on+, you'll have to call the function yourself to have your statements prepared: SELECT prepare_all(); === prepare_all('schema.table') If you're not in a position to always prepare the same set of queries, you can use the second form of +prepare_all+ calling, which accepts a specific statements table: SELECT prepare_all('public.expensive_planning'); This can be automated in a special +pgbouncer+ fake +database+ where the +connect_query+ will prepare specific queries when you know you need them in some occasion, but they're way to expensive to always prepare ahead of time. === discard() The module also offers a +discard()+ function which does the same as +DISCARD ALL+ except that it won't call +DEALLOCATE ALL+. preprepare-0.7/README.html000066400000000000000000000554401235226761200153660ustar00rootroot00000000000000 pre_prepare

Ideas

The pre_prepare module aims to prepare all your statements as soon as possible and in a way that allows client queries not to bother at all and just call EXECUTE.

Setup

compile and install

The module is using the PG_XS build infrastructure, so just:

make
make install
psql -f `pg_config --sharedir`/contrib/pre_prepare.sql -U user dbname

Depending on the way you got PostgreSQL installed in the first place, you may need to use sudo for the make install step.

postgresql.conf

Add a custom class then the following settings:

custom_variable_classes = 'preprepare'
preprepare.relation = 'preprepare.statements'

The pre_prepare.relation is the name of the table where you’ll put all the statements you want to module to prepare. The following SQL query against the given relation must return the names and SQL statements to be prepared.

SELECT name, statement FROM <pre_prepare.relation>;

The statements won’t be edited, so must be the all PREPARE stuff.

pgbouncer

When using pgbouncer, which is a good idea, consider setting up connect_query to prepare all the statements at server connection time.

[databases]
foo = port=5432 connect_query='SELECT prepare_all();'

Of course, if using pre_prepare, you’ll want to avoid using DISCARD ALL as your reset_query

local_preload_libraries

If you have 8.3

It’s unfortunately not possible to call SPI_connect() from the module initialization routine (_PG_init()) when called via local_preload_libraries, it’s too much early. So fully transparent preparing of user given statement is not possible with the pre_prepare module, you still have to explicitely call SELECT prepare_all().

If running 8.4 or later

To call SPI_connect() in fact what’s needed is an opened transaction and a current active Snapshot. Both are possible to acquire from within a dynamically loaded module, so preprepare is supporting the case.

Update your postgresql.conf to have the following:

custom_variable_classes = 'preprepare'
preprepare.at_init  = on
preprepare.relation = 'preprepare.statements'

Then reload PostgreSQL and enjoy: any new connection will have already prepared your statements by the time you’re able to send queries, so you can forget about PREPARE and directly EXECUTE. No need for extra software.

Please note that if your statements contain any error, PostgreSQL will handle it as a FATAL error and this will effectively prevent you from connecting to your server. You’ll have to turn preprepare.at_init off again then reload, or remove pre_prepare from local_preload_libraries then restart.

Usage

First create a table where to store your statements, e.g.:

create table pre_prepare.statements(name text primary key, statement text);

The statement stored is the complete statement including the PREPARE name AS part.

insert into pre_prepare.statements values ('test', 'prepare test as select 1');

prepare_all()

Then connect to PostgreSQL (via pgbouncer if not using local_preload_libraries) and run the EXECUTE command matching with your PREPARE statements, they all are already prepared.

If not using pgbouncer nor preprepare.at_init = on, you’ll have to call the function yourself to have your statements prepared:

SELECT prepare_all();

prepare_all(schema.table)

If you’re not in a position to always prepare the same set of queries, you can use the second form of prepare_all calling, which accepts a specific statements table:

SELECT prepare_all('public.expensive_planning');

This can be automated in a special pgbouncer fake database where the connect_query will prepare specific queries when you know you need them in some occasion, but they’re way to expensive to always prepare ahead of time.

discard()

The module also offers a discard() function which does the same as DISCARD ALL except that it won’t call DEALLOCATE ALL.


preprepare-0.7/Vagrantfile000066400000000000000000000004771235226761200157300ustar00rootroot00000000000000# -*- mode: ruby -*- # vi: set ft=ruby : # Vagrantfile API/syntax version. Don't touch unless you know what you're doing! VAGRANTFILE_API_VERSION = "2" Vagrant.configure("2") do |config| config.vm.box = "wheezy64" config.vm.provision "shell" do |s| s.path = "bootstrap.sh" s.privileged = false end end preprepare-0.7/bootstrap.sh000066400000000000000000000007731235226761200161130ustar00rootroot00000000000000#!/usr/bin/env bash # PostgreSQL sidsrc=/etc/apt/sources.list.d/sid-src.list echo "deb-src http://ftp.fr.debian.org/debian/ sid main" | sudo tee $sidsrc pgdg=/etc/apt/sources.list.d/pgdg.list pgdgkey=https://www.postgresql.org/media/keys/ACCC4CF8.asc echo "deb http://apt.postgresql.org/pub/repos/apt/ wheezy-pgdg main" | sudo tee $pgdg wget --quiet -O - ${pgdgkey} | sudo apt-key add - sudo apt-get update sudo apt-get install -y postgresql-server-dev-all rsync devscripts make -C /vagrant unsign-deb preprepare-0.7/build/000077500000000000000000000000001235226761200146325ustar00rootroot00000000000000preprepare-0.7/build/.gitignore000066400000000000000000000001061235226761200166170ustar00rootroot00000000000000# Ignore everything in this directory * # Except this file !.gitignorepreprepare-0.7/changelog000066400000000000000000000010241235226761200154020ustar00rootroot00000000000000preprepare (0.7) upstream; urgency=medium * Relax PostgreSQL version check to allow all future versions. We'll find problems using the regression tests. -- Christoph Berg Tue, 24 Jun 2014 14:29:30 +0200 preprepare (0.6) upstream; urgency=medium * Add regression test. -- Christoph Berg Tue, 10 Dec 2013 17:18:47 +0100 preprepare (0.1-1) unstable; urgency=low * Initial release -- Dimitri Fontaine Wed, 13 May 2009 16:42:29 +0200 preprepare-0.7/debian/000077500000000000000000000000001235226761200147555ustar00rootroot00000000000000preprepare-0.7/debian/changelog000066400000000000000000000047571235226761200166440ustar00rootroot00000000000000preprepare (0.7-1) unstable; urgency=medium * Ship plugin symlink in the package so users don't need to create them manually. * Use "all" in debian/pgversions. * Add Vcs headers. * Set team as maintainer. -- Christoph Berg Tue, 24 Jun 2014 14:16:19 +0200 preprepare (0.6-2) unstable; urgency=medium * Add make to the test dependencies. -- Christoph Berg Sun, 26 Jan 2014 17:43:54 +0100 preprepare (0.6-1) unstable; urgency=low * New upstream release with 9.3 support. (Closes: #731517) * Convert debian/*.docs to dh_installdocs --all. * debian/rules: Use "pg_buildext loop". * Add myself to Uploaders. * Update description to mention PostgreSQL. * Add example query to README.*. * Run regression tests using autopkgtest. * Add watch file. -- Christoph Berg Tue, 10 Dec 2013 17:23:16 +0100 preprepare (0.5-1) unstable; urgency=low * Fix an error with -Werror=format-security, from ubuntu builds (Closes: #647222) -- Dimitri Fontaine Mon, 31 Oct 2011 21:28:56 +0100 preprepare (0.4-2) unstable; urgency=low [ Dimitri Fontaine ] * Repackage for 9.1 support (Closes: #639482) [ Christoph Berg ] * Remove debian/*.dirs, they are not needed. * Override dh_auto_install to do nothing, dh_install will take care. -- Dimitri Fontaine Mon, 05 Sep 2011 13:04:51 +0200 preprepare (0.4-1.1) unstable; urgency=low * Non-maintainer upload. * debian/{control, postgresql-8.3*, rules} - support only PostgreSQL 8.4, dropping support for 8.3; thanks to Martin Pitt for the report; Closes: #559611 -- Sandro Tosi Thu, 18 Feb 2010 15:08:52 +0100 preprepare (0.4-1) unstable; urgency=low * Better support for GUC options -- Dimitri Fontaine Tue, 18 Aug 2009 10:02:07 +0200 preprepare (0.3-1) unstable; urgency=low * Add support for discard() function * Add support for prepare_all('schema.relation'), overriding GUC setting * Document those additions -- Dimitri Fontaine Sat, 18 Jul 2009 23:11:53 +0200 preprepare (0.2-1) unstable; urgency=low * Add support for local_preload_libraries and preprepare.at_init = on for PostgreSQL 8.4 and following * ITP (Closes: #536782) -- Dimitri Fontaine Tue, 07 Jul 2009 09:58:08 +0200 preprepare (0.1-1) unstable; urgency=low * Initial release -- Dimitri Fontaine Wed, 13 May 2009 16:42:29 +0200 preprepare-0.7/debian/compat000066400000000000000000000000021235226761200161530ustar00rootroot000000000000005 preprepare-0.7/debian/control000066400000000000000000000014531235226761200163630ustar00rootroot00000000000000Source: preprepare Section: database Priority: extra Maintainer: Debian PostgreSQL Maintainers Uploaders: Dimitri Fontaine , Christoph Berg Build-Depends: debhelper (>= 7.0.50~), postgresql-server-dev-all (>= 148~) Standards-Version: 3.9.5 Vcs-Browser: https://github.com/dimitri/preprepare Vcs-Git: https://github.com/dimitri/preprepare.git XS-Testsuite: autopkgtest Package: postgresql-9.3-preprepare Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, postgresql-9.3 Description: pre prepare your PostgreSQL statements server side The pre_prepare module for PostgreSQL aims to prepare all your statements as soon as possible and in a way that allows client queries not to bother at all and just call EXECUTE. preprepare-0.7/debian/control.in000066400000000000000000000014661235226761200167740ustar00rootroot00000000000000Source: preprepare Section: database Priority: extra Maintainer: Debian PostgreSQL Maintainers Uploaders: Dimitri Fontaine , Christoph Berg Build-Depends: debhelper (>= 7.0.50~), postgresql-server-dev-all (>= 148~) Standards-Version: 3.9.5 Vcs-Browser: https://github.com/dimitri/preprepare Vcs-Git: https://github.com/dimitri/preprepare.git XS-Testsuite: autopkgtest Package: postgresql-PGVERSION-preprepare Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, postgresql-PGVERSION Description: pre prepare your PostgreSQL statements server side The pre_prepare module for PostgreSQL aims to prepare all your statements as soon as possible and in a way that allows client queries not to bother at all and just call EXECUTE. preprepare-0.7/debian/copyright000066400000000000000000000023311235226761200167070ustar00rootroot00000000000000This package was debianized by Dimitri Fontaine on Wed, 13 May 2009 16:51:05 +0200 It was downloaded from http://pgfoundry.org/projects/preprepare Copyright Holders: Copyright (c) 2008-2011 - Dimitri Fontaine License: BSD Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies. . IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. . THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. preprepare-0.7/debian/pgversions000066400000000000000000000000041235226761200170710ustar00rootroot00000000000000all preprepare-0.7/debian/rules000077500000000000000000000016551235226761200160440ustar00rootroot00000000000000#!/usr/bin/make -f SRCDIR = $(CURDIR) TARGET = $(CURDIR)/debian/preprepare-%v PKGVERS = $(shell dpkg-parsechangelog | awk -F '[:-]' '/^Version:/ { print substr($$2, 2) }') EXCLUDE = --exclude-vcs --exclude=debian include /usr/share/postgresql-common/pgxs_debian_control.mk .PHONY: debian/control clean: debian/control override_dh_auto_clean: +pg_buildext clean $(SRCDIR) $(TARGET) "$(CFLAGS)" $(MAKE) clean override_dh_auto_build: override_dh_auto_install: +pg_buildext loop postgresql-%v-preprepare override_dh_installdocs: dh_installdocs --all README.asciidoc override_dh_link: set -ex; for v in $(shell pg_buildext supported-versions); do mkdir debian/postgresql-$$v-preprepare/usr/lib/postgresql/$$v/lib/plugins; ln -s ../pre_prepare.so debian/postgresql-$$v-preprepare/usr/lib/postgresql/$$v/lib/plugins; done orig: debian/control clean cd .. && tar czf preprepare_$(PKGVERS).orig.tar.gz $(EXCLUDE) preprepare %: dh $@ preprepare-0.7/debian/source/000077500000000000000000000000001235226761200162555ustar00rootroot00000000000000preprepare-0.7/debian/source/format000066400000000000000000000000141235226761200174630ustar00rootroot000000000000003.0 (quilt) preprepare-0.7/debian/tests/000077500000000000000000000000001235226761200161175ustar00rootroot00000000000000preprepare-0.7/debian/tests/control000066400000000000000000000001331235226761200175170ustar00rootroot00000000000000Depends: @, make, postgresql-server-dev-all Tests: installcheck Restrictions: allow-stderr preprepare-0.7/debian/tests/installcheck000077500000000000000000000005271235226761200205150ustar00rootroot00000000000000#!/bin/sh set -e for v in $(pg_buildext supported-versions); do PGOPTS="-o local_preload_libraries=pre_prepare" if ! pg_virtualenv -v $v $PGOPTS \ make installcheck PG_CONFIG=/usr/lib/postgresql/$v/bin/pg_config; then if [ -r regression.diffs ]; then echo "**** regression.diffs ****" cat regression.diffs fi exit 1 fi done preprepare-0.7/debian/watch000066400000000000000000000001421235226761200160030ustar00rootroot00000000000000version=3 https://github.com/dimitri/preprepare/releases /dimitri/preprepare/archive/v(.*).tar.gz preprepare-0.7/expected/000077500000000000000000000000001235226761200153345ustar00rootroot00000000000000preprepare-0.7/expected/create_extension.out000066400000000000000000000000361235226761200214230ustar00rootroot00000000000000create extension pre_prepare; preprepare-0.7/expected/create_module.out000066400000000000000000000000161235226761200206720ustar00rootroot00000000000000\set ECHO off preprepare-0.7/expected/pre_prepare.out000066400000000000000000000007051235226761200203730ustar00rootroot00000000000000CREATE SCHEMA pre_prepare; SET preprepare.relation = 'pre_prepare.statements'; SET client_min_messages = warning; CREATE TABLE pre_prepare.statements(name text primary key, statement text); RESET client_min_messages; INSERT INTO pre_prepare.statements VALUES ('test', 'prepare test as select 1'); SELECT prepare_all(); NOTICE: Preparing statement name: test prepare_all ------------- (1 row) EXECUTE test; ?column? ---------- 1 (1 row) preprepare-0.7/pgbouncer.ini000066400000000000000000000010361235226761200162200ustar00rootroot00000000000000[pgbouncer] auth_type = trust admin_users = postgres, dim log_disconnections = 1 listen_port = 63210 default_pool_size = 100 server_reset_query = server_check_query = select 1 max_client_conn = 1024 client_login_timeout = 0 log_connections = 1 server_check_delay = 10 listen_addr = * auth_file = /home/dim/pgsql/8.3/data/global/pg_auth log_pooler_errors = 1 unix_socket_dir = /tmp logfile = /tmp/pgbouncer.log pidfile = /tmp/pgbouncer.pid pool_mode = session stats_users = [databases] dim = port=3210 connect_query='SELECT prepare_all();' preprepare-0.7/pre_prepare--unpackaged--0.4.sql000066400000000000000000000002531235226761200213110ustar00rootroot00000000000000 alter extension pre_prepare add function discard(); alter extension pre_prepare add function prepare_all(); alter extension pre_prepare add function prepare_all(text); preprepare-0.7/pre_prepare.c000066400000000000000000000211741235226761200162100ustar00rootroot00000000000000/* * pre_prepare allows to store statements in a table and will prepare them * all when the prepare_all() function is being called. * * Unfortunately it's not possible to SPI_connect() when LOAD is done via * local_preload_libraries, so the function call can't be made transparent * to the client connection. */ #include #include "postgres.h" #include "executor/spi.h" #include "utils/guc.h" #include "utils/elog.h" #include "utils/palloc.h" #include "utils/builtins.h" #include "libpq/pqformat.h" #include "access/xact.h" /* #define DEBUG */ /* * This code has only been tested with PostgreSQL 8.3. */ #ifdef PG_VERSION_NUM #define PG_MAJOR_VERSION (PG_VERSION_NUM / 100) #else #error "Unknown postgresql version" #endif #if PG_MAJOR_VERSION < 803 #error "Unsupported postgresql version" #endif PG_MODULE_MAGIC; /* * In 8.3 it seems that snapmgr.h is unavailable for module code * * That means there's no support for at_init and local_preload_libraries in * this version. */ #if PG_MAJOR_VERSION > 803 #include "utils/snapmgr.h" static bool pre_prepare_at_init = false; #endif static char *pre_prepare_relation = NULL; void _PG_init(void); Datum prepare_all(PG_FUNCTION_ARGS); /* * Check that pre_prepare.relation is setup to an existing table. * * The catalog inquiry could use some optimisation (index use prevented). */ static inline bool check_pre_prepare_relation(const char *relation_name) { int err; char *stmpl = "SELECT 1 FROM pg_class WHERE " \ "(SELECT nspname from pg_namespace WHERE oid = relnamespace) " \ "|| '.' || relname = '%s';"; int len = (strlen(stmpl) - 2) + strlen(relation_name) + 1; char *select = (char *)palloc(len * sizeof(char)); snprintf(select, len, stmpl, relation_name); #ifdef DEBUG elog(NOTICE, select); #endif err = SPI_execute(select, true, 1); if( err != SPI_OK_SELECT ) elog(ERROR, "SPI_execute: %s", SPI_result_code_string(err)); return 1 == SPI_processed; } /* * Prepare all the statements in pre_prepare.relation */ static inline int pre_prepare_all(const char *relation_name) { int err, nbrows = 0; char *stmpl = "SELECT name, statement FROM %s"; int len = (strlen(stmpl) - 2) + strlen(relation_name) + 1; char *select = (char *)palloc(len); snprintf(select, len, stmpl, relation_name); err = SPI_execute(select, true, 0); if( err != SPI_OK_SELECT ) { elog(ERROR, "SPI_execute: %s", SPI_result_code_string(err)); return -1; } nbrows = SPI_processed; if( nbrows > 0 && SPI_tuptable != NULL ) { TupleDesc tupdesc = SPI_tuptable->tupdesc; SPITupleTable *tuptable = SPI_tuptable; int row; for (row = 0; row < nbrows; row++) { HeapTuple tuple = tuptable->vals[row]; char *name = SPI_getvalue(tuple, tupdesc, 1); char *stmt = SPI_getvalue(tuple, tupdesc, 2); elog(NOTICE, "Preparing statement name: %s", name); err = SPI_execute(stmt, false, 0); if( err != SPI_OK_UTILITY ) { elog(ERROR, "SPI_execute: %s", SPI_result_code_string(err)); return -1; } } } else elog(NOTICE, "No statement to prepare found in '%s'", pre_prepare_relation); return nbrows; } /* * _PG_init() - library load-time initialization * * DO NOT make this static nor change its name! * * Init the module, all we have to do here is getting our GUC */ void _PG_init(void) { PG_TRY(); { #if PG_MAJOR_VERSION == 804 bool at_init = false; if( parse_bool(GetConfigOptionByName("prepare.at_init", NULL), &at_init) ) pre_prepare_at_init = at_init; #endif pre_prepare_relation = GetConfigOptionByName("prepare.relation", NULL); } PG_CATCH(); { /* * From 8.4 the Custom variables take two new options, the default value * and a flags field */ #if PG_MAJOR_VERSION == 803 DefineCustomStringVariable("preprepare.relation", "Table name where to find statements to prepare", "Can be schema qualified, must have columns " "\"name\" and \"statement\"", &pre_prepare_relation, PGC_USERSET, NULL, NULL); /* * It's missing a way to use PushActiveSnapshot/PopActiveSnapshot from * within a module in 8.3 for this to be useful. * DefineCustomBoolVariable("preprepare.at_init", "Do we prepare the statements at backend start", "You have to setup local_preload_libraries too", &pre_prepare_at_init, PGC_USERSET, NULL, NULL); */ EmitWarningsOnPlaceholders("prepare.relation"); #elif PG_MAJOR_VERSION == 804 || PG_MAJOR_VERSION == 900 DefineCustomStringVariable("preprepare.relation", "Table name where to find statements to prepare", "Can be schema qualified, must have columns " "\"name\" and \"statement\"", &pre_prepare_relation, "", PGC_USERSET, GUC_NOT_IN_SAMPLE, NULL, NULL); DefineCustomBoolVariable("preprepare.at_init", "Do we prepare the statements at backend start", "You have to setup local_preload_libraries too", &pre_prepare_at_init, false, PGC_USERSET, GUC_NOT_IN_SAMPLE, NULL, NULL); EmitWarningsOnPlaceholders("prepare.relation"); EmitWarningsOnPlaceholders("prepare.at_init"); #else DefineCustomStringVariable("preprepare.relation", "Table name where to find statements to prepare", "Can be schema qualified, must have columns " "\"name\" and \"statement\"", &pre_prepare_relation, "", PGC_USERSET, GUC_NOT_IN_SAMPLE, NULL, NULL, NULL); DefineCustomBoolVariable("preprepare.at_init", "Do we prepare the statements at backend start", "You have to setup local_preload_libraries too", &pre_prepare_at_init, false, PGC_USERSET, GUC_NOT_IN_SAMPLE, NULL, NULL, NULL); EmitWarningsOnPlaceholders("prepare.relation"); EmitWarningsOnPlaceholders("prepare.at_init"); #endif } PG_END_TRY(); #if PG_MAJOR_VERSION >= 804 if( pre_prepare_at_init ) { int err; /* * We want to use SPI, so we need to ensure there's a current started * transaction, then take a snapshot start_xact_command(); */ Snapshot snapshot; StartTransactionCommand(); /* CommandCounterIncrement(); */ snapshot = GetTransactionSnapshot(); PushActiveSnapshot(snapshot); err = SPI_connect(); if (err != SPI_OK_CONNECT) elog(ERROR, "SPI_connect: %s", SPI_result_code_string(err)); if( ! check_pre_prepare_relation(pre_prepare_relation) ) { ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("Can not find relation '%s'", pre_prepare_relation), errhint("Set preprepare.relation to an existing table."))); } pre_prepare_all(pre_prepare_relation); err = SPI_finish(); if (err != SPI_OK_FINISH) elog(ERROR, "SPI_finish: %s", SPI_result_code_string(err)); PopActiveSnapshot(); CommitTransactionCommand(); } #endif } /* * PostgreSQL interface, with the SPI_connect and SPI_finish calls. */ PG_FUNCTION_INFO_V1(prepare_all); Datum prepare_all(PG_FUNCTION_ARGS) { char * relation = NULL; int err; /* * we support for the user to override the GUC by passing in the relation name * SELECT prepare_all('some_other_statements'); */ if( PG_NARGS() == 1 ) relation = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(PG_GETARG_TEXT_P(0)))); else { relation = pre_prepare_relation; /* * The function is STRICT so we don't check this error case in the * previous branch */ if( relation == NULL ) ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("The custom variable preprepare.relation is not set."), errhint("Set preprepare.relation to an existing table."))); } err = SPI_connect(); if (err != SPI_OK_CONNECT) elog(ERROR, "SPI_connect: %s", SPI_result_code_string(err)); if( ! check_pre_prepare_relation(relation) ) { char *hint = "Set preprepare.relation to an existing table, schema qualified"; if( PG_NARGS() == 1 ) hint = "prepare_all requires you to schema qualify the relation name"; ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("Can not find relation '%s'", relation), errhint("%s", hint))); } #ifdef DEBUG elog(NOTICE, "preprepare.relation is found, proceeding"); #endif pre_prepare_all(relation); /* done with SPI */ err = SPI_finish(); if (err != SPI_OK_FINISH) elog(ERROR, "SPI_finish: %s", SPI_result_code_string(err)); PG_RETURN_VOID(); } preprepare-0.7/pre_prepare.control000066400000000000000000000002351235226761200174410ustar00rootroot00000000000000# preprepare extension comment = 'Pre Prepare your Statement server side' default_version = '0.4' module_pathname = '$libdir/pre_prepare' relocatable = true preprepare-0.7/pre_prepare.sql000066400000000000000000000010231235226761200165540ustar00rootroot00000000000000--- --- pre_prepare exports only a prepare_all() function. --- CREATE OR REPLACE FUNCTION prepare_all() RETURNS void AS '$libdir/pre_prepare', 'prepare_all' LANGUAGE C STRICT VOLATILE; CREATE OR REPLACE FUNCTION prepare_all(text) RETURNS void AS '$libdir/pre_prepare', 'prepare_all' LANGUAGE C STRICT VOLATILE; CREATE OR REPLACE FUNCTION discard() RETURNS void LANGUAGE SQL AS $$ SET SESSION AUTHORIZATION DEFAULT; RESET ALL; CLOSE ALL; UNLISTEN *; SELECT pg_advisory_unlock_all(); DISCARD PLANS; DISCARD TEMP; $$; preprepare-0.7/sql/000077500000000000000000000000001235226761200143325ustar00rootroot00000000000000preprepare-0.7/sql/create_extension.sql000066400000000000000000000000361235226761200204110ustar00rootroot00000000000000create extension pre_prepare; preprepare-0.7/sql/create_module.sql000066400000000000000000000000461235226761200176630ustar00rootroot00000000000000\set ECHO off \i pre_prepare--0.4.sql preprepare-0.7/sql/pre_prepare.sql000066400000000000000000000005211235226761200173550ustar00rootroot00000000000000CREATE SCHEMA pre_prepare; SET preprepare.relation = 'pre_prepare.statements'; SET client_min_messages = warning; CREATE TABLE pre_prepare.statements(name text primary key, statement text); RESET client_min_messages; INSERT INTO pre_prepare.statements VALUES ('test', 'prepare test as select 1'); SELECT prepare_all(); EXECUTE test;