"Fossies" - the Fresh Open Source Software Archive

Member "PURELIB/trac/db/convert.py" (27 Aug 2019, 4836 Bytes) of package /windows/misc/Trac-1.4.win32.exe:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "convert.py": 1.3.5_vs_1.3.6.

    1 # -*- coding: utf-8 -*-
    2 #
    3 # Copyright (C) 2017-2019 Edgewall Software
    4 # All rights reserved.
    5 #
    6 # This software is licensed as described in the file COPYING, which
    7 # you should have received as part of this distribution. The terms
    8 # are also available at https://trac.edgewall.org/wiki/TracLicense.
    9 #
   10 # This software consists of voluntary contributions made by many
   11 # individuals. For the exact contribution history, see the revision
   12 # history and logs, available at https://trac.edgewall.org/log/.
   13 
   14 import re
   15 import sys
   16 
   17 from trac.db.api import DatabaseManager, get_column_names
   18 from trac.db import sqlite_backend
   19 from trac.util.text import printfout
   20 
   21 
   22 def copy_tables(src_env, dst_env, src_db, dst_db, src_dburi, dst_dburi):
   23     printfout("Copying tables:")
   24 
   25     if src_dburi.startswith('sqlite:'):
   26         src_db.cnx._eager = False  # avoid uses of eagar cursor
   27     src_cursor = src_db.cursor()
   28     if src_dburi.startswith('sqlite:'):
   29         if type(src_cursor.cursor) is not sqlite_backend.PyFormatCursor:
   30             raise AssertionError('src_cursor.cursor is %r' %
   31                                  src_cursor.cursor)
   32     src_tables = set(DatabaseManager(src_env).get_table_names())
   33     cursor = dst_db.cursor()
   34     dst_dbm = DatabaseManager(dst_env)
   35     tables = set(dst_dbm.get_table_names()) & src_tables
   36     sequences = set(dst_dbm.get_sequence_names())
   37     progress = sys.stdout.isatty() and sys.stderr.isatty()
   38     replace_cast = get_replace_cast(src_db, dst_db, src_dburi, dst_dburi)
   39 
   40     # speed-up copying data with SQLite database
   41     if dst_dburi.startswith('sqlite:'):
   42         sqlite_backend.set_synchronous(cursor, 'OFF')
   43         multirows_insert = sqlite_backend.sqlite_version >= (3, 7, 11)
   44         max_parameters = 999
   45     else:
   46         multirows_insert = True
   47         max_parameters = None
   48 
   49     def copy_table(db, cursor, table):
   50         src_cursor.execute('SELECT * FROM ' + src_db.quote(table))
   51         columns = get_column_names(src_cursor)
   52         n_rows = 100
   53         if multirows_insert and max_parameters:
   54             n_rows = min(n_rows, int(max_parameters // len(columns)))
   55         quoted_table = db.quote(table)
   56         holders = '(%s)' % ','.join(['%s'] * len(columns))
   57         count = 0
   58 
   59         cursor.execute('DELETE FROM ' + quoted_table)
   60         while True:
   61             rows = src_cursor.fetchmany(n_rows)
   62             if not rows:
   63                 break
   64             count += len(rows)
   65             if progress:
   66                 printfout("%d records\r  %s table... ", count, table,
   67                           newline=False)
   68             if replace_cast is not None and table == 'report':
   69                 rows = replace_report_query(rows, columns, replace_cast)
   70             query = 'INSERT INTO %s (%s) VALUES ' % \
   71                     (quoted_table, ','.join(map(db.quote, columns)))
   72             if multirows_insert:
   73                 cursor.execute(query + ','.join([holders] * len(rows)),
   74                                sum(rows, ()))
   75             else:
   76                 cursor.executemany(query + holders, rows)
   77 
   78         return count
   79 
   80     try:
   81         cursor = dst_db.cursor()
   82         for table in sorted(tables):
   83             printfout("  %s table... ", table, newline=False)
   84             count = copy_table(dst_db, cursor, table)
   85             printfout("%d records.", count)
   86         for table in tables & sequences:
   87             dst_db.update_sequence(cursor, table)
   88         dst_db.commit()
   89     except:
   90         dst_db.rollback()
   91         raise
   92 
   93 
   94 def get_replace_cast(src_db, dst_db, src_dburi, dst_dburi):
   95     if src_dburi.split(':', 1) == dst_dburi.split(':', 1):
   96         return None
   97 
   98     type_re = re.compile(r' AS ([^)]+)')
   99     def cast_type(db, type):
  100         match = type_re.search(db.cast('name', type))
  101         return match.group(1)
  102 
  103     type_maps = dict(filter(lambda src_dst: src_dst[0] != src_dst[1].lower(),
  104                             ((cast_type(src_db, t).lower(),
  105                               cast_type(dst_db, t))
  106                              for t in ('text', 'int', 'int64'))))
  107     if not type_maps:
  108         return None
  109 
  110     cast_re = re.compile(r'\bCAST\(\s*([^\s)]+)\s+AS\s+(%s)\s*\)' %
  111                          '|'.join(type_maps), re.IGNORECASE)
  112     def replace_cast(text):
  113         def replace(match):
  114             name, type = match.groups()
  115             return 'CAST(%s AS %s)' \
  116                    % (name, type_maps.get(type.lower(), type))
  117         return cast_re.sub(replace, text)
  118 
  119     return replace_cast
  120 
  121 
  122 def replace_report_query(rows, columns, replace_cast):
  123     idx = columns.index('query')
  124     def replace(row):
  125         row = list(row)
  126         row[idx] = replace_cast(row[idx])
  127         return tuple(row)
  128     return [replace(row) for row in rows]