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

📄 fe-protocol2.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
				case 'P':		/* synchronous (normal) portal */					if (pqGets(&conn->workBuffer, conn))						return;					/* We pretty much ignore this message type... */					break;				case 'T':		/* row descriptions (start of query results) */					if (conn->result == NULL)					{						/* First 'T' in a query sequence */						if (getRowDescriptions(conn))							return;					}					else					{						/*						 * A new 'T' message is treated as the start of						 * another PGresult.  (It is not clear that this is						 * really possible with the current backend.) We stop						 * parsing until the application accepts the current						 * result.						 */						conn->asyncStatus = PGASYNC_READY;						return;					}					break;				case 'D':		/* ASCII data tuple */					if (conn->result != NULL)					{						/* Read another tuple of a normal query response */						if (getAnotherTuple(conn, FALSE))							return;					}					else					{						pqInternalNotice(&conn->noticeHooks,										 "server sent data (\"D\" message) without prior row description (\"T\" message)");						/* Discard the unexpected message; good idea?? */						conn->inStart = conn->inEnd;						return;					}					break;				case 'B':		/* Binary data tuple */					if (conn->result != NULL)					{						/* Read another tuple of a normal query response */						if (getAnotherTuple(conn, TRUE))							return;					}					else					{						pqInternalNotice(&conn->noticeHooks,										 "server sent binary data (\"B\" message) without prior row description (\"T\" message)");						/* Discard the unexpected message; good idea?? */						conn->inStart = conn->inEnd;						return;					}					break;				case 'G':		/* Start Copy In */					conn->asyncStatus = PGASYNC_COPY_IN;					break;				case 'H':		/* Start Copy Out */					conn->asyncStatus = PGASYNC_COPY_OUT;					break;				default:					printfPQExpBuffer(&conn->errorMessage,									  libpq_gettext(													"unexpected response from server; first received character was \"%c\"\n"),									  id);					/* build an error result holding the error message */					pqSaveErrorResult(conn);					/* Discard the unexpected message; good idea?? */					conn->inStart = conn->inEnd;					conn->asyncStatus = PGASYNC_READY;					return;			}					/* switch on protocol character */		}		/* Successfully consumed this message */		conn->inStart = conn->inCursor;	}}/* * parseInput subroutine to read a 'T' (row descriptions) message. * We build a PGresult structure containing the attribute data. * Returns: 0 if completed message, EOF if not enough data yet. * * Note that if we run out of data, we have to release the partially * constructed PGresult, and rebuild it again next time.  Fortunately, * that shouldn't happen often, since 'T' messages usually fit in a packet. */static intgetRowDescriptions(PGconn *conn){	PGresult   *result = NULL;	int			nfields;	int			i;	result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK);	if (!result)		goto failure;	/* parseInput already read the 'T' label. */	/* the next two bytes are the number of fields	*/	if (pqGetInt(&(result->numAttributes), 2, conn))		goto failure;	nfields = result->numAttributes;	/* allocate space for the attribute descriptors */	if (nfields > 0)	{		result->attDescs = (PGresAttDesc *)			pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE);		if (!result->attDescs)			goto failure;		MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc));	}	/* get type info */	for (i = 0; i < nfields; i++)	{		int			typid;		int			typlen;		int			atttypmod;		if (pqGets(&conn->workBuffer, conn) ||			pqGetInt(&typid, 4, conn) ||			pqGetInt(&typlen, 2, conn) ||			pqGetInt(&atttypmod, 4, conn))			goto failure;		/*		 * Since pqGetInt treats 2-byte integers as unsigned, we need to		 * coerce the result to signed form.		 */		typlen = (int) ((int16) typlen);		result->attDescs[i].name = pqResultStrdup(result,												  conn->workBuffer.data);		if (!result->attDescs[i].name)			goto failure;		result->attDescs[i].tableid = 0;		result->attDescs[i].columnid = 0;		result->attDescs[i].format = 0;		result->attDescs[i].typid = typid;		result->attDescs[i].typlen = typlen;		result->attDescs[i].atttypmod = atttypmod;	}	/* Success! */	conn->result = result;	return 0;failure:	if (result)		PQclear(result);	return EOF;}/* * parseInput subroutine to read a 'B' or 'D' (row data) message. * We add another tuple to the existing PGresult structure. * Returns: 0 if completed message, EOF if error or not enough data yet. * * Note that if we run out of data, we have to suspend and reprocess * the message after more data is received.  We keep a partially constructed * tuple in conn->curTuple, and avoid reallocating already-allocated storage. */static intgetAnotherTuple(PGconn *conn, bool binary){	PGresult   *result = conn->result;	int			nfields = result->numAttributes;	PGresAttValue *tup;	/* the backend sends us a bitmap of which attributes are null */	char		std_bitmap[64]; /* used unless it doesn't fit */	char	   *bitmap = std_bitmap;	int			i;	size_t		nbytes;			/* the number of bytes in bitmap  */	char		bmap;			/* One byte of the bitmap */	int			bitmap_index;	/* Its index */	int			bitcnt;			/* number of bits examined in current byte */	int			vlen;			/* length of the current field value */	result->binary = binary;	/* Allocate tuple space if first time for this data message */	if (conn->curTuple == NULL)	{		conn->curTuple = (PGresAttValue *)			pqResultAlloc(result, nfields * sizeof(PGresAttValue), TRUE);		if (conn->curTuple == NULL)			goto outOfMemory;		MemSet(conn->curTuple, 0, nfields * sizeof(PGresAttValue));		/*		 * If it's binary, fix the column format indicators.  We assume the		 * backend will consistently send either B or D, not a mix.		 */		if (binary)		{			for (i = 0; i < nfields; i++)				result->attDescs[i].format = 1;		}	}	tup = conn->curTuple;	/* Get the null-value bitmap */	nbytes = (nfields + BITS_PER_BYTE - 1) / BITS_PER_BYTE;	/* malloc() only for unusually large field counts... */	if (nbytes > sizeof(std_bitmap))	{		bitmap = (char *) malloc(nbytes);		if (!bitmap)			goto outOfMemory;	}	if (pqGetnchar(bitmap, nbytes, conn))		goto EOFexit;	/* Scan the fields */	bitmap_index = 0;	bmap = bitmap[bitmap_index];	bitcnt = 0;	for (i = 0; i < nfields; i++)	{		if (!(bmap & 0200))		{			/* if the field value is absent, make it a null string */			tup[i].value = result->null_field;			tup[i].len = NULL_LEN;		}		else		{			/* get the value length (the first four bytes are for length) */			if (pqGetInt(&vlen, 4, conn))				goto EOFexit;			if (!binary)				vlen = vlen - 4;			if (vlen < 0)				vlen = 0;			if (tup[i].value == NULL)			{				tup[i].value = (char *) pqResultAlloc(result, vlen + 1, binary);				if (tup[i].value == NULL)					goto outOfMemory;			}			tup[i].len = vlen;			/* read in the value */			if (vlen > 0)				if (pqGetnchar((char *) (tup[i].value), vlen, conn))					goto EOFexit;			/* we have to terminate this ourselves */			tup[i].value[vlen] = '\0';		}		/* advance the bitmap stuff */		bitcnt++;		if (bitcnt == BITS_PER_BYTE)		{			bitmap_index++;			bmap = bitmap[bitmap_index];			bitcnt = 0;		}		else			bmap <<= 1;	}	/* Success!  Store the completed tuple in the result */	if (!pqAddTuple(result, tup))		goto outOfMemory;	/* and reset for a new message */	conn->curTuple = NULL;	if (bitmap != std_bitmap)		free(bitmap);	return 0;outOfMemory:	/* Replace partially constructed result with an error result */	/*	 * we do NOT use pqSaveErrorResult() here, because of the likelihood that	 * there's not enough memory to concatenate messages...	 */	pqClearAsyncResult(conn);	printfPQExpBuffer(&conn->errorMessage,					  libpq_gettext("out of memory for query result\n"));	/*	 * XXX: if PQmakeEmptyPGresult() fails, there's probably not much we can	 * do to recover...	 */	conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);	conn->asyncStatus = PGASYNC_READY;	/* Discard the failed message --- good idea? */	conn->inStart = conn->inEnd;EOFexit:	if (bitmap != NULL && bitmap != std_bitmap)		free(bitmap);	return EOF;}/* * Attempt to read an Error or Notice response message. * This is possible in several places, so we break it out as a subroutine. * Entry: 'E' or 'N' message type has already been consumed. * Exit: returns 0 if successfully consumed message. *		 returns EOF if not enough data. */static intpqGetErrorNotice2(PGconn *conn, bool isError){	PGresult   *res = NULL;	PQExpBufferData workBuf;	char	   *startp;	char	   *splitp;	/*	 * Since the message might be pretty long, we create a temporary	 * PQExpBuffer rather than using conn->workBuffer.	workBuffer is intended	 * for stuff that is expected to be short.	 */	initPQExpBuffer(&workBuf);	if (pqGets(&workBuf, conn))		goto failure;	/*	 * Make a PGresult to hold the message.  We temporarily lie about the	 * result status, so that PQmakeEmptyPGresult doesn't uselessly copy	 * conn->errorMessage.	 */	res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY);	if (!res)		goto failure;	res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR;	res->errMsg = pqResultStrdup(res, workBuf.data);	if (!res->errMsg)		goto failure;	/*	 * Break the message into fields.  We can't do very much here, but we can	 * split the severity code off, and remove trailing newlines. Also, we use	 * the heuristic that the primary message extends only to the first	 * newline --- anything after that is detail message.  (In some cases it'd	 * be better classed as hint, but we can hardly be expected to guess that	 * here.)	 */	while (workBuf.len > 0 && workBuf.data[workBuf.len - 1] == '\n')		workBuf.data[--workBuf.len] = '\0';	splitp = strstr(workBuf.data, ":  ");	if (splitp)	{		/* what comes before the colon is severity */		*splitp = '\0';		pqSaveMessageField(res, PG_DIAG_SEVERITY, workBuf.data);		startp = splitp + 3;	}	else	{		/* can't find a colon?  oh well... */		startp = workBuf.data;	}	splitp = strchr(startp, '\n');	if (splitp)	{		/* what comes before the newline is primary message */		*splitp++ = '\0';		pqSaveMessageField(res, PG_DIAG_MESSAGE_PRIMARY, startp);		/* the rest is detail; strip any leading whitespace */		while (*splitp && isspace((unsigned char) *splitp))			splitp++;		pqSaveMessageField(res, PG_DIAG_MESSAGE_DETAIL, splitp);	}	else	{		/* single-line message, so all primary */		pqSaveMessageField(res, PG_DIAG_MESSAGE_PRIMARY, startp);	}	/*	 * Either save error as current async result, or just emit the notice.	 * Also, if it's an error and we were in a transaction block, assume the	 * server has now gone to error-in-transaction state.	 */	if (isError)	{		pqClearAsyncResult(conn);		conn->result = res;		resetPQExpBuffer(&conn->errorMessage);		appendPQExpBufferStr(&conn->errorMessage, res->errMsg);		if (conn->xactStatus == PQTRANS_INTRANS)			conn->xactStatus = PQTRANS_INERROR;	}	else	{		if (res->noticeHooks.noticeRec != NULL)			(*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res);		PQclear(res);	}	termPQExpBuffer(&workBuf);	return 0;failure:	if (res)		PQclear(res);	termPQExpBuffer(&workBuf);	return EOF;}/* * checkXactStatus - attempt to track transaction-block status of server * * This is called each time we receive a command-complete message.	By * watching for messages from BEGIN/COMMIT/ROLLBACK commands, we can do * a passable job of tracking the server's xact status.  BUT: this does * not work at all on 7.3 servers with AUTOCOMMIT OFF.	(Man, was that * feature ever a mistake.)  Caveat user. * * The tags known here are all those used as far back as 7.0; is it worth * adding those from even-older servers? */static voidcheckXactStatus(PGconn *conn, const char *cmdTag){	if (strcmp(cmdTag, "BEGIN") == 0)		conn->xactStatus = PQTRANS_INTRANS;	else if (strcmp(cmdTag, "COMMIT") == 0)		conn->xactStatus = PQTRANS_IDLE;	else if (strcmp(cmdTag, "ROLLBACK") == 0)		conn->xactStatus = PQTRANS_IDLE;	else if (strcmp(cmdTag, "START TRANSACTION") == 0)	/* 7.3 only */		conn->xactStatus = PQTRANS_INTRANS;	/*	 * Normally we get into INERROR state by detecting an Error message.	 * However, if we see one of these tags then we know for sure the server	 * is in abort state ...	 */	else if (strcmp(cmdTag, "*ABORT STATE*") == 0)		/* pre-7.3 only */		conn->xactStatus = PQTRANS_INERROR;}/* * Attempt to read a Notify response message. * This is possible in several places, so we break it out as a subroutine. * Entry: 'A' message type and length have already been consumed. * Exit: returns 0 if successfully consumed Notify message. *		 returns EOF if not enough data. */static intgetNotify(PGconn *conn){	int			be_pid;	int			nmlen;	PGnotify   *newNotify;	if (pqGetInt(&be_pid, 4, conn))		return EOF;	if (pqGets(&conn->workBuffer, conn))		return EOF;	/*	 * Store the relation name right after the PQnotify structure so it can	 * all be freed at once.  We don't use NAMEDATALEN because we don't want	 * to tie this interface to a specific server name length.	 */	nmlen = strlen(conn->workBuffer.data);	newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen + 1);	if (newNotify)	{		newNotify->relname = (char *) newNotify + sizeof(PGnotify);		strcpy(newNotify->relname, conn->workBuffer.data);		/* fake up an empty-string extra field */		newNotify->extra = newNotify->relname + nmlen;		newNotify->be_pid = be_pid;		newNotify->next = NULL;		if (conn->notifyTail)			conn->notifyTail->next = newNotify;

⌨️ 快捷键说明

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