Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3dfcf8c

Browse files
committed
Instead of sending application_name as a SET command after the connection
is made, include it in the startup-packet options. This makes it work morelike every other libpq connection option, in particular it now has the sameresponse to RESET ALL as the rest. This also saves one network round tripfor new applications using application_name. The cost is that if the serveris pre-8.5, it'll reject the startup packet altogether, forcing us to retrythe entire connection cycle. But on balance we shouldn't be optimizing thatcase in preference to the behavior with a new server, especially when doingso creates visible behavioral oddities. Per discussion.
1 parent925b32b commit3dfcf8c

File tree

3 files changed

+91
-217
lines changed

3 files changed

+91
-217
lines changed

‎src/interfaces/libpq/fe-connect.c

Lines changed: 67 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.380 2009/11/29 20:14:53 petere Exp $
11+
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.381 2009/12/02 04:38:35 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -83,8 +83,18 @@ static int ldapServiceLookup(const char *purl, PQconninfoOption *options,
8383
#definePGPASSFILE "pgpass.conf"
8484
#endif
8585

86-
/* fall back options if they are not specified by arguments or defined
87-
by environment variables */
86+
/*
87+
* Pre-8.5 servers will return this SQLSTATE if asked to set
88+
* application_name in a startup packet. We hard-wire the value rather
89+
* than looking into errcodes.h since it reflects historical behavior
90+
* rather than that of the current code.
91+
*/
92+
#defineERRCODE_APPNAME_UNKNOWN "42704"
93+
94+
/*
95+
* fall back options if they are not specified by arguments or defined
96+
* by environment variables
97+
*/
8898
#defineDefaultHost"localhost"
8999
#defineDefaultTty""
90100
#defineDefaultOption""
@@ -262,7 +272,6 @@ static int parseServiceInfo(PQconninfoOption *options,
262272
staticchar*pwdfMatchesString(char*buf,char*token);
263273
staticchar*PasswordFromFile(char*hostname,char*port,char*dbname,
264274
char*username);
265-
staticPostgresPollingStatusTypepqAppnamePoll(PGconn*conn);
266275
staticvoiddefault_threadlock(intacquire);
267276

268277

@@ -901,6 +910,7 @@ connectDBStart(PGconn *conn)
901910
conn->addr_cur=addrs;
902911
conn->addrlist_family=hint.ai_family;
903912
conn->pversion=PG_PROTOCOL(3,0);
913+
conn->send_appname= true;
904914
conn->status=CONNECTION_NEEDED;
905915

906916
/*
@@ -1075,7 +1085,7 @@ PQconnectPoll(PGconn *conn)
10751085
caseCONNECTION_MADE:
10761086
break;
10771087

1078-
/* pqSetenvPoll/pqAppnamePoll will decide whether to proceed. */
1088+
/*We allowpqSetenvPoll to decide whether to proceed. */
10791089
caseCONNECTION_SETENV:
10801090
break;
10811091

@@ -1880,6 +1890,35 @@ PQconnectPoll(PGconn *conn)
18801890
if (res->resultStatus!=PGRES_FATAL_ERROR)
18811891
appendPQExpBuffer(&conn->errorMessage,
18821892
libpq_gettext("unexpected message from server during startup\n"));
1893+
elseif (conn->send_appname&&
1894+
(conn->appname||conn->fbappname))
1895+
{
1896+
/*
1897+
* If we tried to send application_name, check to see
1898+
* if the error is about that --- pre-8.5 servers will
1899+
* reject it at this stage of the process. If so,
1900+
* close the connection and retry without sending
1901+
* application_name. We could possibly get a false
1902+
* SQLSTATE match here and retry uselessly, but there
1903+
* seems no great harm in that; we'll just get the
1904+
* same error again if it's unrelated.
1905+
*/
1906+
constchar*sqlstate;
1907+
1908+
sqlstate=PQresultErrorField(res,PG_DIAG_SQLSTATE);
1909+
if (sqlstate&&
1910+
strcmp(sqlstate,ERRCODE_APPNAME_UNKNOWN)==0)
1911+
{
1912+
PQclear(res);
1913+
conn->send_appname= false;
1914+
/* Must drop the old connection */
1915+
pqsecure_close(conn);
1916+
closesocket(conn->sock);
1917+
conn->sock=-1;
1918+
conn->status=CONNECTION_NEEDED;
1919+
gotokeep_going;
1920+
}
1921+
}
18831922

18841923
/*
18851924
* if the resultStatus is FATAL, then conn->errorMessage
@@ -1899,12 +1938,6 @@ PQconnectPoll(PGconn *conn)
18991938
conn->addrlist=NULL;
19001939
conn->addr_cur=NULL;
19011940

1902-
/*
1903-
* Note: To avoid changing the set of application-visible
1904-
* connection states, v2 environment setup and v3 application
1905-
* name setup both happen in the CONNECTION_SETENV state.
1906-
*/
1907-
19081941
/* Fire up post-connection housekeeping if needed */
19091942
if (PG_PROTOCOL_MAJOR(conn->pversion)<3)
19101943
{
@@ -1913,59 +1946,43 @@ PQconnectPoll(PGconn *conn)
19131946
conn->next_eo=EnvironmentOptions;
19141947
returnPGRES_POLLING_WRITING;
19151948
}
1916-
elseif (conn->sversion >=80500&&
1917-
(conn->appname||conn->fbappname))
1918-
{
1919-
conn->status=CONNECTION_SETENV;
1920-
conn->appname_state=APPNAME_STATE_CMD_SEND;
1921-
returnPGRES_POLLING_WRITING;
1922-
}
19231949

19241950
/* Otherwise, we are open for business! */
19251951
conn->status=CONNECTION_OK;
19261952
returnPGRES_POLLING_OK;
19271953
}
19281954

19291955
caseCONNECTION_SETENV:
1930-
{
1931-
PostgresPollingStatusTyperet;
19321956

1933-
/*
1934-
* Do post-connection housekeeping (only needed in protocol
1935-
* 2.0), or send the application name in PG8.5+.
1936-
*
1937-
* We pretend that the connection is OK for the duration of
1938-
* these queries.
1939-
*/
1940-
conn->status=CONNECTION_OK;
1941-
1942-
if (PG_PROTOCOL_MAJOR(conn->pversion)<3)
1943-
ret=pqSetenvPoll(conn);
1944-
else/* must be here to send app name */
1945-
ret=pqAppnamePoll(conn);
1946-
1947-
switch (ret)
1948-
{
1949-
casePGRES_POLLING_OK:/* Success */
1950-
break;
1957+
/*
1958+
* Do post-connection housekeeping (only needed in protocol 2.0).
1959+
*
1960+
* We pretend that the connection is OK for the duration of these
1961+
* queries.
1962+
*/
1963+
conn->status=CONNECTION_OK;
19511964

1952-
casePGRES_POLLING_READING:/* Still going */
1953-
conn->status=CONNECTION_SETENV;
1954-
returnPGRES_POLLING_READING;
1965+
switch (pqSetenvPoll(conn))
1966+
{
1967+
casePGRES_POLLING_OK:/* Success */
1968+
break;
19551969

1956-
casePGRES_POLLING_WRITING:/* Still going */
1957-
conn->status=CONNECTION_SETENV;
1958-
returnPGRES_POLLING_WRITING;
1970+
casePGRES_POLLING_READING:/* Still going */
1971+
conn->status=CONNECTION_SETENV;
1972+
returnPGRES_POLLING_READING;
19591973

1960-
default:
1961-
gotoerror_return;
1962-
}
1974+
casePGRES_POLLING_WRITING:/* Still going */
1975+
conn->status=CONNECTION_SETENV;
1976+
returnPGRES_POLLING_WRITING;
19631977

1964-
/* We are open for business! */
1965-
conn->status=CONNECTION_OK;
1966-
returnPGRES_POLLING_OK;
1978+
default:
1979+
gotoerror_return;
19671980
}
19681981

1982+
/* We are open for business! */
1983+
conn->status=CONNECTION_OK;
1984+
returnPGRES_POLLING_OK;
1985+
19691986
default:
19701987
appendPQExpBuffer(&conn->errorMessage,
19711988
libpq_gettext("invalid connection state %d, "
@@ -2031,7 +2048,6 @@ makeEmptyPGconn(void)
20312048
conn->options_valid= false;
20322049
conn->nonblocking= false;
20332050
conn->setenv_state=SETENV_STATE_IDLE;
2034-
conn->appname_state=APPNAME_STATE_IDLE;
20352051
conn->client_encoding=PG_SQL_ASCII;
20362052
conn->std_strings= false;/* unless server says differently */
20372053
conn->verbosity=PQERRORS_DEFAULT;
@@ -4048,129 +4064,6 @@ pqGetHomeDirectory(char *buf, int bufsize)
40484064
#endif
40494065
}
40504066

4051-
/*
4052-
*pqAppnamePoll
4053-
*
4054-
* Polls the process of passing the application name to the backend.
4055-
*
4056-
* Ideally, we'd include the appname in the startup packet, but that would
4057-
* cause old backends to reject the unknown parameter. So we send it in a
4058-
* separate query after we have determined the backend version. Once there
4059-
* is no interest in pre-8.5 backends, this should be folded into the startup
4060-
* packet logic.
4061-
*/
4062-
staticPostgresPollingStatusType
4063-
pqAppnamePoll(PGconn*conn)
4064-
{
4065-
PGresult*res;
4066-
4067-
if (conn==NULL||conn->status==CONNECTION_BAD)
4068-
returnPGRES_POLLING_FAILED;
4069-
4070-
/* Check whether there is any data for us */
4071-
switch (conn->appname_state)
4072-
{
4073-
/* This is a reading state. */
4074-
caseAPPNAME_STATE_CMD_WAIT:
4075-
{
4076-
/* Load waiting data */
4077-
intn=pqReadData(conn);
4078-
4079-
if (n<0)
4080-
gotoerror_return;
4081-
if (n==0)
4082-
returnPGRES_POLLING_READING;
4083-
4084-
break;
4085-
}
4086-
4087-
/* This is a writing state, so we just proceed. */
4088-
caseAPPNAME_STATE_CMD_SEND:
4089-
break;
4090-
4091-
/* Should we raise an error if called when not active? */
4092-
caseAPPNAME_STATE_IDLE:
4093-
returnPGRES_POLLING_OK;
4094-
4095-
default:
4096-
printfPQExpBuffer(&conn->errorMessage,
4097-
libpq_gettext("invalid appname state %d, "
4098-
"probably indicative of memory corruption\n"),
4099-
conn->appname_state);
4100-
gotoerror_return;
4101-
}
4102-
4103-
/* We will loop here until there is nothing left to do in this call. */
4104-
for (;;)
4105-
{
4106-
switch (conn->appname_state)
4107-
{
4108-
caseAPPNAME_STATE_CMD_SEND:
4109-
{
4110-
constchar*val;
4111-
charescVal[NAMEDATALEN*2+1];
4112-
charsetQuery[NAMEDATALEN*2+26+1];
4113-
4114-
/* Use appname if present, otherwise use fallback */
4115-
val=conn->appname ?conn->appname :conn->fbappname;
4116-
4117-
/*
4118-
* Escape the data as needed. We can truncate to NAMEDATALEN,
4119-
* so there's no need to cope with malloc.
4120-
*/
4121-
PQescapeStringConn(conn,escVal,val,NAMEDATALEN,NULL);
4122-
4123-
sprintf(setQuery,"SET application_name = '%s'",escVal);
4124-
4125-
if (!PQsendQuery(conn,setQuery))
4126-
gotoerror_return;
4127-
4128-
conn->appname_state=APPNAME_STATE_CMD_WAIT;
4129-
break;
4130-
}
4131-
4132-
caseAPPNAME_STATE_CMD_WAIT:
4133-
{
4134-
if (PQisBusy(conn))
4135-
returnPGRES_POLLING_READING;
4136-
4137-
res=PQgetResult(conn);
4138-
4139-
if (res)
4140-
{
4141-
if (PQresultStatus(res)!=PGRES_COMMAND_OK)
4142-
{
4143-
PQclear(res);
4144-
gotoerror_return;
4145-
}
4146-
PQclear(res);
4147-
/* Keep reading until PQgetResult returns NULL */
4148-
}
4149-
else
4150-
{
4151-
/* Query finished, so we're done */
4152-
conn->appname_state=APPNAME_STATE_IDLE;
4153-
returnPGRES_POLLING_OK;
4154-
}
4155-
break;
4156-
}
4157-
4158-
default:
4159-
printfPQExpBuffer(&conn->errorMessage,
4160-
libpq_gettext("invalid appname state %d, "
4161-
"probably indicative of memory corruption\n"),
4162-
conn->appname_state);
4163-
gotoerror_return;
4164-
}
4165-
}
4166-
4167-
/* Unreachable */
4168-
4169-
error_return:
4170-
conn->appname_state=APPNAME_STATE_IDLE;
4171-
returnPGRES_POLLING_FAILED;
4172-
}
4173-
41744067
/*
41754068
* To keep the API consistent, the locking stubs are always provided, even
41764069
* if they are not required.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp