cubicweb/server/sqlutils.py
changeset 11417 5e5e224239c3
parent 11413 c172fa18565e
child 11767 432f87a63057
equal deleted inserted replaced
11416:9c2fbb872e91 11417:5e5e224239c3
   150                            skip_relations, skip_entities)
   150                            skip_relations, skip_entities)
   151     return stmts
   151     return stmts
   152 
   152 
   153 
   153 
   154 _SQL_DROP_ALL_USER_TABLES_FILTER_FUNCTION = re.compile('^(?!(sql|pg)_)').match
   154 _SQL_DROP_ALL_USER_TABLES_FILTER_FUNCTION = re.compile('^(?!(sql|pg)_)').match
       
   155 
       
   156 
   155 def sql_drop_all_user_tables(driver_or_helper, sqlcursor):
   157 def sql_drop_all_user_tables(driver_or_helper, sqlcursor):
   156     """Return ths sql to drop all tables found in the database system."""
   158     """Return ths sql to drop all tables found in the database system."""
   157     if not getattr(driver_or_helper, 'list_tables', None):
   159     if not getattr(driver_or_helper, 'list_tables', None):
   158         dbhelper = db.get_db_helper(driver_or_helper)
   160         dbhelper = db.get_db_helper(driver_or_helper)
   159     else:
   161     else:
   160         dbhelper = driver_or_helper
   162         dbhelper = driver_or_helper
   161 
   163 
   162     cmds = [dbhelper.sql_drop_sequence('entities_id_seq')]
   164     stmts = [dbhelper.sql_drop_sequence('entities_id_seq')]
   163     # for mssql, we need to drop views before tables
   165     # for mssql, we need to drop views before tables
   164     if hasattr(dbhelper, 'list_views'):
   166     if hasattr(dbhelper, 'list_views'):
   165         cmds += ['DROP VIEW %s;' % name
   167         stmts += ['DROP VIEW %s;' % name
   166                  for name in filter(_SQL_DROP_ALL_USER_TABLES_FILTER_FUNCTION, dbhelper.list_views(sqlcursor))]
   168                   for name in filter(_SQL_DROP_ALL_USER_TABLES_FILTER_FUNCTION,
   167     cmds += ['DROP TABLE %s;' % name
   169                                      dbhelper.list_views(sqlcursor))]
   168              for name in filter(_SQL_DROP_ALL_USER_TABLES_FILTER_FUNCTION, dbhelper.list_tables(sqlcursor))]
   170     stmts += ['DROP TABLE %s;' % name
   169     return '\n'.join(cmds)
   171               for name in filter(_SQL_DROP_ALL_USER_TABLES_FILTER_FUNCTION,
       
   172                                  dbhelper.list_tables(sqlcursor))]
       
   173     return stmts
   170 
   174 
   171 
   175 
   172 class ConnectionWrapper(object):
   176 class ConnectionWrapper(object):
   173     """handle connection to the system source, at some point associated to a
   177     """handle connection to the system source, at some point associated to a
   174     :class:`Session`
   178     :class:`Session`
   197             # bad state. Replace it by a new one.
   201             # bad state. Replace it by a new one.
   198             self.reconnect()
   202             self.reconnect()
   199 
   203 
   200     def close(self, i_know_what_i_do=False):
   204     def close(self, i_know_what_i_do=False):
   201         """close all connections in the set"""
   205         """close all connections in the set"""
   202         if i_know_what_i_do is not True: # unexpected closing safety belt
   206         if i_know_what_i_do is not True:  # unexpected closing safety belt
   203             raise RuntimeError('connections set shouldn\'t be closed')
   207             raise RuntimeError('connections set shouldn\'t be closed')
   204         try:
   208         try:
   205             self.cu.close()
   209             self.cu.close()
   206             self.cu = None
   210             self.cu = None
   207         except Exception:
   211         except Exception:
   214 
   218 
   215     # internals ###############################################################
   219     # internals ###############################################################
   216 
   220 
   217     def cnxset_freed(self):
   221     def cnxset_freed(self):
   218         """connections set is being freed from a session"""
   222         """connections set is being freed from a session"""
   219         pass # no nothing by default
   223         pass  # no nothing by default
   220 
   224 
   221     def reconnect(self):
   225     def reconnect(self):
   222         """reopen a connection for this source or all sources if none specified
   226         """reopen a connection for this source or all sources if none specified
   223         """
   227         """
   224         try:
   228         try:
   265     def cnx(self):
   269     def cnx(self):
   266         if self._cnx is None:
   270         if self._cnx is None:
   267             self._cnx = self._source.get_connection()
   271             self._cnx = self._source.get_connection()
   268             self._cu = self._cnx.cursor()
   272             self._cu = self._cnx.cursor()
   269         return self._cnx
   273         return self._cnx
       
   274 
   270     @cnx.setter
   275     @cnx.setter
   271     def cnx(self, value):
   276     def cnx(self, value):
   272         self._cnx = value
   277         self._cnx = value
   273 
   278 
   274     @property
   279     @property
   275     def cu(self):
   280     def cu(self):
   276         if self._cnx is None:
   281         if self._cnx is None:
   277             self._cnx = self._source.get_connection()
   282             self._cnx = self._source.get_connection()
   278             self._cu = self._cnx.cursor()
   283             self._cu = self._cnx.cursor()
   279         return self._cu
   284         return self._cu
       
   285 
   280     @cu.setter
   286     @cu.setter
   281     def cu(self, value):
   287     def cu(self, value):
   282         self._cu = value
   288         self._cu = value
   283 
   289 
   284 
   290 
   432                 if atype in converters:
   438                 if atype in converters:
   433                     # It is easier to modify preprocess_entity rather
   439                     # It is easier to modify preprocess_entity rather
   434                     # than add_entity (native) as this behavior
   440                     # than add_entity (native) as this behavior
   435                     # may also be used for update.
   441                     # may also be used for update.
   436                     value = converters[atype](value)
   442                     value = converters[atype](value)
   437                 elif atype == 'Password': # XXX could be done using a TYPE_CONVERTERS callback
   443                 elif atype == 'Password':  # XXX could be done using a TYPE_CONVERTERS callback
   438                     # if value is a Binary instance, this mean we got it
   444                     # if value is a Binary instance, this mean we got it
   439                     # from a query result and so it is already encrypted
   445                     # from a query result and so it is already encrypted
   440                     if isinstance(value, Binary):
   446                     if isinstance(value, Binary):
   441                         value = value.getvalue()
   447                         value = value.getvalue()
   442                     else:
   448                     else:
   443                         value = crypt_password(value)
   449                         value = crypt_password(value)
   444                     value = self._binary(value)
   450                     value = self._binary(value)
   445                 elif isinstance(value, Binary):
   451                 elif isinstance(value, Binary):
   446                     value = self._binary(value.getvalue())
   452                     value = self._binary(value.getvalue())
   447             attrs[SQL_PREFIX+str(attr)] = value
   453             attrs[SQL_PREFIX + str(attr)] = value
   448         attrs[SQL_PREFIX+'eid'] = entity.eid
   454         attrs[SQL_PREFIX + 'eid'] = entity.eid
   449         return attrs
   455         return attrs
   450 
   456 
   451     # these are overridden by set_log_methods below
   457     # these are overridden by set_log_methods below
   452     # only defining here to prevent pylint from complaining
   458     # only defining here to prevent pylint from complaining
   453     info = warning = error = critical = exception = debug = lambda msg,*a,**kw: None
   459     info = warning = error = critical = exception = debug = lambda msg, *a, **kw: None
   454 
   460 
   455 set_log_methods(SQLAdapterMixIn, getLogger('cubicweb.sqladapter'))
   461 set_log_methods(SQLAdapterMixIn, getLogger('cubicweb.sqladapter'))
   456 
   462 
   457 
   463 
   458 # connection initialization functions ##########################################
   464 # connection initialization functions ##########################################
   508     _install_sqlite_querier_patch()
   514     _install_sqlite_querier_patch()
   509 
   515 
   510     class group_concat(object):
   516     class group_concat(object):
   511         def __init__(self):
   517         def __init__(self):
   512             self.values = set()
   518             self.values = set()
       
   519 
   513         def step(self, value):
   520         def step(self, value):
   514             if value is not None:
   521             if value is not None:
   515                 self.values.add(value)
   522                 self.values.add(value)
       
   523 
   516         def finalize(self):
   524         def finalize(self):
   517             return ', '.join(text_type(v) for v in self.values)
   525             return ', '.join(text_type(v) for v in self.values)
   518 
   526 
   519     cnx.create_aggregate("GROUP_CONCAT", 1, group_concat)
   527     cnx.create_aggregate("GROUP_CONCAT", 1, group_concat)
   520 
   528 
   534     def limit_size2(text, maxsize):
   542     def limit_size2(text, maxsize):
   535         return _limit_size(text, maxsize)
   543         return _limit_size(text, maxsize)
   536     cnx.create_function("TEXT_LIMIT_SIZE", 2, limit_size2)
   544     cnx.create_function("TEXT_LIMIT_SIZE", 2, limit_size2)
   537 
   545 
   538     from logilab.common.date import strptime
   546     from logilab.common.date import strptime
       
   547 
   539     def weekday(ustr):
   548     def weekday(ustr):
   540         try:
   549         try:
   541             dt = strptime(ustr, '%Y-%m-%d %H:%M:%S')
   550             dt = strptime(ustr, '%Y-%m-%d %H:%M:%S')
   542         except:
   551         except:
   543             dt =  strptime(ustr, '%Y-%m-%d')
   552             dt = strptime(ustr, '%Y-%m-%d')
   544         # expect sunday to be 1, saturday 7 while weekday method return 0 for
   553         # expect sunday to be 1, saturday 7 while weekday method return 0 for
   545         # monday
   554         # monday
   546         return (dt.weekday() + 1) % 7
   555         return (dt.weekday() + 1) % 7
   547     cnx.create_function("WEEKDAY", 1, weekday)
   556     cnx.create_function("WEEKDAY", 1, weekday)
   548 
   557