Skip to content

Commit dd3ea31

Browse files
author
James William Pye
committed
Fix handling of the unix connection parameter.
There was an assorted set of bugs around this: - SocketCreator was referenced instead of SocketFactory. - pg.open(unix = '') would cause a TypeError because of standard parameters. - pq-IRI's [unix:...] representation would not serialize and parse correctly. - The unix keyword was undocumented. - There were no tests for unix domain sockets. Issue reported by twitter.com/rintavarustus
1 parent 8d1854d commit dd3ea31

7 files changed

Lines changed: 60 additions & 11 deletions

File tree

postgresql/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ def open(iri = None, prompt_title = None, **kw):
7474
iri_params = {}
7575

7676
std_params = _pg_param.collect(prompt_title = None)
77+
# If unix is specified, it's going to conflict with any standard
78+
# settings, so remove them right here.
79+
if 'unix' in kw or 'unix' in iri_params:
80+
std_params.pop('host', None)
81+
std_params.pop('port', None)
7782
params = _pg_param.normalize(
7883
list(_pg_param.denormalize_parameters(std_params)) + \
7984
list(_pg_param.denormalize_parameters(iri_params)) + \

postgresql/documentation/changes.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ Changes
88
* **DEPRECATION**: Removed 2PC support documentation.
99
* **DEPRECATION**: Removed pg_python and pg_dotconf 'scripts'.
1010
They are still accessible by python3 -m postgresql.bin.pg_*
11+
* Fix handling of unix domain sockets by pg.open and driver.connect.
12+
[Reported by twitter.com/rintavarustus]
1113

1214
0.9.3 released on 2010-01-01
1315
----------------------------

postgresql/documentation/clientparameters.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ systems it is ``"%APPDATA%\postgresql"``
199199
[PGDATA] is *not* an environment variable.
200200

201201

202+
.. _pg_envvars:
203+
202204
PostgreSQL Environment Variables
203205
================================
204206

@@ -227,6 +229,8 @@ The following is a list of environment variables that will be collected by the
227229
===================== ======================================
228230

229231

232+
.. _pg_passfile:
233+
230234
PostgreSQL Password File
231235
========================
232236

postgresql/documentation/driver.txt

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,8 @@ successful connection, there is no need to pass anything to open::
110110

111111
For a complete list of keywords that `postgresql.open` can accept, see
112112
`Connection Keywords`_.
113-
For more information about the environment variables, see :doc:`Environment
114-
Variables</clientparameters>`.
115-
For more information about the ``pgpassfile``, see :doc:`PostgreSQL Password
116-
File</clientparameters>`.
117-
113+
For more information about the environment variables, see :ref:`pg_envvars`.
114+
For more information about the ``pgpassfile``, see :ref:`pg_passfile`.
118115

119116
`postgresql.driver.connect`
120117
---------------------------
@@ -185,7 +182,8 @@ a connection:
185182
Connect to a single IPv6 addressed host.
186183

187184
``postgresql.driver.default.unix(...)``
188-
Connect to a single unix domain socket.
185+
Connect to a single unix domain socket. Requires the ``unix`` keyword which
186+
must be an absolute path to the unix domain socket to connect to.
189187

190188
``host`` is the usual connector used to establish a connection::
191189

@@ -241,6 +239,11 @@ interfaces:
241239
``port``
242240
The port on the host to connect to.
243241

242+
``unix``
243+
The unix domain socket to connect to. Exclusive with ``host`` and ``port``.
244+
Expects a string containing the absolute path to the unix domain socket to
245+
connect to.
246+
244247
``settings``
245248
A dictionary or key-value pair sequence stating the parameters to give to the
246249
database. These settings are included in the startup packet, and should be

postgresql/driver/pq3.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2425,7 +2425,7 @@ def __init__(self, unix = None, **kw):
24252425
raise TypeError("'unix' is a required keyword and cannot be 'None'")
24262426
self.unix = unix
24272427
# constant socket connector
2428-
self._socketcreator = SocketCreator(
2428+
self._socketcreator = SocketFactory(
24292429
(socket.AF_UNIX, socket.SOCK_STREAM), self.unix
24302430
)
24312431
self._socketcreators = (self._socketcreator,)

postgresql/iri.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def structure(d, fieldproc = ri.unescape):
4242
if host.startswith('[') and host.endswith(']'):
4343
host = host[1:-1]
4444
if host.startswith('unix:'):
45-
cpd['unix'] = host[len('unix:'):]
45+
cpd['unix'] = host[len('unix:'):].replace(':','/')
4646
else:
4747
cpd['host'] = host[1:-1]
4848
else:
@@ -115,7 +115,7 @@ def construct(x, obscure_password = False):
115115

116116
port = None
117117
if 'unix' in x:
118-
host = '[unix:/' + x['unix'] + ']'
118+
host = '[unix:' + x['unix'].replace('/',':') + ']'
119119
# ignore port.. it's a mis-config.
120120
elif 'host' in x:
121121
host = x['host']

postgresql/test/test_connect.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
class test_connect(pg_unittest.TestCaseWithCluster):
1919
"""
20-
postgresql.driver *interface* tests.
20+
postgresql.driver connectivity tests
2121
"""
2222
ip6 = '::1'
2323
ip4 = '127.0.0.1'
@@ -29,10 +29,15 @@ def __init__(self, *args, **kw):
2929
super().__init__(*args,**kw)
3030
# 8.4 nixed this.
3131
self.do_crypt = self.cluster.installation.version_info < (8,4)
32+
self.do_unix = sys.platform != msw
3233

3334
def configure_cluster(self):
3435
super().configure_cluster()
35-
self.cluster.settings['log_min_messages'] = 'log'
36+
self.cluster.settings.update({
37+
'log_min_messages' : 'log',
38+
'unix_socket_directory' : self.cluster.data_directory,
39+
})
40+
3641
# Configure the hba file with the supported methods.
3742
with open(self.cluster.hba_file, 'w') as hba:
3843
hosts = ['0.0.0.0/0',]
@@ -47,6 +52,7 @@ def configure_cluster(self):
4752
m = m
4853
)])
4954
# trusted
55+
hba.writelines(["local all all trust\n"])
5056
hba.writelines(["host test trusted 0.0.0.0/0 trust\n"])
5157
if not msw:
5258
hba.writelines(["host test trusted 0::0/0 trust\n"])
@@ -344,5 +350,34 @@ def test_trusted_connect(self):
344350
with c:
345351
self.failUnlessEqual(c.prepare('select current_user').first(), 'trusted')
346352

