291
291
"directly instantiated.")
294
def _get_zopeless_connection_config(self, dbname, dbhost):
295
# This method exists for testability.
297
# This is only used by scripts, so we must connect to the read-write
298
# DB here -- that's why we use rw_main_master directly.
299
from canonical.database.postgresql import ConnectionString
300
main_connection_string = ConnectionString(dbconfig.rw_main_master)
302
# Override dbname and dbhost in the connection string if they
303
# have been passed in.
305
dbname = main_connection_string.dbname
307
main_connection_string.dbname = dbname
310
dbhost = main_connection_string.host
312
main_connection_string.host = dbhost
314
return str(main_connection_string), dbname, dbhost
317
def initZopeless(cls, dbname=None, dbhost=None, dbuser=None,
318
isolation=ISOLATION_LEVEL_DEFAULT):
320
main_connection_string, dbname, dbhost = (
321
cls._get_zopeless_connection_config(dbname, dbhost))
323
assert dbuser is not None, '''
324
dbuser is now required. All scripts must connect as unique
294
def initZopeless(cls, dbuser=None, isolation=ISOLATION_LEVEL_DEFAULT):
296
raise AssertionError(
297
"dbuser is now required. All scripts must connect as unique "
328
300
isolation_level = {
329
301
ISOLATION_LEVEL_AUTOCOMMIT: 'autocommit',
333
305
# Construct a config fragment:
334
306
overlay = dedent("""\
336
rw_main_master: %(main_connection_string)s
337
308
isolation_level: %(isolation_level)s
339
'isolation_level': isolation_level,
340
'main_connection_string': main_connection_string,
344
overlay += dedent("""\
347
""" % {'dbuser': dbuser})
313
isolation_level=isolation_level,
349
316
if cls._installed is not None:
350
317
if cls._config_overlay != overlay:
419
384
assert cls._installed is not None, (
420
385
"ZopelessTransactionManager not installed")
422
cls.initZopeless(cls._dbname, cls._dbhost, cls._dbuser, isolation)
387
cls.initZopeless(cls._dbuser, isolation)
781
746
transaction.commit()
784
def connect(user, dbname=None, isolation=ISOLATION_LEVEL_DEFAULT):
749
def connect(user=None, dbname=None, isolation=ISOLATION_LEVEL_DEFAULT):
785
750
"""Return a fresh DB-API connection to the MAIN MASTER database.
787
DEPRECATED - if needed, this should become a method on the Store.
789
Use None for the user to connect as the default PostgreSQL user.
790
This is not the default because the option should be rarely used.
752
Can be used without first setting up the Component Architecture,
753
unlike the usual stores.
792
755
Default database name is the one specified in the main configuration file.
794
con = psycopg2.connect(connect_string(user, dbname))
757
con = psycopg2.connect(connect_string(user=user, dbname=dbname))
795
758
con.set_isolation_level(isolation)
799
def connect_string(user, dbname=None):
762
def connect_string(user=None, dbname=None):
800
763
"""Return a PostgreSQL connection string.
802
765
Allows you to pass the generated connection details to external
803
766
programs like pg_dump or embed in slonik scripts.
805
from canonical import lp
807
768
# We must connect to the read-write DB here, so we use rw_main_master
809
770
from canonical.database.postgresql import ConnectionString
810
771
con_str = ConnectionString(dbconfig.rw_main_master)
811
772
if user is not None:
812
773
con_str.user = user
813
if lp.dbhost is not None:
814
con_str.host = lp.dbhost
815
if lp.dbport is not None:
816
con_str.port = lp.dbport
818
dbname = lp.get_dbname() # Note that lp.dbname may be None
819
774
if dbname is not None:
820
775
con_str.dbname = dbname
821
776
return str(con_str)