Commit 9848d365 authored by Marc G. Fournier's avatar Marc G. Fournier

Support Docs & Contrib

parent 1960a3b9
POSTGRES95 Data Base Management System
Copyright (c) 1994-6 Regents of the University of California
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.
This diff is collapsed.
This diff is collapsed.
#!/bin/sh
trap "rm -f /tmp/$$" 0 1 2 3 15
rm -f ./tags
find `pwd`/ -type f -name '*.[chyl]' -print|xargs ctags -t -a -f tags
sort tags >/tmp/$$ && mv /tmp/$$ tags
find . -type d -print |while read DIR
do
[ "$DIR" != "." ] && ln -f -s `pwd`/tags $DIR/tags
done
From scrappy@ki.net Wed Aug 14 20:41:08 1996
Status: RO
X-Status:
Received: from candle.pha.pa.us (maillist@s1-03.ppp.op.net [206.84.209.132]) by quagmire.ki.net (8.7.5/8.7.5) with ESMTP id UAA01234 for <scrappy@ki.net>; Wed, 14 Aug 1996 20:41:00 -0400 (EDT)
Received: (from maillist@localhost) by candle.pha.pa.us (8.7.4/8.7.3) id UAA13966 for scrappy@ki.net; Wed, 14 Aug 1996 20:40:48 -0400 (EDT)
From: Bruce Momjian <maillist@candle.pha.pa.us>
Message-Id: <199608150040.UAA13966@candle.pha.pa.us>
Subject: New migration file
To: scrappy@ki.net (Marc G. Fournier)
Date: Wed, 14 Aug 1996 20:40:47 -0400 (EDT)
X-Mailer: ELM [version 2.4 PL25]
MIME-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Here is a new migratoin file for 1.02.1. It includes the 'copy' change
and a script to convert old ascii files.
---------------------------------------------------------------------------
The following notes are for the benefit of users who want to migrate
databases from postgres95 1.01 and 1.02 to postgres95 1.02.1.
If you are starting afresh with postgres95 1.02.1 and do not need
to migrate old databases, you do not need to read any further.
----------------------------------------------------------------------
In order to upgrade older postgres95 version 1.01 or 1.02 databases to
version 1.02.1, the following steps are required:
1) start up a new 1.02.1 postmaster
2) Add the new built-in functions and operators of 1.02.1 to 1.01 or 1.02
databases. This is done by running the new 1.02.1 server against
your own 1.01 or 1.02 database and applying the queries attached at
the end of thie file. This can be done easily through psql. If your
1.01 or 1.02 database is named "testdb" and you have cut the commands
from the end of this file and saved them in addfunc.sql:
% psql testdb -f addfunc.sql
Those upgrading 1.02 databases will get a warning when executing the
last two statements because they are already present in 1.02. This is
not a cause for concern.
* * *
If you are trying to reload a pg_dump or text-mode 'copy tablename to
stdout' generated with a previous version, you will need to run the
attached sed script on the ASCII file before loading it into the
database. The old format used '.' as end-of-data, while '\.' is now the
end-of-data marker. Also, empty strings are now loaded in as '' rather
than NULL. See the copy manual page for full details.
sed 's/^\.$/\\./g' <in_file >out_file
If you are loading an older binary copy or non-stdout copy, there is no
end-of-data character, and hence no conversion necessary.
---------------------------------------------------------------------------
-- following lines added by agc to reflect the case-insensitive
-- regexp searching for varchar (in 1.02), and bpchar (in 1.02.1)
create operator ~* (leftarg = bpchar, rightarg = text, procedure = texticregexeq);
create operator !~* (leftarg = bpchar, rightarg = text, procedure = texticregexne);
create operator ~* (leftarg = varchar, rightarg = text, procedure = texticregexeq);
create operator !~* (leftarg = varchar, rightarg = text, procedure = texticregexne);
POSTGRES95 Data Base Management System
This directory contains the 1.02 release of Postgres95. See INSTALL for
the installation notes and HISTORY for the changes.
We also have a WWW home page located at:
http://www.ki.net/postgres95
Postgres95 is not public domain software. It is copyrighted by the
University of California but may be used according to the licensing
terms of the the copyright below:
------------------------------------------------------------------------
POSTGRES95 Data Base Management System
Copyright (c) 1994-6 Regents of the University of California
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.
/*
* array_iterator.c --
*
* This file defines a new group of operators which take an
* array and a scalar value, iterate a scalar operator over the
* elements of the array and the value and compute a result as
* the logical OR or AND of the results.
* For example array_int4eq returns true if some of the elements
* of an array of int4 is equal to the given value:
*
* array_int4eq({1,2,3}, 1) --> true
* array_int4eq({1,2,3}, 4) --> false
*
* If we have defined T array types and O scalar operators
* we can define T x O array operators, each of them has a name
* like "array_<basetype><operation>" and takes an array of type T
* iterating the operator O over all the elements. Note however
* that some of the possible combination are invalid, for example
* the array_int4_like because there is no like operator for int4.
* It is now possible to write queries which look inside the arrays:
*
* create table t(id int4[], txt text[]);
* select * from t where t.id *= 123;
* select * from t where t.txt *~ '[a-z]';
* select * from t where t.txt[1:3] **~ '[a-z]';
*
* Copyright (c) 1996, Massimo Dal Zotto <dz@cs.unitn.it>
*/
#include <ctype.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include "postgres.h"
#include "pg_type.h"
#include "miscadmin.h"
#include "syscache.h"
#include "access/xact.h"
#include "utils/builtins.h"
#include "utils/elog.h"
static int32
array_iterator(Oid elemtype, Oid proc, int and, ArrayType *array, Datum value)
{
HeapTuple typ_tuple;
TypeTupleForm typ_struct;
bool typbyval;
int typlen;
func_ptr proc_fn;
int pronargs;
int nitems, i, result;
int ndim, *dim;
char *p;
/* Sanity checks */
if ((array == (ArrayType *) NULL)
|| (ARR_IS_LO(array) == true)) {
/* elog(NOTICE, "array_iterator: array is null"); */
return (0);
}
ndim = ARR_NDIM(array);
dim = ARR_DIMS(array);
nitems = getNitems(ndim, dim);
if (nitems == 0) {
/* elog(NOTICE, "array_iterator: nitems = 0"); */
return (0);
}
/* Lookup element type information */
typ_tuple = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(elemtype),0,0,0);
if (!HeapTupleIsValid(typ_tuple)) {
elog(WARN,"array_iterator: cache lookup failed for type %d", elemtype);
return 0;
}
typ_struct = (TypeTupleForm) GETSTRUCT(typ_tuple);
typlen = typ_struct->typlen;
typbyval = typ_struct->typbyval;
/* Lookup the function entry point */
proc_fn == (func_ptr) NULL;
fmgr_info(proc, &proc_fn, &pronargs);
if ((proc_fn == NULL) || (pronargs != 2)) {
elog(WARN, "array_iterator: fmgr_info lookup failed for oid %d", proc);
return (0);
}
/* Scan the array and apply the operator to each element */
result = 0;
p = ARR_DATA_PTR(array);
for (i = 0; i < nitems; i++) {
if (typbyval) {
switch(typlen) {
case 1:
result = (int) (*proc_fn)(*p, value);
break;
case 2:
result = (int) (*proc_fn)(* (int16 *) p, value);
break;
case 3:
case 4:
result = (int) (*proc_fn)(* (int32 *) p, value);
break;
}
p += typlen;
} else {
result = (int) (*proc_fn)(p, value);
if (typlen > 0) {
p += typlen;
} else {
p += INTALIGN(* (int32 *) p);
}
}
if (result) {
if (!and) {
return (1);
}
} else {
if (and) {
return (0);
}
}
}
if (and && result) {
return (1);
} else {
return (0);
}
}
/*
* Iterators for type _text
*/
int32
array_texteq(ArrayType *array, char* value)
{
return array_iterator((Oid) 25, /* text */
(Oid) 67, /* texteq */
0, /* logical or */
array, (Datum)value);
}
int32
array_all_texteq(ArrayType *array, char* value)
{
return array_iterator((Oid) 25, /* text */
(Oid) 67, /* texteq */
1, /* logical and */
array, (Datum)value);
}
int32
array_textregexeq(ArrayType *array, char* value)
{
return array_iterator((Oid) 25, /* text */
(Oid) 81, /* textregexeq */
0, /* logical or */
array, (Datum)value);
}
int32
array_all_textregexeq(ArrayType *array, char* value)
{
return array_iterator((Oid) 25, /* text */
(Oid) 81, /* textregexeq */
1, /* logical and */
array, (Datum)value);
}
/*
* Iterators for type _char16. Note that the regexp operators
* take the second argument of type text.
*/
int32
array_char16eq(ArrayType *array, char* value)
{
return array_iterator((Oid) 20, /* char16 */
(Oid) 490, /* char16eq */
0, /* logical or */
array, (Datum)value);
}
int32
array_all_char16eq(ArrayType *array, char* value)
{
return array_iterator((Oid) 20, /* char16 */
(Oid) 490, /* char16eq */
1, /* logical and */
array, (Datum)value);
}
int32
array_char16regexeq(ArrayType *array, char* value)
{
return array_iterator((Oid) 20, /* char16 */
(Oid) 700, /* char16regexeq */
0, /* logical or */
array, (Datum)value);
}
int32
array_all_char16regexeq(ArrayType *array, char* value)
{
return array_iterator((Oid) 20, /* char16 */
(Oid) 700, /* char16regexeq */
1, /* logical and */
array, (Datum)value);
}
/*
* Iterators for type _int4
*/
int32
array_int4eq(ArrayType *array, int4 value)
{
return array_iterator((Oid) 23, /* int4 */
(Oid) 65, /* int4eq */
0, /* logical or */
array, (Datum)value);
}
int32
array_all_int4eq(ArrayType *array, int4 value)
{
return array_iterator((Oid) 23, /* int4 */
(Oid) 65, /* int4eq */
1, /* logical and */
array, (Datum)value);
}
int32
array_int4gt(ArrayType *array, int4 value)
{
return array_iterator((Oid) 23, /* int4 */
(Oid) 147, /* int4gt */
0, /* logical or */
array, (Datum)value);
}
int32
array_all_int4gt(ArrayType *array, int4 value)
{
return array_iterator((Oid) 23, /* int4 */
(Oid) 147, /* int4gt */
1, /* logical and */
array, (Datum)value);
}
From: Massimo Dal Zotto <dz@cs.unitn.it>
Date: Mon, 6 May 1996 01:03:37 +0200 (MET DST)
Subject: [PG95]: new operators for arrays
- -----BEGIN PGP SIGNED MESSAGE-----
Hi,
I have written an extension to Postgres95 which allows to use qualification
clauses based on the values of single elements of arrays.
For example I can now select rows having some or all element of an array
attribute equal to a given value or matching a regular expression:
select * from t where t.foo *= 'bar';
select * from t where t.foo **~ '^ba[rz]';
The scheme is quite general, each operator which operates on a base type can
be iterated over the elements of an array. It seem to work well but defining
each new operators requires writing a different C function. Furthermore in
each function there are two hardcoded OIDs which reference a base type and
a procedure. Not very portable. Can anyone suggest a better and more portable
way to do it ? Do you think this could be a useful feature for next release ?
Here is my code, it can be compiled and loaded as a dynamic module without
need to recompile the backend. I have defined only the few operators I needed,
the list can be extended. Feddback is welcome.
/*
* SQL code
- - -- load the new functions
- - --
load '/home/dz/lib/postgres/array_iterator.so';
- - -- define the array operators *=, **=, *~ and **~ for type _text
- - --
create function array_texteq(_text, text)
returns bool
as '/home/dz/lib/postgres/array_iterator.so'
language 'c';
create function array_all_texteq(_text, text)
returns bool
as '/home/dz/lib/postgres/array_iterator.so'
language 'c';
create function array_textregexeq(_text, text)
returns bool
as '/home/dz/lib/postgres/array_iterator.so'
language 'c';
create function array_all_textregexeq(_text, text)
returns bool
as '/home/dz/lib/postgres/array_iterator.so'
language 'c';
create operator *= (
leftarg=_text,
rightarg=text,
procedure=array_texteq);
create operator **= (
leftarg=_text,
rightarg=text,
procedure=array_all_texteq);
create operator *~ (
leftarg=_text,
rightarg=text,
procedure=array_textregexeq);
create operator **~ (
leftarg=_text,
rightarg=text,
procedure=array_all_textregexeq);
- - -- define the array operators *=, **=, *~ and **~ for type _char16
- - --
create function array_char16eq(_char16, char16)
returns bool
as '/home/dz/lib/postgres/array_iterator.so'
language 'c';
create function array_all_char16eq(_char16, char16)
returns bool
as '/home/dz/lib/postgres/array_iterator.so'
language 'c';
create function array_char16regexeq(_char16, text)
returns bool
as '/home/dz/lib/postgres/array_iterator.so'
language 'c';
create function array_all_char16regexeq(_char16, text)
returns bool
as '/home/dz/lib/postgres/array_iterator.so'
language 'c';
create operator *= (
leftarg=_char16,
rightarg=char16,
procedure=array_char16eq);
create operator **= (
leftarg=_char16,
rightarg=char16,
procedure=array_all_char16eq);
create operator *~ (
leftarg=_char16,
rightarg=text,
procedure=array_char16regexeq);
create operator **~ (
leftarg=_char16,
rightarg=text,
procedure=array_all_char16regexeq);
- - -- define the array operators *=, **=, *> and **> for type _int4
- - --
create function array_int4eq(_int4, int4)
returns bool
as '/home/dz/lib/postgres/array_iterator.so'
language 'c';
create function array_all_int4eq(_int4, int4)
returns bool
as '/home/dz/lib/postgres/array_iterator.so'
language 'c';
create function array_int4gt(_int4, int4)
returns bool
as '/home/dz/lib/postgres/array_iterator.so'
language 'c';
create function array_all_int4gt(_int4, int4)
returns bool
as '/home/dz/lib/postgres/array_iterator.so'
language 'c';
create operator *= (
leftarg=_int4,
rightarg=int4,
procedure=array_int4eq);
create operator **= (
leftarg=_int4,
rightarg=int4,
procedure=array_all_int4eq);
create operator *> (
leftarg=_int4,
rightarg=int4,
procedure=array_int4gt);
create operator **> (
leftarg=_int4,
rightarg=int4,
procedure=array_all_int4gt);
*/
/* end of file */
/*
* datetime_functions.c --
*
* This file defines new functions for the time and date data types.
*
* Copyright (c) 1996, Massimo Dal Zotto <dz@cs.unitn.it>
*/
#include <time.h>
#include "postgres.h"
#include "pg_type.h"
#include "utils/palloc.h"
typedef struct DateADT {
char day;
char month;
short year;
} DateADT;
typedef struct TimeADT {
short hr;
short min;
float sec;
} TimeADT;
TimeADT *
time_difference(TimeADT *time1, TimeADT *time2)
{
TimeADT *time = (TimeADT*)palloc(sizeof(TimeADT));
time->sec = time1->sec - time2->sec;
time->min = time1->min - time2->min;
time->hr = time1->hr - time2->hr;
if (time->sec < 0) {
time->sec += 60.0;
time->min--;
} else if (time->sec >= 60.0) {
time->sec -= 60.0;
time->min++;
}
if (time->min < 0) {
time->min += 60;
time->hr--;
} else if (time->min >= 60) {
time->min -= 60;
time->hr++;
}
if (time->hr < 0) {
time->hr += 24;
} else if (time->hr >= 24) {
time->hr -= 24;
}
return (time);
}
TimeADT *
currentTime()
{
time_t current_time;
struct tm *tm;
TimeADT *result = (TimeADT*)palloc(sizeof(TimeADT));
current_time = time(NULL);
tm = localtime(&current_time);
result->sec = tm->tm_sec;
result->min = tm->tm_min;
result->hr = tm->tm_hour;
return (result);
}
int4
currentDate()
{
time_t current_time;
struct tm *tm;
int4 result;
DateADT *date = (DateADT*)&result;
current_time = time(NULL);
tm = localtime(&current_time);
date->day = tm->tm_mday;
date->month = tm->tm_mon+1;
date->year = tm->tm_year+1900;
return (result);
}
int4
hours(TimeADT *time)
{
return (time->hr);
}
int4
minutes(TimeADT *time)
{
return (time->min);
}
int4
seconds(TimeADT *time)
{
int seconds = (int)time->sec;
return (seconds);
}
int4
day(int4 val)
{
DateADT *date = (DateADT*)&val;
return (date->day);
}
int4
month(int4 val)
{
DateADT *date = (DateADT*)&val;
return (date->month);
}
int4
year(int4 val)
{
DateADT *date = (DateADT*)&val;
return (date->year);
}
int4
asMinutes(TimeADT *time)
{
int seconds = (int)time->sec;
return (time->min + 60*time->hr);
}
int4
asSeconds(TimeADT *time)
{
int seconds = (int)time->sec;
return (seconds + 60*time->min + 3600*time->hr);
}
From: Massimo Dal Zotto <dz@cs.unitn.it>
Date: Tue, 14 May 1996 14:31:18 +0200 (MET DST)
Subject: [PG95]: new postgres functions
- -----BEGIN PGP SIGNED MESSAGE-----
Some time ago I read in the mailing list requests of people looking
for more time and date functions. I have now written some of them:
time_difference(time1, time2) ,also defined as operator '-'
hour(time)
minutes(time)
seconds(time)
asMinutes(time)
asSeconds(time)
currentTime()
currentDate()
The file can be compiled as shared library and loaded as dynamic module
without need to recompile the backend. This can also be taken as an example
of the extensibility of postgres (user-defined functions, operators, etc).
I would be nice to see more of these user contributed modules posted to this
list and hopefully accessible from the Postgres home page.
-- SQL code to load and define 'datetime' functions
-- load the new functions
load '/home/dz/lib/postgres/datetime_functions.so';
-- define the new functions in postgres
create function time_difference(time,time)
returns time
as '/home/dz/lib/postgres/datetime_functions.so'
language 'c';
create function currentDate()
returns date
as '/home/dz/lib/postgres/datetime_functions.so'
language 'c';
create function currentTime()
returns time
as '/home/dz/lib/postgres/datetime_functions.so'
language 'c';
create function hours(time)
returns int4
as '/home/dz/lib/postgres/datetime_functions.so'
language 'c';
create function minutes(time)
returns int4
as '/home/dz/lib/postgres/datetime_functions.so'
language 'c';
create function seconds(time)
returns int4
as '/home/dz/lib/postgres/datetime_functions.so'
language 'c';
create function day(date)
returns int4
as '/home/dz/lib/postgres/datetime_functions.so'
language 'c';
create function month(date)
returns int4
as '/home/dz/lib/postgres/datetime_functions.so'
language 'c';
create function year(date)
returns int4
as '/home/dz/lib/postgres/datetime_functions.so'
language 'c';
create function asMinutes(time)
returns int4
as '/home/dz/lib/postgres/datetime_functions.so'
language 'c';
create function asSeconds(time)
returns int4
as '/home/dz/lib/postgres/datetime_functions.so'
language 'c';
create operator - (
leftarg=time,
rightarg=time,
procedure=time_difference);
#
# Makefile
#
#
TARGET = pginsert
CFLAGS = -g -Wall -I/u/postgres95/include
LIBS = -L/u/postgres95/lib -lpq
$(TARGET) : pginsert.o pginterface.o halt.o
$(CC) -o $(TARGET) $(XFLAGS) $(CFLAGS) \
pginsert.o pginterface.o halt.o $(LIBS)
clean:
rm -f *.o $(TARGET) log core
install:
make clean
make CFLAGS=-O
install -s -o bin -g bin $(TARGET) /usr/local/bin
Pginterface 1.0
Attached is a copy of the Postgres support routines I wrote to allow me
to more cleanly interface to the libpg library, more like a 4gl SQL
interface.
It has several features that may be useful for others:
I have simplified the C code that calls libpq by wrapping all the
functionality of libpq in calls to connectdb(), doquery(), fetch(), and
disconnectdb(). Each call returns a structure or value, so if you need
to do more work with the result, you can. Also, I have a global
variable that allows you to disable the error checking I have added to
the doquery() routine.
I have added a function called fetch(), which allows you to pass
pointers as parameters, and on return the variables are filled with the
data from the binary cursor you opened. These binary cursors are not
useful if you are running the query engine on a system with a different
architecture than the database server. If you pass a NULL pointer, the
column is skipped, and you can use libpq to handle it as you wish.
I have used sigprocmask() to block the reception of certain signals
while the program is executing SQL queries. This prevents a user
pressing Control-C from stopping all the back ends. It blocks SIGHUP,
SIGINT, and SIGTERM, but does not block SIGQUIT or obviously kill -9.
If your platform does not support sigprocmask(), you can remove those
function calls. ( Am I correct that abnormal termination can cause
shared memory resynchronization?)
There is a demo program called pginsert that demonstrates how the
library can be used.
You can create a library of pginterface.c and halt.c, and just include
pginterface.h in your source code.
I am willing to maintain this if people find problems or want additional
functionality.
Bruce Momjian (root@candle.pha.pa.us)
/*
**
** halt.c
**
** This is used to print out error messages and exit
*/
#include <varargs.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
/*-------------------------------------------------------------------------
**
** halt - print error message, and call clean up routine or exit
**
**------------------------------------------------------------------------*/
/*VARARGS*/
void halt(va_alist)
va_dcl
{
va_list arg_ptr;
char *format, *pstr;
void (*sig_func)();
va_start(arg_ptr);
format = va_arg(arg_ptr,char *);
if (strncmp(format,"PERROR", 6) != 0)
vfprintf(stderr,format,arg_ptr);
else
{
for (pstr=format+6; *pstr == ' ' || *pstr == ':'; pstr++)
;
vfprintf(stderr,pstr,arg_ptr);
perror("");
}
va_end(arg_ptr);
fflush(stderr);
/* call one clean up function if defined */
if ( (sig_func = signal(SIGTERM, SIG_DFL)) != SIG_DFL &&
sig_func != SIG_IGN)
(*sig_func)(0);
else if ( (sig_func = signal(SIGHUP, SIG_DFL)) != SIG_DFL &&
sig_func != SIG_IGN)
(*sig_func)(0);
else if ( (sig_func = signal(SIGINT, SIG_DFL)) != SIG_DFL &&
sig_func != SIG_IGN)
(*sig_func)(0);
else if ( (sig_func = signal(SIGQUIT, SIG_DFL)) != SIG_DFL &&
sig_func != SIG_IGN)
(*sig_func)(0);
exit(1);
}
/*
** halt.h
**
*/
void halt();
/*
* insert.c
*
*/
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include "halt.h"
#include <libpq-fe.h>
#include "pginterface.h"
int main(int argc, char **argv)
{
char query[4000];
int row =1;
int aint;
float afloat;
double adouble;
char achar[11], achar16[17], abpchar[11], avarchar[51], atext[51];
time_t aabstime;
if (argc != 2)
halt("Usage: %s database\n",argv[0]);
connectdb(argv[1],NULL,NULL,NULL,NULL);
on_error_continue();
doquery("DROP TABLE testfetch");
on_error_stop();
doquery("\
CREATE TABLE testfetch( \
aint int4, \
afloat float4, \
adouble float8, \
achar char, \
achar16 char16, \
abpchar char(10), \
avarchar varchar(50), \
atext text, \
aabstime abstime) \
");
while(1)
{
sprintf(query,"INSERT INTO testfetch VALUES ( \
%d, \
2322.12, \
'923121.0323'::float8, \
'A', \
'Betty', \
'Charley', \
'Doug', \
'Ernie', \
'now' )", row);
doquery(query);
doquery("BEGIN WORK");
doquery("DECLARE c_testfetch BINARY CURSOR FOR \
SELECT * FROM testfetch");
doquery("FETCH ALL IN c_testfetch");
while (fetch(
&aint,
&afloat,
&adouble,
achar,
achar16,
abpchar,
avarchar,
atext,
&aabstime) != END_OF_TUPLES)
printf("int %d\nfloat %f\ndouble %f\nchar %s\nchar16 %s\n\
bpchar %s\nvarchar %s\ntext %s\nabstime %s",
aint,
afloat,
adouble,
achar,
achar16,
abpchar,
avarchar,
atext,
ctime(&aabstime));
doquery("CLOSE c_testfetch");
doquery("COMMIT WORK");
printf("--- %-d rows inserted so far\n",row);
row++;
}
disconnectdb();
return 0;
}
/*
* pginterface.c
*
*/
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <stdarg.h>
#include "halt.h"
#include <libpq-fe.h>
#include "pginterface.h"
static void sig_disconnect();
static void set_signals();
#define NUL '\0'
/* GLOBAL VARIABLES */
static PGconn* conn;
static PGresult* res = NULL;
#define ON_ERROR_STOP 0
#define ON_ERROR_CONTINUE 1
static int on_error_state = ON_ERROR_STOP;
/* LOCAL VARIABLES */
static sigset_t block_sigs, unblock_sigs;
static int tuple;
/*
**
** connectdb - returns PGconn structure
**
*/
PGconn *connectdb( char *dbName,
char *pghost,
char *pgport,
char *pgoptions,
char *pgtty)
{
/* make a connection to the database */
conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);
if (PQstatus(conn) == CONNECTION_BAD)
halt("Connection to database '%s' failed.\n%s\n", dbName,
PQerrorMessage(conn));
set_signals();
return conn;
}
/*
**
** disconnectdb
**
*/
void disconnectdb()
{
PQfinish(conn);
}
/*
**
** doquery - returns PGresult structure
**
*/
PGresult *doquery(char *query)
{
if (res != NULL)
PQclear(res);
sigprocmask(SIG_SETMASK,&block_sigs,NULL);
res = PQexec(conn, query);
sigprocmask(SIG_SETMASK,&unblock_sigs,NULL);
if (on_error_state == ON_ERROR_STOP &&
(res == NULL ||
PQresultStatus(res) == PGRES_BAD_RESPONSE ||
PQresultStatus(res) == PGRES_NONFATAL_ERROR ||
PQresultStatus(res) == PGRES_FATAL_ERROR))
{
if (res != NULL)
fprintf(stderr,"query error: %s\n",PQcmdStatus(res));
else fprintf(stderr,"connection error: %s\n",PQerrorMessage(conn));
PQfinish(conn);
halt("failed request: %s\n", query);
}
tuple = 0;
return res;
}
/*
**
** fetch - returns tuple number (starts at 0), or the value END_OF_TUPLES
** NULL pointers are skipped
**
*/
int fetch(void *param, ...)
{
va_list ap;
int arg, num_args;
num_args = PQnfields(res);
if (tuple >= PQntuples(res))
return END_OF_TUPLES;
va_start(ap, param);
for (arg = 0; arg < num_args; arg++)
{
if (param != NULL)
{
if (PQfsize(res, arg) == -1)
{
memcpy(param,PQgetvalue(res,tuple,arg),PQgetlength(res,tuple,arg));
((char *)param)[PQgetlength(res,tuple,arg)] = NUL;
}
else
memcpy(param,PQgetvalue(res,tuple,arg),PQfsize(res,arg));
}
param = va_arg(ap, char *);
}
va_end(ap);
return tuple++;
}
/*
**
** on_error_stop
**
*/
void on_error_stop()
{
on_error_state = ON_ERROR_STOP;
}
/*
**
** on_error_continue
**
*/
void on_error_continue()
{
on_error_state = ON_ERROR_CONTINUE;
}
/*
**
** sig_disconnect
**
*/
static void sig_disconnect()
{
fprintf(stderr,"exiting...\n");
PQfinish(conn);
exit(1);
}
/*
**
** set_signals
**
*/
static void set_signals()
{
sigemptyset(&block_sigs);
sigemptyset(&unblock_sigs);
sigaddset(&block_sigs,SIGTERM);
sigaddset(&block_sigs,SIGHUP);
sigaddset(&block_sigs,SIGINT);
/* sigaddset(&block_sigs,SIGQUIT); no block */
sigprocmask(SIG_SETMASK,&unblock_sigs,NULL);
signal(SIGTERM,sig_disconnect);
signal(SIGHUP,sig_disconnect);
signal(SIGINT,sig_disconnect);
signal(SIGQUIT,sig_disconnect);
}
/*
* pglib.h
*
*/
PGresult *doquery(char *query);
PGconn *connectdb();
void disconnectdb();
int fetch(void *param, ...);
void on_error_continue();
void on_error_stop();
#define END_OF_TUPLES (-1)
/*****************************************************************************/
/* soundex.c */
/*****************************************************************************/
#include <string.h>
#include <stdio.h>
#include "postgres.h" /* for char16, etc. */
#include "utils/palloc.h" /* for palloc */
#include "libpq-fe.h" /* for TUPLE */
#include <stdio.h>
#include <ctype.h>
/* prototype for soundex function */
char *soundex(char *instr, char *outstr);
text *text_soundex(text *t)
{
/* ABCDEFGHIJKLMNOPQRSTUVWXYZ */
char *table = "01230120022455012623010202";
int count = 0;
text *new_t;
char outstr[6+1]; /* max length of soundex is 6 */
char *instr;
/* make a null-terminated string */
instr=palloc(VARSIZE(t)+1);
memcpy(instr,VARDATA(t),VARSIZE(t)-VARHDRSZ);
instr[VARSIZE(t)-VARHDRSZ] = (char)0;
/* load soundex into outstr */
soundex(instr, outstr);
/* Now the outstr contains the soundex of instr */
/* copy outstr to new_t */
new_t = (text *) palloc(strlen(outstr)+VARHDRSZ);
memset(new_t, 0, strlen(outstr)+1);
VARSIZE(new_t) = strlen(outstr)+VARHDRSZ;
memcpy((void *) VARDATA(new_t),
(void *) outstr,
strlen(outstr));
/* free instr */
pfree(instr);
return(new_t);
}
char *soundex(char *instr, char *outstr)
{ /* ABCDEFGHIJKLMNOPQRSTUVWXYZ */
char *table = "01230120022455012623010202";
int count = 0;
while(!isalpha(instr[0]) && instr[0])
++instr;
if(!instr[0]) { /* Hey! Where'd the string go? */
outstr[0]=(char)0;
return outstr;
}
if(toupper(instr[0]) == 'P' && toupper(instr[1]) == 'H') {
instr[0] = 'F';
instr[1] = 'A';
}
*outstr++ = (char)toupper(*instr++);
while(*instr && count < 5) {
if(isalpha(*instr) && *instr != *(instr-1)) {
*outstr = table[toupper(instr[0]) - 'A'];
if(*outstr != '0') {
++outstr;
++count;
}
}
++instr;
}
*outstr = '\0';
return(outstr);
}
--------------- soundex.sql:
CREATE FUNCTION text_soundex(text) RETURNS text
AS '/usr/local/postgres/postgres95/src/funcs/soundex.so' LANGUAGE 'c';
SELECT text_soundex('hello world!');
CREATE TABLE s (nm text)\g
insert into s values ('john')\g
insert into s values ('joan')\g
insert into s values ('wobbly')\g
select * from s
where text_soundex(nm) = text_soundex('john')\g
select nm from s a, s b
where text_soundex(a.nm) = text_soundex(b.nm)
and a.oid <> b.oid\g
CREATE FUNCTION text_sx_eq(text, text) RETURNS bool AS
'select text_soundex($1) = text_soundex($2)'
LANGUAGE 'sql'\g
CREATE FUNCTION text_sx_lt(text,text) RETURNS bool AS
'select text_soundex($1) < text_soundex($2)'
LANGUAGE 'sql'\g
CREATE FUNCTION text_sx_gt(text,text) RETURNS bool AS
'select text_soundex($1) > text_soundex($2)'
LANGUAGE 'sql';
CREATE FUNCTION text_sx_le(text,text) RETURNS bool AS
'select text_soundex($1) <= text_soundex($2)'
LANGUAGE 'sql';
CREATE FUNCTION text_sx_ge(text,text) RETURNS bool AS
'select text_soundex($1) >= text_soundex($2)'
LANGUAGE 'sql';
CREATE FUNCTION text_sx_ne(text,text) RETURNS bool AS
'select text_soundex($1) <> text_soundex($2)'
LANGUAGE 'sql';
DROP OPERATOR #= (text,text)\g
CREATE OPERATOR #= (leftarg=text, rightarg=text, procedure=text_sx_eq,
commutator=text_sx_eq)\g
SELECT *
FROM s
WHERE text_sx_eq(nm,'john')\g
SELECT *
from s
where s.nm #= 'john';
/*
* string_io.c --
*
* This file defines new input/output conversion routines for strings.
*
* Copyright (c) 1996, Massimo Dal Zotto <dz@cs.unitn.it>
*/
#include <ctype.h>
#include <string.h>
#include "postgres.h"
#include "utils/elog.h"
#include "utils/palloc.h"
#include "utils/builtins.h"
/* define this if you want to see iso-8859 characters */
#define ISO8859
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define VALUE(char) ((char) - '0')
#define DIGIT(val) ((val) + '0')
#define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
#ifndef ISO8859
#define NOTPRINTABLE(c) (!isprint(c))
#else
#define NOTPRINTABLE(c) (!isprint(c) && ((c) < 0xa0))
#endif
/*
* string_output() --
*
* This function takes a pointer to a string data and an optional
* data size and returns a printable representation of the data
* translating all escape sequences to C-like \nnn or \c escapes.
* The function is used by output methods of various string types.
*
* Arguments:
* data - input data (can be NULL)
* size - optional size of data. A negative value indicates
* that data is a null terminated string.
*
* Returns:
* a pointer to a new string containing the printable
* representation of data.
*/
char *
string_output(char *data, int size)
{
register unsigned char c, *p, *r, *result;
register int l, len;
if (data == NULL) {
result = (char *) palloc(2);
result[0] = '-';
result[1] = '\0';
return (result);
}
if (size < 0) {
size = strlen(data);
}
/* adjust string length for escapes */
len = size;
for (p=data,l=size; l>0; p++,l--) {
switch (*p) {
case '\\':
case '"' :
case '{':
case '}':
case '\b':
case '\f':
case '\n':
case '\r':
case '\t':
case '\v':
len++;
break;
default:
if (NOTPRINTABLE(c)) {
len += 3;
}
}
}
len++;
result = (char *) palloc(len);
for (p=data,r=result,l=size; (l > 0) && (c = *p); p++,l--) {
switch (c) {
case '\\':
case '"' :
case '{':
case '}':
*r++ = '\\';
*r++ = c;
break;
case '\b':
*r++ = '\\';
*r++ = 'b';
break;
case '\f':
*r++ = '\\';
*r++ = 'f';
break;
case '\n':
*r++ = '\\';
*r++ = 'n';
break;
case '\r':
*r++ = '\\';
*r++ = 'r';
break;
case '\t':
*r++ = '\\';
*r++ = 't';
break;
case '\v':
*r++ = '\\';
*r++ = 'v';
break;
default:
if (NOTPRINTABLE(c)) {
*r = '\\';
r += 3;
*r-- = DIGIT(c & 07);
c >>= 3;
*r-- = DIGIT(c & 07);
c >>= 3;
*r = DIGIT(c & 03);
r += 3;
} else {
*r++ = c;
}
}
}
*r = '\0';
return((char *) result);
}
/*
* string_input() --
*
* This function accepts a C string in input and copies it into a new
* object allocated with palloc() translating all escape sequences.
* An optional header can be allocatd before the string, for example
* to hold the length of a varlena object.
* This function is not necessary for input from sql commands because
* the parser already does escape translation, all data input routines
* receive strings in internal form.
*
* Arguments:
* str - input string possibly with escapes
* size - the required size of new data. A value of 0
* indicates a variable size string, while a
* negative value indicates a variable size string
* of size not greater than this absolute value.
* hdrsize - size of an optional header to be allocated before
* the data. It must then be filled by the caller.
* rtn_size - an optional pointer to an int variable where the
* size of the new string is stored back.
*
* Returns:
* a pointer to the new string or the header.
*/
char *
string_input(char *str, int size, int hdrsize, int *rtn_size)
{
register unsigned char *p, *r;
unsigned char *result;
int len;
if ((str == NULL) || (hdrsize < 0)) {
return (char *) NULL;
}
/* Compute result size */
len = strlen(str);
for (p=str; *p; ) {
if (*p++ == '\\') {
if (ISOCTAL(*p)) {
if (ISOCTAL(*(p+1))) {
p++;
len--;
}
if (ISOCTAL(*(p+1))) {
p++;
len--;
}
}
if (*p) p++;
len--;
}
}
/* result has variable length */
if (size == 0) {
size = len+1;
} else
/* result has variable length with maximum size */
if (size < 0) {
size = MIN(len, - size)+1;
}
result = (char *) palloc(hdrsize+size);
memset(result, 0, hdrsize+size);
if (rtn_size) {
*rtn_size = size;
}
r = result + hdrsize;
for (p=str; *p; ) {
register unsigned char c;
if ((c = *p++) == '\\') {
switch (c = *p++) {
case '\0':
p--;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
c = VALUE(c);
if (isdigit(*p)) {
c = (c<<3) + VALUE(*p++);
}
if (isdigit(*p)) {
c = (c<<3) + VALUE(*p++);
}
*r++ = c;
break;
case 'b':
*r++ = '\b';
break;
case 'f':
*r++ = '\f';
break;
case 'n':
*r++ = '\n';
break;
case 'r':
*r++ = '\r';
break;
case 't':
*r++ = '\t';
break;
case 'v':
*r++ = '\v';
break;
default:
*r++ = c;
}
} else {
*r++ = c;
}
}
return((char *) result);
}
char *
c_charout(int32 c)
{
char str[2];
str[0] = (char) c;
str[1] = '\0';
return (string_output(str, 1));
}
char *
c_char2out(uint16 s)
{
return (string_output((char *) &s, 2));
}
char *
c_char4out(uint32 s)
{
return (string_output((char *) &s, 4));
}
char *
c_char8out(char *s)
{
return (string_output(s, 8));
}
char *
c_char16out(char *s)
{
return (string_output(s, 16));
}
/*
* This can be used for text, bytea, SET and unknown data types
*/
char *
c_textout(struct varlena *vlena)
{
int len = 0;
char *s = NULL;
if (vlena) {
len = VARSIZE(vlena) - VARHDRSZ;
s = VARDATA(vlena);
}
return (string_output(s, len));
}
/*
* This can be used for varchar and bpchar strings
*/
char *
c_varcharout(char *s)
{
int len;
if (s) {
len = *(int32*)s - 4;
s += 4;
}
return (string_output(s, len));
}
#ifdef 0
struct varlena *
c_textin(char *str)
{
struct varlena *result;
int len;
if (str == NULL) {
return ((struct varlena *) NULL);
}
result = (struct varlena *) string_input(str, 0, VARHDRSZ, &len);
VARSIZE(result) = len;
return (result);
}
char *
c_char16in(char *str)
{
return (string_input(str, 16, 0, NULL));
}
#endif
- - -- load the new functions
- - --
load '/home/dz/lib/postgres/string_output.so';
- - -- create function c_textin(opaque)
- - -- returns text
- - -- as '/home/dz/lib/postgres/string_output.so'
- - -- language 'c';
create function c_charout(opaque)
returns int4
as '/home/dz/lib/postgres/string_output.so'
language 'c';
create function c_char2out(opaque)
returns int4
as '/home/dz/lib/postgres/string_output.so'
language 'c';
create function c_char4out(opaque)
returns int4
as '/home/dz/lib/postgres/string_output.so'
language 'c';
create function c_char8out(opaque)
returns int4
as '/home/dz/lib/postgres/string_output.so'
language 'c';
create function c_char16out(opaque)
returns int4
as '/home/dz/lib/postgres/string_output.so'
language 'c';
create function c_textout(opaque)
returns int4
as '/home/dz/lib/postgres/string_output.so'
language 'c';
create function c_varcharout(opaque)
returns int4
as '/home/dz/lib/postgres/string_output.so'
language 'c';
- - -- define a function which sets the new output routines for char types
- - --
- - -- select c_mode();
- - --
create function c_mode()
returns text
as 'update pg_type set typoutput=''c_charout'' where typname=''char''\;
update pg_type set typoutput=''c_char2out'' where typname=''char2''\;
update pg_type set typoutput=''c_char4out'' where typname=''char4''\;
update pg_type set typoutput=''c_char8out'' where typname=''char8''\;
update pg_type set typoutput=''c_char16out'' where typname=''char16''\;
update pg_type set typoutput=''c_textout'' where typname=''text''\;
update pg_type set typoutput=''c_textout'' where typname=''bytea''\;
update pg_type set typoutput=''c_textout'' where typname=''unknown''\;
update pg_type set typoutput=''c_textout'' where typname=''SET''\;
update pg_type set typoutput=''c_varcharout'' where typname=''varchar''\;
update pg_type set typoutput=''c_varcharout'' where typname=''bpchar''\;
select ''c_mode''::text'
language 'sql';
- - -- define a function which restores the original routines for char types
- - --
- - -- select pg_mode();
- - --
create function pg_mode()
returns text
as 'update pg_type set typoutput=''charout'' where typname=''char''\;
update pg_type set typoutput=''char2out'' where typname=''char2''\;
update pg_type set typoutput=''char4out'' where typname=''char4''\;
update pg_type set typoutput=''char8out'' where typname=''char8''\;
update pg_type set typoutput=''char16out'' where typname=''char16''\;
update pg_type set typoutput=''textout'' where typname=''text''\;
update pg_type set typoutput=''textout'' where typname=''bytea''\;
update pg_type set typoutput=''textout'' where typname=''unknown''\;
update pg_type set typoutput=''textout'' where typname=''SET''\;
update pg_type set typoutput=''varcharout'' where typname=''varchar''\;
update pg_type set typoutput=''varcharout'' where typname=''bpchar''\;
select ''pg_mode''::text'
language 'sql';
- - -- or do the changes manually
- - --
- - -- update pg_type set typoutput='charout' where typname='char';
- - -- update pg_type set typoutput='char2out' where typname='char2';
- - -- update pg_type set typoutput='char4out' where typname='char4';
- - -- update pg_type set typoutput='char8out' where typname='char8';
- - -- update pg_type set typoutput='char16out' where typname='char16';
- - -- update pg_type set typoutput='textout' where typname='text';
- - -- update pg_type set typoutput='textout' where typname='bytea';
- - -- update pg_type set typoutput='textout' where typname='unknown';
- - -- update pg_type set typoutput='textout' where typname='SET';
- - -- update pg_type set typoutput='varcharout' where typname='varchar';
- - -- update pg_type set typoutput='varcharout' where typname='bpchar';
- - --
- - -- update pg_type set typoutput='c_charout' where typname='char';
- - -- update pg_type set typoutput='c_char2out' where typname='char2';
- - -- update pg_type set typoutput='c_char4out' where typname='char4';
- - -- update pg_type set typoutput='c_char8out' where typname='char8';
- - -- update pg_type set typoutput='c_char16out' where typname='char16';
- - -- update pg_type set typoutput='c_textout' where typname='text';
- - -- update pg_type set typoutput='c_textout' where typname='bytea';
- - -- update pg_type set typoutput='c_textout' where typname='unknown';
- - -- update pg_type set typoutput='c_textout' where typname='SET';
- - -- update pg_type set typoutput='c_varcharout' where typname='varchar';
- - -- update pg_type set typoutput='c_varcharout' where typname='bpchar';
From ccshag@cclabs.missouri.edu Wed Jul 10 04:27:16 1996
Received: from realtime.cc.missouri.edu (realtime.cc.missouri.edu [128.206.212.69]) by ki.net (8.7.5/8.7.5) with ESMTP id EAA12722 for <scrappy@ki.net>; Wed, 10 Jul 1996 04:27:13 -0400 (EDT)
Received: from localhost (ccshag@localhost) by realtime.cc.missouri.edu (8.7.1/8.7.1) with SMTP id DAA00915; Wed, 10 Jul 1996 03:26:42 -0500 (CDT)
X-Authentication-Warning: realtime.cc.missouri.edu: ccshag owned process doing -bs
Date: Wed, 10 Jul 1996 03:26:41 -0500 (CDT)
From: "Paul 'Shag' Walmsley" <ccshag@cclabs.missouri.edu>
Sender: ccshag@cclabs.missouri.edu
To: postgres95-hackers@oozoo.vnet.net
cc: pixel@tiger.coe.missouri.edu, michael.siebenborn@ae3.Hypo.DE,
scrappy@ki.net
Subject: Workaround for database corruption problems [long]
Message-ID: <Pine.SGI.3.93.960710023021.673B-100000@realtime.cc.missouri.edu>
X-Disclaimer: The opinions of this writer do not necessarily represent those of the University of Missouri-Columbia.
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
Status: RO
X-Status:
I've been poking through the guts of POSTGRES95 in pursuit of the
previously-mentioned "database corruption" problem, and I think that I
have some preliminary answers and a workaround for people to play around
with.
Specifically, the problem that I'm referring to is manifested by
pg_log, pg_time, or pg_variable either growing to huge sizes (usually
128MB) or showing evidence of internal corruption. Symptoms that appear
to the user include receiving messages like the following in psql or
monitor:
"WARN:cannot open segment 1 of relation pg_time"
"WARN:cannot write block 16384 of pg_log"
.. which are followed up in a 'postmaster -d 3' debug log by a
"NOTICE:AbortTransaction and not in in-progress state"
It's been my experience that this problem is difficult to reproduce on
demand; I've tried several different ways and haven't succeeded. (If
anyone knows how to reliably reproduce this, please E-mail me.) I was,
however, able to obtain a database in a corrupted state from one of the
fellows on campus here running POSTGRES95; and following is something of a
post-mortem.
----------
The problem with the database is that after any query, POSTGRES95 attempts
to generate a huge pg_log file and fails (running out of disk space) with
a "WARN:cannot write block 16384 of pg_log" message. The contents of the
database and its internal structure were reasonably intact - I discovered
that I was able to execute a single SQL query per-backend, and could
therefore back the contents of the database up with a COPY command. (I
wasn't able to use pg_dump; it failed on its BEGIN TRANSACTION step.)
Inspection of data/pg_log, data/pg_variable, and data/pg_time revealed the
following;
realtime /usr/postgres95 > od -x data/pg_log.old | head
0000000 0060 2000 2000 2000 f680 0000 ed00 0000
0000020 e300 0000 dc00 0000 ce00 0000 bc00 0000
0000040 b140 0000 a740 0000 9dc0 0000 9180 0000
0000060 8580 0000 7c80 0000 6fc0 0000 6480 0000
0000100 58c0 0000 4fc0 0000 4640 0000 3a80 0000
0000120 30c0 0000 23c0 0000 1900 0000 0c40 0000
0000140 0000 0000 0000 0000 0000 0000 0000 0000
*
0000200 8800 0000 0000 0000 0800 0000 0000 0000
0000220 0800 0000 0000 0000 0800 0000 0000 0000
Now, already something is obviously wrong: pg_log shouldn't have any
values other than 0, 1, 2, 4, 8, a, c, or e for each nybble (see the XID_
... definitions in src/backend/access/transam.h:35; two of these can be
stored per nybble.)
realtime /usr/postgres95 > od -x data/pg_variable.old | head
0000000 0058 2000 2000 2740 f240 0000 e400 0000
0000020 d780 0000 cac0 0000 b840 0000 a900 0000
0000040 9f80 0000 9280 0000 8580 0000 78c0 0000
0000060 6c80 0000 6200 0000 5800 0000 4f80 0000
0000100 44c0 0000 39c0 0000 2d80 0000 2600 0000
0000120 1c00 0000 0e00 0000 0000 0000 0000 0000
0000140 0000 0000 0000 0000 0000 0000 0000 0000
*
0000700 0000 01bc 0000 009c 0014 ffff ffff 0000
0000720 0004 5f0b 0000 0000 0000 0ba3 0000 0c23
This is obviously broken too; the only bytes that should be non-zero in
pg_variable are the first 16 (see src/backend/access/transam.h:99).
realtime /usr/postgres95 > od -x data/pg_time.old | head -10
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
0004000 31c6 09ae 0000 0000 31c6 09b3 31a9 79a6
0004020 31a9 79a6 31a9 79a8 31a9 79a9 31a9 79a9
0004040 31a9 79a9 31a9 79aa 31a9 79aa 31a9 79aa
0004060 31a9 79aa 31a9 79aa 31a9 79ab 31a9 79ab
0004100 31a9 79ab 31a9 79ac 31a9 79ac 31a9 79ac
0004120 31a9 79ac 31a9 79ad 31a9 79ad 31a9 79ae
0004140 31a9 79ae 31a9 79af 31a9 79af 31a9 79af
0004160 31a9 79b0 31a9 79b0 31a9 79b4 31a9 79b4
realtime /usr/postgres95 > od -x data/pg_time.old +32b | head -10
0032000 6665 6520 666f 7220 31c5 cb61 696e 6720
0032020 6465 7665 6c6f 7065 7273 2062 7579 2061
0032040 206c 6f77 2d69 6e63 6f6d 6520 6170 6172
0032060 746d 656e 7420 636f 6d70 6c65 7869 6e20
0032100 7468 6520 7472 6561 7375 7265 7227 7320
0032120 7761 7264 2066 726f 6d20 7468 6520 6665
0032140 6465 7261 6c20 676f 7665 726e 6d65 6e74
0032160 2066 6f72 2024 313b 2064 6576 656c 6f70
0032200 6572 7361 6c73 6f20 31c5 cb7c 31be 91a2
0032220 31be 91a2 31be 91a2 31be 91a2 31be 91a3
The first part of pg_time looked okay -- filled with 4-byte time values
with the occasional "00 00 00 00" here and there -- but inspection into
pg_time's guts revealed some preposterous numbers.
For your comparing pleasure, I include copies of what these files
_should_ look like -- more or less -- from a newly initdb'd database
directory:
realtime /usr/postgres95 > od -x data-new-initdb/pg_log
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
0000200 8aaa aaaa aaaa aaa8 0000 0000 0000 0000
0000220 0000 0000 0000 0000 0000 0000 0000 0000
*
0020000
realtime /usr/postgres95 > od -x data-new-initdb/pg_variable
0000000 0000 0000 0000 0222 0000 021e 0000 5120
0000020 0000 0000 0000 0000 0000 0000 0000 0000
*
0020000
realtime /usr/postgres95 > od -x data-new-initdb/pg_time
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
0004000 31e3 4fb3 0000 0000 31e3 4fb4 31e3 4fb4
0004020 31e3 4fb4 31e3 4fb5 31e3 4fb5 31e3 4fb5
0004040 31e3 4fb6 31e3 4fb6 31e3 4fb6 31e3 4fb6
0004060 31e3 4fb7 31e3 4fb7 31e3 4fb7 31e3 4fb7
0004100 31e3 4fb8 31e3 4fb8 31e3 4fb8 31e3 4fb9
0004120 31e3 4fb9 31e3 4fb9 31e3 4fb9 31e3 4fba
0004140 31e3 4fba 31e3 4fba 31e3 4fbb 31e3 4fbb
0004160 31e3 4fbb 31e3 4fbb 31e3 4fbb 0000 0000
0004200 0000 0000 0000 0000 0000 0000 0000 0000
*
0020000
What's more, if I view pg_log, pg_variable, and pg_time with a text
editor, I discover that the corrupted areas contain fragments of tuples
from the database!
----------
Since I have been unable to reproduce this problem on demand (and
therefore have a complete picture of all of the queries executed on the
database), I've only been able to speculate on the original cause of the
problem. One explanation would be some kind of buffer manager bug; or
perhaps the backend is running low on file descriptors and bollixing
existing ones? I intend to continue tracking this down as I have the
time, but in the interim, I've created a quick Perl script that is
designed to restore some sense of rationality to the
pg_{log,time,variable} files. It's a horribly barbaric way to do this --
at the very least, it almost certainly breaks time travel, and will
almost certainly result in duplicate oid problems -- but it restored my
pathological database here to a sufficiently working state such that I
could run pg_dump on it and do various other queries with it. The script
is included at the bottom of this message.
Anyway, fellow posthackers, assuming that no one raises any red flags
about this, I'll post it on postgres95@oozoo.vnet.net as a temporary
stop-gap workaround to allow people to recover their databases when this
sort of problem occurs.
I wish I had more time to do this kind of thing.
- Paul "Shag" Walmsley <ccshag@cclabs.missouri.edu>
"Knowing is not enough." -- Hal Hartley, "Surviving Desire"
#!/bin/perl
#
# zap_ltv - attempt to restore a POSTGRES95 database afflicted with
# pg_log, pg_time, or pg_variable corruption to
# minimal functionality
#
# Paul Walmsley <ccshag@cclabs.missouri.edu>
#
# Legalese:
#
# In no event shall Paul Walmsley be liable to any party for direct,
# indirect, special, incidental, or consequential damages, including
# lost profits, arising from the use of this software, even if Paul Walmsley
# has been advised of the possibility of such damage. Paul Walmsley
# 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 Paul Walmsley has no obligations to provide maintenance, support,
# updates, enhancements, or modifications.
#
# Thanks, Berkeley ;-)
print "This program should only be run if POSTGRES95 is not currently\n";
print "running on this system. It should also not be run unless you \n";
print "are having seemingly unrecoverable problems with your POSTGRES95\n";
print "database related to pg_log, pg_time, or pg_variable corruption.\n\n";
print "This program replaces the existing pg_log, pg_time, and pg_variable\n";
print "files with \"clean\" copies of those files. This will almost \n";
print "certainly result in duplicate IDs when any INSERTs are attempted,\n";
print "and probably has other side-effects as well. Back up your databases\n"
print "and re-initdb from scratch after using this!\n\n";
print "This program will attempt to make a backup of your pg_time,\n";
print "pg_log, and pg_variable files (to pg_time.backup, pg_log.backup,\n";
print "and pg_variable.backup, respectively).\n\n";
print "This program bears no guarantees nor any warranties whatsoever.\n";
print "View the source for details.\n\n";
print "Press ENTER to zap your pg_log, pg_time, and pg_variable files:";
$trash=<STDIN>;
$pg_log_data=pack('xxxx@8192',0);
$pg_time_data=pack('xxxx@8192',0);
# next_tid, last_tid, and oid are pulled from a fresh initdb
$pg_variable_data=pack('xxxxxxCCxxCCxxCC@8192',2,34,2,30,81,32);
if (length($pg_log_data)!=8192) {
die "pg_log_data must be exactly 8192 bytes long";
}
if (length($pg_time_data)!=8192) {
die "pg_time_data must be exactly 8192 bytes long";
}
if (length($pg_variable_data)!=8192) {
die "pg_variable_data must be exactly 8192 bytes long";
}
if (! -f 'pg_database') {
die "This program must be run from your POSTGRES95 data directory.";
}
system('cp pg_log pg_log.backup');
open(PG_LOG,'>pg_log');
binmode(PG_LOG);
$written=syswrite(PG_LOG,$pg_log_data,8192);
close(PG_LOG);
if ($written!=8192) {
die "pg_log write failed: $!";
}
$written=0;
system('cp pg_time pg_time.backup');
open(PG_TIME,'>pg_time');
binmode(PG_TIME);
$written=syswrite(PG_TIME,$pg_time_data,8192);
close(PG_TIME);
if ($written!=8192) {
die "pg_time write failed: $!";
}
$written=0;
system('cp pg_variable pg_variable.backup');
open(PG_VARIABLE,'>pg_variable');
binmode(PG_VARIABLE);
$written=syswrite(PG_VARIABLE,$pg_variable_data,8192);
close(PG_VARIABLE);
if ($written!=8192) {
die "pg_variable write failed: $!";
}
print "Done.\n";
-- add builtin functions that are new to 1.01
create function int4eqoid (int4, oid) returns bool as 'foo'
language 'internal';
create function oideqint4 (oid, int4) returns bool as 'foo'
language 'internal';
create function char2icregexeq (char2, text) returns bool as 'foo'
language 'internal';
create function char2icregexne (char2, text) returns bool as 'foo'
language 'internal';
create function char4icregexeq (char4, text) returns bool as 'foo'
language 'internal';
create function char4icregexne (char4, text) returns bool as 'foo'
language 'internal';
create function char8icregexeq (char8, text) returns bool as 'foo'
language 'internal';
create function char8icregexne (char8, text) returns bool as 'foo'
language 'internal';
create function char16icregexeq (char16, text) returns bool as 'foo'
language 'internal';
create function char16icregexne (char16, text) returns bool as 'foo'
language 'internal';
create function texticregexeq (text, text) returns bool as 'foo'
language 'internal';
create function texticregexne (text, text) returns bool as 'foo'
language 'internal';
-- add builtin functions that are new to 1.01
create operator = (leftarg = int4, rightarg = oid, procedure = int4eqoid);
create operator = (leftarg = oid, rightarg = int4, procedure = oideqint4);
create operator ~* (leftarg = char2, rightarg = text, procedure = char2icregexeq);
create operator !~* (leftarg = char2, rightarg = text, procedure = char2icregexne);
create operator ~* (leftarg = char4, rightarg = text, procedure = char4icregexeq);
create operator !~* (leftarg = char4, rightarg = text, procedure = char4icregexne);
create operator ~* (leftarg = char8, rightarg = text, procedure = char8icregexeq);
create operator !~* (leftarg = char8, rightarg = text, procedure = char8icregexne);
create operator ~* (leftarg = char16, rightarg = text, procedure = char16icregexeq);
create operator !~* (leftarg = char16, rightarg = text, procedure = char16icregexne);
create operator ~* (leftarg = text, rightarg = text, procedure = texticregexeq);
create operator !~* (leftarg = text, rightarg = text, procedure = texticregexne);
This diff is collapsed.
The following notes are for the benefit of users who want to migrate
databases from postgres95 1.0 to postgres95 1.01.
If you are starting afresh with postgres95 1.01 and do not need
to migrate old databases, you do not need to read any further.
----------------------------------------------------------------------
In order to postgres95 version 1.01 with databases created with
postgres95 version 1.0, the following steps are required:
1) Set the definition of NAMEDATALEN in src/Makefile.global to 16
and OIDNAMELEN to 20.
2) Decide whether you want to use Host based authentication.
A) If you do, you must create a file name "pg_hba" in your top-level data
directory (typically the value of your $PGDATA). src/libpq/pg_hba
shows an example syntax.
B) If you do not want host-based authentication, you can comment out
the line
HBA = 1
in src/Makefile.global
Note that host-based authentication is turned on by default, and if
you do not take steps A or B above, the out-of-the-box 1.01 will
not allow you to connect to 1.0 databases.
3) compile and install 1.01, but DO NOT do the initdb step.
4) before doing anything else, terminate your 1.0 postmaster, and
backup your existing $PGDATA directory.
5) set your PGDATA environment variable to your 1.0 databases, but set up
path up so that 1.01 binaries are being used.
6) modify the file $PGDATA/PG_VERSION from 5.0 to 5.1
7) start up a new 1.01 postmaster
5) Add the new built-in functions and operators of 1.01 to 1.0
databases. This is done by running the new 1.01 server against
your own 1.0 database and applying the queries in the file
1.0_to_1.01.sql. This can be done easily through psql. If your
1.0 database is name "testdb":
% psql testdb -f 1.0_to_1.01.sql
#-------------------------------------------------------------------------
#
# Makefile
# Makefile for doc directory to install man pages
#
# Copyright (c) 1994, Regents of the University of California
# Copyright (c) 1996, Dr George D Detlefsen
#
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/doc/Makefile,v 1.1.1.1 1996/08/18 22:14:17 scrappy Exp $
#
#-------------------------------------------------------------------------
MKDIR= ../src/mk
include $(MKDIR)/postgres.mk
CLEANFILES=*
install-man:
-mkdir -p $(POSTMANDIR)
-mkdir $(POSTMANDIR)/man1
-mkdir $(POSTMANDIR)/man3
-mkdir $(POSTMANDIR)/man5
-mkdir $(POSTMANDIR)/manl
cp man/*.1* $(POSTMANDIR)/man1
cp man/*.3* $(POSTMANDIR)/man3
cp man/*.5* $(POSTMANDIR)/man5
cp man/*.l* $(POSTMANDIR)/manl
install:: install-man
varchar.diff
------------
This patch was necessary for the OpenLink Postgres Database Agent.
I think this fixes a bug anyway.
The following query demonstrates this bug:
create table foo (bar varchar);
insert into foo values (''); -- no problem
select * from foo where bar = ''; -- fails
fsync.diff
----------
This patch adds an option to disable synchronous writes.
It adds an extra option to postgres: -F
When started with -F, all fsync() calls will be no-ops,
so you'll be in big trouble when your machine suddenly crashes and your disk
cache is not flushed.
Use at your own risk (but it is *much* faster with large inserts)
This also speeds up initdb for initial database bootstrapping
To start postmaster with this "feature" enabled, type
postmaster -o -F -S
From: ernst.molitor@uni-bonn.de
Hi,
thank you for the latest Postgres95 distribution!
>does the createuser bug still persist, or have
>we finally worked that one out?
As has been indication by Bruce Momjian, the createuser problem was
caused by a bug in flex 2.5.3 (which has been confirmed by Vern
Paxson, the flex maintainer - many thanks to them); the bug will be
fixed in flex 2.5.4. Vern Paxson has been so kind as to supply me with
a patch that will be part of the 2.5.4 release; I'm including it below
in case someone has installed flex 2.5.3 and doesn't want to go
back to 2.5.2...
Regards,
Ernst
---
*** flex-2.5.3/flex.skl Sat May 25 21:02:33 1996
--- flex.skl Tue Jul 2 16:35:49 1996
***************
*** 1,7 ****
/* A lexical scanner generated by flex */
/* Scanner skeleton version:
! * $Header: /cvsroot/pgsql/doc/Attic/README.flex,v 1.1.1.1 1996/08/18 22:14:17 scrappy Exp $
*/
#define FLEX_SCANNER
--- 1,7 ----
/* A lexical scanner generated by flex */
/* Scanner skeleton version:
! * $Header: /cvsroot/pgsql/doc/Attic/README.flex,v 1.1.1.1 1996/08/18 22:14:17 scrappy Exp $
*/
#define FLEX_SCANNER
***************
*** 783,789 ****
/* don't do the read, it's not guaranteed to return an EOF,
* just force an EOF
*/
! yy_n_chars = 0;
else
{
--- 783,789 ----
/* don't do the read, it's not guaranteed to return an EOF,
* just force an EOF
*/
! yy_current_buffer->yy_n_chars = yy_n_chars = 0;
else
{
***************
*** 838,843 ****
--- 838,845 ----
/* Read in more data. */
YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
yy_n_chars, num_to_read );
+
+ yy_current_buffer->yy_n_chars = yy_n_chars;
}
if ( yy_n_chars == 0 )
***************
*** 947,953 ****
yy_cp += (int) (dest - source);
yy_bp += (int) (dest - source);
! yy_n_chars = yy_current_buffer->yy_buf_size;
if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
YY_FATAL_ERROR( "flex scanner push-back overflow" );
--- 949,956 ----
yy_cp += (int) (dest - source);
yy_bp += (int) (dest - source);
! yy_current_buffer->yy_n_chars =
! yy_n_chars = yy_current_buffer->yy_buf_size;
if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
YY_FATAL_ERROR( "flex scanner push-back overflow" );
***************
*** 997,1009 ****
switch ( yy_get_next_buffer() )
{
case EOB_ACT_END_OF_FILE:
{
if ( yywrap() )
- {
- yy_c_buf_p = yytext_ptr + offset;
return EOF;
- }
if ( ! yy_did_buffer_switch_on_eof )
YY_NEW_FILE;
--- 1000,1025 ----
switch ( yy_get_next_buffer() )
{
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin );
+
+ /* fall through */
+
case EOB_ACT_END_OF_FILE:
{
if ( yywrap() )
return EOF;
if ( ! yy_did_buffer_switch_on_eof )
YY_NEW_FILE;
***************
*** 1017,1031 ****
case EOB_ACT_CONTINUE_SCAN:
yy_c_buf_p = yytext_ptr + offset;
break;
-
- case EOB_ACT_LAST_MATCH:
- #ifdef __cplusplus
- YY_FATAL_ERROR(
- "unexpected last match in yyinput()" );
- #else
- YY_FATAL_ERROR(
- "unexpected last match in input()" );
- #endif
}
}
}
--- 1033,1038 ----
In order to co-ordinate both usage and development of Postgres95,
there are currently two mailing lists available:
General Discussion
- mainly geared towards usage of PostGres95 and associated
support & third-party software
- send a message of subscribe to postgres95-request@postgres95.vnet.net
- a digest version of this list is available. To subscribe, send
a message of subscribe to:
postgres95-digest-request@postgres95.vnet.net
- archives and back issues of these lists are stored on:
ftp://postgres95.vnet.net/pub/postgres95/archives
ftp://postgres95.vnet.net/pub/postgres95/digests
Developers Mailling List
- those wishing to help improve Postgres95 and further develop it
- send a message of subscribe to pg95-dev-request@ki.net
WWW: http://www.ki.net/postgres95
FTP: ftp://ftp.ki.net/pub/postgres95
The current source tree, with all patches installed, is available
via sup @ sup.ki.net, or in a .tar.gz file available at:
ftp://ftp.ki.net/pub/postgres95
From scrappy@ki.net Thu Aug 1 13:39:58 1996
Status: RO
X-Status:
Received: from daemun.ilt.com ([204.247.102.21]) by ki.net (8.7.5/8.7.5) with ESMTP id NAA16984 for <scrappy@ki.net>; Thu, 1 Aug 1996 13:39:51 -0400 (EDT)
From: postgres@madmax.ilt.com
Received: from madmax.ilt.com (madmax [199.26.203.43]) by daemun.ilt.com (8.7.5/8.7.3) with SMTP id KAA02799 for <scrappy@ki.net>; Thu, 1 Aug 1996 10:39:31 -0700 (PDT)
Received: by madmax.ilt.com (SMI-8.6/ILT-SVR4-1.1)
id KAA19226; Thu, 1 Aug 1996 10:34:46 -0700
Date: Thu, 1 Aug 1996 10:34:46 -0700
Message-Id: <199608011734.KAA19226@madmax.ilt.com>
To: scrappy@ki.net
Subject: RELEASE.patchlevel
## Postgres95
##
## This file is used to maintain sequencing of patches
version: 1.02
patch level: 0
patch date: Thu Aug 1 18:00:00 EDT 1996
From scrappy@ki.net Tue Aug 6 19:57:11 1996
Status: RO
X-Status:
Received: from candle.pha.pa.us (maillist@s1-03.ppp.op.net [206.84.209.132]) by quagmire.ki.net (8.7.5/8.7.5) with ESMTP id TAA01576 for <scrappy@ki.net>; Tue, 6 Aug 1996 19:57:08 -0400 (EDT)
Received: (from maillist@localhost) by candle.pha.pa.us (8.7.4/8.7.3) id TAA11618 for scrappy@ki.net; Tue, 6 Aug 1996 19:57:37 -0400 (EDT)
From: Bruce Momjian <maillist@candle.pha.pa.us>
Message-Id: <199608062357.TAA11618@candle.pha.pa.us>
Subject: add TODO to distribution
To: scrappy@ki.net (Marc G. Fournier)
Date: Tue, 6 Aug 1996 19:57:36 -0400 (EDT)
X-Mailer: ELM [version 2.4 PL25]
MIME-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Here is the current TODO list. Let's add it to the next distribution.
This was not ready at the time of the 1.02 release.
---------------------------------------------------------------------------
=================================================
TODO list (FAQ) for Postgres95
==================================================
last updated: Mon Aug 5 21:00:12 EDT 1996
current maintainer: Bruce Momjian (maillist@candle.pha.pa.us)
original author: Jolly Chen (jolly@cs.berkeley.edu)
RELIABILITY
-----------
Overhaul mdmgr/smgr to fix double unlinking and double opens, cleanup
Memory leaks (hunt and destroy with tools like Purify)
fix unitialized reads of memory
fix array over-runs of memory writes
Re-visit and fix vacuum
can't vacuum large objects
can't shrink tables, pg_time and pg_log
Fix all NULL features
DROP AGGREGATE should take in basetype as an arg
Add other language types for built-in functions
expand to allow tcl, perl, java,
generalize the function manager switch to pass
function sources to interpreter engines.
Fix large object mapping scheme
not to stuff everything as files in a single directory
Fix CLUSTER
Prevent improper index creation
Starting quote in insert string errors
Change default decimal constant representation from float4 to float8
ALTER TABLE bug - running postgress process needs to re-read table definition
Allow libpq to distinguish between text value '' and null
Allow non-postgres users with createdb privs to destroydb's
PERFORMANCE
-----------
Optimizing disjunctive queries
Other optimizer bugs
Is fsync use optimized?
Multi-representational types, a la Illustra. For example, have a
text type that is stored in-tuple when less than 8K and in large
objects, when greater than 8K.
ENHANCEMENTS
------------
Add full ANSI SQL capabilities ( a vendor has offered to help)
add subselects
column constraints (using rules), esp. primary keys
add DEFAULT, UNIQUE, RESTRAINT, and CHECK capabilities
report "Not implemented" if valid syntax is supplied
add OUTER joins
make VIEWs updateable where possible
add UNIONS, INTERSECTS, SUBTRACTS
add temporary tables
add assertions
add domains
add sql3 recursive unions
add the concept of dataspaces
Implement HAVING clause
Implement IN qualifier
Add a way to preserve oid's when doing dump and load
if not, make oid's accessable in insert rules
Add word index for text fields, maybe with trigrams, i.e.:
' (cat | dog) & ! fox ' meaning text has cat or dog, but not fox
Allow compression of large fields or a compressed field type
Fix the rules system
robust
making INSTEAD rules work
Full set of text operations and functions
word searches, concat, upper/lower(), max() on text, char
Replace table-level locking with row or page-level locking
Large objects
overwriting blocks has problems
there are other problems, too.
Better interface for adding to pg_group
Make multi-field indexes easier to create
allow optimizer to effectively use parameters without accessing table
Improve debugging output
Add int8 type
Add table comments
Add support for tables >2G
Incorporate the PERL PG95 interface library into source tree
Threaded version of the server or libpq
Add REGEX internationalization
DOCUMENTATION
-------------
Better documentation. Write a real book on postgres, perhaps?
Document OPENLINK fsync patch
Update usermanual source
Reduce size of regression diffs
PORTABILITY
-----------
Windows NT port
Mariposa project at Berkeley has a person who's working on this
Binary distributions for linux
Merge bsdi_2_1 to bsdi
Merge i386_solaris and sparc_solaris into solaris
To report a bug, please complete the following form and send it by
email to pg95-dev@ki.net
============================================================================
POSTGRES95 BUG REPORT TEMPLATE
============================================================================
Your name :
Your email address :
System Configuration
---------------------
Architecture (example: Intel Pentium) :
Operating System (example: Linux 1.3.42 ELF) :
Postgres95 version (example: Postgres95-1.01) : Postgres95-1.02
Compiler used (example: gcc 2.7.0) :
Please enter a FULL description of your problem:
------------------------------------------------
Please describe a way to repeat the problem. Please try to provide a
concise reproducible example, if at all possible:
----------------------------------------------------------------------
If you know how this problem might be fixed, list the solution below:
---------------------------------------------------------------------
pgtcl is a tcl package for front-end programs to interface with Postgres95
backends. PgTcl does not use the libpq library but communicates to
the backend directly via the frontend-backend protocol. Thus, it is
more efficient than previous postgres->tcl bindings which are layered
on top of libpq. In addition, pgtcl can handle multiple backend
connections from a single frontend application.
If you have any questions or bug reports, please send them to
Jolly Chen at jolly@cs.berkeley.edu.
-------------------------------------------------------------------
The pgtcl package provides the following commands.
pg_connect - opens a connection to the backend server
pg_disconnect - closes a connection
pg_exec - send a query to the backend
pg_result - manipulate the results of a query
pg_lo_creat - create a large object
pg_lo_open - open a large object
pg_lo_close - close a large object
pg_lo_read - read a large object
pg_lo_write - write a large object
pg_lo_lseek - seek to a position on a large object
pg_lo_tell - return the current seek position of a large object
pg_lo_unlink - delete a large object
pg_lo_import - import a Unix file into a large object
pg_lo_export - export a large object into a Unix file
1) pg_connect: opens a connection to the backend
syntax:
pg_connect dbName [-host hostName] [-port portNumber] [-tty pqtty] [-options optionalBackendArgs]]
the return result is either an error message or a handle for a database
connection. Handles start with the prefix "pgp"
2) pg_disconnect: closes a connection
syntax:
pg_disconnect connection
The argument passed in must be a connection pointer.
3) pg_exec: send a query string to the backend
syntax:
pg_exec connection query
the return result is either an error message or a handle for a query
result. Handles start with the prefix "pgp"
4) pg_result: get information about a query result
syntax:
pg_result result ?option?
the options are:
-status
the status of the result
-oid
if the last query was an insert, returns the oid of the
inserted tuple
-conn
the connection that produced the result
-assign arrayName
assign the results to an array
-numTuples
the number of tuples in the query
-attributes
returns a list of the name/type pairs of the tuple attributes
-getTuple tupleNumber
returns the values of the tuple in a list
-clear
clear the result buffer. Do not reuse after this
----------------------------------------------------------------------------
The pg_lo* routines are interfaces to the Inversion large objects in postgres.
The functions are designed to mimic the analogous file system functions in
the standard Unix file system interface.
The pg_lo* routines should typically be used within a BEGIN/END transaction
block becaus the file descriptor returned by pg_lo_open is only valid for
the current transaction. pg_lo_import and pg_lo_export MUST be used
in a BEGIN/END transaction block.
* pg_lo_creat: create a large object
syntax:
g_lo_creat conn mode
mode can be any OR'ing together of INV_READ, INV_WRITE, and INV_ARCHIVE.
The OR delimiter character is "|".
e.g. [pg_lo_creat $conn "INV_READ|INV_WRITE"]
returns the oid of the large object created.
* pg_lo_open: open a large object
syntax:
pg_lo_open conn objOid mode
where mode can be either "r", "w", or "rw"
returns a file descriptor for use in later pg_lo* routines
* pg_lo_close: close a large object
syntax:
pg_lo_close conn fd
* pg_lo_read: read a large object
syntax:
pg_lo_read conn fd bufVar len
reads at most len bytes from a large object into a variable named bufVar.
Note that the third argument should be a variable name.
* pg_lo_write: write a large object
syntax:
pg_lo_write conn fd buf len
write at most len bytes to a large object.
The third argument should be the actual string to write, not a variable name.
* pg_lo_lseek: seek to a position on a large object
syntax:
pg_lo_lseek conn fd offset whence
whence can be "SEEK_CUR", "SEEK_END", or "SEEK_SET"
* pg_lo_tell: return the current seek position of a large object
syntax:
pg_lo_tell conn fd
* pg_lo_unlink: delete a large object
syntax:
pg_lo_unlink conn lobjId
* pg_lo_import: import a Unix file into a large object
syntax:
pg_lo_import conn filename
pg_lo_import must be called within a BEGIN/END transaction block
* pg_lo_export: export a large object into a Unix file
syntax:
pg_lo_export conn lobjId filename
pg_lo_export must be called within a BEGIN/END transaction block
------------------------------------------------------------------
Here's a small example of how to use the routines:
# getDBs :
# get the names of all the databases at a given host and port number
# with the defaults being the localhost and port 5432
# return them in alphabetical order
proc getDBs { {host "localhost"} {port "5432"} } {
# datnames is the list to be result
set conn [pg_connect template1 -host $host -port $port]
set res [pg_exec $conn "SELECT datname FROM pg_database ORDER BY datname"]
set ntups [pg_result $res -numTuples]
for {set i 0} {$i < $ntups} {incr i} {
lappend datnames [pg_result $res -getTuple $i]
}
pg_disconnect $conn
return $datnames
}
The page.5 source should be run through pic when generating troff
output. nroff doesn't handle pic.
.\" This is -*-nroff-*-
.\" XXX standard disclaimer belongs here....
.\" $Header: /cvsroot/pgsql/doc/man/Attic/abort.l,v 1.1.1.1 1996/08/18 22:14:19 scrappy Exp $
.TH ABORT SQL 01/23/93 Postgres95 Postgres95
.\" XXX This .XA has to go after the .TH so that the index page number goes
.\" in the right place...
.SH Abort
.SH NAME
abort \(em abort the current transaction
.SH SYNOPSIS
.nf
\fBabort\fP \fB[transaction]\fR
.fi
.SH DESCRIPTION
This command aborts the current transaction and causes all the
updates made by the transaction to be discarded.
.IR "abort"
is functionally equivalent to
.IR "rollback".
.SH "SEE ALSO"
begin(l),
end(l),
rollback(l).
.\" This is -*-nroff-*-
.\" XXX standard disclaimer belongs here....
.\" $Header: /cvsroot/pgsql/doc/man/Attic/alter_table.l,v 1.1.1.1 1996/08/18 22:14:19 scrappy Exp $
.TH "ALTER TABLE" SQL 11/5/95 Postgres95 Postgres95
.SH NAME
alter table \(em add attributes to a class
.SH SYNOPSIS
.nf
\fBalter table\fR classname [*]
\fBadd column\fR attname type
.fi
.SH DESCRIPTION
The
.BR "alter table"
command
causes a new attribute to be added to an existing class,
.IR classname .
The new attributes and their types are specified
in the same style and with the the same restrictions as in
.IR create table (l).
.PP
In order to add an attribute to each class in an entire inheritance
hierarchy, use the
.IR classname
of the superclass and append a \*(lq*\*(rq. (By default, the
attribute will not be added to any of the subclasses.) This should
.BR always
be done when adding an attribute to a superclass. If it is not,
queries on the inheritance hierarchy such as
.nf
select * from super* s
.fi
will not work because the subclasses will be missing an attribute
found in the superclass.
.PP
For efficiency reasons, default values for added attributes are not
placed in existing instances of a class. That is, existing instances
will have NULL values in the new attributes. If non-NULL values are
desired, a subsequent
.IR update (l)
query should be run.
.PP
You must own the class in order to change its schema.
.SH EXAMPLE
.nf
--
-- add the date of hire to the emp class
--
alter table emp add column hiredate abstime
.fi
.nf
--
-- add a health-care number to all persons
-- (including employees, students, ...)
--
alter table person * add column health_care_id int4
.fi
.SH "SEE ALSO"
create table (l),
update (l).
.\" This is -*-nroff-*-
.\" XXX standard disclaimer belongs here....
.\" $Header: /cvsroot/pgsql/doc/man/Attic/begin.l,v 1.1.1.1 1996/08/18 22:14:20 scrappy Exp $
.TH BEGIN SQL 11/05/95 Postgres95 Postgres95
.SH NAME
begin \(em begins a transaction
.SH SYNOPSIS
.nf
\fBbegin\fP \fB[transaction|work]\fR
.fi
.SH DESCRIPTION
This command begins a user transaction which Postgres will guarantee is
serializable with respect to all concurrently executing transactions.
Postgres uses two-phase locking to perform this task. If the transaction
is committed, Postgres will ensure that all updates are done or none of
them are done. Transactions have the standard ACID (atomic,
consistent, isolatable, and durable) property.
.SH "SEE ALSO"
abort(l),
end(l).
.\" This is -*-nroff-*-
.\" XXX standard disclaimer belongs here....
.\" $Header: /cvsroot/pgsql/doc/man/Attic/bki.5,v 1.1.1.1 1996/08/18 22:14:20 scrappy Exp $
.TH BKI FILES 01/23/93 Postgres95 Postgres95
.SH NAME
\&.../src/backend/obj/{local,dbdb}.bki \(em template scripts
.SH DESCRIPTION
Backend Interface (BKI) files are scripts that describe the contents
of the initial Postgres database. This database is constructed during
system installation, by the
.IR initdb
command.
.IR Initdb
executes the Postgres backend with a special set of flags, that cause it
to consume the BKI scripts and bootstrap a database.
.PP
These files are automatically generated from system header files
during installation. They are not intended for use by humans, and you
do not need to understand their contents in order to use Postgres. These
files are copied to
.nf
\&.../files/{global1,local1_XXX}.bki
.fi
during system installation.
.PP
All new user databases will be created by copying the template
database that Postgres constructs from the BKI files. Thus, a simple way
to customize the template database is to let the Postgres initialization
script create it for you, and then to run the terminal monitor to make
the changes you want.
.PP
The Postgres backend interprets BKI files as described below. This
description will be easier to understand if the example in
\*(lq.../files/global1.bki\*(rq is at hand.
.PP
Commands are composed of a command name followed by space separated
arguments. Arguments to a command which begin with a \*(lq$\*(rq are
treated specially. If \*(lq$$\*(rq are the first two characters, then
the first \*(lq$\*(rq is ignored and the argument is then processed
normally. If the \*(lq$\*(rq is followed by space, then it is treated
as a
.SM NULL
value. Otherwise, the characters following the \*(lq$\*(rq are
interpreted as the name of a macro causing the argument to be replaced
with the macro's value. It is an error for this macro to be
undefined.
.PP
Macros are defined using
.nf
define macro macro_name = macro_value
.fi
and are undefined using
.nf
undefine macro macro_name
.fi
and redefined using the same syntax as define.
.PP
Lists of general commands and macro commands
follow.
.SH "GENERAL COMMANDS"
.TP 5n
.BR "open" " classname"
Open the class called
.IR classname
for further manipulation.
.TP
.BR "close" " [classname]"
Close the open class called
.IR classname.
It is an error if
.IR classname
is not already opened. If no
.IR classname
is given, then the currently open class is closed.
.TP
.BR print
Print the currently open class.
.TP
.BR "insert" " [oid=oid_value] " "(" " value1 value2 ... " ")"
Insert a new instance to the open class using
.IR value1 ,
.IR value2 ,
etc., for its attribute values and
.IR oid_value
for its OID. If
.IR oid_value
is not \*(lq0\*(rq, then this value will be used as the instance's
object identifier. Otherwise, it is an error.
.TP
.BR "insert (" " value1 value2 ... " ")"
As above, but the system generates a unique object identifier.
.TP
.BR "create" " classname " "(" " name1 = type1, name2 = type2, ... " ")"
Create a class named
.IR classname
with the attributes given in parentheses.
.TP
.BR "open (" " name1 = type1, name2 = type2,... " ") as" " classname"
Open a class named
.IR classname
for writing but do not record its existence in the system catalogs.
(This is primarily to aid in bootstrapping.)
.TP
.BR "destroy" " classname"
Destroy the class named
.IR classname .
.TP
.BR "define index" " index-name " "on" " class-name " "using" " amname "
( opclass attr | function({attr}) )
.br
Create an index named
.IR index_name
on the class named
.IR classname
using the
.IR amname
access method. The fields to index are called
.IR name1 ,
.IR name2 ,
etc., and the operator collections to use are
.IR collection_1 ,
.IR collection_2 ,
etc., respectively.
.SH "MACRO COMMANDS"
.TP
.BR "define function" " macro_name " "as" " rettype function_name ( args )"
Define a function prototype for a function named
.IR macro_name
which has its value of type
.IR rettype
computed from the execution
.IR function_name
with the arguments
.IR args
declared in a C-like manner.
.TP
.BR "define macro" " macro_name " "from file" " filename"
Define a macro named
.IR macname
which has its value
read from the file called
.IR filename .
.\" .uh "DEBUGGING COMMANDS"
.\" .sp
.\" .in .5i
.\" r
.\" .br
.\" Randomly print the open class.
.\" .sp
.\" m -1
.\" .br
.\" Toggle display of time information.
.\" .sp
.\" m 0
.\" .br
.\" Set retrievals to now.
.\" .sp
.\" m 1 Jan 1 01:00:00 1988
.\" .br
.\" Set retrievals to snapshots of the specfied time.
.\" .sp
.\" m 2 Jan 1 01:00:00 1988, Feb 1 01:00:00 1988
.\" .br
.\" Set retrievals to ranges of the specified times.
.\" Either time may be replaced with space
.\" if an unbounded time range is desired.
.\" .sp
.\" \&.A classname natts name1 type1 name2 type2 ...
.\" .br
.\" Add attributes named
.\" .ul
.\" name1,
.\" .ul
.\" name2,
.\" etc. of
.\" types
.\" .ul
.\" type1,
.\" .ul
.\" type2,
.\" etc. to the
.\" .ul
.\" class
.\" classname.
.\" .sp
.\" \&.RR oldclassname newclassname
.\" .br
.\" Rename the
.\" .ul
.\" oldclassname
.\" class to
.\" .ul
.\" newclassname.
.\" .sp
.\" \&.RA classname oldattname newattname
.\" .br
.\" Rename the
.\" .ul
.\" oldattname
.\" attribute in the class named
.\" .ul
.\" classname
.\" to
.\" .ul
.\" newattname.
.SH EXAMPLE
The following set of commands will create the \*(lqpg_opclass\*(rq
class containing the
.IR int_ops
collection as object
.IR 421,
print out the class, and then close it.
.nf
create pg_opclass (opcname=char16)
open pg_opclass
insert oid=421 (int_ops)
print
close pg_opclass
.fi
.SH "SEE ALSO"
initdb(1),
createdb(1),
createdb(l),
template(files).
This diff is collapsed.
This diff is collapsed.
.\" This is -*-nroff-*-
.\" XXX standard disclaimer belongs here....
.\" $Header: /cvsroot/pgsql/doc/man/Attic/cleardbdir.1,v 1.1.1.1 1996/08/18 22:14:20 scrappy Exp $
.TH CLEARDBDIR UNIX 11/05/95 Postgres95 Postgres95
.SH NAME
cleardbdir \(em completely destroys all database files
.SH SYNOPSIS
.BR "cleardbdir"
.SH DESCRIPTION
.IR cleardbdir
destroys all the database files. It is used only by the
Postgres super-user
before re-initializing the entire installation for a particular site. Normal
database users should never use this command.
.PP
The
Postgres super-user
should ensure the
.IR postmaster
process is not running before running cleardbdir.
.SH "SEE ALSO"
initdb(1)
.\" This is -*-nroff-*-
.\" XXX standard disclaimer belongs here....
.\" $Header: /cvsroot/pgsql/doc/man/Attic/close.l,v 1.1.1.1 1996/08/18 22:14:20 scrappy Exp $
.TH CLOSE SQL 11/05/95 Postgres95 Postgres95
.SH NAME
close \(em close a cursor
.SH SYNOPSIS
.nf
\fBclose\fP [cursor_name]
.fi
.SH DESCRIPTION
.BR Close
frees the resources associated with a cursor,
.IR cursor_name.
After this cursor is closed, no subsequent operations are allowed on
it. A cursor should be closed when it is no longer needed. If
.IR cursor_name.
is not specified, then the blank cursor is closed.
.SH EXAMPLE
.nf
/*
* close the cursor FOO
*/
close FOO
.fi
.SH "SEE ALSO"
fetch(l),
select(l).
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment