Subject: Another mysterious postgres bug

From: [email-masked] (Wolf-D. Ihlenfeldt)
Date: Thu, 2 Sep 93 15:23:52 jst

I am running Postgres4.1 on Sparc/SunOS4.1.2.

It seems you cannot create lo directories (function p_mkdir())
and define rules (i.e. 'define rewrite rule dummyR is on delete to dummy
do instead nothing' or something more meaningful) in the same program run,
but it works fine if you submit those two requests in separate runs.

Take the following test program: (to be linked with libpq)

------------------------------------------------------------------------

#include <stdio.h>
#include <tmp/libpq-fe.h>
#include <tmp/libpq-fs.h>

void howto() {
	(void) fputs("usage: testpgm [-t] [-ppoints] [dbase]\n",stderr);
	(void) fputs("-t: encapsulate each checkpoint into a separate transation\n",stderr);
	(void) fputs("-p: specify checkpoints to be executed (default:only #1)\n",stderr);
	(void) fputs("    the checkpoint string consists of digits [0-9] selecting checkpoints.\n",stderr);
	(void) fputs("example: 'testpgm -p134 aaaargrh'\n         will run checkpoints 1,3 and 4 on database 'aaaargrh'\n",stderr);
	exit(1);
}

void begintrans()
{
	if (*PQexec("begin") == 'E') {
		(void) puts("'begin' failed.");
		exit(1);
	}
	(void) puts("begin transaction");
}

void endtrans()
{
	if (*PQexec("end") == 'E') {
		(void) puts("'end' failed.");
		exit(1);
	}
	(void) puts("end transaction");
}

int main(argc,argv)
int argc;
char **argv;
{
	char *s,*dbase = "buggy";
	static int do_chkpt[10];
	int offset,tflag,c,i,intrans=0;
	extern char *optarg;
	extern int optind;

	do_chkpt[1] = 1;
	while((c=getopt(argc,argv,"tp:"))!=-1) {
		switch(c) {
			case 't':
				tflag = 1;
				break;
			case 'p':
				do_chkpt[1] = 0;
				for(s=optarg;*s;s++) if (isdigit(*s)) do_chkpt[*s-'0'] = 1;
				break;
			default:
				howto();
		}
	}

	if (argc-optind>1) howto();

	if (argc<optind==1) dbase = argv[optind];
	PQsetdb(dbase);

	for (i=0;i<10;i++) if (do_chkpt[i]) {
		(void) printf("executing checkpoint %d\n",i);
		if (!intrans) {
			begintrans();
			intrans = 1;
		}
		switch(i) {

		case 0: /* ------------------------------------------------- */
			if (*PQexec("create dummy (i=int4)") == 'E') {
				(void) puts("'create' failed.");
				(void) PQexec("abort");
				exit(1);
			}
			if (*PQexec("define rewrite rule dummyR is on delete to dummy do instead nothing") == 'E') {
				(void) puts("'define rule' failed.");
				(void) PQexec("abort");
				exit(1);
			}
		break;

		case 1: /* ------------------------------------------------- */
			if (p_mkdir("/Test",INV_READ|INV_WRITE)) {
				(void) puts("'mkdir' failed.");
				(void) PQexec("abort");
				exit(1);
			}
		break;

		}
		if (tflag) {
			endtrans();
			intrans = 0;
		}
	}
	if (intrans) endtrans();
	(void) puts("test successful.");
	exit(0);
}
------------------------------------------------------------------------

Create a virgin database

createdb buggy

and either of the two operations alone only works fine:

testpgm -p0

or 

testpgm -p1

(i.e. create dummy table and define rule on it or create lo directory).
If the runs are repeated on the same database,
the program terminates with the expected errors (directory exists or

WARN:Sep  2 14:41:55:amcreate: dummy relation already exists
NOTICE:Sep  2 14:41:55:(transaction aborted): queries ignored until END

Perfect.

However, if you want both in one run (on a virgin database), with the command

destroydb buggy
createdb buggy

testpgm -p01

the program fails miserably with a completely incomprehensible
error message:

Error: Unexpected identifier: Cx$@o@v5(J4$@v5(J8

The same error is produced regardless whether each request is
encapsulated in separate begin-end pairs (test progam option -t)
or not. The database gets so screwed up that an attempt do remove
it (destroydb command) hangs the backend with the interesting
message:

WARN:Sep  2 14:59:12:cannot write block 1 of pg_type [buggy] blind

Most interesting, it is possible to delete the db after killing backend and
postmaster, run ipclean and restart the system.

If the order of the requests is reversed, (i.e. first create directory,
then define rule) everything is fine, until a second p_mkdir
(on another directory) is attempted. In this case, the crash
occurs in the second p_mkdir.

This test program was created while bugfighting a larger application.
In this app, half a dozen lo directories are created and some 50
Postquel instructiones executed, until finally a rule is defined. After
that, some 50 more Postquel instructions follow, which all work
fine. Eventually, it is time to create another lo directory and we have
fireworks again. Everything was ok until I included this single
rule. Grrr.

WDI