Revision 3431
Added by Aaron Marcuse-Kubitza over 12 years ago
lib/sql_io.py | ||
---|---|---|
1 | 1 |
# Database import/export |
2 | 2 |
|
3 |
import operator |
|
4 |
|
|
3 | 5 |
import exc |
4 | 6 |
import dicts |
5 | 7 |
import sql |
... | ... | |
256 | 258 |
if mapping == {}: # need at least one column for INSERT SELECT |
257 | 259 |
mapping = {out_pkey: None} # ColDict will replace with default value |
258 | 260 |
|
259 |
# Create input joins from list of input tables |
|
260 | 261 |
in_tables_ = in_tables[:] # don't modify input! |
261 | 262 |
in_tables0 = in_tables_.pop(0) # first table is separate |
262 |
errors_table_ = errors_table(db, in_tables0) |
|
263 | 263 |
in_pkey = sql.pkey(db, in_tables0, recover=True) |
264 | 264 |
in_pkey_col = sql_gen.as_Col(in_pkey, in_tables0) |
265 |
|
|
266 |
# Determine if can use optimization for only literal values |
|
267 |
is_literals = not reduce(operator.or_, map(sql_gen.is_table_col, |
|
268 |
mapping.values())) |
|
269 |
is_literals_or_function = is_literals or is_function |
|
270 |
|
|
271 |
if is_literals: |
|
272 |
in_tables0 = None |
|
273 |
errors_table_ = None |
|
274 |
else: |
|
275 |
errors_table_ = errors_table(db, in_tables0) |
|
276 |
|
|
277 |
# Create input joins from list of input tables |
|
265 | 278 |
input_joins = [in_tables0]+[sql_gen.Join(v, |
266 | 279 |
{in_pkey: sql_gen.join_same_not_null}) for v in in_tables_] |
267 | 280 |
|
268 |
if into == None: |
|
269 |
into = into_table_name(out_table, in_tables0, mapping, is_func) |
|
270 |
into = sql_gen.as_Table(into) |
|
281 |
if not is_literals: |
|
282 |
if into == None: |
|
283 |
into = into_table_name(out_table, in_tables0, mapping, is_func) |
|
284 |
into = sql_gen.as_Table(into) |
|
285 |
|
|
286 |
# Set column sources |
|
287 |
in_cols = filter(sql_gen.is_table_col, mapping.values()) |
|
288 |
for col in in_cols: |
|
289 |
if col.table == in_tables0: col.set_srcs(sql_gen.src_self) |
|
290 |
|
|
291 |
log_debug('Joining together input tables into temp table') |
|
292 |
# Place in new table so don't modify input and for speed |
|
293 |
in_table = sql_gen.Table('in') |
|
294 |
mapping = dicts.join(mapping, sql.flatten(db, in_table, input_joins, |
|
295 |
in_cols, preserve=[in_pkey_col])) |
|
296 |
input_joins = [in_table] |
|
297 |
db.log_debug('Temp table: '+strings.as_tt(in_table.to_str(db)), level=2) |
|
271 | 298 |
|
272 |
# Set column sources |
|
273 |
in_cols = filter(sql_gen.is_table_col, mapping.values()) |
|
274 |
for col in in_cols: |
|
275 |
if col.table == in_tables0: col.set_srcs(sql_gen.src_self) |
|
276 |
|
|
277 |
log_debug('Joining together input tables into temp table') |
|
278 |
# Place in new table for speed and so don't modify input if values edited |
|
279 |
in_table = sql_gen.Table('in') |
|
280 |
mapping = dicts.join(mapping, sql.flatten(db, in_table, input_joins, |
|
281 |
in_cols, preserve=[in_pkey_col])) |
|
282 |
input_joins = [in_table] |
|
283 |
db.log_debug('Temp table: '+strings.as_tt(in_table.to_str(db)), level=2) |
|
284 |
|
|
285 | 299 |
mapping = sql_gen.ColDict(db, out_table, mapping) |
286 | 300 |
# after applying dicts.join() because that returns a plain dict |
287 | 301 |
|
... | ... | |
295 | 309 |
default = None |
296 | 310 |
|
297 | 311 |
# Save default values for all rows since in_table may have rows deleted |
298 |
if is_function: full_in_table = in_table |
|
312 |
if is_literals: pass |
|
313 |
elif is_function: full_in_table = in_table |
|
299 | 314 |
else: |
300 | 315 |
full_in_table = sql_gen.suffixed_table(in_table, '_full') |
301 | 316 |
full_in_table_cols = [in_pkey_col] |
... | ... | |
305 | 320 |
sql.run_query_into(db, sql.mk_select(db, in_table, full_in_table_cols, |
306 | 321 |
order_by=None), into=full_in_table, add_pkey_=True) |
307 | 322 |
|
308 |
pkeys_names = [in_pkey, out_pkey] |
|
309 |
pkeys_cols = [in_pkey_col, out_pkey_col] |
|
323 |
if not is_literals: |
|
324 |
pkeys_names = [in_pkey, out_pkey] |
|
325 |
pkeys_cols = [in_pkey_col, out_pkey_col] |
|
310 | 326 |
|
311 | 327 |
pkeys_table_exists_ref = [False] |
312 | 328 |
def insert_into_pkeys(joins, cols, **kw_args): |
... | ... | |
321 | 337 |
def mk_main_select(joins, cols): |
322 | 338 |
return sql.mk_select(db, joins, cols, limit=limit_ref[0], order_by=None) |
323 | 339 |
|
324 |
insert_in_table = in_table |
|
325 |
insert_in_tables = [insert_in_table] |
|
340 |
if is_literals: insert_in_table = None |
|
341 |
else: |
|
342 |
insert_in_table = in_table |
|
343 |
insert_in_tables = [insert_in_table] |
|
326 | 344 |
join_cols = sql_gen.ColDict(db, out_table) |
327 | 345 |
|
328 | 346 |
exc_strs = set() |
... | ... | |
371 | 389 |
sql.delete(db, insert_in_table, sql_gen.ColValueCond(in_col, value)) |
372 | 390 |
if value == None: not_null_cols.add(in_col) |
373 | 391 |
|
374 |
def insert_pkeys_table(which): |
|
375 |
return sql_gen.Table(sql_gen.concat(in_table.name, |
|
376 |
'_insert_'+which+'_pkeys')) |
|
377 |
insert_out_pkeys = insert_pkeys_table('out') |
|
378 |
insert_in_pkeys = insert_pkeys_table('in') |
|
392 |
if not is_literals: |
|
393 |
def insert_pkeys_table(which): |
|
394 |
return sql_gen.Table(sql_gen.concat(in_table.name, |
|
395 |
'_insert_'+which+'_pkeys')) |
|
396 |
insert_out_pkeys = insert_pkeys_table('out') |
|
397 |
insert_in_pkeys = insert_pkeys_table('in') |
|
379 | 398 |
|
380 | 399 |
# Do inserts and selects |
381 | 400 |
while True: |
382 | 401 |
if limit_ref[0] == 0: # special case |
402 |
if is_literals: return None |
|
383 | 403 |
log_debug('Creating an empty pkeys table') |
384 | 404 |
cur = sql.run_query_into(db, sql.mk_select(db, out_table, |
385 | 405 |
[out_pkey], order_by=None, limit=0), into=insert_out_pkeys) |
... | ... | |
400 | 420 |
if has_joins: |
401 | 421 |
insert_args.update(dict(ignore=True)) |
402 | 422 |
else: |
403 |
insert_args.update(dict(returning=out_pkey, |
|
404 |
into=insert_out_pkeys)) |
|
423 |
insert_args.update(dict(returning=out_pkey)) |
|
424 |
if not is_literals: |
|
425 |
insert_args.update(dict(into=insert_out_pkeys)) |
|
405 | 426 |
main_select = mk_main_select([insert_in_table], [sql_gen.with_table( |
406 | 427 |
c, insert_in_table) for c in mapping.values()]) |
407 | 428 |
|
408 | 429 |
try: |
409 | 430 |
cur = None |
410 | 431 |
if is_function: |
411 |
insert_into_pkeys(input_joins, [in_pkey_col, func_call], |
|
412 |
recover=True) |
|
432 |
if is_literals: cur = sql.select(db, fields=[func_call]) |
|
433 |
else: |
|
434 |
insert_into_pkeys(input_joins, [in_pkey_col, func_call], |
|
435 |
recover=True) |
|
413 | 436 |
else: |
414 | 437 |
cur = sql.insert_select(db, out_table, mapping.keys(), |
415 | 438 |
main_select, **insert_args) |
... | ... | |
443 | 466 |
log_debug('Ignoring existing rows, comparing on these columns:\n' |
444 | 467 |
+strings.as_inline_table(join_cols, ustr=col_ustr)) |
445 | 468 |
|
469 |
if is_literals: |
|
470 |
return sql.value(sql.select(db, out_table, [out_pkey_col], |
|
471 |
mapping, order_by=None)) |
|
472 |
|
|
446 | 473 |
# Uniquify input table to avoid internal duplicate keys |
447 | 474 |
insert_in_table = sql.distinct_table(db, insert_in_table, |
448 | 475 |
join_cols.values()) |
... | ... | |
477 | 504 |
if cur != None and row_ct_ref != None and cur.rowcount >= 0: |
478 | 505 |
row_ct_ref[0] += cur.rowcount |
479 | 506 |
|
480 |
if is_function: pass # pkeys table already created |
|
507 |
if is_literals_or_function: pass # pkeys table already created
|
|
481 | 508 |
elif has_joins: |
482 | 509 |
select_joins = input_joins+[sql_gen.Join(out_table, join_cols)] |
483 | 510 |
log_debug('Getting output table pkeys of existing/inserted rows') |
... | ... | |
503 | 530 |
|
504 | 531 |
sql.empty_temp(db, [insert_out_pkeys, insert_in_pkeys]) |
505 | 532 |
|
506 |
if not is_function: |
|
533 |
if not is_literals_or_function:
|
|
507 | 534 |
log_debug('Setting pkeys of missing rows to ' |
508 | 535 |
+strings.as_tt(repr(default))) |
509 | 536 |
missing_rows_joins = [full_in_table, sql_gen.Join(into, |
... | ... | |
514 | 541 |
sql_gen.NamedCol(out_pkey, default)]) |
515 | 542 |
# otherwise, there is already an entry for every row |
516 | 543 |
|
517 |
assert (sql.table_row_count(db, into) |
|
518 |
== sql.table_row_count(db, full_in_table)) |
|
519 |
|
|
520 |
sql.empty_temp(db, insert_in_tables+[full_in_table]) |
|
521 |
|
|
522 |
srcs = [] |
|
523 |
if is_func: srcs = sql_gen.cols_srcs(in_cols) |
|
524 |
return sql_gen.Col(out_pkey, into, srcs) |
|
544 |
if is_literals: return sql.value(cur) |
|
545 |
else: |
|
546 |
assert (sql.table_row_count(db, into) |
|
547 |
== sql.table_row_count(db, full_in_table)) |
|
548 |
|
|
549 |
sql.empty_temp(db, insert_in_tables+[full_in_table]) |
|
550 |
|
|
551 |
srcs = [] |
|
552 |
if is_func: srcs = sql_gen.cols_srcs(in_cols) |
|
553 |
return sql_gen.Col(out_pkey, into, srcs) |
Also available in: Unified diff
sql_io.py: put_table(): Added optimization for only literal values, which does the same operations as put() but with the additional error handling of put_table()