183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Mimic the sqlite3 console shell's .dump command
283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Author: Paul Kippes <kippesp@gmail.com>
383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Every identifier in sql is quoted based on a comment in sqlite
583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# documentation "SQLite adds new keywords from time to time when it
683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# takes on new features. So to prevent your code from being broken by
783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# future enhancements, you should normally quote any identifier that
883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# is an English language word, even if you do not have to."
983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
1083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef _iterdump(connection):
1183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    """
1283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    Returns an iterator to the dump of the database in an SQL text format.
1383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
1483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    Used to produce an SQL dump of the database.  Useful to save an in-memory
1583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    database for later restoration.  This function should not be called
1683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    directly but instead called from the Connection method, iterdump().
1783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    """
1883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
1983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    cu = connection.cursor()
2083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    yield('BEGIN TRANSACTION;')
2183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
2283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    # sqlite_master table contains the SQL CREATE statements for the database.
2383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    q = """
2483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        SELECT "name", "type", "sql"
2583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        FROM "sqlite_master"
2683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            WHERE "sql" NOT NULL AND
2783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            "type" == 'table'
2883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            ORDER BY "name"
2983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        """
3083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    schema_res = cu.execute(q)
3183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    for table_name, type, sql in schema_res.fetchall():
3283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if table_name == 'sqlite_sequence':
3383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            yield('DELETE FROM "sqlite_sequence";')
3483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        elif table_name == 'sqlite_stat1':
3583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            yield('ANALYZE "sqlite_master";')
3683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        elif table_name.startswith('sqlite_'):
3783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            continue
3883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # NOTE: Virtual table support not implemented
3983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        #elif sql.startswith('CREATE VIRTUAL TABLE'):
4083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        #    qtable = table_name.replace("'", "''")
4183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        #    yield("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"\
4283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        #        "VALUES('table','{0}','{0}',0,'{1}');".format(
4383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        #        qtable,
4483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        #        sql.replace("''")))
4583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        else:
4683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            yield('%s;' % sql)
4783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
4883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # Build the insert statement for each row of the current table
4983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        table_name_ident = table_name.replace('"', '""')
5083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        res = cu.execute('PRAGMA table_info("{0}")'.format(table_name_ident))
5183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        column_names = [str(table_info[1]) for table_info in res.fetchall()]
5283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        q = """SELECT 'INSERT INTO "{0}" VALUES({1})' FROM "{0}";""".format(
5383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            table_name_ident,
5483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            ",".join("""'||quote("{0}")||'""".format(col.replace('"', '""')) for col in column_names))
5583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        query_res = cu.execute(q)
5683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        for row in query_res:
5783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            yield("%s;" % row[0])
5883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
5983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    # Now when the type is 'index', 'trigger', or 'view'
6083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    q = """
6183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        SELECT "name", "type", "sql"
6283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        FROM "sqlite_master"
6383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            WHERE "sql" NOT NULL AND
6483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            "type" IN ('index', 'trigger', 'view')
6583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        """
6683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    schema_res = cu.execute(q)
6783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    for name, type, sql in schema_res.fetchall():
6883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        yield('%s;' % sql)
6983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
7083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    yield('COMMIT;')
71