Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Convert site to github pages

  • Loading branch information...
commit 592017d2cf82db6de9a1b7404ea93cec7d1e9d51 1 parent e2e79f6
Duke Leto authored
Showing with 0 additions and 5,335 deletions.
  1. +0 −46 CREDITS
  2. +0 −70 HACKING.git
  3. +0 −7 HACKING.parrot
  4. +0 −34 HACKING.postgres
  5. +0 −19 HISTORY
  6. +0 −83 IDEAS
  7. +0 −201 LICENSE
  8. +0 −53 META.json
  9. +0 −70 Makefile
  10. +0 −10 PLATFORMS
  11. 0  {html → }/PLParrot_PGCon_2010.pdf
  12. 0  {html → }/PLParrot_SFPM_20100525.pdf
  13. +0 −114 README.md
  14. +0 −39 ROADMAP
  15. +0 −23 TODO
  16. +0 −105 bin/text2macro.pl
  17. 0  {html → }/community.html
  18. +0 −2  config.h
  19. 0  {html → }/css/project-site.css
  20. 0  {html → }/docs.html
  21. +0 −41 expected/test.out
  22. 0  {html → }/img/PLParrot.jpg
  23. 0  {html → }/index.html
  24. 0  libsrc/handler/.placeholder
  25. +0 −23 load_pir.test.sql
  26. +0 −1,539 pgtap.sql
  27. +0 −599 plparrot.c
  28. +0 −41 plparrot.sql.in
  29. +0 −49 plparrot_secure.pir
  30. 0  {html → }/plperl6.html
  31. +0 −65 plperl6.pir
  32. 0  {html → }/plpir.html
  33. +0 −6 ports/debian/README.Debian
  34. +0 −9 ports/debian/README.source
  35. +0 −5 ports/debian/changelog
  36. +0 −1  ports/debian/compat
  37. +0 −21 ports/debian/control
  38. +0 −219 ports/debian/copyright
  39. +0 −4 ports/debian/cron.d.ex
  40. +0 −2  ports/debian/docs
  41. +0 −45 ports/debian/emacsen-install.ex
  42. +0 −15 ports/debian/emacsen-remove.ex
  43. +0 −25 ports/debian/emacsen-startup.ex
  44. +0 −157 ports/debian/init.d.ex
  45. +0 −296 ports/debian/init.d.lsb.ex
  46. +0 −59 ports/debian/manpage.1.ex
  47. +0 −154 ports/debian/manpage.sgml.ex
  48. +0 −291 ports/debian/manpage.xml.ex
  49. +0 −2  ports/debian/menu.ex
  50. +0 −2  ports/debian/plparrot-dev.dirs
  51. +0 −6 ports/debian/plparrot-dev.install
  52. +0 −10 ports/debian/plparrot.default.ex
  53. +0 −20 ports/debian/plparrot.doc-base.EX
  54. +0 −1  ports/debian/plparrot1.dirs
  55. +0 −1  ports/debian/plparrot1.install
  56. +0 −39 ports/debian/postinst.ex
  57. +0 −37 ports/debian/postrm.ex
  58. +0 −35 ports/debian/preinst.ex
  59. +0 −38 ports/debian/prerm.ex
  60. +0 −13 ports/debian/rules
  61. +0 −1  ports/debian/shlibs.local.ex
  62. +0 −23 ports/debian/watch.ex
  63. +0 −62 ports/fedora/postgresql-plparrot.spec
  64. +0 −1  sql
  65. +0 −206 t/sql/plperl6.sql
  66. +0 −296 t/sql/test.sql
  67. 0  {html → }/template.html
