Code

Ticket #3163: create_db_schema-trunk7512-qsrf_ready.diff

File create_db_schema-trunk7512-qsrf_ready.diff, 25.0 KB (added by honeyman, 6 years ago)

create_db_schema Meta option implementation (Django trunk 7512, qsrf-ready)

Line 
1Index: django/db/models/options.py
2===================================================================
3--- django/db/models/options.py (revision 7512)
4+++ django/db/models/options.py (working copy)
5@@ -22,7 +22,7 @@
6 DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering',
7                  'unique_together', 'permissions', 'get_latest_by',
8                  'order_with_respect_to', 'app_label', 'db_tablespace',
9-                 'abstract')
10+                 'abstract', 'create_db_schema')
11 
12 class Options(object):
13     def __init__(self, meta):
14@@ -37,6 +37,7 @@
15         self.get_latest_by = None
16         self.order_with_respect_to = None
17         self.db_tablespace = settings.DEFAULT_TABLESPACE
18+        self.create_db_schema = True
19         self.admin = None
20         self.meta = meta
21         self.pk = None
22Index: django/core/management/commands/syncdb.py
23===================================================================
24--- django/core/management/commands/syncdb.py   (revision 7512)
25+++ django/core/management/commands/syncdb.py   (working copy)
26@@ -57,24 +57,25 @@
27             app_name = app.__name__.split('.')[-2]
28             model_list = models.get_models(app)
29             for model in model_list:
30-                # Create the model's database table, if it doesn't already exist.
31-                if verbosity >= 2:
32-                    print "Processing %s.%s model" % (app_name, model._meta.object_name)
33-                if table_name_converter(model._meta.db_table) in tables:
34-                    continue
35-                sql, references = sql_model_create(model, self.style, seen_models)
36-                seen_models.add(model)
37-                created_models.add(model)
38-                for refto, refs in references.items():
39-                    pending_references.setdefault(refto, []).extend(refs)
40-                    if refto in seen_models:
41-                        sql.extend(sql_for_pending_references(refto, self.style, pending_references))
42-                sql.extend(sql_for_pending_references(model, self.style, pending_references))
43-                if verbosity >= 1:
44-                    print "Creating table %s" % model._meta.db_table
45-                for statement in sql:
46-                    cursor.execute(statement)
47-                tables.append(table_name_converter(model._meta.db_table))
48+                if model._meta.create_db_schema:
49+                    # Create the model's database table, if it doesn't already exist.
50+                    if verbosity >= 2:
51+                        print "Processing %s.%s model" % (app_name, model._meta.object_name)
52+                    if table_name_converter(model._meta.db_table) in tables:
53+                        continue
54+                    sql, references = sql_model_create(model, self.style, seen_models)
55+                    seen_models.add(model)
56+                    created_models.add(model)
57+                    for refto, refs in references.items():
58+                        pending_references.setdefault(refto, []).extend(refs)
59+                        if refto in seen_models:
60+                            sql.extend(sql_for_pending_references(refto, self.style, pending_references))
61+                    sql.extend(sql_for_pending_references(model, self.style, pending_references))
62+                    if verbosity >= 1:
63+                        print "Creating table %s" % model._meta.db_table
64+                    for statement in sql:
65+                        cursor.execute(statement)
66+                    tables.append(table_name_converter(model._meta.db_table))
67 
68         # Create the m2m tables. This must be done after all tables have been created
69         # to ensure that all referred tables will exist.
70@@ -121,19 +122,20 @@
71             app_name = app.__name__.split('.')[-2]
72             for model in models.get_models(app):
73                 if model in created_models:
74-                    index_sql = sql_indexes_for_model(model, self.style)
75-                    if index_sql:
76-                        if verbosity >= 1:
77-                            print "Installing index for %s.%s model" % (app_name, model._meta.object_name)
78-                        try:
79-                            for sql in index_sql:
80-                                cursor.execute(sql)
81-                        except Exception, e:
82-                            sys.stderr.write("Failed to install index for %s.%s model: %s" % \
83-                                                (app_name, model._meta.object_name, e))
84-                            transaction.rollback_unless_managed()
85-                        else:
86-                            transaction.commit_unless_managed()
87+                    if model._meta.create_db_schema:
88+                        index_sql = sql_indexes_for_model(model, self.style)
89+                        if index_sql:
90+                            if verbosity >= 1:
91+                                print "Installing index for %s.%s model" % (app_name, model._meta.object_name)
92+                            try:
93+                                for sql in index_sql:
94+                                    cursor.execute(sql)
95+                            except Exception, e:
96+                                sys.stderr.write("Failed to install index for %s.%s model: %s" % \
97+                                                    (app_name, model._meta.object_name, e))
98+                                transaction.rollback_unless_managed()
99+                            else:
100+                                transaction.commit_unless_managed()
101 
102         # Install the 'initial_data' fixture, using format discovery
103         from django.core.management import call_command
104Index: django/core/management/sql.py
105===================================================================
106--- django/core/management/sql.py       (revision 7512)
107+++ django/core/management/sql.py       (working copy)
108@@ -13,20 +13,24 @@
109     cursor = connection.cursor()
110     return get_introspection_module().get_table_list(cursor)
111 
112-def django_table_list(only_existing=False):
113+def django_table_list(only_existing=False, filter_not_generated_tables=False):
114     """
115     Returns a list of all table names that have associated Django models and
116     are in INSTALLED_APPS.
117 
118     If only_existing is True, the resulting list will only include the tables
119     that actually exist in the database.
120+
121+    If filter_not_generated_tables is True, then all tables with associated Django models
122+    which have Meta option create_db_schema=False will not be added to the list.
123     """
124     from django.db import models
125     tables = []
126     for app in models.get_apps():
127         for model in models.get_models(app):
128-            tables.append(model._meta.db_table)
129-            tables.extend([f.m2m_db_table() for f in model._meta.local_many_to_many])
130+            if (not filter_not_generated_tables) or (model._meta.create_db_schema):
131+                tables.append(model._meta.db_table)
132+                tables.extend([f.m2m_db_table() for f in model._meta.local_many_to_many])
133     if only_existing:
134         existing = table_list()
135         tables = [t for t in tables if t in existing]
136@@ -45,8 +49,13 @@
137         converter = lambda x: x
138     return set([m for m in all_models if converter(m._meta.db_table) in map(converter, table_list)])
139 
140-def sequence_list():
141-    "Returns a list of information about all DB sequences for all models in all apps."
142+def sequence_list(filter_not_generated_tables=False):
143+    """
144+    Returns a list of information about all DB sequences for all models in all apps.
145+
146+    If filter_not_generated_tables is True, then only the sequences for the Django models
147+    which have Meta option create_db_schema=False will be added to the list.
148+    """
149     from django.db import models
150 
151     apps = models.get_apps()
152@@ -54,10 +63,11 @@
153 
154     for app in apps:
155         for model in models.get_models(app):
156-            for f in model._meta.local_fields:
157-                if isinstance(f, models.AutoField):
158-                    sequence_list.append({'table': model._meta.db_table, 'column': f.column})
159-                    break # Only one AutoField is allowed per model, so don't bother continuing.
160+            if (not filter_not_generated_tables) or (model._meta.create_db_schema):
161+                for f in model._meta.local_fields:
162+                    if isinstance(f, models.AutoField):
163+                        sequence_list.append({'table': model._meta.db_table, 'column': f.column})
164+                        break # Only one AutoField is allowed per model, so don't bother continuing.
165 
166             for f in model._meta.local_many_to_many:
167                 sequence_list.append({'table': f.m2m_db_table(), 'column': None})
168@@ -158,8 +168,9 @@
169     for model in app_models:
170         if cursor and table_name_converter(model._meta.db_table) in table_names:
171             # Drop the table now
172-            output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
173-                style.SQL_TABLE(qn(model._meta.db_table))))
174+            if model._meta.create_db_schema:
175+                output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
176+                    style.SQL_TABLE(qn(model._meta.db_table))))
177             if connection.features.supports_constraints and model in references_to_delete:
178                 for rel_class, f in references_to_delete[model]:
179                     table = rel_class._meta.db_table
180@@ -167,11 +178,12 @@
181                     r_table = model._meta.db_table
182                     r_col = model._meta.get_field(f.rel.field_name).column
183                     r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))
184-                    output.append('%s %s %s %s;' % \
185-                        (style.SQL_KEYWORD('ALTER TABLE'),
186-                        style.SQL_TABLE(qn(table)),
187-                        style.SQL_KEYWORD(connection.ops.drop_foreignkey_sql()),
188-                        style.SQL_FIELD(truncate_name(r_name, connection.ops.max_name_length()))))
189+                    if rel_class._meta.create_db_schema:
190+                        output.append('%s %s %s %s;' % \
191+                            (style.SQL_KEYWORD('ALTER TABLE'),
192+                            style.SQL_TABLE(qn(table)),
193+                            style.SQL_KEYWORD(connection.ops.drop_foreignkey_sql()),
194+                            style.SQL_FIELD(truncate_name(r_name, connection.ops.max_name_length()))))
195                 del references_to_delete[model]
196             if model._meta.has_auto_field:
197                 ds = connection.ops.drop_sequence_sql(model._meta.db_table)
198@@ -208,16 +220,16 @@
199 def sql_flush(style, only_django=False):
200     """
201     Returns a list of the SQL statements used to flush the database.
202-   
203+
204     If only_django is True, then only table names that have associated Django
205     models and are in INSTALLED_APPS will be included.
206     """
207     from django.db import connection
208     if only_django:
209-        tables = django_table_list()
210+        tables = django_table_list(filter_not_generated_tables=True)
211     else:
212         tables = table_list()
213-    statements = connection.ops.sql_flush(style, tables, sequence_list())
214+    statements = connection.ops.sql_flush(style, tables, sequence_list(filter_not_generated_tables=True))
215     return statements
216 
217 def sql_custom(app):
218@@ -297,22 +309,24 @@
219         table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
220             ", ".join([style.SQL_FIELD(qn(opts.get_field(f).column)) for f in field_constraints]))
221 
222-    full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' (']
223-    for i, line in enumerate(table_output): # Combine and add commas.
224-        full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
225-    full_statement.append(')')
226-    if opts.db_tablespace and connection.features.supports_tablespaces:
227-        full_statement.append(connection.ops.tablespace_sql(opts.db_tablespace))
228-    full_statement.append(';')
229-    final_output.append('\n'.join(full_statement))
230+    # Now build up the CREATE TABLE section but only if the model requires it
231+    if opts.create_db_schema:
232+        full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' (']
233+        for i, line in enumerate(table_output): # Combine and add commas.
234+            full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
235+        full_statement.append(')')
236+        if opts.db_tablespace and connection.features.supports_tablespaces:
237+            full_statement.append(connection.ops.tablespace_sql(opts.db_tablespace))
238+        full_statement.append(';')
239+        final_output.append('\n'.join(full_statement))
240 
241-    if opts.has_auto_field:
242-        # Add any extra SQL needed to support auto-incrementing primary keys.
243-        auto_column = opts.auto_field.db_column or opts.auto_field.name
244-        autoinc_sql = connection.ops.autoinc_sql(opts.db_table, auto_column)
245-        if autoinc_sql:
246-            for stmt in autoinc_sql:
247-                final_output.append(stmt)
248+        if opts.has_auto_field:
249+            # Add any extra SQL needed to support auto-incrementing primary keys.
250+            auto_column = opts.auto_field.db_column or opts.auto_field.name
251+            autoinc_sql = connection.ops.autoinc_sql(opts.db_table, auto_column)
252+            if autoinc_sql:
253+                for stmt in autoinc_sql:
254+                    final_output.append(stmt)
255 
256     return final_output, pending_references
257 
258@@ -337,10 +351,11 @@
259                 # For MySQL, r_name must be unique in the first 64 characters.
260                 # So we are careful with character usage here.
261                 r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
262-                final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
263-                    (qn(r_table), truncate_name(r_name, connection.ops.max_name_length()),
264-                    qn(r_col), qn(table), qn(col),
265-                    connection.ops.deferrable_sql()))
266+                if rel_opts.create_db_schema:
267+                    final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
268+                        (qn(r_table), truncate_name(r_name, connection.ops.max_name_length()),
269+                        qn(r_col), qn(table), qn(col),
270+                        connection.ops.deferrable_sql()))
271             del pending_references[model]
272     return final_output
273 
274@@ -413,7 +428,7 @@
275             for r_table, r_col, table, col in deferred:
276                 r_name = '%s_refs_%s_%x' % (r_col, col,
277                         abs(hash((r_table, table))))
278-                final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' %
279+                final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' %
280                 (qn(r_table),
281                 truncate_name(r_name, connection.ops.max_name_length()),
282                 qn(r_col), qn(table), qn(col),
283@@ -460,22 +475,23 @@
284     output = []
285 
286     qn = connection.ops.quote_name
287-    for f in model._meta.local_fields:
288-        if f.db_index and not ((f.primary_key or f.unique) and connection.features.autoindexes_primary_keys):
289-            unique = f.unique and 'UNIQUE ' or ''
290-            tablespace = f.db_tablespace or model._meta.db_tablespace
291-            if tablespace and connection.features.supports_tablespaces:
292-                tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace)
293-            else:
294-                tablespace_sql = ''
295-            output.append(
296-                style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
297-                style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
298-                style.SQL_KEYWORD('ON') + ' ' + \
299-                style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + \
300-                "(%s)" % style.SQL_FIELD(qn(f.column)) + \
301-                "%s;" % tablespace_sql
302-            )
303+    if model._meta.create_db_schema:
304+        for f in model._meta.local_fields:
305+            if f.db_index and not ((f.primary_key or f.unique) and connection.features.autoindexes_primary_keys):
306+                unique = f.unique and 'UNIQUE ' or ''
307+                tablespace = f.db_tablespace or model._meta.db_tablespace
308+                if tablespace and connection.features.supports_tablespaces:
309+                    tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace)
310+                else:
311+                    tablespace_sql = ''
312+                output.append(
313+                    style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
314+                    style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
315+                    style.SQL_KEYWORD('ON') + ' ' + \
316+                    style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + \
317+                    "(%s)" % style.SQL_FIELD(qn(f.column)) + \
318+                    "%s;" % tablespace_sql
319+                )
320     return output
321 
322 def emit_post_sync_signal(created_models, verbosity, interactive):
323Index: tests/modeltests/create_db_schema/__init__.py
324===================================================================
325Index: tests/modeltests/create_db_schema/models.py
326===================================================================
327--- tests/modeltests/create_db_schema/models.py (revision 0)
328+++ tests/modeltests/create_db_schema/models.py (revision 0)
329@@ -0,0 +1,201 @@
330+"""
331+xx. create_db_schema
332+
333+Models can have a ``create_db_schema`` attribute, which specifies
334+whether the SQL code is generated for the table on various manage.py operations
335+or not.
336+"""
337+
338+from django.db import models
339+
340+"""
341+General test strategy:
342+* All tests are numbered (01, 02, 03... etc).
343+* Each test contains three models (A, B, C, followed with the number of test),
344+  containing both indexed and non-indexed fields (to verify sql_index),
345+  usual fields (model A), foreign keys (model B) and many-to-many fields (model C).
346+  D table is generated automatically as intermediate M2M one.
347+* The normal (default; create_db_schema = True) behaviour during the manage.py
348+  operations is not thoroughly checked; it is the duty of the appropriate tests
349+  for the primary functionality of these operations.
350+  The most attention is paid to whether the create_db_schema = False
351+  disables the SQL generation properly.
352+* The intermediate table for M2M relations is not ever verified explicitly,
353+  because it is not ever marked with create_db_schema explicitly.
354+"""
355+
356+# This dictionary maps the name of the model/SQL table (like 'A01')
357+# to the boolean specifying whether this name should appear in the final SQL
358+checks = {}
359+
360+
361+"""
362+01: create_db_schema is not set.
363+    In such case, it should be equal (by default) to True,
364+    and SQL is generated for all three models.
365+"""
366+checks['A01'] = True
367+checks['B01'] = True
368+checks['C01'] = True
369+
370+class A01(models.Model):
371+    class Meta: db_table = 'A01'
372+
373+    f_a = models.TextField(db_index = True)
374+    f_b = models.IntegerField()
375+
376+class B01(models.Model):
377+    class Meta: db_table = 'B01'
378+
379+    fk_a = models.ForeignKey(A01)
380+    f_a = models.TextField(db_index = True)
381+    f_b = models.IntegerField()
382+
383+class C01(models.Model):
384+    class Meta: db_table = 'C01'
385+
386+    mm_a = models.ManyToManyField(A01, db_table = 'D01')
387+    f_a = models.TextField(db_index = True)
388+    f_b = models.IntegerField()
389+
390+
391+"""
392+02: create_db_schema is set to True.
393+    SQL is generated for all three models.
394+"""
395+checks['A02'] = True
396+checks['B02'] = True
397+checks['C02'] = True
398+
399+class A02(models.Model):
400+    class Meta:
401+        db_table = 'A02'
402+        create_db_schema = True
403+
404+    f_a = models.TextField(db_index = True)
405+    f_b = models.IntegerField()
406+
407+class B02(models.Model):
408+    class Meta:
409+        db_table = 'B02'
410+        create_db_schema = True
411+
412+    fk_a = models.ForeignKey(A02)
413+    f_a = models.TextField(db_index = True)
414+    f_b = models.IntegerField()
415+
416+class C02(models.Model):
417+    class Meta:
418+        db_table = 'C02'
419+        create_db_schema = True
420+
421+    mm_a = models.ManyToManyField(A02, db_table = 'D02')
422+    f_a = models.TextField(db_index = True)
423+    f_b = models.IntegerField()
424+
425+
426+"""
427+03: create_db_schema is set to False.
428+    SQL is NOT generated for any of the three models.
429+"""
430+checks['A03'] = False
431+checks['B03'] = False
432+checks['C03'] = False
433+
434+class A03(models.Model):
435+    class Meta:
436+        db_table = 'A03'
437+        create_db_schema = False
438+
439+    f_a = models.TextField(db_index = True)
440+    f_b = models.IntegerField()
441+
442+class B03(models.Model):
443+    class Meta:
444+        db_table = 'B03'
445+        create_db_schema = False
446+
447+    fk_a = models.ForeignKey(A03)
448+    f_a = models.TextField(db_index = True)
449+    f_b = models.IntegerField()
450+
451+class C03(models.Model):
452+    class Meta:
453+        db_table = 'C03'
454+        create_db_schema = False
455+
456+    mm_a = models.ManyToManyField(A03, db_table = 'D03')
457+    f_a = models.TextField(db_index = True)
458+    f_b = models.IntegerField()
459+
460+
461+# We will use short names for these templates
462+sql_templates = {
463+       'create table': 'CREATE TABLE "%s"',
464+       'create index': 'CREATE INDEX "%s_f_a"',
465+       'drop table': 'DROP TABLE "%s"',
466+       'delete from': 'DELETE FROM "%s"'
467+}
468+
469+def get_failed_models(arr_sql, sql_template_names):
470+    """
471+    Find the models which should not be in the SQL but they are present,
472+    or they should be in the SQL but they are missing.
473+    """
474+    txt_sql = ' '.join(arr_sql)
475+    for (model, should_be_present) in checks.iteritems():
476+        # Do we expect to see the model name in the SQL text?
477+        for sql_template_name in sql_template_names:
478+            # We are interested not in just the model name like "A01",
479+            # but in the whole string like 'CREATE TABLE "A01"'
480+            # so we apply the model name to the template
481+            # to find out the expected string
482+            expected = (sql_templates[sql_template_name])%model
483+            if ((expected in txt_sql) != should_be_present):
484+                # Our expectations failed!
485+                yield 'The string %s %s present in SQL but it %s.'%(
486+                    expected,
487+                    {False: 'is not', True: 'is'}[expected in txt_sql],
488+                    {False: 'should not be', True: 'should be'}[should_be_present]
489+                    )
490+
491+
492+__test__ = {'API_TESTS':"""
493+>>> from django.db.models import get_app
494+>>> from django.core.management.sql import *
495+>>> from django.core.management.color import no_style
496+>>> import sys
497+
498+>>> myapp = get_app('create_db_schema')
499+>>> mystyle = no_style()
500+
501+# a. Verify sql_create
502+>>> list(get_failed_models( sql_create(myapp, mystyle), ['create table'] ))
503+[]
504+
505+# b. Verify sql_delete
506+>>> list(get_failed_models( sql_delete(myapp, mystyle), ['drop table'] ))
507+[]
508+
509+# c. Verify sql_reset
510+>>> list(get_failed_models( sql_reset(myapp, mystyle), ['drop table', 'create table', 'create index'] ))
511+[]
512+
513+# d. Verify sql_flush
514+>>> # sql_flush(mystyle)
515+>>> list(get_failed_models( sql_flush(mystyle), ['delete from'] ))
516+[]
517+
518+# e. Verify sql_custom
519+# No custom data provided, should not be no output.
520+>>> sql_custom(myapp)
521+[]
522+
523+# f. Verify sql_indexes
524+>>> list(get_failed_models( sql_indexes(myapp, mystyle), ['create index'] ))
525+[]
526+
527+# g. Verify sql_all
528+>>> list(get_failed_models( sql_all(myapp, mystyle), ['create table', 'create index'] ))
529+[]
530+"""}
531Index: AUTHORS
532===================================================================
533--- AUTHORS     (revision 7512)
534+++ AUTHORS     (working copy)
535@@ -382,6 +382,7 @@
536     ymasuda@ethercube.com
537     Jarek Zgoda <jarek.zgoda@gmail.com>
538     Cheng Zhang
539+    Alexander Myodov <amyodov@gmail.com>
540 
541 A big THANK YOU goes to:
542 
543Index: docs/model-api.txt
544===================================================================
545--- docs/model-api.txt  (revision 7512)
546+++ docs/model-api.txt  (working copy)
547@@ -1090,6 +1090,28 @@
548 that aren't allowed in Python variable names -- notably, the hyphen --
549 that's OK. Django quotes column and table names behind the scenes.
550 
551+``create_db_schema``
552+--------------------
553+
554+**New in Django development version**
555+
556+Marks this model as requiring SQL operations when calling ``manage.py``::
557+
558+    create_db_schema = False
559+
560+If this isn't given, Django will use ``create_db_schema = True``
561+what means that the operations like ``manage.py sqlreset``, ``manage.py syncdb``
562+and others will regenerate the appropriate table when needed.
563+If the option is set to False, the appropriate table will not be affected with
564+any SQL operations.
565+
566+This is useful for databases where some DB tables are controlled by Django models,
567+but some other DB tables and views are created via raw SQL and should not be affected
568+by any ``manage.py`` actions.
569+Note that if the initial SQL data is provided (see `Providing initial SQL
570+data`_ below), it still will be present in the output of
571+``sqlall``/``sqlcustom`` commands.
572+
573 ``db_tablespace``
574 -----------------
575