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

📄 fe-connect.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 3 页
字号:
	SOCKET_SIZE_TYPE laddrlen;	int			portno,				family;	char		beresp;	int			on = 1;	/*	 * parse dbName to get all additional info in it, if any	 */	if (update_db_info(conn) != 0)		goto connect_errReturn;	/*	 * Initialize the startup packet.	 */	MemSet((char *) &sp, 0, sizeof(StartupPacket));	sp.protoVersion = (ProtocolVersion) htonl(PG_PROTOCOL_LIBPQ);	strncpy(sp.user, conn->pguser, SM_USER);	strncpy(sp.database, conn->dbName, SM_DATABASE);	strncpy(sp.tty, conn->pgtty, SM_TTY);	if (conn->pgoptions)		strncpy(sp.options, conn->pgoptions, SM_OPTIONS);	/*	 * Open a connection to postmaster/backend.	 */	if (conn->pghost != NULL)	{		hp = gethostbyname(conn->pghost);		if ((hp == NULL) || (hp->h_addrtype != AF_INET))		{			(void) sprintf(conn->errorMessage,						   "connectDB() --  unknown hostname: %s\n",						   conn->pghost);			goto connect_errReturn;		}		family = AF_INET;	}	else	{		hp = NULL;		family = AF_UNIX;	}	MemSet((char *) &conn->raddr, 0, sizeof(conn->raddr));	conn->raddr.sa.sa_family = family;	portno = atoi(conn->pgport);	if (family == AF_INET)	{		memmove((char *) &(conn->raddr.in.sin_addr),				(char *) hp->h_addr,				hp->h_length);		conn->raddr.in.sin_port = htons((unsigned short) (portno));		conn->raddr_len = sizeof(struct sockaddr_in);	}#if !defined(WIN32) && !defined(__CYGWIN32__)	else		conn->raddr_len = UNIXSOCK_PATH(conn->raddr.un, portno);#endif	/* Connect to the server  */	if ((conn->sock = socket(family, SOCK_STREAM, 0)) < 0)	{		(void) sprintf(conn->errorMessage,					   "connectDB() -- socket() failed: errno=%d\n%s\n",					   errno, strerror(errno));		goto connect_errReturn;	}	if (connect(conn->sock, &conn->raddr.sa, conn->raddr_len) < 0)	{		(void) sprintf(conn->errorMessage,					   "connectDB() -- connect() failed: %s\n"					   "Is the postmaster running%s at '%s' and accepting connections on %s '%s'?\n",					   strerror(errno),					   (family == AF_INET) ? " (with -i)" : "",					   conn->pghost ? conn->pghost : "localhost",					 (family == AF_INET) ? "TCP/IP port" : "Unix socket",					   conn->pgport);		goto connect_errReturn;	}	/*	 * Set the right options. We need nonblocking I/O, and we don't want	 * delay of outgoing data.	 */#ifndef WIN32	if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) < 0)#else	if (ioctlsocket(conn->sock, FIONBIO, &on) != 0)#endif	{		(void) sprintf(conn->errorMessage,					   "connectDB() -- fcntl() failed: errno=%d\n%s\n",					   errno, strerror(errno));		goto connect_errReturn;	}	if (family == AF_INET)	{		struct protoent *pe;		pe = getprotobyname("TCP");		if (pe == NULL)		{			(void) sprintf(conn->errorMessage,						   "connectDB(): getprotobyname failed\n");			goto connect_errReturn;		}		if (setsockopt(conn->sock, pe->p_proto, TCP_NODELAY,#ifdef WIN32					   (char *)#endif					   &on,					   sizeof(on)) < 0)		{			(void) sprintf(conn->errorMessage,					  "connectDB() -- setsockopt failed: errno=%d\n%s\n",						   errno, strerror(errno));#ifdef WIN32			printf("Winsock error: %i\n", WSAGetLastError());#endif			goto connect_errReturn;		}	}	/* Fill in the client address */	laddrlen = sizeof(conn->laddr);	if (getsockname(conn->sock, &conn->laddr.sa, &laddrlen) < 0)	{		(void) sprintf(conn->errorMessage,				   "connectDB() -- getsockname() failed: errno=%d\n%s\n",					   errno, strerror(errno));		goto connect_errReturn;	}	/* Ensure our buffers are empty */	conn->inStart = conn->inCursor = conn->inEnd = 0;	conn->outCount = 0;	/* Send the startup packet. */	if (pqPacketSend(conn, (char *) &sp, sizeof(StartupPacket)) != STATUS_OK)	{		sprintf(conn->errorMessage,		  "connectDB() --  couldn't send startup packet: errno=%d\n%s\n",				errno, strerror(errno));		goto connect_errReturn;	}	/*	 * Perform the authentication exchange: wait for backend messages and	 * respond as necessary. We fall out of this loop when done talking to	 * the postmaster.	 */	for (;;)	{		/* Wait for some data to arrive (or for the channel to close) */		if (pqWait(TRUE, FALSE, conn))			goto connect_errReturn;		/* Load data, or detect EOF */		if (pqReadData(conn) < 0)			goto connect_errReturn;		/*		 * Scan the message. If we run out of data, loop around to try		 * again.		 */		conn->inCursor = conn->inStart;		if (pqGetc(&beresp, conn))			continue;			/* no data yet */		/* Handle errors. */		if (beresp == 'E')		{			if (pqGets(conn->errorMessage, sizeof(conn->errorMessage), conn))				continue;			goto connect_errReturn;		}		/* Otherwise it should be an authentication request. */		if (beresp != 'R')		{			(void) sprintf(conn->errorMessage,					 "connectDB() -- expected authentication request\n");			goto connect_errReturn;		}		/* Get the type of request. */		if (pqGetInt((int *) &areq, 4, conn))			continue;		/* Get the password salt if there is one. */		if (areq == AUTH_REQ_CRYPT)		{			if (pqGetnchar(conn->salt, sizeof(conn->salt), conn))				continue;		}		/* OK, we successfully read the message; mark data consumed */		conn->inStart = conn->inCursor;		/* Respond to the request if necessary. */		if (fe_sendauth(areq, conn, conn->pghost, conn->pgpass,						conn->errorMessage) != STATUS_OK)			goto connect_errReturn;		if (pqFlush(conn))			goto connect_errReturn;		/* Are we done? */		if (areq == AUTH_REQ_OK)			break;	}	/*	 * Now we expect to hear from the backend. A ReadyForQuery message	 * indicates that startup is successful, but we might also get an	 * Error message indicating failure. (Notice messages indicating	 * nonfatal warnings are also allowed by the protocol, as is a	 * BackendKeyData message.) Easiest way to handle this is to let	 * PQgetResult() read the messages. We just have to fake it out about	 * the state of the connection.	 */	conn->status = CONNECTION_OK;	conn->asyncStatus = PGASYNC_BUSY;	res = PQgetResult(conn);	/* NULL return indicating we have gone to IDLE state is expected */	if (res)	{		if (res->resultStatus != PGRES_FATAL_ERROR)			sprintf(conn->errorMessage,					"connectDB() -- unexpected message during startup\n");		PQclear(res);		goto connect_errReturn;	}	/*	 * Given the new protocol that sends a ReadyForQuery message after	 * successful backend startup, it should no longer be necessary to	 * send an empty query to test for startup.	 */#ifdef NOT_USED	/*	 * Send a blank query to make sure everything works; in particular,	 * that the database exists.	 */	res = PQexec(conn, " ");	if (res == NULL || res->resultStatus != PGRES_EMPTY_QUERY)	{		/* PQexec has put error message in conn->errorMessage */		closePGconn(conn);		PQclear(res);		goto connect_errReturn;	}	PQclear(res);#endif	/*	 * Post-connection housekeeping. Send environment variables to server	 */	PQsetenv(conn);	return CONNECTION_OK;connect_errReturn:	if (conn->sock >= 0)	{#ifdef WIN32		closesocket(conn->sock);#else		close(conn->sock);#endif		conn->sock = -1;	}	return CONNECTION_BAD;}voidPQsetenv(PGconn *conn){	struct EnvironmentOptions *eo;	char		setQuery[80];	/* mjl: size okay? XXX */#ifdef MULTIBYTE	char	   *envname = "PGCLIENTENCODING";	static char envbuf[64];		/* big enough? */	char	   *env;	char	   *encoding = 0;	PGresult   *rtn;#endif#ifdef MULTIBYTE	/* query server encoding */	env = getenv(envname);	if (!env || *env == '\0')	{		rtn = PQexec(conn, "select getdatabaseencoding()");		if (rtn && PQresultStatus(rtn) == PGRES_TUPLES_OK)		{			encoding = PQgetvalue(rtn, 0, 0);			if (encoding)			{				/* set client encoding */				sprintf(envbuf, "%s=%s", envname, encoding);				putenv(envbuf);			}		}		PQclear(rtn);		if (!encoding)		{						/* this should not happen */			sprintf(envbuf, "%s=%s", envname, pg_encoding_to_char(MULTIBYTE));			putenv(envbuf);		}	}#endif	for (eo = EnvironmentOptions; eo->envName; eo++)	{		const char *val;		if ((val = getenv(eo->envName)))		{			PGresult   *res;			if (strcasecmp(val, "default") == 0)				sprintf(setQuery, "SET %s = %.60s", eo->pgName, val);			else				sprintf(setQuery, "SET %s = '%.60s'", eo->pgName, val);#ifdef CONNECTDEBUG			printf("Use environment variable %s to send %s\n", eo->envName, setQuery);#endif			res = PQexec(conn, setQuery);			PQclear(res);		/* Don't care? */		}	}}	/* PQsetenv() *//* * makeEmptyPGconn *	 - create a PGconn data structure with (as yet) no interesting data */static PGconn *makeEmptyPGconn(void){	PGconn	   *conn = (PGconn *) malloc(sizeof(PGconn));	if (conn == NULL)		return conn;	/* Zero all pointers */	MemSet((char *) conn, 0, sizeof(PGconn));	conn->noticeHook = defaultNoticeProcessor;	conn->status = CONNECTION_BAD;	conn->asyncStatus = PGASYNC_IDLE;	conn->notifyList = DLNewList();	conn->sock = -1;	conn->inBufSize = PQ_BUFFER_SIZE;	conn->inBuffer = (char *) malloc(conn->inBufSize);	conn->outBufSize = PQ_BUFFER_SIZE;	conn->outBuffer = (char *) malloc(conn->outBufSize);	if (conn->inBuffer == NULL || conn->outBuffer == NULL)	{		freePGconn(conn);		conn = NULL;	}	return conn;}/* * freePGconn *	 - free the PGconn data structure * */static voidfreePGconn(PGconn *conn){	if (!conn)		return;	pqClearAsyncResult(conn);	/* deallocate result and curTuple */	if (conn->sock >= 0)#ifdef WIN32		closesocket(conn->sock);#else		close(conn->sock);#endif	if (conn->pghost)		free(conn->pghost);	if (conn->pgport)		free(conn->pgport);	if (conn->pgtty)		free(conn->pgtty);	if (conn->pgoptions)		free(conn->pgoptions);	if (conn->dbName)		free(conn->dbName);	if (conn->pguser)		free(conn->pguser);	if (conn->pgpass)		free(conn->pgpass);	/* Note that conn->Pfdebug is not ours to close or free */	if (conn->notifyList)		DLFreeList(conn->notifyList);	if (conn->lobjfuncs)		free(conn->lobjfuncs);	if (conn->inBuffer)		free(conn->inBuffer);	if (conn->outBuffer)		free(conn->outBuffer);	free(conn);}/*   closePGconn	 - properly close a connection to the backend*/static voidclosePGconn(PGconn *conn){	if (conn->sock >= 0)	{		/*		 * Try to send "close connection" message to backend. Ignore any		 * error. Note: this routine used to go to substantial lengths to		 * avoid getting SIGPIPE'd if the connection were already closed.		 * Now we rely on pqFlush to avoid the signal.		 */		(void) pqPuts("X", conn);		(void) pqFlush(conn);	}	/*	 * Close the connection, reset all transient state, flush I/O buffers.	 */	if (conn->sock >= 0)#ifdef WIN32		closesocket(conn->sock);#else		close(conn->sock);#endif	conn->sock = -1;	conn->status = CONNECTION_BAD;		/* Well, not really _bad_ - just										 * absent */	conn->asyncStatus = PGASYNC_IDLE;	pqClearAsyncResult(conn);	/* deallocate result and curTuple */	if (conn->lobjfuncs)		free(conn->lobjfuncs);	conn->lobjfuncs = NULL;	conn->inStart = conn->inCursor = conn->inEnd = 0;	conn->outCount = 0;}/*   PQfinish:	  properly close a connection to the backend	  also frees the PGconn data structure so it shouldn't be re-used	  after this*/voidPQfinish(PGconn *conn){	if (conn)	{		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);		conn->status = connectDB(conn);	}}/*

⌨️ 快捷键说明

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