Allow multiple collations per connection

This fixes collation for translated reports and multi-user access
for PostgreSQL.
This commit is contained in:
Nick Hall 2017-07-14 17:06:05 +01:00
parent 95d84573d4
commit b83283e081
12 changed files with 275 additions and 124 deletions

View File

@ -605,12 +605,15 @@ class DbReadBase:
"""
raise NotImplementedError
def get_citation_handles(self, sort_handles=False):
def get_citation_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Citation in
the database.
If sort_handles is True, the list is sorted by Citation title.
:param sort_handles: If True, the list is sorted by Citation title.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
"""
raise NotImplementedError
@ -624,24 +627,30 @@ class DbReadBase:
"""
raise NotImplementedError
def get_family_handles(self, sort_handles=False):
def get_family_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Family in
the database.
If sort_handles is True, the list is sorted by surnames.
:param sort_handles: If True, the list is sorted by surnames.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
.. warning:: For speed the keys are directly returned, so handles are
bytes type
"""
raise NotImplementedError
def get_media_handles(self, sort_handles=False):
def get_media_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Media in
the database.
If sort_handles is True, the list is sorted by title.
:param sort_handles: If True, the list is sorted by title.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
.. warning:: For speed the keys are directly returned, so handles are
bytes type
@ -658,24 +667,30 @@ class DbReadBase:
"""
raise NotImplementedError
def get_person_handles(self, sort_handles=False):
def get_person_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Person in
the database.
If sort_handles is True, the list is sorted by surnames.
:param sort_handles: If True, the list is sorted by surnames.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
.. warning:: For speed the keys are directly returned, so handles are
bytes type
"""
raise NotImplementedError
def get_place_handles(self, sort_handles=False):
def get_place_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Place in
the database.
If sort_handles is True, the list is sorted by Place title.
:param sort_handles: If True, the list is sorted by Place title.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
.. warning:: For speed the keys are directly returned, so handles are
bytes type
@ -692,24 +707,30 @@ class DbReadBase:
"""
raise NotImplementedError
def get_source_handles(self, sort_handles=False):
def get_source_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Source in
the database.
If sort_handles is True, the list is sorted by Source title.
:param sort_handles: If True, the list is sorted by Source title.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
.. warning:: For speed the keys are directly returned, so handles are
bytes type
"""
raise NotImplementedError
def get_tag_handles(self, sort_handles=False):
def get_tag_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Tag in
the database.
If sort_handles is True, the list is sorted by Tag name.
:param sort_handles: If True, the list is sorted by Tag name.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
.. warning:: For speed the keys are directly returned, so handles are
bytes type

View File

@ -68,6 +68,7 @@ from .dbconst import DBLOGNAME
from ..errors import HandleError
from ..utils.callback import Callback
from ..lib import Researcher
from ..const import GRAMPS_LOCALE as glocale
LOG = logging.getLogger(DBLOGNAME)
@ -531,12 +532,15 @@ class DummyDb(M_A_M_B("NewBaseClass", (DbReadBase, Callback, object,), {})):
LOG.warning("handle %s does not exist in the dummy database", handle)
raise HandleError('Handle %s not found' % handle)
def get_family_handles(self, sort_handles=False):
def get_family_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Family in
the database.
If sort_handles is True, the list is sorted by surnames.
:param sort_handles: If True, the list is sorted by surnames.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
"""
if not self.db_is_open:
LOG.warning("database is closed")
@ -584,12 +588,15 @@ class DummyDb(M_A_M_B("NewBaseClass", (DbReadBase, Callback, object,), {})):
LOG.warning("database is closed")
return []
def get_media_handles(self, sort_handles=False):
def get_media_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Media in
the database.
If sort_handles is True, the list is sorted by title.
:param sort_handles: If True, the list is sorted by title.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
"""
if not self.db_is_open:
LOG.warning("database is closed")
@ -834,12 +841,15 @@ class DummyDb(M_A_M_B("NewBaseClass", (DbReadBase, Callback, object,), {})):
LOG.warning("handle %s does not exist in the dummy database", handle)
raise HandleError('Handle %s not found' % handle)
def get_person_handles(self, sort_handles=False):
def get_person_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Person in
the database.
If sort_handles is True, the list is sorted by surnames.
:param sort_handles: If True, the list is sorted by surnames.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
"""
if not self.db_is_open:
LOG.warning("database is closed")
@ -892,12 +902,15 @@ class DummyDb(M_A_M_B("NewBaseClass", (DbReadBase, Callback, object,), {})):
LOG.warning("handle %s does not exist in the dummy database", handle)
raise HandleError('Handle %s not found' % handle)
def get_place_handles(self, sort_handles=False):
def get_place_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Place in
the database.
If sort_handles is True, the list is sorted by Place title.
:param sort_handles: If True, the list is sorted by Place title.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
"""
if not self.db_is_open:
LOG.warning("database is closed")
@ -1102,12 +1115,15 @@ class DummyDb(M_A_M_B("NewBaseClass", (DbReadBase, Callback, object,), {})):
LOG.warning("handle %s does not exist in the dummy database", handle)
raise HandleError('Handle %s not found' % handle)
def get_source_handles(self, sort_handles=False):
def get_source_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Source in
the database.
If sort_handles is True, the list is sorted by Source title.
:param sort_handles: If True, the list is sorted by Source title.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
"""
if not self.db_is_open:
LOG.warning("database is closed")
@ -1160,12 +1176,15 @@ class DummyDb(M_A_M_B("NewBaseClass", (DbReadBase, Callback, object,), {})):
LOG.warning("handle %s does not exist in the dummy database", handle)
raise HandleError('Handle %s not found' % handle)
def get_citation_handles(self, sort_handles=False):
def get_citation_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Citation in
the database.
If sort_handles is True, the list is sorted by Citation title.
:param sort_handles: If True, the list is sorted by Citation title.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
"""
if not self.db_is_open:
LOG.warning("database is closed")
@ -1209,12 +1228,15 @@ class DummyDb(M_A_M_B("NewBaseClass", (DbReadBase, Callback, object,), {})):
LOG.warning("tag name %s does not exist in the dummy database", val)
return None
def get_tag_handles(self, sort_handles=False):
def get_tag_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Tag in
the database.
If sort_handles is True, the list is sorted by Tag name.
:param sort_handles: If True, the list is sorted by Tag name.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
"""
if not self.db_is_open:
LOG.warning("database is closed")

View File

@ -33,6 +33,7 @@ Proxy class for the Gramps databases. Apply filter
from .proxybase import ProxyDbBase
from ..lib import (Date, Person, Name, Surname, NameOriginType, Family, Source,
Citation, Event, Media, Place, Repository, Note, Tag)
from ..const import GRAMPS_LOCALE as glocale
class FilterProxyDb(ProxyDbBase):
"""
@ -385,10 +386,15 @@ class FilterProxyDb(ProxyDbBase):
else:
return None
def get_person_handles(self, sort_handles=False):
def get_person_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Person in
the database. If sort_handles is True, the list is sorted by surnames
the database.
:param sort_handles: If True, the list is sorted by surnames.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
"""
# FIXME: plist is not a sorted list of handles
return list(self.plist)
@ -426,10 +432,15 @@ class FilterProxyDb(ProxyDbBase):
"""
return map(self.get_event_from_handle, self.elist)
def get_family_handles(self, sort_handles=False):
def get_family_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Family in
the database. If sort_handles is True, the list is sorted by surnames
the database.
:param sort_handles: If True, the list is sorted by surnames.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
"""
# FIXME: flist is not a sorted list of handles
return list(self.flist)

View File

@ -38,6 +38,7 @@ import types
from ..db.base import DbReadBase, DbWriteBase
from ..lib import (Citation, Event, Family, Media, Note, Person, Place,
Repository, Source, Tag)
from ..const import GRAMPS_LOCALE as glocale
class ProxyCursor:
"""
@ -199,26 +200,28 @@ class ProxyDbBase(DbReadBase):
return ProxyCursor(self.get_raw_tag_data,
self.get_tag_handles)
def get_person_handles(self, sort_handles=False):
def get_person_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Person in
the database. If sort_handles is True, the list is sorted by surnames
"""
if (self.db is not None) and self.db.is_open():
proxied = set(self.iter_person_handles())
all = self.basedb.get_person_handles(sort_handles=sort_handles)
all = self.basedb.get_person_handles(sort_handles=sort_handles,
locale=locale)
return [hdl for hdl in all if hdl in proxied]
else:
return []
def get_family_handles(self, sort_handles=False):
def get_family_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Family in
the database. If sort_handles is True, the list is sorted by surnames
"""
if (self.db is not None) and self.db.is_open():
proxied = set(self.iter_family_handles())
all = self.basedb.get_family_handles(sort_handles=sort_handles)
all = self.basedb.get_family_handles(sort_handles=sort_handles,
locale=locale)
return [hdl for hdl in all if hdl in proxied]
else:
return []
@ -233,7 +236,7 @@ class ProxyDbBase(DbReadBase):
else:
return []
def get_source_handles(self, sort_handles=False):
def get_source_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Source in
the database.
@ -243,7 +246,7 @@ class ProxyDbBase(DbReadBase):
else:
return []
def get_citation_handles(self, sort_handles=False):
def get_citation_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Citation in
the database.
@ -253,7 +256,7 @@ class ProxyDbBase(DbReadBase):
else:
return []
def get_place_handles(self, sort_handles=False):
def get_place_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Place in
the database.
@ -263,7 +266,7 @@ class ProxyDbBase(DbReadBase):
else:
return []
def get_media_handles(self, sort_handles=False):
def get_media_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Media in
the database.
@ -293,7 +296,7 @@ class ProxyDbBase(DbReadBase):
else:
return []
def get_tag_handles(self, sort_handles=False):
def get_tag_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Tag in
the database.

View File

@ -935,6 +935,12 @@ class GrampsLocale:
return string
return key
def get_collation(self):
"""
Return the collation without any character encoding.
"""
return self.collation.split('.')[0]
def strcoll(self, string1, string2):
"""
Given two localized strings, compare them and return -1 if

View File

@ -36,6 +36,7 @@ import os
from sys import maxsize
from operator import itemgetter
import ast
from functools import partial
try:
from bsddb3 import db
@ -1024,7 +1025,7 @@ class DbBsddbRead(DbReadBase, Callback):
"""
return [key.decode('utf-8') for key in table.keys(txn=self.txn)]
def get_person_handles(self, sort_handles=False):
def get_person_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Person in
the database.
@ -1034,11 +1035,12 @@ class DbBsddbRead(DbReadBase, Callback):
if self.db_is_open:
handle_list = self._all_handles(self.person_map)
if sort_handles:
handle_list.sort(key=self.__sortbyperson_key)
handle_list.sort(key=partial(self.__sortbyperson_key,
locale=locale))
return handle_list
return []
def get_place_handles(self, sort_handles=False):
def get_place_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Place in
the database.
@ -1049,11 +1051,12 @@ class DbBsddbRead(DbReadBase, Callback):
if self.db_is_open:
handle_list = self._all_handles(self.place_map)
if sort_handles:
handle_list.sort(key=self.__sortbyplace_key)
handle_list.sort(key=partial(self.__sortbyplace_key,
locale=locale))
return handle_list
return []
def get_source_handles(self, sort_handles=False):
def get_source_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Source in
the database.
@ -1063,11 +1066,12 @@ class DbBsddbRead(DbReadBase, Callback):
if self.db_is_open:
handle_list = self._all_handles(self.source_map)
if sort_handles:
handle_list.sort(key=self.__sortbysource_key)
handle_list.sort(key=partial(self.__sortbysource_key,
locale=locale))
return handle_list
return []
def get_citation_handles(self, sort_handles=False):
def get_citation_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Citation in
the database.
@ -1077,11 +1081,12 @@ class DbBsddbRead(DbReadBase, Callback):
if self.db_is_open:
handle_list = self._all_handles(self.citation_map)
if sort_handles:
handle_list.sort(key=self.__sortbycitation_key)
handle_list.sort(key=partial(self.__sortbycitation_key,
locale=locale))
return handle_list
return []
def get_media_handles(self, sort_handles=False):
def get_media_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Media in
the database.
@ -1091,7 +1096,8 @@ class DbBsddbRead(DbReadBase, Callback):
if self.db_is_open:
handle_list = self._all_handles(self.media_map)
if sort_handles:
handle_list.sort(key=self.__sortbymedia_key)
handle_list.sort(key=partial(self.__sortbymedia_key,
locale=locale))
return handle_list
return []
@ -1104,7 +1110,7 @@ class DbBsddbRead(DbReadBase, Callback):
return self._all_handles(self.event_map)
return []
def get_family_handles(self, sort_handles=False):
def get_family_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Family in
the database.
@ -1114,7 +1120,8 @@ class DbBsddbRead(DbReadBase, Callback):
if self.db_is_open:
handle_list = self._all_handles(self.family_map)
if sort_handles:
handle_list.sort(key=self.__sortbyfamily_key)
handle_list.sort(key=partial(self.__sortbyfamily_key,
locale=locale))
return handle_list
return []
@ -1136,7 +1143,7 @@ class DbBsddbRead(DbReadBase, Callback):
return self._all_handles(self.note_map)
return []
def get_tag_handles(self, sort_handles=False):
def get_tag_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Tag in
the database.
@ -1146,7 +1153,8 @@ class DbBsddbRead(DbReadBase, Callback):
if self.db_is_open:
handle_list = self._all_handles(self.tag_map)
if sort_handles:
handle_list.sort(key=self.__sortbytag_key)
handle_list.sort(key=partial(self.__sortbytag_key,
locale=locale))
return handle_list
return []
@ -1774,24 +1782,24 @@ class DbBsddbRead(DbReadBase, Callback):
"""
return self.__has_gramps_id(self.cid_trans, gramps_id)
def __sortbyperson_key(self, handle):
def __sortbyperson_key(self, handle, locale=glocale):
handle = handle.encode('utf-8')
return glocale.sort_key(find_fullname(handle,
self.person_map.get(handle)))
return locale.sort_key(find_fullname(handle,
self.person_map.get(handle)))
def __sortbyfamily_key(self, handle):
def __sortbyfamily_key(self, handle, locale=glocale):
handle = handle.encode('utf-8')
data = self.family_map.get(handle)
data2 = data[2]
data3 = data[3]
if data2: # father handle
data2 = data2.encode('utf-8')
return glocale.sort_key(find_fullname(data2,
self.person_map.get(data2)))
return locale.sort_key(find_fullname(data2,
self.person_map.get(data2)))
elif data3: # mother handle
data3 = data3.encode('utf-8')
return glocale.sort_key(find_fullname(data3,
self.person_map.get(data3)))
return locale.sort_key(find_fullname(data3,
self.person_map.get(data3)))
return ''
def __sortbyplace(self, first, second):
@ -1800,9 +1808,9 @@ class DbBsddbRead(DbReadBase, Callback):
return glocale.strcoll(self.place_map.get(first)[2],
self.place_map.get(second)[2])
def __sortbyplace_key(self, place):
def __sortbyplace_key(self, place, locale=glocale):
place = place.encode('utf-8')
return glocale.sort_key(self.place_map.get(place)[2])
return locale.sort_key(self.place_map.get(place)[2])
def __sortbysource(self, first, second):
first = first.encode('utf-8')
@ -1811,10 +1819,10 @@ class DbBsddbRead(DbReadBase, Callback):
source2 = str(self.source_map[second][2])
return glocale.strcoll(source1, source2)
def __sortbysource_key(self, key):
def __sortbysource_key(self, key, locale=glocale):
key = key.encode('utf-8')
source = str(self.source_map[key][2])
return glocale.sort_key(source)
return locale.sort_key(source)
def __sortbycitation(self, first, second):
first = first.encode('utf-8')
@ -1823,10 +1831,10 @@ class DbBsddbRead(DbReadBase, Callback):
citation2 = str(self.citation_map[second][3])
return glocale.strcoll(citation1, citation2)
def __sortbycitation_key(self, key):
def __sortbycitation_key(self, key, locale=glocale):
key = key.encode('utf-8')
citation = str(self.citation_map[key][3])
return glocale.sort_key(citation)
return locale.sort_key(citation)
def __sortbymedia(self, first, second):
first = first.encode('utf-8')
@ -1835,10 +1843,10 @@ class DbBsddbRead(DbReadBase, Callback):
media2 = self.media_map[second][4]
return glocale.strcoll(media1, media2)
def __sortbymedia_key(self, key):
def __sortbymedia_key(self, key, locale=glocale):
key = key.encode('utf-8')
media = self.media_map[key][4]
return glocale.sort_key(media)
return locale.sort_key(media)
def __sortbytag(self, first, second):
first = first.encode('utf-8')
@ -1847,10 +1855,10 @@ class DbBsddbRead(DbReadBase, Callback):
tag2 = self.tag_map[second][1]
return glocale.strcoll(tag1, tag2)
def __sortbytag_key(self, key):
def __sortbytag_key(self, key, locale=glocale):
key = key.encode('utf-8')
tag = self.tag_map[key][1]
return glocale.sort_key(tag)
return locale.sort_key(tag)
def set_mediapath(self, path):
"""Set the default media path for database."""

View File

@ -401,44 +401,57 @@ class DBAPI(DbGeneric):
else:
return key
def get_person_handles(self, sort_handles=False):
def get_person_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Person in
the database.
If sort_handles is True, the list is sorted by surnames.
:param sort_handles: If True, the list is sorted by surnames.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
"""
if sort_handles:
self.dbapi.execute("SELECT handle FROM person "
"ORDER BY surname COLLATE glocale")
if locale != glocale:
self.dbapi.check_collation(locale)
self.dbapi.execute('SELECT handle FROM person '
'ORDER BY surname '
'COLLATE "%s"' % locale.get_collation())
else:
self.dbapi.execute("SELECT handle FROM person")
rows = self.dbapi.fetchall()
return [row[0] for row in rows]
def get_family_handles(self, sort_handles=False):
def get_family_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Family in
the database.
If sort_handles is True, the list is sorted by surnames.
:param sort_handles: If True, the list is sorted by surnames.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
"""
if sort_handles:
sql = ("SELECT family.handle " +
"FROM family " +
"LEFT JOIN person AS father " +
"ON family.father_handle = father.handle " +
"LEFT JOIN person AS mother " +
"ON family.mother_handle = mother.handle " +
"ORDER BY (CASE WHEN father.handle IS NULL " +
"THEN mother.surname " +
"ELSE father.surname " +
"END), " +
"(CASE WHEN family.handle IS NULL " +
"THEN mother.given_name " +
"ELSE father.given_name " +
"END) " +
"COLLATE glocale")
if locale != glocale:
self.dbapi.check_collation(locale)
sql = ('SELECT family.handle ' +
'FROM family ' +
'LEFT JOIN person AS father ' +
'ON family.father_handle = father.handle ' +
'LEFT JOIN person AS mother ' +
'ON family.mother_handle = mother.handle ' +
'ORDER BY (CASE WHEN father.handle IS NULL ' +
'THEN mother.surname ' +
'ELSE father.surname ' +
'END), ' +
'(CASE WHEN family.handle IS NULL ' +
'THEN mother.given_name ' +
'ELSE father.given_name ' +
'END) ' +
'COLLATE "%s"' % locale.get_collation())
self.dbapi.execute(sql)
else:
self.dbapi.execute("SELECT handle FROM family")
@ -454,46 +467,67 @@ class DBAPI(DbGeneric):
rows = self.dbapi.fetchall()
return [row[0] for row in rows]
def get_citation_handles(self, sort_handles=False):
def get_citation_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Citation in
the database.
If sort_handles is True, the list is sorted by Citation title.
:param sort_handles: If True, the list is sorted by Citation title.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
"""
if sort_handles:
self.dbapi.execute("SELECT handle FROM citation "
"ORDER BY page COLLATE glocale")
if locale != glocale:
self.dbapi.check_collation(locale)
self.dbapi.execute('SELECT handle FROM citation '
'ORDER BY page '
'COLLATE "%s"' % locale.get_collation())
else:
self.dbapi.execute("SELECT handle FROM citation")
rows = self.dbapi.fetchall()
return [row[0] for row in rows]
def get_source_handles(self, sort_handles=False):
def get_source_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Source in
the database.
If sort_handles is True, the list is sorted by Source title.
:param sort_handles: If True, the list is sorted by Source title.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
"""
if sort_handles:
self.dbapi.execute("SELECT handle FROM source "
"ORDER BY title COLLATE glocale")
if locale != glocale:
self.dbapi.check_collation(locale)
self.dbapi.execute('SELECT handle FROM source '
'ORDER BY title '
'COLLATE "%s"' % locale.get_collation())
else:
self.dbapi.execute("SELECT handle from source")
rows = self.dbapi.fetchall()
return [row[0] for row in rows]
def get_place_handles(self, sort_handles=False):
def get_place_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Place in
the database.
If sort_handles is True, the list is sorted by Place title.
:param sort_handles: If True, the list is sorted by Place title.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
"""
if sort_handles:
self.dbapi.execute("SELECT handle FROM place "
"ORDER BY title COLLATE glocale")
if locale != glocale:
self.dbapi.check_collation(locale)
self.dbapi.execute('SELECT handle FROM place '
'ORDER BY title '
'COLLATE "%s"' % locale.get_collation())
else:
self.dbapi.execute("SELECT handle FROM place")
rows = self.dbapi.fetchall()
@ -508,16 +542,23 @@ class DBAPI(DbGeneric):
rows = self.dbapi.fetchall()
return [row[0] for row in rows]
def get_media_handles(self, sort_handles=False):
def get_media_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Media in
the database.
If sort_handles is True, the list is sorted by title.
:param sort_handles: If True, the list is sorted by title.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
"""
if sort_handles:
self.dbapi.execute("SELECT handle FROM media "
"ORDER BY desc COLLATE glocale")
if locale != glocale:
self.dbapi.check_collation(locale)
self.dbapi.execute('SELECT handle FROM media '
'ORDER BY desc '
'COLLATE "%s"' % locale.get_collation())
else:
self.dbapi.execute("SELECT handle FROM media")
rows = self.dbapi.fetchall()
@ -532,16 +573,23 @@ class DBAPI(DbGeneric):
rows = self.dbapi.fetchall()
return [row[0] for row in rows]
def get_tag_handles(self, sort_handles=False):
def get_tag_handles(self, sort_handles=False, locale=glocale):
"""
Return a list of database handles, one handle for each Tag in
the database.
If sort_handles is True, the list is sorted by Tag name.
:param sort_handles: If True, the list is sorted by Tag name.
:type sort_handles: bool
:param locale: The locale to use for collation.
:type locale: A GrampsLocale object.
"""
if sort_handles:
self.dbapi.execute("SELECT handle FROM tag "
"ORDER BY name COLLATE glocale")
if locale != glocale:
self.dbapi.check_collation(locale)
self.dbapi.execute('SELECT handle FROM tag '
'ORDER BY name '
'COLLATE "%s"' % locale.get_collation())
else:
self.dbapi.execute("SELECT handle FROM tag")
rows = self.dbapi.fetchall()

View File

@ -26,7 +26,6 @@
#-------------------------------------------------------------------------
import psycopg2
import re
import os
#-------------------------------------------------------------------------
#
@ -34,6 +33,7 @@ import os
#
#-------------------------------------------------------------------------
from gramps.gen.db.dbconst import ARRAYSIZE
from gramps.gen.const import GRAMPS_LOCALE as glocale
psycopg2.paramstyle = 'format'
@ -57,9 +57,24 @@ class Postgresql:
self.__connection = psycopg2.connect(*args, **kwargs)
self.__connection.autocommit = True
self.__cursor = self.__connection.cursor()
locale = os.environ.get('LANG', 'en_US.utf8')
self.execute("DROP COLLATION IF EXISTS glocale")
self.execute("CREATE COLLATION glocale (LOCALE = '%s')" % locale)
self.check_collation(glocale)
def check_collation(self, locale):
"""
Checks that a collation exists and if not creates it.
:param locale: Locale to be checked.
:param type: A GrampsLocale object.
"""
# Duplicating system collations works, but to delete them the schema
# must be specified, so get the current schema
self.execute('SELECT current_schema()')
current_schema, = self.fetchone()
collation = locale.get_collation()
self.execute('DROP COLLATION IF EXISTS "%s"."%s"'
% (current_schema, collation))
self.execute('CREATE COLLATION "%s"'
"(LOCALE = '%s')" % (collation, locale.collation))
def _hack_query(self, query):
query = query.replace("?", "%s")

View File

@ -83,8 +83,20 @@ class Sqlite:
self.log = logging.getLogger(".sqlite")
self.__connection = sqlite3.connect(*args, **kwargs)
self.__cursor = self.__connection.cursor()
self.__connection.create_collation("glocale", glocale.strcoll)
self.__connection.create_function("regexp", 2, regexp)
self.__collations = []
self.check_collation(glocale)
def check_collation(self, locale):
"""
Checks that a collation exists and if not creates it.
:param locale: Locale to be checked.
:param type: A GrampsLocale object.
"""
collation = locale.get_collation()
if collation not in self.__collations:
self.__connection.create_collation(collation, locale.strcoll)
def execute(self, *args, **kwargs):
"""

View File

@ -660,7 +660,8 @@ class FamilyGroup(Report):
self.dump_family(child_family_handle, (generation+1))
def write_report(self):
flist = self.db.get_family_handles(sort_handles=True)
flist = self.db.get_family_handles(sort_handles=True,
locale=self._locale)
if not self.filter:
fam_list = flist
else:

View File

@ -815,7 +815,8 @@ class IndivCompleteReport(Report):
def write_report(self):
""" write the report """
plist = self._db.get_person_handles(sort_handles=True)
plist = self._db.get_person_handles(sort_handles=True,
locale=self._locale)
if self.filter:
ind_list = self.filter.apply(self._db, plist, user=self._user)
else:

View File

@ -542,7 +542,8 @@ class TagReport(Report):
def write_media(self):
""" write the media associated with the tag """
mlist = self.database.get_media_handles(sort_handles=True)
mlist = self.database.get_media_handles(sort_handles=True,
locale=self._locale)
filter_class = GenericFilterFactory('Media')
a_filter = filter_class()
a_filter.add_rule(rules.media.HasTag([self.tag]))
@ -711,7 +712,8 @@ class TagReport(Report):
def write_sources(self):
""" write the sources associated with the tag """
slist = self.database.get_source_handles(sort_handles=True)
slist = self.database.get_source_handles(sort_handles=True,
locale=self._locale)
filter_class = GenericFilterFactory('Source')
a_filter = filter_class()
a_filter.add_rule(rules.source.HasTag([self.tag]))
@ -791,7 +793,8 @@ class TagReport(Report):
def write_citations(self):
""" write the citations associated with the tag """
clist = self.database.get_citation_handles(sort_handles=True)
clist = self.database.get_citation_handles(sort_handles=True,
locale=self._locale)
filter_class = GenericFilterFactory('Citation')
a_filter = filter_class()
a_filter.add_rule(rules.citation.HasTag([self.tag]))