server/sources/native.py
changeset 2625 d6012db7b93e
parent 2620 de68f84b8f54
child 2627 d710278e0c1c
equal deleted inserted replaced
2624:c0b5b189190e 2625:d6012db7b93e
    26 from cubicweb import UnknownEid, AuthenticationError, Binary, server
    26 from cubicweb import UnknownEid, AuthenticationError, Binary, server
    27 from cubicweb.server.utils import crypt_password
    27 from cubicweb.server.utils import crypt_password
    28 from cubicweb.server.sqlutils import (SQL_PREFIX, SQLAdapterMixIn,
    28 from cubicweb.server.sqlutils import (SQL_PREFIX, SQLAdapterMixIn,
    29                                       sql_source_backup, sql_source_restore)
    29                                       sql_source_backup, sql_source_restore)
    30 from cubicweb.server.rqlannotation import set_qdata
    30 from cubicweb.server.rqlannotation import set_qdata
    31 from cubicweb.server.sources import AbstractSource
    31 from cubicweb.server.sources import AbstractSource, dbg_st_search, dbg_results
    32 from cubicweb.server.sources.rql2sql import SQLGenerator
    32 from cubicweb.server.sources.rql2sql import SQLGenerator
    33 
    33 
    34 
    34 
    35 ATTR_MAP = {}
    35 ATTR_MAP = {}
    36 NONSYSTEM_ETYPES = set()
    36 NONSYSTEM_ETYPES = set()
    56     def fetchall(self):
    56     def fetchall(self):
    57         return self.cu.fetchall()
    57         return self.cu.fetchall()
    58 
    58 
    59     def fetchone(self):
    59     def fetchone(self):
    60         return self.cu.fetchone()
    60         return self.cu.fetchone()
       
    61 
    61 
    62 
    62 def make_schema(selected, solution, table, typemap):
    63 def make_schema(selected, solution, table, typemap):
    63     """return a sql schema to store RQL query result"""
    64     """return a sql schema to store RQL query result"""
    64     sql = []
    65     sql = []
    65     varmap = {}
    66     varmap = {}
    72             sql.append('%s %s' % (name, typemap[ttype]))
    73             sql.append('%s %s' % (name, typemap[ttype]))
    73         except KeyError:
    74         except KeyError:
    74             # assert not schema(ttype).is_final()
    75             # assert not schema(ttype).is_final()
    75             sql.append('%s %s' % (name, typemap['Int']))
    76             sql.append('%s %s' % (name, typemap['Int']))
    76     return ','.join(sql), varmap
    77     return ','.join(sql), varmap
       
    78 
    77 
    79 
    78 def _modified_sql(table, etypes):
    80 def _modified_sql(table, etypes):
    79     # XXX protect against sql injection
    81     # XXX protect against sql injection
    80     if len(etypes) > 1:
    82     if len(etypes) > 1:
    81         restr = 'type IN (%s)' % ','.join("'%s'" % etype for etype in etypes)
    83         restr = 'type IN (%s)' % ','.join("'%s'" % etype for etype in etypes)
   302         a rql syntax tree and a solution dictionary mapping each used
   304         a rql syntax tree and a solution dictionary mapping each used
   303         variable to a possible type). If cachekey is given, the query
   305         variable to a possible type). If cachekey is given, the query
   304         necessary to fetch the results (but not the results themselves)
   306         necessary to fetch the results (but not the results themselves)
   305         may be cached using this key.
   307         may be cached using this key.
   306         """
   308         """
   307         if server.DEBUG & server.DBG_RQL:
   309         assert dbg_st_search(self.uri, union, varmap, args, cachekey)
   308             print 'RQL FOR NATIVE SOURCE %s: %s' % (self.uri, union.as_string())
       
   309             if varmap:
       
   310                 print 'using varmap', varmap
       
   311             if server.DEBUG & server.DBG_MORE:
       
   312                 print 'args', args
       
   313                 print 'cache key', cachekey
       
   314                 print 'solutions', ','.join(str(s.solutions) for s in union.children)
       
   315         # remember number of actually selected term (sql generation may append some)
   310         # remember number of actually selected term (sql generation may append some)
   316         if cachekey is None:
   311         if cachekey is None:
   317             self.no_cache += 1
   312             self.no_cache += 1
   318             # generate sql query if we are able to do so (not supported types...)
   313             # generate sql query if we are able to do so (not supported types...)
   319             sql, query_args = self._rql_sqlgen.generate(union, args, varmap)
   314             sql, query_args = self._rql_sqlgen.generate(union, args, varmap)
   334                 self.dbapi_module.InterfaceError):
   329                 self.dbapi_module.InterfaceError):
   335             # FIXME: better detection of deconnection pb
   330             # FIXME: better detection of deconnection pb
   336             self.info("request failed '%s' ... retry with a new cursor", sql)
   331             self.info("request failed '%s' ... retry with a new cursor", sql)
   337             session.pool.reconnect(self)
   332             session.pool.reconnect(self)
   338             cursor = self.doexec(session, sql, args)
   333             cursor = self.doexec(session, sql, args)
   339         res = self.process_result(cursor)
   334         results = self.process_result(cursor)
   340         if server.DEBUG & (server.DBG_SQL | server.DBG_RQL):
   335         assert dbg_results(results)
   341             print '------>', res
   336         return results
   342         return res
       
   343 
   337 
   344     def flying_insert(self, table, session, union, args=None, varmap=None):
   338     def flying_insert(self, table, session, union, args=None, varmap=None):
   345         """similar as .syntax_tree_search, but inserts data in the
   339         """similar as .syntax_tree_search, but inserts data in the
   346         temporary table (on-the-fly if possible, eg for the system
   340         temporary table (on-the-fly if possible, eg for the system
   347         source whose the given cursor come from). If not possible,
   341         source whose the given cursor come from). If not possible,
   348         inserts all data by calling .executemany().
   342         inserts all data by calling .executemany().
   349         """
   343         """
   350         if self.uri == 'system':
   344         assert dbg_st_search(
   351             if server.DEBUG & server.DBG_RQL:
   345             uri, union, varmap, args,
   352                 print 'FLYING RQL FOR SOURCE %s: %s', self.uri, union.as_string()
   346             prefix='ON THE FLY temp data insertion into %s from' % table)
   353                 if varmap:
   347         # generate sql queries if we are able to do so
   354                     print 'USING VARMAP', varmap
   348         sql, query_args = self._rql_sqlgen.generate(union, args, varmap)
   355                 if server.DEBUG & server.DBG_MORE:
   349         query = 'INSERT INTO %s %s' % (table, sql.encode(self.encoding))
   356                     print 'SOLUTIONS', ','.join(str(s.solutions) for s in union.children)
   350         self.doexec(session, query, self.merge_args(args, query_args))
   357             # generate sql queries if we are able to do so
       
   358             sql, query_args = self._rql_sqlgen.generate(union, args, varmap)
       
   359             query = 'INSERT INTO %s %s' % (table, sql.encode(self.encoding))
       
   360             self.doexec(session, query, self.merge_args(args, query_args))
       
   361         else:
       
   362             super(NativeSQLSource, self).flying_insert(table, session, union,
       
   363                                                        args, varmap)
       
   364 
   351 
   365     def _manual_insert(self, results, table, session):
   352     def _manual_insert(self, results, table, session):
   366         """insert given result into a temporary table on the system source"""
   353         """insert given result into a temporary table on the system source"""
       
   354         if server.DEBUG & server.DBG_RQL:
       
   355             print '  manual insertion of', res, 'into', table
   367         if not results:
   356         if not results:
   368             return
   357             return
   369         query_args = ['%%(%s)s' % i for i in xrange(len(results[0]))]
   358         query_args = ['%%(%s)s' % i for i in xrange(len(results[0]))]
   370         query = 'INSERT INTO %s VALUES(%s)' % (table, ','.join(query_args))
   359         query = 'INSERT INTO %s VALUES(%s)' % (table, ','.join(query_args))
   371         kwargs_list = []
   360         kwargs_list = []
   434         """Execute a query.
   423         """Execute a query.
   435         it's a function just so that it shows up in profiling
   424         it's a function just so that it shows up in profiling
   436         """
   425         """
   437         cursor = session.pool[self.uri]
   426         cursor = session.pool[self.uri]
   438         if server.DEBUG & server.DBG_SQL:
   427         if server.DEBUG & server.DBG_SQL:
   439             print 'exec', query, args
   428             cnx = session.pool.connection(self.uri)
       
   429             # getattr to get the actual connection if cnx is a ConnectionWrapper
       
   430             # instance
       
   431             print 'exec', query, args, getattr(cnx, '_cnx', cnx)
   440         try:
   432         try:
   441             # str(query) to avoid error if it's an unicode string
   433             # str(query) to avoid error if it's an unicode string
   442             cursor.execute(str(query), args)
   434             cursor.execute(str(query), args)
   443         except Exception, ex:
   435         except Exception, ex:
   444             self.critical("sql: %r\n args: %s\ndbms message: %r",
   436             self.critical("sql: %r\n args: %s\ndbms message: %r",