fe-connect.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,647 行 · 第 1/5 页

C
2,647
字号
	{		closePGconn(conn);		freePGconn(conn);	}}/* PQreset :   resets the connection to the backend   closes the existing connection and makes a new one*/voidPQreset(PGconn *conn){	if (conn)	{		closePGconn(conn);		if (connectDBStart(conn))			(void) connectDBComplete(conn);	}}/* PQresetStart :   resets the connection to the backend   closes the existing connection and makes a new one   Returns 1 on success, 0 on failure.*/intPQresetStart(PGconn *conn){	if (conn)	{		closePGconn(conn);		return connectDBStart(conn);	}	return 0;}/* PQresetPoll :   resets the connection to the backend   closes the existing connection and makes a new one*/PostgresPollingStatusTypePQresetPoll(PGconn *conn){	if (conn)		return PQconnectPoll(conn);	return PGRES_POLLING_FAILED;}/* * PQrequestCancel: attempt to request cancellation of the current operation. * * The return value is TRUE if the cancel request was successfully * dispatched, FALSE if not (in which case conn->errorMessage is set). * Note: successful dispatch is no guarantee that there will be any effect at * the backend.  The application must read the operation result as usual. * * XXX it was a bad idea to have the error message returned in * conn->errorMessage, since it could overwrite a message already there. * Would be better to return it in a char array passed by the caller. * * CAUTION: we want this routine to be safely callable from a signal handler * (for example, an application might want to call it in a SIGINT handler). * This means we cannot use any C library routine that might be non-reentrant. * malloc/free are often non-reentrant, and anything that might call them is * just as dangerous.  We avoid sprintf here for that reason.  Building up * error messages with strcpy/strcat is tedious but should be quite safe. * We also save/restore errno in case the signal handler support doesn't. * * NOTE: this routine must not generate any error message longer than * INITIAL_EXPBUFFER_SIZE (currently 256), since we dare not try to * expand conn->errorMessage! */intPQrequestCancel(PGconn *conn){	int			save_errno = SOCK_ERRNO;	int			tmpsock = -1;	char		sebuf[256];	struct	{		uint32		packetlen;		CancelRequestPacket cp;	}			crp;	/* Check we have an open connection */	if (!conn)		return FALSE;	if (conn->sock < 0)	{		strcpy(conn->errorMessage.data,			   "PQrequestCancel() -- connection is not open\n");		conn->errorMessage.len = strlen(conn->errorMessage.data);#ifdef WIN32		WSASetLastError(save_errno);#else		errno = save_errno;#endif		return FALSE;	}	/*	 * We need to open a temporary connection to the postmaster. Use the	 * information saved by connectDB to do this with only kernel calls.	 */	if ((tmpsock = socket(conn->raddr.addr.ss_family, SOCK_STREAM, 0)) < 0)	{		strcpy(conn->errorMessage.data,			   "PQrequestCancel() -- socket() failed: ");		goto cancel_errReturn;	}retry3:	if (connect(tmpsock, (struct sockaddr *) & conn->raddr.addr,				conn->raddr.salen) < 0)	{		if (SOCK_ERRNO == EINTR)			/* Interrupted system call - we'll just try again */			goto retry3;		strcpy(conn->errorMessage.data,			   "PQrequestCancel() -- connect() failed: ");		goto cancel_errReturn;	}	/*	 * We needn't set nonblocking I/O or NODELAY options here.	 */	/* Create and send the cancel request packet. */	crp.packetlen = htonl((uint32) sizeof(crp));	crp.cp.cancelRequestCode = (MsgType) htonl(CANCEL_REQUEST_CODE);	crp.cp.backendPID = htonl(conn->be_pid);	crp.cp.cancelAuthCode = htonl(conn->be_key);retry4:	if (send(tmpsock, (char *) &crp, sizeof(crp), 0) != (int) sizeof(crp))	{		if (SOCK_ERRNO == EINTR)			/* Interrupted system call - we'll just try again */			goto retry4;		strcpy(conn->errorMessage.data,			   "PQrequestCancel() -- send() failed: ");		goto cancel_errReturn;	}	/*	 * Wait for the postmaster to close the connection, which indicates that	 * it's processed the request.  Without this delay, we might issue another	 * command only to find that our cancel zaps that command instead of the	 * one we thought we were canceling.  Note we don't actually expect this	 * read to obtain any data, we are just waiting for EOF to be signaled.	 */retry5:	if (recv(tmpsock, (char *) &crp, 1, 0) < 0)	{		if (SOCK_ERRNO == EINTR)			/* Interrupted system call - we'll just try again */			goto retry5;		/* we ignore other error conditions */	}	/* All done */	closesocket(tmpsock);#ifdef WIN32	WSASetLastError(save_errno);#else	errno = save_errno;#endif	return TRUE;cancel_errReturn:	strcat(conn->errorMessage.data, SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));	strcat(conn->errorMessage.data, "\n");	conn->errorMessage.len = strlen(conn->errorMessage.data);	if (tmpsock >= 0)	{		closesocket(tmpsock);#ifdef WIN32		WSASetLastError(save_errno);#else		errno = save_errno;#endif	}	return FALSE;}/* * pqPacketSend() -- convenience routine to send a message to server. * * pack_type: the single-byte message type code.  (Pass zero for startup * packets, which have no message type code.) * * buf, buf_len: contents of message.  The given length includes only what * is in buf; the message type and message length fields are added here. * * RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise. * SIDE_EFFECTS: may block. * * Note: all messages sent with this routine have a length word, whether * it's protocol 2.0 or 3.0. */intpqPacketSend(PGconn *conn, char pack_type,			 const void *buf, size_t buf_len){	/* Start the message. */	if (pqPutMsgStart(pack_type, true, conn))		return STATUS_ERROR;	/* Send the message body. */	if (pqPutnchar(buf, buf_len, conn))		return STATUS_ERROR;	/* Finish the message. */	if (pqPutMsgEnd(conn))		return STATUS_ERROR;	/* Flush to ensure backend gets it. */	if (pqFlush(conn))		return STATUS_ERROR;	return STATUS_OK;}#ifndef SYSCONFDIR#error "You must compile this file with SYSCONFDIR defined."#endif#define MAXBUFSIZE 256static intparseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage){	char	   *service = conninfo_getval(options, "service");	char	   *serviceFile = SYSCONFDIR "/pg_service.conf";	bool		group_found = false;	int			linenr = 0,				i;	/*	 * We have to special-case the environment variable PGSERVICE here,	 * since this is and should be called before inserting environment	 * defaults for other connection options.	 */	if (service == NULL)		service = getenv("PGSERVICE");	if (service != NULL)	{		FILE	   *f;		char		buf[MAXBUFSIZE],				   *line;		f = fopen(serviceFile, "r");		if (f == NULL)		{			printfPQExpBuffer(errorMessage, "ERROR: Service file '%s' not found\n",							  serviceFile);			return 1;		}		while ((line = fgets(buf, MAXBUFSIZE - 1, f)) != NULL)		{			linenr++;			if (strlen(line) >= MAXBUFSIZE - 2)			{				fclose(f);				printfPQExpBuffer(errorMessage,						"ERROR: line %d too long in service file '%s'\n",								  linenr,								  serviceFile);				return 2;			}			/* ignore EOL at end of line */			if (strlen(line) && line[strlen(line) - 1] == '\n')				line[strlen(line) - 1] = 0;			/* ignore leading blanks */			while (*line && isspace((unsigned char) line[0]))				line++;			/* ignore comments and empty lines */			if (strlen(line) == 0 || line[0] == '#')				continue;			/* Check for right groupname */			if (line[0] == '[')			{				if (group_found)				{					/* group info already read */					fclose(f);					return 0;				}				if (strncmp(line + 1, service, strlen(service)) == 0 &&					line[strlen(service) + 1] == ']')					group_found = true;				else					group_found = false;			}			else			{				if (group_found)				{					/*					 * Finally, we are in the right group and can parse					 * the line					 */					char	   *key,							   *val;					bool		found_keyword;					key = line;					val = strchr(line, '=');					if (val == NULL)					{						printfPQExpBuffer(errorMessage,										  "ERROR: syntax error in service file '%s', line %d\n",										  serviceFile,										  linenr);						fclose(f);						return 3;					}					*val++ = '\0';					/*					 * Set the parameter --- but don't override any					 * previous explicit setting.					 */					found_keyword = false;					for (i = 0; options[i].keyword; i++)					{						if (strcmp(options[i].keyword, key) == 0)						{							if (options[i].val == NULL)								options[i].val = strdup(val);							found_keyword = true;							break;						}					}					if (!found_keyword)					{						printfPQExpBuffer(errorMessage,										  "ERROR: syntax error in service file '%s', line %d\n",										  serviceFile,										  linenr);						fclose(f);						return 3;					}				}			}		}		fclose(f);	}	return 0;}/* * Conninfo parser routine * * If successful, a malloc'd PQconninfoOption array is returned. * If not successful, NULL is returned and an error message is * left in errorMessage. */static PQconninfoOption *conninfo_parse(const char *conninfo, PQExpBuffer errorMessage){	char	   *pname;	char	   *pval;	char	   *buf;	char	   *tmp;	char	   *cp;	char	   *cp2;	PQconninfoOption *options;	PQconninfoOption *option;	char		errortmp[PQERRORMSG_LENGTH];	/* Make a working copy of PQconninfoOptions */	options = malloc(sizeof(PQconninfoOptions));	if (options == NULL)	{		printfPQExpBuffer(errorMessage,						  libpq_gettext("out of memory\n"));		return NULL;	}	memcpy(options, PQconninfoOptions, sizeof(PQconninfoOptions));	/* Need a modifiable copy of the input string */	if ((buf = strdup(conninfo)) == NULL)	{		printfPQExpBuffer(errorMessage,						  libpq_gettext("out of memory\n"));		PQconninfoFree(options);		return NULL;	}	cp = buf;	while (*cp)	{		/* Skip blanks before the parameter name */		if (isspace((unsigned char) *cp))		{			cp++;			continue;		}		/* Get the parameter name */		pname = cp;		while (*cp)		{			if (*cp == '=')				break;			if (isspace((unsigned char) *cp))			{				*cp++ = '\0';				while (*cp)				{					if (!isspace((unsigned char) *cp))						break;					cp++;				}				break;			}			cp++;		}		/* Check that there is a following '=' */		if (*cp != '=')		{			printfPQExpBuffer(errorMessage,							  libpq_gettext("missing \"=\" after \"%s\" in connection info string\n"),							  pname);			PQconninfoFree(options);			free(buf);			return NULL;		}		*cp++ = '\0';		/* Skip blanks after the '=' */		while (*cp)		{			if (!isspace((unsigned char) *cp))				break;			cp++;		}		/* Get the parameter value */		pval = cp;		if (*cp != '\'')		{			cp2 = pval;			while (*cp)			{				if (isspace((unsigned char) *cp))				{					*cp++ = '\0';					break;				}				if (*cp == '\\')				{					cp++;					if (*cp != '\0')						*cp2++ = *cp++;				}				else					*cp2++ = *cp++;			}			*cp2 = '\0';		}		else		{			cp2 = pval;			cp++;			for (;;)			{				if (*cp == '\0')				{					printfPQExpBuffer(errorMessage,									  libpq_gettext("unterminated quoted string in connection info string\n"));					PQconninfoFree(options);					free(buf);					return NULL;				}				if (*cp == '\\')				{					cp++;					if (*cp != '\0')						*cp2++ = *cp++;					continue;				}				if (*cp == '\'')				{					*cp2 = '\0';					cp++;					break;				}				*cp2++ = *cp++;			}		}		/*		 * Now we have the name and the value. Search for the param		 * record.		 */

⌨️ 快捷键说明

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