⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pg_backup_archiver.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 4 页
字号:
	ArchiveHandle *AH = (ArchiveHandle *) AHX;	if (!AH->StartBlobPtr)		die_horribly(AH, modulename, "large-object output not supported in chosen format\n");	(*AH->StartBlobPtr) (AH, AH->currToc, oid);	return 1;}/* Called by a dumper to signal end of a BLOB */intEndBlob(Archive *AHX, Oid oid){	ArchiveHandle *AH = (ArchiveHandle *) AHX;	if (AH->EndBlobPtr)		(*AH->EndBlobPtr) (AH, AH->currToc, oid);	return 1;}/********** * BLOB Restoration **********//* * Called by a format handler before any blobs are restored */voidStartRestoreBlobs(ArchiveHandle *AH){	AH->blobCount = 0;}/* * Called by a format handler after all blobs are restored */voidEndRestoreBlobs(ArchiveHandle *AH){	if (AH->txActive)	{		ahlog(AH, 2, "committing large-object transactions\n");		CommitTransaction(AH);	}	if (AH->blobTxActive)		CommitTransactionXref(AH);	ahlog(AH, 1, "restored %d large objects\n", AH->blobCount);}/* * Called by a format handler to initiate restoration of a blob */voidStartRestoreBlob(ArchiveHandle *AH, Oid oid){	Oid			loOid;	AH->blobCount++;	if (!AH->createdBlobXref)	{		if (!AH->connection)			die_horribly(AH, modulename, "cannot restore large objects without a database connection\n");		CreateBlobXrefTable(AH);		AH->createdBlobXref = 1;	}	/* Initialize the LO Buffer */	AH->lo_buf_used = 0;	/*	 * Start long-running TXs if necessary	 */	if (!AH->txActive)	{		ahlog(AH, 2, "starting large-object transactions\n");		StartTransaction(AH);	}	if (!AH->blobTxActive)		StartTransactionXref(AH);	loOid = lo_creat(AH->connection, INV_READ | INV_WRITE);	if (loOid == 0)		die_horribly(AH, modulename, "could not create large object\n");	ahlog(AH, 2, "restoring large object with OID %u as %u\n", oid, loOid);	InsertBlobXref(AH, oid, loOid);	AH->loFd = lo_open(AH->connection, loOid, INV_WRITE);	if (AH->loFd == -1)		die_horribly(AH, modulename, "could not open large object\n");	AH->writingBlob = 1;}voidEndRestoreBlob(ArchiveHandle *AH, Oid oid){	if (AH->lo_buf_used > 0)	{		/* Write remaining bytes from the LO buffer */		size_t		res;		res = lo_write(AH->connection, AH->loFd, (void *) AH->lo_buf, AH->lo_buf_used);		ahlog(AH, 5, "wrote remaining %lu bytes of large-object data (result = %lu)\n",			  (unsigned long) AH->lo_buf_used, (unsigned long) res);		if (res != AH->lo_buf_used)			die_horribly(AH, modulename, "could not write to large object (result: %lu, expected: %lu)\n",				   (unsigned long) res, (unsigned long) AH->lo_buf_used);		AH->lo_buf_used = 0;	}	lo_close(AH->connection, AH->loFd);	AH->writingBlob = 0;	/*	 * Commit every BLOB_BATCH_SIZE blobs...	 */	if (((AH->blobCount / BLOB_BATCH_SIZE) * BLOB_BATCH_SIZE) == AH->blobCount)	{		ahlog(AH, 2, "committing large-object transactions\n");		CommitTransaction(AH);		CommitTransactionXref(AH);	}}/*********** * Sorting and Reordering ***********//* * Move TOC entries of the specified type to the START of the TOC. * * This is public, but if you use it anywhere but SortTocByObjectType, * you are risking breaking things. */voidMoveToStart(Archive *AHX, const char *oType){	ArchiveHandle *AH = (ArchiveHandle *) AHX;	TocEntry   *te = AH->toc->next;	TocEntry   *newTe;	while (te != AH->toc)	{		te->_moved = 0;		te = te->next;	}	te = AH->toc->prev;	while (te != AH->toc && !te->_moved)	{		newTe = te->prev;		if (strcmp(te->desc, oType) == 0)			_moveAfter(AH, AH->toc, te);		te = newTe;	}}/* * Move TOC entries of the specified type to the end of the TOC. * * This is public, but if you use it anywhere but SortTocByObjectType, * you are risking breaking things. */voidMoveToEnd(Archive *AHX, const char *oType){	ArchiveHandle *AH = (ArchiveHandle *) AHX;	TocEntry   *te = AH->toc->next;	TocEntry   *newTe;	while (te != AH->toc)	{		te->_moved = 0;		te = te->next;	}	te = AH->toc->next;	while (te != AH->toc && !te->_moved)	{		newTe = te->next;		if (strcmp(te->desc, oType) == 0)			_moveBefore(AH, AH->toc, te);		te = newTe;	}}/* * Sort TOC by object type (items of same type keep same relative order) * * This is factored out to ensure that pg_dump and pg_restore stay in sync * about the standard ordering. */voidSortTocByObjectType(Archive *AH){	/*	 * Procedural languages have to be declared just after database and	 * schema creation, before they are used.	 */	MoveToStart(AH, "ACL LANGUAGE");	MoveToStart(AH, "PROCEDURAL LANGUAGE");	MoveToStart(AH, "FUNC PROCEDURAL LANGUAGE");	MoveToStart(AH, "SCHEMA");	MoveToStart(AH, "<Init>");	/* Database entries *must* be at front (see also pg_restore.c) */	MoveToStart(AH, "DATABASE");	MoveToEnd(AH, "TABLE DATA");	MoveToEnd(AH, "BLOBS");	MoveToEnd(AH, "INDEX");	MoveToEnd(AH, "CONSTRAINT");	MoveToEnd(AH, "FK CONSTRAINT");	MoveToEnd(AH, "TRIGGER");	MoveToEnd(AH, "RULE");	MoveToEnd(AH, "SEQUENCE SET");	/*	 * Moving all comments to end is annoying, but must do it for comments	 * on stuff we just moved, and we don't seem to have quite enough	 * dependency structure to get it really right...	 */	MoveToEnd(AH, "COMMENT");}/* * Sort TOC by OID *//* Public */voidSortTocByOID(Archive *AHX){	ArchiveHandle *AH = (ArchiveHandle *) AHX;	_SortToc(AH, _tocSortCompareByOIDNum);}/* * Sort TOC by ID *//* Public */voidSortTocByID(Archive *AHX){	ArchiveHandle *AH = (ArchiveHandle *) AHX;	_SortToc(AH, _tocSortCompareByIDNum);}voidSortTocFromFile(Archive *AHX, RestoreOptions *ropt){	ArchiveHandle *AH = (ArchiveHandle *) AHX;	FILE	   *fh;	char		buf[1024];	char	   *cmnt;	char	   *endptr;	int			id;	TocEntry   *te;	TocEntry   *tePrev;	int			i;	/* Allocate space for the 'wanted' array, and init it */	ropt->idWanted = (int *) malloc(sizeof(int) * AH->tocCount);	for (i = 0; i < AH->tocCount; i++)		ropt->idWanted[i] = 0;	ropt->limitToList = 1;	/* Mark all entries as 'not moved' */	te = AH->toc->next;	while (te != AH->toc)	{		te->_moved = 0;		te = te->next;	}	/* Set prev entry as head of list */	tePrev = AH->toc;	/* Setup the file */	fh = fopen(ropt->tocFile, PG_BINARY_R);	if (!fh)		die_horribly(AH, modulename, "could not open TOC file\n");	while (fgets(buf, 1024, fh) != NULL)	{		/* Find a comment */		cmnt = strchr(buf, ';');		if (cmnt == buf)			continue;		/* End string at comment */		if (cmnt != NULL)			cmnt[0] = '\0';		/* Skip if all spaces */		if (strspn(buf, " \t") == strlen(buf))			continue;		/* Get an ID */		id = strtol(buf, &endptr, 10);		if (endptr == buf)		{			write_msg(modulename, "WARNING: line ignored: %s\n", buf);			continue;		}		/* Find TOC entry */		te = _getTocEntry(AH, id);		if (!te)			die_horribly(AH, modulename, "could not find entry for ID %d\n", id);		ropt->idWanted[id - 1] = 1;		_moveAfter(AH, tePrev, te);		tePrev = te;	}	if (fclose(fh) != 0)		die_horribly(AH, modulename, "could not close TOC file: %s\n", strerror(errno));}/********************** * 'Convenience functions that look like standard IO functions * for writing data when in dump mode. **********************//* Public */intarchputs(const char *s, Archive *AH){	return WriteData(AH, s, strlen(s));}/* Public */intarchputc(const char c, Archive *AH){	return WriteData(AH, &c, 1);}/* Public */intarchprintf(Archive *AH, const char *fmt,...){	char	   *p = NULL;	va_list		ap;	int			bSize = strlen(fmt) + 256;	int			cnt = -1;	/*	 * This is paranoid: deal with the possibility that vsnprintf is	 * willing to ignore trailing null	 */	/*	 * or returns > 0 even if string does not fit. It may be the case that	 * it returns cnt = bufsize	 */	while (cnt < 0 || cnt >= (bSize - 1))	{		if (p != NULL)			free(p);		bSize *= 2;		p = (char *) malloc(bSize);		if (p == NULL)			exit_horribly(AH, modulename, "out of memory\n");		va_start(ap, fmt);		cnt = vsnprintf(p, bSize, fmt, ap);		va_end(ap);	}	WriteData(AH, p, cnt);	free(p);	return cnt;}/******************************* * Stuff below here should be 'private' to the archiver routines *******************************/OutputContextSetOutput(ArchiveHandle *AH, char *filename, int compression){	OutputContext sav;	int			fn;	/* Replace the AH output file handle */	sav.OF = AH->OF;	sav.gzOut = AH->gzOut;	if (filename)		fn = -1;	else if (AH->FH)		fn = fileno(AH->FH);	else if (AH->fSpec)	{		fn = -1;		filename = AH->fSpec;	}	else		fn = fileno(stdout);	/* If compression explicitly requested, use gzopen */#ifdef HAVE_LIBZ	if (compression != 0)	{		char		fmode[10];		/* Don't use PG_BINARY_x since this is zlib */		sprintf(fmode, "wb%d", compression);		if (fn >= 0)			AH->OF = gzdopen(dup(fn), fmode);		else			AH->OF = gzopen(filename, fmode);		AH->gzOut = 1;	}	else#endif	{							/* Use fopen */		if (fn >= 0)			AH->OF = fdopen(dup(fn), PG_BINARY_W);		else			AH->OF = fopen(filename, PG_BINARY_W);		AH->gzOut = 0;	}	if (!AH->OF)		die_horribly(AH, modulename, "could not open output file: %s\n", strerror(errno));	return sav;}voidResetOutput(ArchiveHandle *AH, OutputContext sav){	int			res;	if (AH->gzOut)		res = GZCLOSE(AH->OF);	else		res = fclose(AH->OF);	if (res != 0)		die_horribly(AH, modulename, "could not close output file: %s\n",					 strerror(errno));	AH->gzOut = sav.gzOut;	AH->OF = sav.OF;}/* *	Print formatted text to the output file (usually stdout). */intahprintf(ArchiveHandle *AH, const char *fmt,...){	char	   *p = NULL;	va_list		ap;	int			bSize = strlen(fmt) + 256;		/* Should be enough */	int			cnt = -1;	/*	 * This is paranoid: deal with the possibility that vsnprintf is	 * willing to ignore trailing null	 */	/*	 * or returns > 0 even if string does not fit. It may be the case that	 * it returns cnt = bufsize	 */	while (cnt < 0 || cnt >= (bSize - 1))	{		if (p != NULL)			free(p);		bSize *= 2;		p = (char *) malloc(bSize);		if (p == NULL)			die_horribly(AH, modulename, "out of memory\n");		va_start(ap, fmt);		cnt = vsnprintf(p, bSize, fmt, ap);		va_end(ap);	}	ahwrite(p, 1, cnt, AH);	free(p);	return cnt;}voidahlog(ArchiveHandle *AH, int level, const char *fmt,...){	va_list		ap;	if (AH->debugLevel < level && (!AH->public.verbose || level > 1))		return;	va_start(ap, fmt);	_write_msg(NULL, fmt, ap);	va_end(ap);}/* * Single place for logic which says 'We are restoring to a direct DB connection'. */intRestoringToDB(ArchiveHandle *AH){	return (AH->ropt && AH->ropt->useDB && AH->connection);}/* *	Write buffer to the output file (usually stdout). This is user for *	outputting 'restore' scripts etc. It is even possible for an archive *	format to create a custom output routine to 'fake' a restore if it *	wants to generate a script (see TAR output). */intahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH){	size_t		res;	if (AH->writingBlob)	{		if (AH->lo_buf_used + size * nmemb > AH->lo_buf_size)		{			/* Split LO buffer */			size_t		remaining = AH->lo_buf_size - AH->lo_buf_used;			size_t		slack = nmemb * size - remaining;			memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, remaining);			res = lo_write(AH->connection, AH->loFd, AH->lo_buf, AH->lo_buf_size);			ahlog(AH, 5, "wrote %lu bytes of large object data (result = %lu)\n",				  (unsigned long) AH->lo_buf_size, (unsigned long) res);			if (res != AH->lo_buf_size)				die_horribly(AH, modulename,							 "could not write to large object (result: %lu, expected: %lu)\n",				   (unsigned long) res, (unsigned long) AH->lo_buf_size);			memcpy(AH->lo_buf, (char *) ptr + remaining, slack);			AH->lo_buf_used = slack;		}		else		{			/* LO Buffer is still large enough, buffer it */			memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, size * nmemb);			AH->lo_buf_used += size * nmemb;		}		return size * nmemb;	}	else if (AH->gzOut)	{		res = GZWRITE((void *) ptr, size, nmemb, AH->OF);		if (res != (nmemb * size))			die_horribly(AH, modulename, "could not write to compressed archive\n");		return res;	}	else if (AH->CustomOutPtr)	{		res = AH->CustomOutPtr (AH, ptr, size * nmemb);		if (res != (nmemb * size))			die_horribly(AH, modulename, "could not write to custom output routine\n");		return res;	}	else	{		/*		 * If we're doing a restore, and it's direct to DB, and we're		 * connected then send it to the DB.		 */		if (RestoringToDB(AH))			return ExecuteSqlCommandBuf(AH, (void *) ptr, size * nmemb);		/* Always 1, currently */		else		{			res = fwrite((void *) ptr, size, nmemb, AH->OF);			if (res != nmemb)				die_horribly(AH, modulename, "could not write to output file (%lu != %lu)\n",							 (unsigned long) res, (unsigned long) nmemb);			return res;		}	}}/* Common exit code */static void_write_msg(const char *modulename, const char *fmt, va_list ap){	if (modulename)		fprintf(stderr, "%s: [%s] ", progname, gettext(modulename));	else		fprintf(stderr, "%s: ", progname);	vfprintf(stderr, gettext(fmt), ap);}voidwrite_msg(const char *modulename, const char *fmt,...){	va_list		ap;	va_start(ap, fmt);	_write_msg(modulename, fmt, ap);	va_end(ap);}static void_die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt, va_list ap){	_write_msg(modulename, fmt, ap);	if (AH)	{		if (AH->public.verbose)			write_msg(NULL, "*** aborted because of error\n");		if (AH->connection)			PQfinish(AH->connection);		if (AH->blobConnection)			PQfinish(AH->blobConnection);	}	exit(1);}/* External use */voidexit_horribly(Archive *AH, const char *modulename, const char *fmt,...){	va_list		ap;	va_start(ap, fmt);	_die_horribly((ArchiveHandle *) AH, modulename, fmt, ap);}/* Archiver use (just different arg declaration) */voiddie_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt,...){	va_list		ap;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -