5 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
5 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
6 """ |
6 """ |
7 __docformat__ = "restructuredtext en" |
7 __docformat__ = "restructuredtext en" |
8 |
8 |
9 from warnings import warn |
9 from warnings import warn |
10 from datetime import datetime, timedelta |
10 from datetime import datetime, date, timedelta |
11 |
11 |
12 from logilab.common.shellutils import ProgressBar |
12 from logilab.common.shellutils import ProgressBar |
13 from logilab.common import db |
13 from logilab.common import db |
14 from logilab.common.adbh import get_adv_func_helper |
14 from logilab.common.adbh import get_adv_func_helper |
15 from logilab.common.sqlgen import SQLGenerator |
15 from logilab.common.sqlgen import SQLGenerator |
16 |
16 |
17 from indexer import get_indexer |
17 from indexer import get_indexer |
18 |
18 |
19 from cubicweb import Binary, ConfigurationError |
19 from cubicweb import Binary, ConfigurationError |
|
20 from cubicweb.utils import todate, todatetime |
20 from cubicweb.common.uilib import remove_html_tags |
21 from cubicweb.common.uilib import remove_html_tags |
21 from cubicweb.server import SQL_CONNECT_HOOKS |
22 from cubicweb.server import SQL_CONNECT_HOOKS |
22 from cubicweb.server.utils import crypt_password |
23 from cubicweb.server.utils import crypt_password |
23 |
24 |
24 |
25 |
66 w(indexer.sql_grant_user(user)) |
67 w(indexer.sql_grant_user(user)) |
67 w('') |
68 w('') |
68 w(grant_schema(schema, user, set_owner, skip_entities=skip_entities, prefix=SQL_PREFIX)) |
69 w(grant_schema(schema, user, set_owner, skip_entities=skip_entities, prefix=SQL_PREFIX)) |
69 return '\n'.join(output) |
70 return '\n'.join(output) |
70 |
71 |
71 |
72 |
72 def sqlschema(schema, driver, text_index=True, |
73 def sqlschema(schema, driver, text_index=True, |
73 user=None, set_owner=False, |
74 user=None, set_owner=False, |
74 skip_relations=('has_text', 'identity'), skip_entities=()): |
75 skip_relations=('has_text', 'identity'), skip_entities=()): |
75 """return the system sql schema, according to the given parameters""" |
76 """return the system sql schema, according to the given parameters""" |
76 from yams.schema2sql import schema2sql |
77 from yams.schema2sql import schema2sql |
77 from cubicweb.server.sources import native |
78 from cubicweb.server.sources import native |
84 if text_index: |
85 if text_index: |
85 indexer = get_indexer(driver) |
86 indexer = get_indexer(driver) |
86 w(indexer.sql_init_fti()) |
87 w(indexer.sql_init_fti()) |
87 w('') |
88 w('') |
88 dbhelper = get_adv_func_helper(driver) |
89 dbhelper = get_adv_func_helper(driver) |
89 w(schema2sql(dbhelper, schema, prefix=SQL_PREFIX, |
90 w(schema2sql(dbhelper, schema, prefix=SQL_PREFIX, |
90 skip_entities=skip_entities, skip_relations=skip_relations)) |
91 skip_entities=skip_entities, skip_relations=skip_relations)) |
91 if dbhelper.users_support and user: |
92 if dbhelper.users_support and user: |
92 w('') |
93 w('') |
93 w(sqlgrants(schema, driver, user, text_index, set_owner, |
94 w(sqlgrants(schema, driver, user, text_index, set_owner, |
94 skip_relations, skip_entities)) |
95 skip_relations, skip_entities)) |
95 return '\n'.join(output) |
96 return '\n'.join(output) |
96 |
97 |
97 |
98 |
98 def sqldropschema(schema, driver, text_index=True, |
99 def sqldropschema(schema, driver, text_index=True, |
99 skip_relations=('has_text', 'identity'), skip_entities=()): |
100 skip_relations=('has_text', 'identity'), skip_entities=()): |
100 """return the sql to drop the schema, according to the given parameters""" |
101 """return the sql to drop the schema, according to the given parameters""" |
101 from yams.schema2sql import dropschema2sql |
102 from yams.schema2sql import dropschema2sql |
102 from cubicweb.server.sources import native |
103 from cubicweb.server.sources import native |
103 output = [] |
104 output = [] |
119 |
120 |
120 class SQLAdapterMixIn(object): |
121 class SQLAdapterMixIn(object): |
121 """Mixin for SQL data sources, getting a connection from a configuration |
122 """Mixin for SQL data sources, getting a connection from a configuration |
122 dictionary and handling connection locking |
123 dictionary and handling connection locking |
123 """ |
124 """ |
124 |
125 |
125 def __init__(self, source_config): |
126 def __init__(self, source_config): |
126 try: |
127 try: |
127 self.dbdriver = source_config['db-driver'].lower() |
128 self.dbdriver = source_config['db-driver'].lower() |
128 self.dbname = source_config['db-name'] |
129 self.dbname = source_config['db-name'] |
129 except KeyError: |
130 except KeyError: |
136 self.encoding = source_config.get('db-encoding', 'UTF-8') |
137 self.encoding = source_config.get('db-encoding', 'UTF-8') |
137 self.dbapi_module = db.get_dbapi_compliant_module(self.dbdriver) |
138 self.dbapi_module = db.get_dbapi_compliant_module(self.dbdriver) |
138 self.binary = self.dbapi_module.Binary |
139 self.binary = self.dbapi_module.Binary |
139 self.dbhelper = self.dbapi_module.adv_func_helper |
140 self.dbhelper = self.dbapi_module.adv_func_helper |
140 self.sqlgen = SQLGenerator() |
141 self.sqlgen = SQLGenerator() |
141 |
142 |
142 def get_connection(self, user=None, password=None): |
143 def get_connection(self, user=None, password=None): |
143 """open and return a connection to the database""" |
144 """open and return a connection to the database""" |
144 if user or self.dbuser: |
145 if user or self.dbuser: |
145 self.info('connecting to %s@%s for user %s', self.dbname, |
146 self.info('connecting to %s@%s for user %s', self.dbname, |
146 self.dbhost or 'localhost', user or self.dbuser) |
147 self.dbhost or 'localhost', user or self.dbuser) |
214 # from a query result and so it is already encrypted |
215 # from a query result and so it is already encrypted |
215 if isinstance(value, Binary): |
216 if isinstance(value, Binary): |
216 value = value.getvalue() |
217 value = value.getvalue() |
217 else: |
218 else: |
218 value = crypt_password(value) |
219 value = crypt_password(value) |
|
220 # XXX needed for sqlite but I don't think it is for other backends |
|
221 elif atype == 'Datetime' and isinstance(value, date): |
|
222 value = todatetime(value) |
|
223 elif atype == 'Date' and isinstance(value, datetime): |
|
224 value = todate(value) |
219 elif isinstance(value, Binary): |
225 elif isinstance(value, Binary): |
220 value = self.binary(value.getvalue()) |
226 value = self.binary(value.getvalue()) |
221 # XXX <3.2 bw compat |
227 # XXX <3.2 bw compat |
222 elif type(value) is DateTimeType: |
228 elif type(value) is DateTimeType: |
223 warn('found mx date time instance, please update to use datetime', |
229 warn('found mx date time instance, please update to use datetime', |
252 return ', '.join(self.values) |
258 return ', '.join(self.values) |
253 # renamed to GROUP_CONCAT in cubicweb 2.45, keep old name for bw compat for |
259 # renamed to GROUP_CONCAT in cubicweb 2.45, keep old name for bw compat for |
254 # some time |
260 # some time |
255 cnx.create_aggregate("CONCAT_STRINGS", 1, concat_strings) |
261 cnx.create_aggregate("CONCAT_STRINGS", 1, concat_strings) |
256 cnx.create_aggregate("GROUP_CONCAT", 1, concat_strings) |
262 cnx.create_aggregate("GROUP_CONCAT", 1, concat_strings) |
257 |
263 |
258 def _limit_size(text, maxsize, format='text/plain'): |
264 def _limit_size(text, maxsize, format='text/plain'): |
259 if len(text) < maxsize: |
265 if len(text) < maxsize: |
260 return text |
266 return text |
261 if format in ('text/html', 'text/xhtml', 'text/xml'): |
267 if format in ('text/html', 'text/xhtml', 'text/xml'): |
262 text = remove_html_tags(text) |
268 text = remove_html_tags(text) |