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() |
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", |