353+
def test_Unix_connect(self):
354+
if msw:
355+
return
356+
unix_domain_socket = os.path.join(
357+
self.cluster.data_directory,
358+
'.s.PGSQL.' + self.cluster.settings['port']
359+
)
360+
C = pg_driver.default.unix(
361+
user = 'test',
362+
unix = unix_domain_socket,
363+
)
364+
with C() as c:
365+
self.failUnlessEqual(c.prepare('select 1').first(), 1)
366+
self.failUnlessEqual(c.client_address, None)
367+
368+
def test_pg_open_unix(self):
369+
if msw:
370+
return
371+
unix_domain_socket = os.path.join(
372+
self.cluster.data_directory,
373+
'.s.PGSQL.' + self.cluster.settings['port']
374+
)
375+
with pg_open(unix = unix_domain_socket, user = 'test') as c:
376+
self.failUnlessEqual(c.prepare('select 1').first(), 1)
377+
self.failUnlessEqual(c.client_address, None)
378+
with pg_open('pq://test@[unix:' + unix_domain_socket.replace('/',':') + ']') as c:
379+
self.failUnlessEqual(c.prepare('select 1').first(), 1)
380+
self.failUnlessEqual(c.client_address, None)
381+
347382
if __name__ == '__main__':
348383
unittest.main()

0 commit comments

Comments
 (0)