46 CREDITS
View
@@ -1,46 +0,0 @@
-=pod
-
- Following in the steps of other open source projects that
- eventually take over the world, here is the partial list
- of people who have contributed to PL/Parrot and its supporting
- works. It is sorted by name and formatted to allow easy
- grepping and beautification by scripts.
- The fields are: name (N), email (E), web-address (W),
- description (D), main username (U), alias usernames (A)
- and snail-mail address (S).
-
- Thanks,
-
- The PL/Parrot Team
- PS: Yes, this looks remarkably like the Linux CREDITS format
- PPS: This file is encoded in UTF-8
-
-----------
-
-N: Jonathan Leto
-E: jonathan@leto.net
-W: http://leto.net
-U: dukeleto
-S: Portland, OR
-
-N: David Fetter
-E: david@fetter.org
-W: http://www.pgexperts.com/
-U: davidfetter
-S: Oakland, CA, USA
-
-N: David Wheeler
-E: david.wheeler@pgexperts.com
-W: http://www.pgexperts.com/
-U: theory
-S: Portland, OR, USA
-
-N: Joshua Tolley
-E: eggyknap@gmail.com
-W: http://eggyknap.blogspot.com
-U: eggyknap
-S: Salt Lake City, UT, USA
-
-N: Daniel Arbelo Arrocha
-E: arbelo@gmail.com
-U: darbelo
70 HACKING.git
View
@@ -1,70 +0,0 @@
-=head1 Recommended Git Workflow for Working on PL/Parrot
-
-You should be using Git >= 1.6.x . Make sure you do before doing anything in this file.
-
-=head1 Workflow #1 (used by dukeleto)
-
- git remote update # this updates your index and the symbolic ref origin/master
-
-The benefit of this way is that "git remote update" only updates your index and doesn't care
-about changes in your working copy i.e. you can have a messy, uncommited pig sty in your local
-copy and remote update just doesn't care.
-
- git diff ..origin/master # look at the difference between local master and origin/master
-
-This shows commits which are in origin/master but not in master.
-
-If you want an colored ASCII representation of your history (also known as VCS porn):
-
- git log --pretty=format:'%C(yellow)%h%Creset %s %Cred%an%Creset %Cblue%d%Creset %Cgreen%cr%Creset %cd' --graph --all
-
-I have this aliased to both "git lg" for "log --graph" and "git plog" for "pretty log". For other useful aliases, see
-
-http://github.com/leto/Util/blob/master/config/.gitconfig
-
-If you want to merge the changes from origin/master into your local master:
-
- git rebase origin/master
-
-Why not just a merge? That would leave a "merged branch 'master'" commit, which
-gets old real quick. We also spam the #parrot channel with our commits, so it
-is best to not have all those (mostly useless) merge commits.
-
-=head1 Workflow #2 (pretty much equivalent, but less flexible)
-
-Something equivalent to the above can be accomplished with:
-
- git pull --rebase # same as git rebase
-
-but this command *does* care about having a clean working copy, so if you have uncommitted changes, you
-will have to stash them:
-
- git stash "this is a work in progress"
-
-This command will leave you with a clean working copy, so that after you type "git pull --rebase" you can type:
-
- git stash pop # apply the latest commit on the stash and pop it off
-
-You could have used "git stash apply" if you wanted to apply it but leave it on
-the stash. You might want to do this if you want to apply something to multiple
-branches.
-
-If you want to type "git pull" and you always want it to use --rebase then you can do:
-
- git config branch.master.rebase true
-
-I think it is better to just use "git rebase", so if you type "git pull" it
-does what you expect, but that is up to personal taste.
-
-=head1 How to Write a Commit Message
-
-Commit messages should look like this:
-
-This is the first line, which is roughly 50 columns, no more than 80
-
-Previous line intentionally left blank! That line separates the short commit
-message from the long commit message. Utils that need to print things on one
-line will use the short commit messages, others that don't care will show the
-long commit message.
-
-=cut
7 HACKING.parrot
View
@@ -1,7 +0,0 @@
-Here's a way to have fresh parrots.
-
-Figure out what to put in instead of -j4 by figuring out how many
-cores are available. On Linux, you can cat /proc/cpuinfo.
-
-export PATH=$HOME/installed_parrot/bin:$PATH
-alias new_parrot="make realclean; perl Configure.pl --optimize --prefix=$HOME/installed_parrot && nice -n20 gmake -j4"
34 HACKING.postgres
View
@@ -1,34 +0,0 @@
-PostgreSQL depends on some environment variables and directories which
-are easiest to have via a .bashrc like this:
-
-export PG_PREFIX=/home/shackle/tip
-export PGDATA=$PG_PREFIX/data
-export PATH=$PG_PREFIX/bin:$PATH
-export PGPORT=2225
-export PGUSER=shackle
-export PGDATABASE=postgres
-
-When you want to work on CVS TIP (aka git master) of PostgreSQL, you'd
-source this file first. If you want to change to another
-PostgreSQL, do:
-
- make maintainer-clean
- . /path/to/new/.bashrc.whatever
-
-When compiling PostgreSQL, here's a handy-ish configure invocation:
-
- ./configure \
- --prefix=$PG_PREFIX \
- --with-pgport=$PGPORT \
- --with-perl \
- --with-libxml \
- --enable-debug \
- --enable-cassert
-
-If you have ccache installed, you may also want to do
-
- CC="ccache gcc" ./configure ...
-
-To avoid confusion, you also might want to un-symlink plparrot from
-beneath the other source tree and symlink it under contrib/ in the
-source tree you want to use.
19 HISTORY
View
@@ -1,19 +0,0 @@
-David Fetter recounts:
-
-As has long been my wont, in about May of 2006, I was looking around for
-something cool to do in PostgreSQL that no one had done before. I figured
-perl6 would make a great PL, but there was no implementation at the time, or at
-least nothing that looked like it might become embeddable Parrot, despite its
-long ride on the fail whale, looked like the most promising way for the long
-term, So i came up with a couple of designs inspired by the PL/Java and PL/J
-projects. PL/Java produced working code, although to this day I'm not sure
-that it's production quality. It did this by instantiating a jvm in each
-connection. PL/J's design was in some sense more elegant, but it never got
-anywhere. In PL/J, there was to be some kind of IPC to a java "server." The
-problem is that IPC and little servers are extremely difficult to get right, so
-for now, I'm thinking that the PL/Java model has more JFDI.
-
-Jonathan "Duke" Leto adds:
-
-I started hacking on PL/Parrot in October of 2009 and it started to actually work
-in April 2010.
83 IDEAS
View
@@ -1,83 +0,0 @@
-
-Ways to get Parrot in your Postgres database:
-
-* Embedd One VM per postgres backend
- ** load via a shared library (.so or .dylib)
-* pure NCI
-
-Notes for the PostgreSQL side:
-
-* PL/LOLCODE http://pgfoundry.org/projects/pllolcode/
-
-* http://www.postgresql.org/docs/8.4/static/xfunc-c.html
-
-* http://www.postgresql.org/docs/8.4/static/plhandler.html
-
-* http://developer.postgresql.org/pgdocs/postgres/parser-stage.html
-
-* http://www.postgresonline.com/journal/index.php?/archives/6-Language-Architecture-in-PostgreSQL.html
-
-Notes for the Parrot side:
-
-* mod_parrot http://www.parrot.org/mod_parrot
-
-* Parrot Core Embedding Docs: http://docs.parrot.org/parrot/latest/html/docs/pdds/draft/pdd10_embedding.pod.html
-
-Other random semi-related stuff
-
-* PL/R http://www.joeconway.com/plr/
-
-* PL/Scheme http://plscheme.projects.postgresql.org/
-
-* R in Postgres: http://www.omegahat.org/RSPostgres/
-
-Things we'll need to build:
-1) A C-based shared object containing at minimum a "language handler" function.
-This is what PostgreSQL calls when trying to execute a PL/Parrot function, and
-it's responsible for invoking the interpreter. This will probably be called
-plparrot.so
-
-2) Some sort of module PL/Parrot functions can import which will allow them to
-talk to the database.
-
-There will be some interesting interaction, perhaps, between these two modules.
-The handler function is the only one that will have capacity to talk to the
-database (barring opening a new connection to the database from Parrot, but
-that would obviate the benefits of a procedural language). Presumably the .so
-will need to export functions to the module to allow it to get to the database.
-
-The first step in all this is to get the handler function working, so you can
-run Parrot routines that don't access the database, you can pass them data, and
-they can return data. Second will be to make the database interaction module
-work.
-
-Update:
-01:54 eggyknap : So presumably we can write, in nqp-rx, something that can export some functions and be loaded by any function written in a
- language parrot understands... and presumably those exported functions can actually wrap C code we'll write in the C bits
- of pl/parrot?
-01:54 dukeleto : eggyknap: that sounds about right
-01:55 dukeleto : eggyknap: please write that down somewhere :)
-01:55 eggyknap : Sweet... 'cuz that's how it's gotta work, AFAICS.
-
-
-David Wheeler suggests shelling out directly to psql from the test harness instead of using pg_prove. Fewer dependencies!
-
-This is how the pgTAP plugin for Test::Harness does it:
-http://github.com/AndyA/Test-Harness/blob/master/lib/TAP/Parser/SourceHandler/pgTAP.pm
-
-psql
- --no-psqlrc
- --no-align
- --quiet
- --pset pager=
- --pset tuples_only=true
- --set ON_ERROR_ROLLBACK=1
- --set ON_ERROR_STOP=1
-
-
-IDEAS FOR EXPOSING POSTGRES FUNCTIONS IN PL/PARROT
-* At minimum we need to expose a set of functions: elog(), and SPI stuff, and possibly even utility functions to get pieces of PostgreSQL data types that might not map cleanly to Parrot HLLs
-* One possibility is to create a PMC that people use to access PostgreSQL. This PMC would include methods corresponding to each of the functions we need to expose
- ** Update: per dukeleto this idea won't fly -- PMCs only have some functions available, not a set of arbitrary function names. http://docs.parrot.org/parrot/devel/html/docs/pdds/pdd17_pmc.pod.html
-* Alternatively we can just make the functions available somehow. The primary advantage of PMC over this method as I (eggyknap) see it, is that it seems easier to figure out how to write a PMC than to figure out how to make functions magically available in PL/Parrot functions
- ** Good place to look for examples: runtime/parrot/library/OpenGL.pir
201 LICENSE
View
@@ -1,201 +0,0 @@
- The Artistic License 2.0
-
- Copyright (c) 2000-2006, The Perl Foundation.
-
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-Preamble
-
-This license establishes the terms under which a given free software
-Package may be copied, modified, distributed, and/or redistributed.
-The intent is that the Copyright Holder maintains some artistic
-control over the development of that Package while still keeping the
-Package available as open source and free software.
-
-You are always permitted to make arrangements wholly outside of this
-license directly with the Copyright Holder of a given Package. If the
-terms of this license do not permit the full use that you propose to
-make of the Package, you should contact the Copyright Holder and seek
-a different licensing arrangement.
-
-Definitions
-
- "Copyright Holder" means the individual(s) or organization(s)
- named in the copyright notice for the entire Package.
-
- "Contributor" means any party that has contributed code or other
- material to the Package, in accordance with the Copyright Holder's
- procedures.
-
- "You" and "your" means any person who would like to copy,
- distribute, or modify the Package.
-
- "Package" means the collection of files distributed by the
- Copyright Holder, and derivatives of that collection and/or of
- those files. A given Package may consist of either the Standard
- Version, or a Modified Version.
-
- "Distribute" means providing a copy of the Package or making it
- accessible to anyone else, or in the case of a company or
- organization, to others outside of your company or organization.
-
- "Distributor Fee" means any fee that you charge for Distributing
- this Package or providing support for this Package to another
- party. It does not mean licensing fees.
-
- "Standard Version" refers to the Package if it has not been
- modified, or has been modified only in ways explicitly requested
- by the Copyright Holder.
-
- "Modified Version" means the Package, if it has been changed, and
- such changes were not explicitly requested by the Copyright
- Holder.
-
- "Original License" means this Artistic License as Distributed with
- the Standard Version of the Package, in its current version or as
- it may be modified by The Perl Foundation in the future.
-
- "Source" form means the source code, documentation source, and
- configuration files for the Package.
-
- "Compiled" form means the compiled bytecode, object code, binary,
- or any other form resulting from mechanical transformation or
- translation of the Source form.
-
-
-Permission for Use and Modification Without Distribution
-
-(1) You are permitted to use the Standard Version and create and use
-Modified Versions for any purpose without restriction, provided that
-you do not Distribute the Modified Version.
-
-
-Permissions for Redistribution of the Standard Version
-
-(2) You may Distribute verbatim copies of the Source form of the
-Standard Version of this Package in any medium without restriction,
-either gratis or for a Distributor Fee, provided that you duplicate
-all of the original copyright notices and associated disclaimers. At
-your discretion, such verbatim copies may or may not include a
-Compiled form of the Package.
-
-(3) You may apply any bug fixes, portability changes, and other
-modifications made available from the Copyright Holder. The resulting
-Package will still be considered the Standard Version, and as such
-will be subject to the Original License.
-
-
-Distribution of Modified Versions of the Package as Source
-
-(4) You may Distribute your Modified Version as Source (either gratis
-or for a Distributor Fee, and with or without a Compiled form of the
-Modified Version) provided that you clearly document how it differs
-from the Standard Version, including, but not limited to, documenting
-any non-standard features, executables, or modules, and provided that
-you do at least ONE of the following:
-
- (a) make the Modified Version available to the Copyright Holder
- of the Standard Version, under the Original License, so that the
- Copyright Holder may include your modifications in the Standard
- Version.
-
- (b) ensure that installation of your Modified Version does not
- prevent the user installing or running the Standard Version. In
- addition, the Modified Version must bear a name that is different
- from the name of the Standard Version.
-
- (c) allow anyone who receives a copy of the Modified Version to
- make the Source form of the Modified Version available to others
- under
-
- (i) the Original License or
-
- (ii) a license that permits the licensee to freely copy,
- modify and redistribute the Modified Version using the same
- licensing terms that apply to the copy that the licensee
- received, and requires that the Source form of the Modified
- Version, and of any works derived from it, be made freely
- available in that license fees are prohibited but Distributor
- Fees are allowed.
-
-
-Distribution of Compiled Forms of the Standard Version
-or Modified Versions without the Source
-
-(5) You may Distribute Compiled forms of the Standard Version without
-the Source, provided that you include complete instructions on how to
-get the Source of the Standard Version. Such instructions must be
-valid at the time of your distribution. If these instructions, at any
-time while you are carrying out such distribution, become invalid, you
-must provide new instructions on demand or cease further distribution.
-If you provide valid instructions or cease distribution within thirty
-days after you become aware that the instructions are invalid, then
-you do not forfeit any of your rights under this license.
-
-(6) You may Distribute a Modified Version in Compiled form without
-the Source, provided that you comply with Section 4 with respect to
-the Source of the Modified Version.
-
-
-Aggregating or Linking the Package
-
-(7) You may aggregate the Package (either the Standard Version or
-Modified Version) with other packages and Distribute the resulting
-aggregation provided that you do not charge a licensing fee for the
-Package. Distributor Fees are permitted, and licensing fees for other
-components in the aggregation are permitted. The terms of this license
-apply to the use and Distribution of the Standard or Modified Versions
-as included in the aggregation.
-
-(8) You are permitted to link Modified and Standard Versions with
-other works, to embed the Package in a larger work of your own, or to
-build stand-alone binary or bytecode versions of applications that
-include the Package, and Distribute the result without restriction,
-provided the result does not expose a direct interface to the Package.
-
-
-Items That are Not Considered Part of a Modified Version
-
-(9) Works (including, but not limited to, modules and scripts) that
-merely extend or make use of the Package, do not, by themselves, cause
-the Package to be a Modified Version. In addition, such works are not
-considered parts of the Package itself, and are not subject to the
-terms of this license.
-
-
-General Provisions
-
-(10) Any use, modification, and distribution of the Standard or
-Modified Versions is governed by this Artistic License. By using,
-modifying or distributing the Package, you accept this license. Do not
-use, modify, or distribute the Package, if you do not accept this
-license.
-
-(11) If your Modified Version has been derived from a Modified
-Version made by someone other than you, you are nevertheless required
-to ensure that your Modified Version complies with the requirements of
-this license.
-
-(12) This license does not grant you the right to use any trademark,
-service mark, tradename, or logo of the Copyright Holder.
-
-(13) This license includes the non-exclusive, worldwide,
-free-of-charge patent license to make, have made, use, offer to sell,
-sell, import and otherwise transfer the Package with respect to any
-patent claims licensable by the Copyright Holder that are necessarily
-infringed by the Package. If you institute patent litigation
-(including a cross-claim or counterclaim) against any party alleging
-that the Package constitutes direct or contributory patent
-infringement, then this Artistic License to you shall terminate on the
-date that such litigation is filed.
-
-(14) Disclaimer of Warranty:
-THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
-IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED
-WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
-NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL
-LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
-DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF
-ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53 META.json
View
@@ -1,53 +0,0 @@
-{
- "name": "plparrot",
- "abstract": "Parrot Virtual Machine and Rakudo Perl 6 as PostgreSQL procedural languages",
- "description": "PL/Parrot embeds Parrot in PostgreSQL and also comes with PL/Perl6 if Rakudo Perl 6 is available",
- "version": "0.4.0",
- "generated_by": "Jonathan \"Duke\" Leto",
- "meta-spec": {
- "version": "1.0.0",
- "url": "http://pgxn.org/meta/spec.txt"
- },
- "maintainer": [
- "Jonathan \"Duke\" Leto <jonathan@leto.net>"
- ],
- "prereqs": {
- "runtime": {
- "requires": {
- "plpgsql": 0,
- "PostgreSQL": "8.5.0"
- },
- "recommends": {
- "PostgreSQL": "9.0.0"
- }
- }
- },
-
- "license": "artistic_2",
- "meta-spec": {
- "version": "1.0.0",
- "url": "http://pgxn.org/meta/spec.txt"
- },
- "tags": [ "parrot", "perl6", "rakudo", "pir", "vm", "perl" ],
- "provides": {
- "plparrot": {
- "file": "plparrot.sql",
- "version": "0.4.0"
- },
- "plperl6": {
- "file": "plparrot.sql",
- "version": "0.4.0"
- }
- },
- "resources": {
- "homepage": "http://pl.parrot.org",
- "bugtracker": {
- "web": "http://github.com/leto/plparrot/issues/"
- },
- "repository": {
- "url": "git://github.com/leto/plparrot.git",
- "web": "https://github.com/leto/plparrot/",
- "type": "git"
- }
- }
-}
70 Makefile
View
@@ -1,70 +0,0 @@
-NAME = plparrot
-MODULE_big = plparrot
-OBJS= plparrot.o
-DATA_built = plparrot.sql
-REGRESS_OPTS = --dbname=$(PL_TESTDB) --load-language=plpgsql
-TESTS = t/sql/test.sql
-PLPERL6_TESTS = t/sql/plperl6.sql
-REGRESS = $(patsubst t/sql/%.sql,%,$(TESTS))
-
-EXTRA_CLEAN =
-
-PG_CONFIG = pg_config
-PGXS := $(shell $(PG_CONFIG) --pgxs)
-include $(PGXS)
-
-O = $(shell parrot_config o)
-PARROTINCLUDEDIR = $(shell parrot_config includedir)
-PARROTVERSIONDIR = $(shell parrot_config versiondir)
-PARROTLIBDIR = $(shell parrot_config libdir)
-PARROTINC = $(PARROTINCLUDEDIR)$(PARROTVERSIONDIR)
-PARROTCONFIG = $(PARROTLIBDIR)/$(PARROTVERSIONDIR)/parrot_config
-PARROTLANGDIR = $(PARROTLIBDIR)$(PARROTVERSIONDIR)/languages
-PERL6PBC = $(PARROTLANGDIR)/perl6/perl6.pbc
-PARROTLDFLAGS = $(shell parrot_config ldflags)
-PARROTLINKFLAGS = $(shell parrot_config inst_libparrot_linkflags) $(PARROTCONFIG)$O
-PARROTSHA1 = $(shell parrot_config sha1)
-
-
-PARROT_VERSION = $(shell parrot_config VERSION)
-
-# We may need to do various things with various versions of PostgreSQL.
-# VERSION = $(shell $(PG_CONFIG) --version | awk '{print $$2}')
-# PGVER_MAJOR = $(shell echo $(VERSION) | awk -F. '{ print ($$1 + 0) }')
-# PGVER_MINOR = $(shell echo $(VERSION) | awk -F. '{ print ($$2 + 0) }')
-# PGVER_PATCH = $(shell echo $(VERSION) | awk -F. '{ print ($$3 + 0) }')
-
-
-override CPPFLAGS := -I$(PARROTINC) -I$(srcdir) $(CPPFLAGS)
-override CFLAGS := $(PARROTLDFLAGS) $(PARROTLINKFLAGS) $(CFLAGS)
-
-ifneq ( $(strip $(wildcard $PERL6PBC)),)
-override CFLAGS := $(CFLAGS) -DHAS_PERL6 -D'PERL6PBC="$(PERL6PBC)"'
-endif
-
-# It would be nice if this ran before we compiled
-all: check_version headers
- @echo
- @echo
- @echo "Happy Hacking with PL/Parrot!"
- @echo
- @echo
-
-headers:
- ./bin/text2macro.pl plparrot_secure.pir > plparrot.h
- ./bin/text2macro.pl plperl6.pir > plperl6.h
-
-check_version:
- @echo
- @echo "Found Parrot Virtual Machine $(PARROT_VERSION) $(PARROTSHA1)"
- @echo
-
-test: all
- psql -AX -f $(TESTS)
-
-test_plperl6: all
- psql -AX -f $(PLPERL6_TESTS)
-
-release:
- [ -d plparrot-$(VERSION) ] || ln -s . plparrot-$(VERSION)
- git ls-files | grep -v .gitignore | perl -lane 'print "plparrot-$(VERSION)/$$F[0]"' | tar -zcv -T - -f plparrot-$(VERSION).tar.gz
10 PLATFORMS
View
@@ -1,10 +0,0 @@
-PL/Parrot was reported to compile and run tests on the following platforms:
-
-os;arch;psql;parrot;user;date
-Ubuntu 9.10;amd64;52b2760d4d7c27e29e1ae06c54e3067acb1f06a8;r46594;dukeleto20100513
-CentOS 5.4;amd64;c40ed912630bfd3d09ba93c64cdbbde61a2087ae;r45143;dukeleto;20100324
-CentOS 5.4;amd64;0306f8e34c8925ba01154da3f516edbc01fe60bd;r44603;dukeleto;20100303
-OS X 10.5;x86;8.3.8;2.0.0-devel;dukeleto;20100127
-Fedora 12;x86;c46f3447f1efbc9fbc30ce5d5b9c65bd75e10b89;?;davidfetter;20100127
-OpenBSD 4.6;x86;8.4.2;2.0.0-devel;darbelo;20100126
-Ubuntu 9.04;x86;8.3.9;1.9.0-devel;eggyknap;20100126
0  html/PLParrot_PGCon_2010.pdf → PLParrot_PGCon_2010.pdf
View
File renamed without changes
0  html/PLParrot_SFPM_20100525.pdf → PLParrot_SFPM_20100525.pdf
View
File renamed without changes
114 README.md
View
@@ -1,114 +0,0 @@
-# PL/Parrot 0.04
-
-PL/Parrot is a PostgreSQL procedural language for the Parrot virtual machine.
-
-
-# Installation
-
-For the impatient, to install PL/Parrot into a PostgreSQL database, just do this:
-
- make
- make install
- make installcheck
-
-If you get an error such as:
-
-Makefile:13: /usr/lib/postgresql/8.4/lib/pgxs/src/makefiles/pgxs.mk: No such file or directory
-make: *** No rule to make target `/usr/lib/postgresql/8.4/lib/pgxs/src/makefiles/pgxs.mk'. Stop.
-
-then you probably installed postgres from a debian package. You need to install the
-postgresql-server-dev-X package, where X is your version of PostgreSQL. For example:
-
- sudo apt-get install postgresql-server-dev-8.4
-
-To run the tests with pg_prove you should create the plpgsql language in your database.
-The default database name is your current username, so this should work:
-
- createlang plpgsql $USER
- make test
-
-If you encounter an error such as:
-
- "Makefile", line 8: Need an operator
-
-You need to use GNU make, which may well be installed on your system as
-'gmake':
-
- gmake
- gmake install
- gmake installcheck
-
-If you encounter an error such as:
-
- make: pg_config: Command not found
-
-Be sure that you have `pg_config` installed and in your path. If you used a
-package management system such as RPM to install PostgreSQL, be sure that the
-`-devel` package is also installed. If necessary, add the path to `pg_config`
-to your `$PATH` environment variable:
-
- env PATH=$PATH:/path/to/pgsql/bin \
- make && make install && make installcheck
-
-And finally, if all that fails, copy the entire distribution directory to the
-`contrib/` subdirectory of the PostgreSQL source tree and try it there without
-the `$USE_PGXS` variable:
-
- make NO_PGXS=1
- make install NO_PGXS=1
- make installcheck NO_PGXS=1
-
-If you encounter an error such as:
-
- ERROR: must be owner of database regression
-
-You need to run the test suite using a super user, such as the default
-"postgres" super user:
-
- make installcheck PGUSER=postgres
-
-# Testing PL/Parrot with PL/Parrot
-
-In addition to the PostgreSQL-standard `installcheck` target, the `test`
-target uses the `pg_prove` Perl program to do its testing, which requires
-TAP::Harness, included in
-[Test::Harness](http://search.cpan.org/dist/Test-Harness/ "Test::Harness on
-CPAN") 3.x. You'll need to make sure that you use a database with PL/pgSQL
-loaded, or else the tests won't work. `pg_prove` supports a number of
-environment variables that you might need to use, including all the usual
-PostgreSQL client environment variables:
-
-* `$PGDATABASE`
-* `$PGHOST`
-* `$PGPORT`
-* `$PGUSER`
-
-You can use it to run the test suite as a database super user like so:
-
- make test PGUSER=postgres
-
-Of course, if you're running the tests from the `contrib/` directory, you
-should add the `NO_PGXS` variable.
-
-# Adding PL/Parrot to a Database
-
-Once PL/Parrot has been built and tested, you can install it into a
-PL/pgSQL-enabled database:
-
- psql -d dbname -f plparrot.sql
-
-If you want PL/Parrot to be available to all new databases, install it into the
-"template1" database:
-
- psql -d template1 -f plparrot.sql
-
-The `plparrot.sql script will also be installed in the `contrib` directory
-under the directory output by `pg_config --sharedir`. So you can always do
-this:
-
- psql -d template1 -f `pg_config --sharedir`/contrib/plparrot.sql
-
-# License
-
-This code is distributed under the terms of the Artistic License 2.0.
-For more details, see the full text of the license in the file LICENSE.
39 ROADMAP
View
@@ -1,39 +0,0 @@
-
-=head1 PL/Parrot ROADMAP
-
-This document describes the roadmap for PL/Parrot. Please be as specific as possible.
-
-* Datatype marshalling is another big step -- eggyknap knows about this stuff.
- Function parameters need to be converted from pgsql Datum types to something
- Parrot can both understand and have access to. The function's return value(s)
- then need to be converted back to Datums.
-
- This has been accomplished for integers, floats and string types. More code
- needs to be written for all of the various PG datatypes. It also needs
- to be thought out how HLL's deal with datatype conversion.
-
-* Make installation and configuration easier
-
- In general, there should be a "Parrot way" to install PL/Parrot (via
- Plumage) and a "Postgres way" (whatever that is) to keep people in both
- camps happy.
-
-* Implement spi_exec_query() for PIR
-
- This involves many intermediate steps that should be listed in detail here.
- eggyknap's version:
- * In PL/Perl, there's some XS code to allow PL/Perl functions access to
- spi_exec_query and several other SPI functions (the complete list of
- which is here:
- http://www.postgresql.org/docs/current/static/spi.html). PL/Python
- creates some Python function objects and registers them with the
- Python interpreter. Presumably for Parrot, we'll create a compiled
- module Parrot code can load, containing those functions. I've no idea
- how to build such a thing.
-
- eggyknap idea:
- Originally I'd thought we'd provide some module or something users
- would load, and then use for database access. Perhaps it makes more
- sense to build a PMC that provides db access functions, and make it
- available in the default namespace
-
23 TODO
View
@@ -1,23 +0,0 @@
-=head1 TODO items for PL/Parrot
-
-* Tests for the Socket PMC (does it even work?)
-
-* Developer documentation
-
-* End-user/sysadmin/DBA documentation
-
-* use distutils.pir and/or allow install via Plumage ?
-
-* Add support for returning "setof" supported datatypes (see PL/Perl test suite)
-
-* Add support for custom datatypes (see PL/Perl test suite)
-
-* Add support for more PG datatypes (in order of importance):
-
-** Timestamp datatypes
-
-*** These can currently be passed back and forth between Postgres + Parrot, but
-there is no interface to modify them from PIR
-
-
-
105 bin/text2macro.pl
View
@@ -1,105 +0,0 @@
-#!/usr/bin/env perl
-
-# This is borrowed from PostgreSQL, it is just a copy for the
-# convenience of PL/Parrot developers
-
-# $PostgreSQL:$
-
-=head1 NAME
-
-text2macro.pl - convert text files into C string-literal macro definitions
-
-=head1 SYNOPSIS
-
- text2macro [options] file ... > output.h
-
-Options:
-
- --prefix=S - add prefix S to the names of the macros
- --name=S - use S as the macro name (assumes only one file)
- --strip=S - don't include lines that match perl regex S
-
-=head1 DESCRIPTION
-
-Reads one or more text files and outputs a corresponding series of C
-pre-processor macro definitions. Each macro defines a string literal that
-contains the contents of the corresponding text file. The basename of the text
-file as capitalized and used as the name of the macro, along with an optional prefix.
-
-=cut
-
-use strict;
-use warnings;
-
-use Getopt::Long;
-
-GetOptions(
- 'prefix=s' => \my $opt_prefix,
- 'name=s' => \my $opt_name,
- 'strip=s' => \my $opt_strip,
- 'selftest!' => sub { exit selftest() },
-) or exit 1;
-
-die "No text files specified"
- unless @ARGV;
-
-print qq{
-/*
- * DO NOT EDIT - THIS FILE IS AUTOGENERATED - CHANGES WILL BE LOST
- * Written by $0 from @ARGV
- */
-};
-
-for my $src_file (@ARGV) {
-
- (my $macro = $src_file) =~ s/ .*? (\w+) (?:\.\w+) $/$1/x;
-
- open my $src_fh, $src_file # not 3-arg form
- or die "Can't open $src_file: $!";
-
- printf qq{#define %s%s \\\n},
- $opt_prefix || '',
- ($opt_name) ? $opt_name : uc $macro;
- while (<$src_fh>) {
- chomp;
-
- next if $opt_strip and m/$opt_strip/o;
-
- # escape the text to suite C string literal rules
- s/\\/\\\\/g;
- s/"/\\"/g;
-
- printf qq{"%s\\n" \\\n}, $_;
- }
- print qq{""\n\n};
-}
-
-print "/* end */\n";
-
-exit 0;
-
-
-sub selftest {
- my $tmp = "text2macro_tmp";
- my $string = q{a '' '\\'' "" "\\"" "\\\\" "\\\\n" b};
-
- open my $fh, ">$tmp.pl" or die;
- print $fh $string;
- close $fh;
-
- system("perl $0 --name=X $tmp.pl > $tmp.c") == 0 or die;
- open $fh, ">>$tmp.c";
- print $fh "#include <stdio.h>\n";
- print $fh "int main() { puts(X); return 0; }\n";
- close $fh;
- system("cat -n $tmp.c");
-
- system("make $tmp") == 0 or die;
- open $fh, "./$tmp |" or die;
- my $result = <$fh>;
- unlink <$tmp.*>;
-
- warn "Test string: $string\n";
- warn "Result : $result";
- die "Failed!" if $result ne "$string\n";
-}
0  html/community.html → community.html
View
File renamed without changes
2  config.h
View
@@ -1,2 +0,0 @@
-/* Default max sub lenght of 64KB */
-#define MAX_SUBROUTINE_LENGTH 1024*64
0  html/css/project-site.css → css/project-site.css
View
File renamed without changes
0  html/docs.html → docs.html
View
File renamed without changes
41 expected/test.out
View
@@ -1,41 +0,0 @@
-\unset ECHO
-psql:plparrot.sql:18: NOTICE: language "plparrot" does not exist, skipping
-psql:plparrot.sql:22: NOTICE: language "plparrotu" does not exist, skipping
-psql:plparrot.sql:26: NOTICE: language "plpir" does not exist, skipping
-psql:plparrot.sql:30: NOTICE: language "plpiru" does not exist, skipping
-psql:plparrot.sql:33: NOTICE: language "plperl6" does not exist, skipping
-psql:plparrot.sql:36: NOTICE: language "plperl6u" does not exist, skipping
-1..33
-ok 1 - we can .include PIR libraries included with Parrot
-ok 2 - we can load_bytecode PBC libraries included with Parrot
-ok 3 - FileHandle.open is mocked in PL/PIR
-ok 4 - FileHandle.open is not mocked in PL/PIRU
-ok 5 - File.open is mocked
-ok 6 - We can pass a text in
-ok 7 - We can return a text
-ok 8 - We can pass a varchar in
-ok 9 - We can return a varchar
-ok 10 - We can concat and return a varchar
-ok 11 - We can pass an int and float as arguments
-ok 12 - We can pass a char in
-ok 13 - We can return a char
-ok 14 - We can pass in an int
-ok 15 - We can return an int
-ok 16 - plpir is an alias for plparrot
-ok 17 - plpiru can return values
-ok 18 - plparrotu can return values
-ok 19 - Immutable works
-ok 20 - Strict works
-ok 21 - We can increment an int and return it
-ok 22 - We can return an int
-ok 23 - We can return void
-ok 24 - We can return a float
-ok 25 - We can add to a float and return it
-ok 26 - We can pass a timestamp in
-ok 27 - We can return a timestamp
-ok 28 - We can pass a timestamptz in
-ok 29 - We can return a timestamptz
-ok 30 - We can pass a time in
-ok 31 - We can return a time
-ok 32 - PL/Parrot should be trusted
-ok 33 - PL/PIR should be trusted
0  html/img/PLParrot.jpg → img/PLParrot.jpg
View
File renamed without changes
0  html/index.html → index.html
View
File renamed without changes
0  libsrc/handler/.placeholder
View
No changes.
23 load_pir.test.sql
View
@@ -1,23 +0,0 @@
-begin;
--- PL/Parrot is copyright Jonathan "Duke" Leto and friends 2009-2010
--- This code is released under the Artistic 2.0 License, see LICENSE for
--- details.
-
--- handler function
-CREATE OR REPLACE FUNCTION plparrot_call_handler ()
-RETURNS language_handler AS '$libdir/plparrot' LANGUAGE C;
-
--- language
-DROP LANGUAGE IF EXISTS plparrot CASCADE;
-CREATE LANGUAGE plparrot HANDLER plparrot_call_handler;
-
-create or replace function plp_test() RETURNS VOID language plparrot as $$
- syntax error
- my name is 'fred'
- $P0 = open '/tmp/testfile.plparrot.txt', 'w'
- print $P0, 'Nobody expects this to work'
- close $P0
-$$;
-
-select plp_test();
-rollback;
1,539 pgtap.sql
View
@@ -1,1539 +0,0 @@
--- PL/Parrot is copyright Jonathan "Duke" Leto and friends 2009-2010
--- This code is released under the Artistic 2.0 License, see LICENSE for
--- details.
-
--- This could be called pgTAP Lite, it is a subset of pgTAP proper,
--- with all schema-related functions removed
-
--- This file defines pgTAP, a collection of functions for TAP-based unit
--- testing. It is distributed under the revised FreeBSD license. You can
--- find the original here:
---
--- http://github.com/theory/pgtap/raw/master/pgtap.sql.in
---
--- The home page for the pgTAP project is:
---
--- http://pgtap.org/
-
--- ## CREATE SCHEMA TAPSCHEMA;
--- ## SET search_path TO TAPSCHEMA, public;
-
-CREATE OR REPLACE FUNCTION pg_version()
-RETURNS text AS 'SELECT current_setting(''server_version'')'
-LANGUAGE SQL IMMUTABLE;
-
-CREATE OR REPLACE FUNCTION pg_version_num()
-RETURNS integer AS $$
- SELECT s.a[1]::int * 10000
- + COALESCE(substring(s.a[2] FROM '[[:digit:]]+')::int, 0) * 100
- + COALESCE(substring(s.a[3] FROM '[[:digit:]]+')::int, 0)
- FROM (
- SELECT string_to_array(current_setting('server_version'), '.') AS a
- ) AS s;
-$$ LANGUAGE SQL IMMUTABLE;
-
-CREATE OR REPLACE FUNCTION os_name()
-RETURNS TEXT AS 'SELECT ''darwin''::text;'
-LANGUAGE SQL IMMUTABLE;
-
-CREATE OR REPLACE FUNCTION pgtap_version()
-RETURNS NUMERIC AS 'SELECT 0.23;'
-LANGUAGE SQL IMMUTABLE;
-
-CREATE OR REPLACE FUNCTION plan( integer )
-RETURNS TEXT AS $$
-DECLARE
- rcount INTEGER;
- cmm text := current_setting('client_min_messages');
-BEGIN
- BEGIN
- PERFORM set_config('client_min_messages', 'warning', true);
- EXECUTE '
- CREATE SEQUENCE __tresults___numb_seq;
- CREATE SEQUENCE __tcache___numb_seq;
-
- CREATE TEMP TABLE __tcache__ (
- id integer default nextval(''__tcache___numb_seq''),
- label TEXT NOT NULL,
- value INTEGER NOT NULL,
- note TEXT NOT NULL DEFAULT ''''
- );
- GRANT ALL ON TABLE __tcache__ TO PUBLIC;
-
- CREATE TEMP TABLE __tresults__ (
- numb integer default nextval(''__tresults___numb_seq''),
- ok BOOLEAN NOT NULL DEFAULT TRUE,
- aok BOOLEAN NOT NULL DEFAULT TRUE,
- descr TEXT NOT NULL DEFAULT '''',
- type TEXT NOT NULL DEFAULT '''',
- reason TEXT NOT NULL DEFAULT ''''
- );
- GRANT ALL ON TABLE __tresults__ TO PUBLIC;
- GRANT ALL ON TABLE __tresults___numb_seq TO PUBLIC;
- ';
-
- EXCEPTION WHEN duplicate_table THEN
- PERFORM set_config('client_min_messages', cmm, true);
- -- Raise an exception if there's already a plan.
- EXECUTE 'SELECT TRUE FROM __tcache__ WHERE label = ''plan''';
- GET DIAGNOSTICS rcount = ROW_COUNT;
- IF rcount > 0 THEN
- RAISE EXCEPTION 'You tried to plan twice!';
- END IF;
- END;
-
- PERFORM set_config('client_min_messages', cmm, true);
-
- -- Save the plan and return.
- PERFORM _set('plan', $1 );
- RETURN '1..' || $1;
-END;
-$$ LANGUAGE plpgsql strict;
-
-CREATE OR REPLACE FUNCTION no_plan()
-RETURNS SETOF boolean AS $$
-BEGIN
- PERFORM plan(0);
- RETURN;
-END;
-$$ LANGUAGE plpgsql strict;
-
-CREATE OR REPLACE FUNCTION _get ( text )
-RETURNS integer AS $$
-DECLARE
- ret integer;
-BEGIN
- EXECUTE 'SELECT value FROM __tcache__ WHERE label = ' || quote_literal($1) || ' LIMIT 1' INTO ret;
- RETURN ret;
-END;
-$$ LANGUAGE plpgsql strict;
-
-CREATE OR REPLACE FUNCTION _get_latest ( text )
-RETURNS integer[] AS $$
-DECLARE
- ret integer[];
-BEGIN
- EXECUTE 'SELECT ARRAY[ id, value] FROM __tcache__ WHERE label = ' ||
- quote_literal($1) || ' AND id = (SELECT MAX(id) FROM __tcache__ WHERE label = ' ||
- quote_literal($1) || ') LIMIT 1' INTO ret;
- RETURN ret;
-END;
-$$ LANGUAGE plpgsql strict;
-
-CREATE OR REPLACE FUNCTION _get_latest ( text, integer )
-RETURNS integer AS $$
-DECLARE
- ret integer;
-BEGIN
- EXECUTE 'SELECT MAX(id) FROM __tcache__ WHERE label = ' ||
- quote_literal($1) || ' AND value = ' || $2 INTO ret;
- RETURN ret;
-END;
-$$ LANGUAGE plpgsql strict;
-
-CREATE OR REPLACE FUNCTION _get_note ( text )
-RETURNS text AS $$
-DECLARE
- ret text;
-BEGIN
- EXECUTE 'SELECT note FROM __tcache__ WHERE label = ' || quote_literal($1) || ' LIMIT 1' INTO ret;
- RETURN ret;
-END;
-$$ LANGUAGE plpgsql strict;
-
-CREATE OR REPLACE FUNCTION _get_note ( integer )
-RETURNS text AS $$
-DECLARE
- ret text;
-BEGIN
- EXECUTE 'SELECT note FROM __tcache__ WHERE id = ' || $1 || ' LIMIT 1' INTO ret;
- RETURN ret;
-END;
-$$ LANGUAGE plpgsql strict;
-
-CREATE OR REPLACE FUNCTION _set ( text, integer, text )
-RETURNS integer AS $$
-DECLARE
- rcount integer;
-BEGIN
- EXECUTE 'UPDATE __tcache__ SET value = ' || $2
- || CASE WHEN $3 IS NULL THEN '' ELSE ', note = ' || quote_literal($3) END
- || ' WHERE label = ' || quote_literal($1);
- GET DIAGNOSTICS rcount = ROW_COUNT;
- IF rcount = 0 THEN
- RETURN _add( $1, $2, $3 );
- END IF;
- RETURN $2;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION _set ( text, integer )
-RETURNS integer AS $$
- SELECT _set($1, $2, '')
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION _set ( integer, integer )
-RETURNS integer AS $$
-BEGIN
- EXECUTE 'UPDATE __tcache__ SET value = ' || $2
- || ' WHERE id = ' || $1;
- RETURN $2;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION _add ( text, integer, text )
-RETURNS integer AS $$
-BEGIN
- EXECUTE 'INSERT INTO __tcache__ (label, value, note) values (' ||
- quote_literal($1) || ', ' || $2 || ', ' || quote_literal(COALESCE($3, '')) || ')';
- RETURN $2;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION _add ( text, integer )
-RETURNS integer AS $$
- SELECT _add($1, $2, '')
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION add_result ( bool, bool, text, text, text )
-RETURNS integer AS $$
-BEGIN
- EXECUTE 'INSERT INTO __tresults__ ( ok, aok, descr, type, reason )
- VALUES( ' || $1 || ', '
- || $2 || ', '
- || quote_literal(COALESCE($3, '')) || ', '
- || quote_literal($4) || ', '
- || quote_literal($5) || ' )';
- RETURN currval('__tresults___numb_seq');
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION num_failed ()
-RETURNS INTEGER AS $$
-DECLARE
- ret integer;
-BEGIN
- EXECUTE 'SELECT COUNT(*)::INTEGER FROM __tresults__ WHERE ok = FALSE' INTO ret;
- RETURN ret;
-END;
-$$ LANGUAGE plpgsql strict;
-
-CREATE OR REPLACE FUNCTION _finish ( INTEGER, INTEGER, INTEGER)
-RETURNS SETOF TEXT AS $$
-DECLARE
- curr_test ALIAS FOR $1;
- exp_tests INTEGER := $2;
- num_faild ALIAS FOR $3;
- plural CHAR;
-BEGIN
- plural := CASE exp_tests WHEN 1 THEN '' ELSE 's' END;
-
- IF curr_test IS NULL THEN
- RAISE EXCEPTION '# No tests run!';
- END IF;
-
- IF exp_tests = 0 OR exp_tests IS NULL THEN
- -- No plan. Output one now.
- exp_tests = curr_test;
- RETURN NEXT '1..' || exp_tests;
- END IF;
-
- IF curr_test <> exp_tests THEN
- RETURN NEXT diag(
- 'Looks like you planned ' || exp_tests || ' test' ||
- plural || ' but ran ' || curr_test
- );
- ELSIF num_faild > 0 THEN
- RETURN NEXT diag(
- 'Looks like you failed ' || num_faild || ' test' ||
- CASE num_faild WHEN 1 THEN '' ELSE 's' END
- || ' of ' || exp_tests
- );
- ELSE
-
- END IF;
- RETURN;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION finish ()
-RETURNS SETOF TEXT AS $$
- SELECT * FROM _finish(
- _get('curr_test'),
- _get('plan'),
- num_failed()
- );
-$$ LANGUAGE sql;
-
-CREATE OR REPLACE FUNCTION diag ( msg text )
-RETURNS TEXT AS $$
- SELECT '# ' || replace(
- replace(
- replace( $1, E'\r\n', E'\n# ' ),
- E'\n',
- E'\n# '
- ),
- E'\r',
- E'\n# '
- );
-$$ LANGUAGE sql strict;
-
-CREATE OR REPLACE FUNCTION ok ( boolean, text )
-RETURNS TEXT AS $$
-DECLARE
- aok ALIAS FOR $1;
- descr text := $2;
- test_num INTEGER;
- todo_why TEXT;
- ok BOOL;
-BEGIN
- todo_why := _todo();
- ok := CASE
- WHEN aok = TRUE THEN aok
- WHEN todo_why IS NULL THEN COALESCE(aok, false)
- ELSE TRUE
- END;
- IF _get('plan') IS NULL THEN
- RAISE EXCEPTION 'You tried to run a test without a plan! Gotta have a plan';
- END IF;
-
- test_num := add_result(
- ok,
- COALESCE(aok, false),
- descr,
- CASE WHEN todo_why IS NULL THEN '' ELSE 'todo' END,
- COALESCE(todo_why, '')
- );
-
- RETURN (CASE aok WHEN TRUE THEN '' ELSE 'not ' END)
- || 'ok ' || _set( 'curr_test', test_num )
- || CASE descr WHEN '' THEN '' ELSE COALESCE( ' - ' || substr(diag( descr ), 3), '' ) END
- || COALESCE( ' ' || diag( 'TODO ' || todo_why ), '')
- || CASE aok WHEN TRUE THEN '' ELSE E'\n' ||
- diag('Failed ' ||
- CASE WHEN todo_why IS NULL THEN '' ELSE '(TODO) ' END ||
- 'test ' || test_num ||
- CASE descr WHEN '' THEN '' ELSE COALESCE(': "' || descr || '"', '') END ) ||
- CASE WHEN aok IS NULL THEN E'\n' || diag(' (test result was NULL)') ELSE '' END
- END;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION ok ( boolean )
-RETURNS TEXT AS $$
- SELECT ok( $1, NULL );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION is (anyelement, anyelement, text)
-RETURNS TEXT AS $$
-DECLARE
- result BOOLEAN;
- output TEXT;
-BEGIN
- -- Would prefer $1 IS NOT DISTINCT FROM, but that's not supported by 8.1.
- result := NOT $1 IS DISTINCT FROM $2;
- output := ok( result, $3 );
- RETURN output || CASE result WHEN TRUE THEN '' ELSE E'\n' || diag(
- ' have: ' || COALESCE( $1::text, 'NULL' ) ||
- E'\n want: ' || COALESCE( $2::text, 'NULL' )
- ) END;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION is (anyelement, anyelement)
-RETURNS TEXT AS $$
- SELECT is( $1, $2, NULL);
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION isnt (anyelement, anyelement, text)
-RETURNS TEXT AS $$
-DECLARE
- result BOOLEAN;
- output TEXT;
-BEGIN
- result := $1 IS DISTINCT FROM $2;
- output := ok( result, $3 );
- RETURN output || CASE result WHEN TRUE THEN '' ELSE E'\n' || diag(
- ' ' || COALESCE( $1::text, 'NULL' ) ||
- E'\n <>' ||
- E'\n ' || COALESCE( $2::text, 'NULL' )
- ) END;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION isnt (anyelement, anyelement)
-RETURNS TEXT AS $$
- SELECT isnt( $1, $2, NULL);
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION _alike ( BOOLEAN, ANYELEMENT, TEXT, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- result ALIAS FOR $1;
- got ALIAS FOR $2;
- rx ALIAS FOR $3;
- descr ALIAS FOR $4;
- output TEXT;
-BEGIN
- output := ok( result, descr );
- RETURN output || CASE result WHEN TRUE THEN '' ELSE E'\n' || diag(
- ' ' || COALESCE( quote_literal(got), 'NULL' ) ||
- E'\n doesn''t match: ' || COALESCE( quote_literal(rx), 'NULL' )
- ) END;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION matches ( anyelement, text, text )
-RETURNS TEXT AS $$
- SELECT _alike( $1 ~ $2, $1, $2, $3 );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION matches ( anyelement, text )
-RETURNS TEXT AS $$
- SELECT _alike( $1 ~ $2, $1, $2, NULL );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION imatches ( anyelement, text, text )
-RETURNS TEXT AS $$
- SELECT _alike( $1 ~* $2, $1, $2, $3 );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION imatches ( anyelement, text )
-RETURNS TEXT AS $$
- SELECT _alike( $1 ~* $2, $1, $2, NULL );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION alike ( anyelement, text, text )
-RETURNS TEXT AS $$
- SELECT _alike( $1 ~~ $2, $1, $2, $3 );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION alike ( anyelement, text )
-RETURNS TEXT AS $$
- SELECT _alike( $1 ~~ $2, $1, $2, NULL );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION ialike ( anyelement, text, text )
-RETURNS TEXT AS $$
- SELECT _alike( $1 ~~* $2, $1, $2, $3 );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION ialike ( anyelement, text )
-RETURNS TEXT AS $$
- SELECT _alike( $1 ~~* $2, $1, $2, NULL );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION _unalike ( BOOLEAN, ANYELEMENT, TEXT, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- result ALIAS FOR $1;
- got ALIAS FOR $2;
- rx ALIAS FOR $3;
- descr ALIAS FOR $4;
- output TEXT;
-BEGIN
- output := ok( result, descr );
- RETURN output || CASE result WHEN TRUE THEN '' ELSE E'\n' || diag(
- ' ' || COALESCE( quote_literal(got), 'NULL' ) ||
- E'\n matches: ' || COALESCE( quote_literal(rx), 'NULL' )
- ) END;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION doesnt_match ( anyelement, text, text )
-RETURNS TEXT AS $$
- SELECT _unalike( $1 !~ $2, $1, $2, $3 );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION doesnt_match ( anyelement, text )
-RETURNS TEXT AS $$
- SELECT _unalike( $1 !~ $2, $1, $2, NULL );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION doesnt_imatch ( anyelement, text, text )
-RETURNS TEXT AS $$
- SELECT _unalike( $1 !~* $2, $1, $2, $3 );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION doesnt_imatch ( anyelement, text )
-RETURNS TEXT AS $$
- SELECT _unalike( $1 !~* $2, $1, $2, NULL );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION unalike ( anyelement, text, text )
-RETURNS TEXT AS $$
- SELECT _unalike( $1 !~~ $2, $1, $2, $3 );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION unalike ( anyelement, text )
-RETURNS TEXT AS $$
- SELECT _unalike( $1 !~~ $2, $1, $2, NULL );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION unialike ( anyelement, text, text )
-RETURNS TEXT AS $$
- SELECT _unalike( $1 !~~* $2, $1, $2, $3 );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION unialike ( anyelement, text )
-RETURNS TEXT AS $$
- SELECT _unalike( $1 !~~* $2, $1, $2, NULL );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION cmp_ok (anyelement, text, anyelement, text)
-RETURNS TEXT AS $$
-DECLARE
- have ALIAS FOR $1;
- op ALIAS FOR $2;
- want ALIAS FOR $3;
- descr ALIAS FOR $4;
- result BOOLEAN;
- output TEXT;
-BEGIN
- EXECUTE 'SELECT ' ||
- COALESCE(quote_literal( have ), 'NULL') || '::' || pg_typeof(have) || ' '
- || op || ' ' ||
- COALESCE(quote_literal( want ), 'NULL') || '::' || pg_typeof(want)
- INTO result;
- output := ok( COALESCE(result, FALSE), descr );
- RETURN output || CASE result WHEN TRUE THEN '' ELSE E'\n' || diag(
- ' ' || COALESCE( quote_literal(have), 'NULL' ) ||
- E'\n ' || op ||
- E'\n ' || COALESCE( quote_literal(want), 'NULL' )
- ) END;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION cmp_ok (anyelement, text, anyelement)
-RETURNS TEXT AS $$
- SELECT cmp_ok( $1, $2, $3, NULL );
-$$ LANGUAGE sql;
-
-CREATE OR REPLACE FUNCTION pass ( text )
-RETURNS TEXT AS $$
- SELECT ok( TRUE, $1 );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION pass ()
-RETURNS TEXT AS $$
- SELECT ok( TRUE, NULL );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION fail ( text )
-RETURNS TEXT AS $$
- SELECT ok( FALSE, $1 );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION fail ()
-RETURNS TEXT AS $$
- SELECT ok( FALSE, NULL );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION todo ( why text, how_many int )
-RETURNS SETOF BOOLEAN AS $$
-BEGIN
- PERFORM _add('todo', COALESCE(how_many, 1), COALESCE(why, ''));
- RETURN;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION todo ( how_many int, why text )
-RETURNS SETOF BOOLEAN AS $$
-BEGIN
- PERFORM _add('todo', COALESCE(how_many, 1), COALESCE(why, ''));
- RETURN;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION todo ( why text )
-RETURNS SETOF BOOLEAN AS $$
-BEGIN
- PERFORM _add('todo', 1, COALESCE(why, ''));
- RETURN;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION todo ( how_many int )
-RETURNS SETOF BOOLEAN AS $$
-BEGIN
- PERFORM _add('todo', COALESCE(how_many, 1), '');
- RETURN;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION todo_start (text)
-RETURNS SETOF BOOLEAN AS $$
-BEGIN
- PERFORM _add('todo', -1, COALESCE($1, ''));
- RETURN;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION todo_start ()
-RETURNS SETOF BOOLEAN AS $$
-BEGIN
- PERFORM _add('todo', -1, '');
- RETURN;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION in_todo ()
-RETURNS BOOLEAN AS $$
-DECLARE
- todos integer;
-BEGIN
- todos := _get('todo');
- RETURN CASE WHEN todos IS NULL THEN FALSE ELSE TRUE END;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION todo_end ()
-RETURNS SETOF BOOLEAN AS $$
-DECLARE
- id integer;
-BEGIN
- id := _get_latest( 'todo', -1 );
- IF id IS NULL THEN
- RAISE EXCEPTION 'todo_end() called without todo_start()';
- END IF;
- EXECUTE 'DELETE FROM __tcache__ WHERE id = ' || id;
- RETURN;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION _todo()
-RETURNS TEXT AS $$
-DECLARE
- todos INT[];
- note text;
-BEGIN
- -- Get the latest id and value, because todo() might have been called
- -- again before the todos ran out for the first call to todo(). This
- -- allows them to nest.
- todos := _get_latest('todo');
- IF todos IS NULL THEN
- -- No todos.
- RETURN NULL;
- END IF;
- IF todos[2] = 0 THEN
- -- Todos depleted. Clean up.
- EXECUTE 'DELETE FROM __tcache__ WHERE id = ' || todos[1];
- RETURN NULL;
- END IF;
- -- Decrement the count of counted todos and return the reason.
- IF todos[2] <> -1 THEN
- PERFORM _set(todos[1], todos[2] - 1);
- END IF;
- note := _get_note(todos[1]);
-
- IF todos[2] = 1 THEN
- -- This was the last todo, so delete the record.
- EXECUTE 'DELETE FROM __tcache__ WHERE id = ' || todos[1];
- END IF;
-
- RETURN note;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION skip ( why text, how_many int )
-RETURNS TEXT AS $$
-DECLARE
- output TEXT[];
-BEGIN
- output := '{}';
- FOR i IN 1..how_many LOOP
- output = array_append(output, ok( TRUE, 'SKIP: ' || COALESCE( why, '') ) );
- END LOOP;
- RETURN array_to_string(output, E'\n');
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION skip ( text )
-RETURNS TEXT AS $$
- SELECT ok( TRUE, 'SKIP: ' || $1 );
-$$ LANGUAGE sql;
-
-CREATE OR REPLACE FUNCTION skip( int, text )
-RETURNS TEXT AS 'SELECT skip($2, $1)'
-LANGUAGE sql;
-
-CREATE OR REPLACE FUNCTION skip( int )
-RETURNS TEXT AS 'SELECT skip(NULL, $1)'
-LANGUAGE sql;
-
-CREATE OR REPLACE FUNCTION _query( TEXT )
-RETURNS TEXT AS $$
- SELECT CASE
- WHEN $1 LIKE '"%' OR $1 !~ '[[:space:]]' THEN 'EXECUTE ' || $1
- ELSE $1
- END;
-$$ LANGUAGE SQL;
-
--- throws_ok ( sql, errcode, errmsg, description )
-CREATE OR REPLACE FUNCTION throws_ok ( TEXT, CHAR(5), TEXT, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- query TEXT := _query($1);
- errcode ALIAS FOR $2;
- errmsg ALIAS FOR $3;
- desctext ALIAS FOR $4;
- descr TEXT;
-BEGIN
- descr := COALESCE(
- desctext,
- 'threw ' || errcode || ': ' || errmsg,
- 'threw ' || errcode,
- 'threw ' || errmsg,
- 'threw an exception'
- );
- EXECUTE query;
- RETURN ok( FALSE, descr ) || E'\n' || diag(
- ' caught: no exception' ||
- E'\n wanted: ' || COALESCE( errcode, 'an exception' )
- );
-EXCEPTION WHEN OTHERS THEN
- IF (errcode IS NULL OR SQLSTATE = errcode)
- AND ( errmsg IS NULL OR SQLERRM = errmsg)
- THEN
- -- The expected errcode and/or message was thrown.
- RETURN ok( TRUE, descr );
- ELSE
- -- This was not the expected errcodeor.
- RETURN ok( FALSE, descr ) || E'\n' || diag(
- ' caught: ' || SQLSTATE || ': ' || SQLERRM ||
- E'\n wanted: ' || COALESCE( errcode, 'an exception' ) ||
- COALESCE( ': ' || errmsg, '')
- );
- END IF;
-END;
-$$ LANGUAGE plpgsql;
-
--- throws_ok ( sql, errcode, errmsg )
--- throws_ok ( sql, errmsg, description )
-CREATE OR REPLACE FUNCTION throws_ok ( TEXT, TEXT, TEXT )
-RETURNS TEXT AS $$
-BEGIN
- IF octet_length($2) = 5 THEN
- RETURN throws_ok( $1, $2::char(5), $3, NULL );
- ELSE
- RETURN throws_ok( $1, NULL, $2, $3 );
- END IF;
-END;
-$$ LANGUAGE plpgsql;
-
--- throws_ok ( query, errcode )
--- throws_ok ( query, errmsg )
-CREATE OR REPLACE FUNCTION throws_ok ( TEXT, TEXT )
-RETURNS TEXT AS $$
-BEGIN
- IF octet_length($2) = 5 THEN
- RETURN throws_ok( $1, $2::char(5), NULL, NULL );
- ELSE
- RETURN throws_ok( $1, NULL, $2, NULL );
- END IF;
-END;
-$$ LANGUAGE plpgsql;
-
--- throws_ok ( sql )
-CREATE OR REPLACE FUNCTION throws_ok ( TEXT )
-RETURNS TEXT AS $$
- SELECT throws_ok( $1, NULL, NULL, NULL );
-$$ LANGUAGE SQL;
-
--- Magically cast integer error codes.
--- throws_ok ( sql, errcode, errmsg, description )
-CREATE OR REPLACE FUNCTION throws_ok ( TEXT, int4, TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT throws_ok( $1, $2::char(5), $3, $4 );
-$$ LANGUAGE SQL;
-
--- throws_ok ( sql, errcode, errmsg )
-CREATE OR REPLACE FUNCTION throws_ok ( TEXT, int4, TEXT )
-RETURNS TEXT AS $$
- SELECT throws_ok( $1, $2::char(5), $3, NULL );
-$$ LANGUAGE SQL;
-
--- throws_ok ( sql, errcode )
-CREATE OR REPLACE FUNCTION throws_ok ( TEXT, int4 )
-RETURNS TEXT AS $$
- SELECT throws_ok( $1, $2::char(5), NULL, NULL );
-$$ LANGUAGE SQL;
-
--- lives_ok( sql, description )
-CREATE OR REPLACE FUNCTION lives_ok ( TEXT, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- code TEXT := _query($1);
- descr ALIAS FOR $2;
-BEGIN
- EXECUTE code;
- RETURN ok( TRUE, descr );
-EXCEPTION WHEN OTHERS THEN
- -- There should have been no exception.
- RETURN ok( FALSE, descr ) || E'\n' || diag(
- ' died: ' || SQLSTATE || ': ' || SQLERRM
- );
-END;
-$$ LANGUAGE plpgsql;
-
--- lives_ok( sql )
-CREATE OR REPLACE FUNCTION lives_ok ( TEXT )
-RETURNS TEXT AS $$
- SELECT lives_ok( $1, NULL );
-$$ LANGUAGE SQL;
-
--- performs_ok ( sql, milliseconds, description )
-CREATE OR REPLACE FUNCTION performs_ok ( TEXT, NUMERIC, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- query TEXT := _query($1);
- max_time ALIAS FOR $2;
- descr ALIAS FOR $3;
- starts_at TEXT;
- act_time NUMERIC;
-BEGIN
- starts_at := timeofday();
- EXECUTE query;
- act_time := extract( millisecond from timeofday()::timestamptz - starts_at::timestamptz);
- IF act_time < max_time THEN RETURN ok(TRUE, descr); END IF;
- RETURN ok( FALSE, descr ) || E'\n' || diag(
- ' runtime: ' || act_time || ' ms' ||
- E'\n exceeds: ' || max_time || ' ms'
- );
-END;
-$$ LANGUAGE plpgsql;
-
--- performs_ok ( sql, milliseconds )
-CREATE OR REPLACE FUNCTION performs_ok ( TEXT, NUMERIC )
-RETURNS TEXT AS $$
- SELECT performs_ok(
- $1, $2, 'Should run in less than ' || $2 || ' ms'
- );
-$$ LANGUAGE sql;
-
-CREATE OR REPLACE FUNCTION _rexists ( CHAR, NAME, NAME )
-RETURNS BOOLEAN AS $$
- SELECT EXISTS(
- SELECT true
- FROM pg_catalog.pg_namespace n
- JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace
- WHERE c.relkind = $1
- AND n.nspname = $2
- AND c.relname = $3
- );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION _rexists ( CHAR, NAME )
-RETURNS BOOLEAN AS $$
- SELECT EXISTS(
- SELECT true
- FROM pg_catalog.pg_class c
- WHERE c.relkind = $1
- AND pg_catalog.pg_table_is_visible(c.oid)
- AND c.relname = $2
- );
-$$ LANGUAGE SQL;
-
-
-CREATE OR REPLACE FUNCTION has_table ( NAME, NAME, TEXT )
-RETURNS TEXT AS $$
- SELECT ok( _rexists( 'r', $1, $2 ), $3 );
-$$ LANGUAGE SQL;
-
--- has_table( table, description )
-CREATE OR REPLACE FUNCTION has_table ( NAME, TEXT )
-RETURNS TEXT AS $$
- SELECT ok( _rexists( 'r', $1 ), $2 );
-$$ LANGUAGE SQL;
-
--- has_table( table )
-CREATE OR REPLACE FUNCTION has_table ( NAME )
-RETURNS TEXT AS $$
- SELECT has_table( $1, 'Table ' || quote_ident($1) || ' should exist' );
-$$ LANGUAGE SQL;
-
-CREATE OR REPLACE FUNCTION _temptable ( TEXT, TEXT )
-RETURNS TEXT AS $$
-BEGIN
- EXECUTE 'CREATE TEMP TABLE ' || $2 || ' AS ' || _query($1);
- return $2;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION _temptable ( anyarray, TEXT )
-RETURNS TEXT AS $$
-BEGIN
- CREATE TEMP TABLE _____coltmp___ AS
- SELECT $1[i]
- FROM generate_series(array_lower($1, 1), array_upper($1, 1)) s(i);
- EXECUTE 'ALTER TABLE _____coltmp___ RENAME TO ' || $2;
- return $2;
-END;
-$$ LANGUAGE plpgsql;
-
-
-CREATE OR REPLACE FUNCTION _docomp( TEXT, TEXT, TEXT, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- have ALIAS FOR $1;
- want ALIAS FOR $2;
- extras TEXT[] := '{}';
- missing TEXT[] := '{}';
- res BOOLEAN := TRUE;
- msg TEXT := '';
- rec RECORD;
-BEGIN
- BEGIN
- -- Find extra records.
- FOR rec in EXECUTE 'SELECT * FROM ' || have || ' EXCEPT ' || $4
- || 'SELECT * FROM ' || want LOOP
- extras := extras || rec::text;
- END LOOP;
-
- -- Find missing records.
- FOR rec in EXECUTE 'SELECT * FROM ' || want || ' EXCEPT ' || $4
- || 'SELECT * FROM ' || have LOOP
- missing := missing || rec::text;
- END LOOP;
-
- -- Drop the temporary tables.
- EXECUTE 'DROP TABLE ' || have;
- EXECUTE 'DROP TABLE ' || want;
- EXCEPTION WHEN syntax_error OR datatype_mismatch THEN
- msg := E'\n' || diag(
- E' Columns differ between queries:\n'
- || ' have: (' || _temptypes(have) || E')\n'
- || ' want: (' || _temptypes(want) || ')'
- );
- EXECUTE 'DROP TABLE ' || have;
- EXECUTE 'DROP TABLE ' || want;
- RETURN ok(FALSE, $3) || msg;
- END;
-
- -- What extra records do we have?
- IF extras[1] IS NOT NULL THEN
- res := FALSE;
- msg := E'\n' || diag(
- E' Extra records:\n '
- || array_to_string( extras, E'\n ' )
- );
- END IF;
-
- -- What missing records do we have?
- IF missing[1] IS NOT NULL THEN
- res := FALSE;
- msg := msg || E'\n' || diag(
- E' Missing records:\n '
- || array_to_string( missing, E'\n ' )
- );
- END IF;
-
- RETURN ok(res, $3) || msg;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION _relcomp( TEXT, TEXT, TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _docomp(
- _temptable( $1, '__taphave__' ),
- _temptable( $2, '__tapwant__' ),
- $3, $4
- );
-$$ LANGUAGE sql;
-
-CREATE OR REPLACE FUNCTION _relcomp( TEXT, anyarray, TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _docomp(
- _temptable( $1, '__taphave__' ),
- _temptable( $2, '__tapwant__' ),
- $3, $4
- );
-$$ LANGUAGE sql;
-
--- set_eq( sql, sql, description )
-CREATE OR REPLACE FUNCTION set_eq( TEXT, TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _relcomp( $1, $2, $3, '' );
-$$ LANGUAGE sql;
-
--- set_eq( sql, sql )
-CREATE OR REPLACE FUNCTION set_eq( TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _relcomp( $1, $2, NULL::text, '' );
-$$ LANGUAGE sql;
-
--- set_eq( sql, array, description )
-CREATE OR REPLACE FUNCTION set_eq( TEXT, anyarray, TEXT )
-RETURNS TEXT AS $$
- SELECT _relcomp( $1, $2, $3, '' );
-$$ LANGUAGE sql;
-
--- set_eq( sql, array )
-CREATE OR REPLACE FUNCTION set_eq( TEXT, anyarray )
-RETURNS TEXT AS $$
- SELECT _relcomp( $1, $2, NULL::text, '' );
-$$ LANGUAGE sql;
-
--- bag_eq( sql, sql, description )
-CREATE OR REPLACE FUNCTION bag_eq( TEXT, TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _relcomp( $1, $2, $3, 'ALL ' );
-$$ LANGUAGE sql;
-
--- bag_eq( sql, sql )
-CREATE OR REPLACE FUNCTION bag_eq( TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _relcomp( $1, $2, NULL::text, 'ALL ' );
-$$ LANGUAGE sql;
-
--- bag_eq( sql, array, description )
-CREATE OR REPLACE FUNCTION bag_eq( TEXT, anyarray, TEXT )
-RETURNS TEXT AS $$
- SELECT _relcomp( $1, $2, $3, 'ALL ' );
-$$ LANGUAGE sql;
-
--- bag_eq( sql, array )
-CREATE OR REPLACE FUNCTION bag_eq( TEXT, anyarray )
-RETURNS TEXT AS $$
- SELECT _relcomp( $1, $2, NULL::text, 'ALL ' );
-$$ LANGUAGE sql;
-
-CREATE OR REPLACE FUNCTION _do_ne( TEXT, TEXT, TEXT, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- have ALIAS FOR $1;
- want ALIAS FOR $2;
- extras TEXT[] := '{}';
- missing TEXT[] := '{}';
- res BOOLEAN := TRUE;
- msg TEXT := '';
-BEGIN
- BEGIN
- -- Find extra records.
- EXECUTE 'SELECT EXISTS ( '
- || '( SELECT * FROM ' || have || ' EXCEPT ' || $4
- || ' SELECT * FROM ' || want
- || ' ) UNION ( '
- || ' SELECT * FROM ' || want || ' EXCEPT ' || $4
- || ' SELECT * FROM ' || have
- || ' ) LIMIT 1 )' INTO res;
-
- -- Drop the temporary tables.
- EXECUTE 'DROP TABLE ' || have;
- EXECUTE 'DROP TABLE ' || want;
- EXCEPTION WHEN syntax_error OR datatype_mismatch THEN
- msg := E'\n' || diag(
- E' Columns differ between queries:\n'
- || ' have: (' || _temptypes(have) || E')\n'
- || ' want: (' || _temptypes(want) || ')'
- );
- EXECUTE 'DROP TABLE ' || have;
- EXECUTE 'DROP TABLE ' || want;
- RETURN ok(FALSE, $3) || msg;
- END;
-
- -- Return the value from the query.
- RETURN ok(res, $3);
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION _relne( TEXT, TEXT, TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _do_ne(
- _temptable( $1, '__taphave__' ),
- _temptable( $2, '__tapwant__' ),
- $3, $4
- );
-$$ LANGUAGE sql;
-
-CREATE OR REPLACE FUNCTION _relne( TEXT, anyarray, TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _do_ne(
- _temptable( $1, '__taphave__' ),
- _temptable( $2, '__tapwant__' ),
- $3, $4
- );
-$$ LANGUAGE sql;
-
--- set_ne( sql, sql, description )
-CREATE OR REPLACE FUNCTION set_ne( TEXT, TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _relne( $1, $2, $3, '' );
-$$ LANGUAGE sql;
-
--- set_ne( sql, sql )
-CREATE OR REPLACE FUNCTION set_ne( TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _relne( $1, $2, NULL::text, '' );
-$$ LANGUAGE sql;
-
--- set_ne( sql, array, description )
-CREATE OR REPLACE FUNCTION set_ne( TEXT, anyarray, TEXT )
-RETURNS TEXT AS $$
- SELECT _relne( $1, $2, $3, '' );
-$$ LANGUAGE sql;
-
--- set_ne( sql, array )
-CREATE OR REPLACE FUNCTION set_ne( TEXT, anyarray )
-RETURNS TEXT AS $$
- SELECT _relne( $1, $2, NULL::text, '' );
-$$ LANGUAGE sql;
-
--- bag_ne( sql, sql, description )
-CREATE OR REPLACE FUNCTION bag_ne( TEXT, TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _relne( $1, $2, $3, 'ALL ' );
-$$ LANGUAGE sql;
-
--- bag_ne( sql, sql )
-CREATE OR REPLACE FUNCTION bag_ne( TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _relne( $1, $2, NULL::text, 'ALL ' );
-$$ LANGUAGE sql;
-
--- bag_ne( sql, array, description )
-CREATE OR REPLACE FUNCTION bag_ne( TEXT, anyarray, TEXT )
-RETURNS TEXT AS $$
- SELECT _relne( $1, $2, $3, 'ALL ' );
-$$ LANGUAGE sql;
-
--- bag_ne( sql, array )
-CREATE OR REPLACE FUNCTION bag_ne( TEXT, anyarray )
-RETURNS TEXT AS $$
- SELECT _relne( $1, $2, NULL::text, 'ALL ' );
-$$ LANGUAGE sql;
-
-CREATE OR REPLACE FUNCTION _relcomp( TEXT, TEXT, TEXT, TEXT, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- have TEXT := _temptable( $1, '__taphave__' );
- want TEXT := _temptable( $2, '__tapwant__' );
- results TEXT[] := '{}';
- res BOOLEAN := TRUE;
- msg TEXT := '';
- rec RECORD;
-BEGIN
- BEGIN
- -- Find relevant records.
- FOR rec in EXECUTE 'SELECT * FROM ' || want || ' ' || $4
- || ' SELECT * FROM ' || have LOOP
- results := results || rec::text;
- END LOOP;
-
- -- Drop the temporary tables.
- EXECUTE 'DROP TABLE ' || have;
- EXECUTE 'DROP TABLE ' || want;
- EXCEPTION WHEN syntax_error OR datatype_mismatch THEN
- msg := E'\n' || diag(
- E' Columns differ between queries:\n'
- || ' have: (' || _temptypes(have) || E')\n'
- || ' want: (' || _temptypes(want) || ')'
- );
- EXECUTE 'DROP TABLE ' || have;
- EXECUTE 'DROP TABLE ' || want;
- RETURN ok(FALSE, $3) || msg;
- END;
-
- -- What records do we have?
- IF results[1] IS NOT NULL THEN
- res := FALSE;
- msg := msg || E'\n' || diag(
- ' ' || $5 || E' records:\n '
- || array_to_string( results, E'\n ' )
- );
- END IF;
-
- RETURN ok(res, $3) || msg;
-END;
-$$ LANGUAGE plpgsql;
-
--- set_has( sql, sql, description )
-CREATE OR REPLACE FUNCTION set_has( TEXT, TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _relcomp( $1, $2, $3, 'EXCEPT', 'Missing' );
-$$ LANGUAGE sql;
-
--- set_has( sql, sql )
-CREATE OR REPLACE FUNCTION set_has( TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _relcomp( $1, $2, NULL::TEXT, 'EXCEPT', 'Missing' );
-$$ LANGUAGE sql;
-
--- bag_has( sql, sql, description )
-CREATE OR REPLACE FUNCTION bag_has( TEXT, TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _relcomp( $1, $2, $3, 'EXCEPT ALL', 'Missing' );
-$$ LANGUAGE sql;
-
--- bag_has( sql, sql )
-CREATE OR REPLACE FUNCTION bag_has( TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _relcomp( $1, $2, NULL::TEXT, 'EXCEPT ALL', 'Missing' );
-$$ LANGUAGE sql;
-
--- set_hasnt( sql, sql, description )
-CREATE OR REPLACE FUNCTION set_hasnt( TEXT, TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _relcomp( $1, $2, $3, 'INTERSECT', 'Extra' );
-$$ LANGUAGE sql;
-
--- set_hasnt( sql, sql )
-CREATE OR REPLACE FUNCTION set_hasnt( TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _relcomp( $1, $2, NULL::TEXT, 'INTERSECT', 'Extra' );
-$$ LANGUAGE sql;
-
--- bag_hasnt( sql, sql, description )
-CREATE OR REPLACE FUNCTION bag_hasnt( TEXT, TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _relcomp( $1, $2, $3, 'INTERSECT ALL', 'Extra' );
-$$ LANGUAGE sql;
-
--- bag_hasnt( sql, sql )
-CREATE OR REPLACE FUNCTION bag_hasnt( TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT _relcomp( $1, $2, NULL::TEXT, 'INTERSECT ALL', 'Extra' );
-$$ LANGUAGE sql;
-
--- results_eq( cursor, cursor, description )
-CREATE OR REPLACE FUNCTION results_eq( refcursor, refcursor, text )
-RETURNS TEXT AS $$
-DECLARE
- have ALIAS FOR $1;
- want ALIAS FOR $2;
- have_rec RECORD;
- want_rec RECORD;
- have_found BOOLEAN;
- want_found BOOLEAN;
- rownum INTEGER := 1;
-BEGIN
- FETCH have INTO have_rec;
- have_found := FOUND;
- FETCH want INTO want_rec;
- want_found := FOUND;
- WHILE have_found OR want_found LOOP
- IF have_rec IS DISTINCT FROM want_rec OR have_found <> want_found THEN
- RETURN ok( false, $3 ) || E'\n' || diag(
- ' Results differ beginning at row ' || rownum || E':\n' ||
- ' have: ' || CASE WHEN have_found THEN have_rec::text ELSE 'NULL' END || E'\n' ||
- ' want: ' || CASE WHEN want_found THEN want_rec::text ELSE 'NULL' END
- );
- END IF;
- rownum = rownum + 1;
- FETCH have INTO have_rec;
- have_found := FOUND;
- FETCH want INTO want_rec;
- want_found := FOUND;
- END LOOP;
-
- RETURN ok( true, $3 );
-EXCEPTION
- WHEN datatype_mismatch THEN
- RETURN ok( false, $3 ) || E'\n' || diag(
- E' Columns differ between queries:\n' ||
- ' have: ' || CASE WHEN have_found THEN have_rec::text ELSE 'NULL' END || E'\n' ||
- ' want: ' || CASE WHEN want_found THEN want_rec::text ELSE 'NULL' END
- );
-END;
-$$ LANGUAGE plpgsql;
-
--- results_eq( cursor, cursor )
-CREATE OR REPLACE FUNCTION results_eq( refcursor, refcursor )
-RETURNS TEXT AS $$
- SELECT results_eq( $1, $2, NULL::text );
-$$ LANGUAGE sql;
-
--- results_eq( sql, sql, description )
-CREATE OR REPLACE FUNCTION results_eq( TEXT, TEXT, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- have REFCURSOR;
- want REFCURSOR;
- res TEXT;
-BEGIN
- OPEN have FOR EXECUTE _query($1);
- OPEN want FOR EXECUTE _query($2);
- res := results_eq(have, want, $3);
- CLOSE have;
- CLOSE want;
- RETURN res;
-END;
-$$ LANGUAGE plpgsql;
-
--- results_eq( sql, sql )
-CREATE OR REPLACE FUNCTION results_eq( TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT results_eq( $1, $2, NULL::text );
-$$ LANGUAGE sql;
-
--- results_eq( sql, array, description )
-CREATE OR REPLACE FUNCTION results_eq( TEXT, anyarray, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- have REFCURSOR;
- want REFCURSOR;
- res TEXT;
-BEGIN
- OPEN have FOR EXECUTE _query($1);
- OPEN want FOR SELECT $2[i]
- FROM generate_series(array_lower($2, 1), array_upper($2, 1)) s(i);
- res := results_eq(have, want, $3);
- CLOSE have;
- CLOSE want;
- RETURN res;
-END;
-$$ LANGUAGE plpgsql;
-
--- results_eq( sql, array )
-CREATE OR REPLACE FUNCTION results_eq( TEXT, anyarray )
-RETURNS TEXT AS $$
- SELECT results_eq( $1, $2, NULL::text );
-$$ LANGUAGE sql;
-
--- results_eq( sql, cursor, description )
-CREATE OR REPLACE FUNCTION results_eq( TEXT, refcursor, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- have REFCURSOR;
- res TEXT;
-BEGIN
- OPEN have FOR EXECUTE _query($1);
- res := results_eq(have, $2, $3);
- CLOSE have;
- RETURN res;
-END;
-$$ LANGUAGE plpgsql;
-
--- results_eq( sql, cursor )
-CREATE OR REPLACE FUNCTION results_eq( TEXT, refcursor )
-RETURNS TEXT AS $$
- SELECT results_eq( $1, $2, NULL::text );
-$$ LANGUAGE sql;
-
--- results_eq( cursor, sql, description )
-CREATE OR REPLACE FUNCTION results_eq( refcursor, TEXT, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- want REFCURSOR;
- res TEXT;
-BEGIN
- OPEN want FOR EXECUTE _query($2);
- res := results_eq($1, want, $3);
- CLOSE want;
- RETURN res;
-END;
-$$ LANGUAGE plpgsql;
-
--- results_eq( cursor, sql )
-CREATE OR REPLACE FUNCTION results_eq( refcursor, TEXT )
-RETURNS TEXT AS $$
- SELECT results_eq( $1, $2, NULL::text );
-$$ LANGUAGE sql;
-
--- results_eq( cursor, array, description )
-CREATE OR REPLACE FUNCTION results_eq( refcursor, anyarray, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- want REFCURSOR;
- res TEXT;
-BEGIN
- OPEN want FOR SELECT $2[i]
- FROM generate_series(array_lower($2, 1), array_upper($2, 1)) s(i);
- res := results_eq($1, want, $3);
- CLOSE want;
- RETURN res;
-END;
-$$ LANGUAGE plpgsql;
-
--- results_eq( cursor, array )
-CREATE OR REPLACE FUNCTION results_eq( refcursor, anyarray )
-RETURNS TEXT AS $$
- SELECT results_eq( $1, $2, NULL::text );
-$$ LANGUAGE sql;
-
--- results_ne( cursor, cursor, description )
-CREATE OR REPLACE FUNCTION results_ne( refcursor, refcursor, text )
-RETURNS TEXT AS $$
-DECLARE
- have ALIAS FOR $1;
- want ALIAS FOR $2;
- have_rec RECORD;
- want_rec RECORD;
- have_found BOOLEAN;
- want_found BOOLEAN;
-BEGIN
- FETCH have INTO have_rec;
- have_found := FOUND;
- FETCH want INTO want_rec;
- want_found := FOUND;
- WHILE have_found OR want_found LOOP
- IF have_rec IS DISTINCT FROM want_rec OR have_found <> want_found THEN
- RETURN ok( true, $3 );
- ELSE
- FETCH have INTO have_rec;
- have_found := FOUND;
- FETCH want INTO want_rec;
- want_found := FOUND;
- END IF;
- END LOOP;
- RETURN ok( false, $3 );
-EXCEPTION
- WHEN datatype_mismatch THEN
- RETURN ok( false, $3 ) || E'\n' || diag(
- E' Columns differ between queries:\n' ||
- ' have: ' || CASE WHEN have_found THEN have_rec::text ELSE 'NULL' END || E'\n' ||
- ' want: ' || CASE WHEN want_found THEN want_rec::text ELSE 'NULL' END
- );
-END;
-$$ LANGUAGE plpgsql;
-
--- results_ne( cursor, cursor )
-CREATE OR REPLACE FUNCTION results_ne( refcursor, refcursor )
-RETURNS TEXT AS $$
- SELECT results_ne( $1, $2, NULL::text );
-$$ LANGUAGE sql;
-
--- results_ne( sql, sql, description )
-CREATE OR REPLACE FUNCTION results_ne( TEXT, TEXT, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- have REFCURSOR;
- want REFCURSOR;
- res TEXT;
-BEGIN
- OPEN have FOR EXECUTE _query($1);
- OPEN want FOR EXECUTE _query($2);
- res := results_ne(have, want, $3);
- CLOSE have;
- CLOSE want;
- RETURN res;
-END;
-$$ LANGUAGE plpgsql;
-
--- results_ne( sql, sql )
-CREATE OR REPLACE FUNCTION results_ne( TEXT, TEXT )
-RETURNS TEXT AS $$
- SELECT results_ne( $1, $2, NULL::text );
-$$ LANGUAGE sql;
-
--- results_ne( sql, array, description )
-CREATE OR REPLACE FUNCTION results_ne( TEXT, anyarray, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- have REFCURSOR;
- want REFCURSOR;
- res TEXT;
-BEGIN
- OPEN have FOR EXECUTE _query($1);
- OPEN want FOR SELECT $2[i]
- FROM generate_series(array_lower($2, 1), array_upper($2, 1)) s(i);
- res := results_ne(have, want, $3);
- CLOSE have;
- CLOSE want;
- RETURN res;
-END;
-$$ LANGUAGE plpgsql;
-
--- results_ne( sql, array )
-CREATE OR REPLACE FUNCTION results_ne( TEXT, anyarray )
-RETURNS TEXT AS $$
- SELECT results_ne( $1, $2, NULL::text );
-$$ LANGUAGE sql;
-
--- results_ne( sql, cursor, description )
-CREATE OR REPLACE FUNCTION results_ne( TEXT, refcursor, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- have REFCURSOR;
- res TEXT;
-BEGIN
- OPEN have FOR EXECUTE _query($1);
- res := results_ne(have, $2, $3);
- CLOSE have;
- RETURN res;
-END;
-$$ LANGUAGE plpgsql;
-
--- results_ne( sql, cursor )
-CREATE OR REPLACE FUNCTION results_ne( TEXT, refcursor )
-RETURNS TEXT AS $$
- SELECT results_ne( $1, $2, NULL::text );
-$$ LANGUAGE sql;
-
--- results_ne( cursor, sql, description )
-CREATE OR REPLACE FUNCTION results_ne( refcursor, TEXT, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- want REFCURSOR;
- res TEXT;
-BEGIN
- OPEN want FOR EXECUTE _query($2);
- res := results_ne($1, want, $3);
- CLOSE want;
- RETURN res;
-END;
-$$ LANGUAGE plpgsql;
-
--- results_ne( cursor, sql )
-CREATE OR REPLACE FUNCTION results_ne( refcursor, TEXT )
-RETURNS TEXT AS $$
- SELECT results_ne( $1, $2, NULL::text );
-$$ LANGUAGE sql;
-
--- results_ne( cursor, array, description )
-CREATE OR REPLACE FUNCTION results_ne( refcursor, anyarray, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- want REFCURSOR;
- res TEXT;
-BEGIN
- OPEN want FOR SELECT $2[i]
- FROM generate_series(array_lower($2, 1), array_upper($2, 1)) s(i);
- res := results_ne($1, want, $3);
- CLOSE want;
- RETURN res;
-END;
-$$ LANGUAGE plpgsql;
-
--- results_ne( cursor, array )
-CREATE OR REPLACE FUNCTION results_ne( refcursor, anyarray )
-RETURNS TEXT AS $$
- SELECT results_ne( $1, $2, NULL::text );
-$$ LANGUAGE sql;
-
--- isa_ok( value, regtype, description )
-CREATE OR REPLACE FUNCTION isa_ok( anyelement, regtype, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- typeof regtype := pg_typeof($1);
-BEGIN
- IF typeof = $2 THEN RETURN ok(true, $3 || ' isa ' || $2 ); END IF;
- RETURN ok(false, $3 || ' isa ' || $2 ) || E'\n' ||
- diag(' ' || $3 || ' isn''t a "' || $2 || '" it''s a "' || typeof || '"');
-END;
-$$ LANGUAGE plpgsql;
-
--- isa_ok( value, regtype )
-CREATE OR REPLACE FUNCTION isa_ok( anyelement, regtype )
-RETURNS TEXT AS $$
- SELECT isa_ok($1, $2, 'the value');
-$$ LANGUAGE sql;
-
-CREATE OR REPLACE FUNCTION _is_trusted( NAME )
-RETURNS BOOLEAN AS $$
- SELECT lanpltrusted FROM pg_catalog.pg_language WHERE lanname = $1;
-$$ LANGUAGE SQL;
-
--- language_is_trusted( language, description )
-CREATE OR REPLACE FUNCTION language_is_trusted( NAME, TEXT )
-RETURNS TEXT AS $$
-DECLARE
- is_trusted boolean := _is_trusted($1);
-BEGIN
- IF is_trusted IS NULL THEN
- RETURN fail( $2 ) || E'\n' || diag( ' Procedural language ' || quote_ident($1) || ' does not exist') ;
- END IF;
- RETURN ok( is_trusted, $2 );
-END;
-$$ LANGUAGE plpgsql;
-
599 plparrot.c