xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/sqlite3/dump.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker# Mimic the sqlite3 console shell's .dump command
2*cda5da8dSAndroid Build Coastguard Worker# Author: Paul Kippes <[email protected]>
3*cda5da8dSAndroid Build Coastguard Worker
4*cda5da8dSAndroid Build Coastguard Worker# Every identifier in sql is quoted based on a comment in sqlite
5*cda5da8dSAndroid Build Coastguard Worker# documentation "SQLite adds new keywords from time to time when it
6*cda5da8dSAndroid Build Coastguard Worker# takes on new features. So to prevent your code from being broken by
7*cda5da8dSAndroid Build Coastguard Worker# future enhancements, you should normally quote any identifier that
8*cda5da8dSAndroid Build Coastguard Worker# is an English language word, even if you do not have to."
9*cda5da8dSAndroid Build Coastguard Worker
10*cda5da8dSAndroid Build Coastguard Workerdef _iterdump(connection):
11*cda5da8dSAndroid Build Coastguard Worker    """
12*cda5da8dSAndroid Build Coastguard Worker    Returns an iterator to the dump of the database in an SQL text format.
13*cda5da8dSAndroid Build Coastguard Worker
14*cda5da8dSAndroid Build Coastguard Worker    Used to produce an SQL dump of the database.  Useful to save an in-memory
15*cda5da8dSAndroid Build Coastguard Worker    database for later restoration.  This function should not be called
16*cda5da8dSAndroid Build Coastguard Worker    directly but instead called from the Connection method, iterdump().
17*cda5da8dSAndroid Build Coastguard Worker    """
18*cda5da8dSAndroid Build Coastguard Worker
19*cda5da8dSAndroid Build Coastguard Worker    cu = connection.cursor()
20*cda5da8dSAndroid Build Coastguard Worker    yield('BEGIN TRANSACTION;')
21*cda5da8dSAndroid Build Coastguard Worker
22*cda5da8dSAndroid Build Coastguard Worker    # sqlite_master table contains the SQL CREATE statements for the database.
23*cda5da8dSAndroid Build Coastguard Worker    q = """
24*cda5da8dSAndroid Build Coastguard Worker        SELECT "name", "type", "sql"
25*cda5da8dSAndroid Build Coastguard Worker        FROM "sqlite_master"
26*cda5da8dSAndroid Build Coastguard Worker            WHERE "sql" NOT NULL AND
27*cda5da8dSAndroid Build Coastguard Worker            "type" == 'table'
28*cda5da8dSAndroid Build Coastguard Worker            ORDER BY "name"
29*cda5da8dSAndroid Build Coastguard Worker        """
30*cda5da8dSAndroid Build Coastguard Worker    schema_res = cu.execute(q)
31*cda5da8dSAndroid Build Coastguard Worker    sqlite_sequence = []
32*cda5da8dSAndroid Build Coastguard Worker    for table_name, type, sql in schema_res.fetchall():
33*cda5da8dSAndroid Build Coastguard Worker        if table_name == 'sqlite_sequence':
34*cda5da8dSAndroid Build Coastguard Worker            rows = cu.execute('SELECT * FROM "sqlite_sequence";').fetchall()
35*cda5da8dSAndroid Build Coastguard Worker            sqlite_sequence = ['DELETE FROM "sqlite_sequence"']
36*cda5da8dSAndroid Build Coastguard Worker            sqlite_sequence += [
37*cda5da8dSAndroid Build Coastguard Worker                f'INSERT INTO "sqlite_sequence" VALUES(\'{row[0]}\',{row[1]})'
38*cda5da8dSAndroid Build Coastguard Worker                for row in rows
39*cda5da8dSAndroid Build Coastguard Worker            ]
40*cda5da8dSAndroid Build Coastguard Worker            continue
41*cda5da8dSAndroid Build Coastguard Worker        elif table_name == 'sqlite_stat1':
42*cda5da8dSAndroid Build Coastguard Worker            yield('ANALYZE "sqlite_master";')
43*cda5da8dSAndroid Build Coastguard Worker        elif table_name.startswith('sqlite_'):
44*cda5da8dSAndroid Build Coastguard Worker            continue
45*cda5da8dSAndroid Build Coastguard Worker        # NOTE: Virtual table support not implemented
46*cda5da8dSAndroid Build Coastguard Worker        #elif sql.startswith('CREATE VIRTUAL TABLE'):
47*cda5da8dSAndroid Build Coastguard Worker        #    qtable = table_name.replace("'", "''")
48*cda5da8dSAndroid Build Coastguard Worker        #    yield("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"\
49*cda5da8dSAndroid Build Coastguard Worker        #        "VALUES('table','{0}','{0}',0,'{1}');".format(
50*cda5da8dSAndroid Build Coastguard Worker        #        qtable,
51*cda5da8dSAndroid Build Coastguard Worker        #        sql.replace("''")))
52*cda5da8dSAndroid Build Coastguard Worker        else:
53*cda5da8dSAndroid Build Coastguard Worker            yield('{0};'.format(sql))
54*cda5da8dSAndroid Build Coastguard Worker
55*cda5da8dSAndroid Build Coastguard Worker        # Build the insert statement for each row of the current table
56*cda5da8dSAndroid Build Coastguard Worker        table_name_ident = table_name.replace('"', '""')
57*cda5da8dSAndroid Build Coastguard Worker        res = cu.execute('PRAGMA table_info("{0}")'.format(table_name_ident))
58*cda5da8dSAndroid Build Coastguard Worker        column_names = [str(table_info[1]) for table_info in res.fetchall()]
59*cda5da8dSAndroid Build Coastguard Worker        q = """SELECT 'INSERT INTO "{0}" VALUES({1})' FROM "{0}";""".format(
60*cda5da8dSAndroid Build Coastguard Worker            table_name_ident,
61*cda5da8dSAndroid Build Coastguard Worker            ",".join("""'||quote("{0}")||'""".format(col.replace('"', '""')) for col in column_names))
62*cda5da8dSAndroid Build Coastguard Worker        query_res = cu.execute(q)
63*cda5da8dSAndroid Build Coastguard Worker        for row in query_res:
64*cda5da8dSAndroid Build Coastguard Worker            yield("{0};".format(row[0]))
65*cda5da8dSAndroid Build Coastguard Worker
66*cda5da8dSAndroid Build Coastguard Worker    # Now when the type is 'index', 'trigger', or 'view'
67*cda5da8dSAndroid Build Coastguard Worker    q = """
68*cda5da8dSAndroid Build Coastguard Worker        SELECT "name", "type", "sql"
69*cda5da8dSAndroid Build Coastguard Worker        FROM "sqlite_master"
70*cda5da8dSAndroid Build Coastguard Worker            WHERE "sql" NOT NULL AND
71*cda5da8dSAndroid Build Coastguard Worker            "type" IN ('index', 'trigger', 'view')
72*cda5da8dSAndroid Build Coastguard Worker        """
73*cda5da8dSAndroid Build Coastguard Worker    schema_res = cu.execute(q)
74*cda5da8dSAndroid Build Coastguard Worker    for name, type, sql in schema_res.fetchall():
75*cda5da8dSAndroid Build Coastguard Worker        yield('{0};'.format(sql))
76*cda5da8dSAndroid Build Coastguard Worker
77*cda5da8dSAndroid Build Coastguard Worker    # gh-79009: Yield statements concerning the sqlite_sequence table at the
78*cda5da8dSAndroid Build Coastguard Worker    # end of the transaction.
79*cda5da8dSAndroid Build Coastguard Worker    for row in sqlite_sequence:
80*cda5da8dSAndroid Build Coastguard Worker        yield('{0};'.format(row))
81*cda5da8dSAndroid Build Coastguard Worker
82*cda5da8dSAndroid Build Coastguard Worker    yield('COMMIT;')
83