Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #121 -- Django now quotes all names in SQL queries. Also added …

…unit tests to confirm. Thanks, Robin Munn and Sune.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@1224 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit f6bf41e59ac032c253e3b4e1b267010c6d456a26 1 parent 6e40d8c
Adrian Holovaty authored November 14, 2005
6  django/bin/daily_cleanup.py
@@ -7,8 +7,10 @@
7 7
 def clean_up():
8 8
     # Clean up old database records
9 9
     cursor = db.cursor()
10  
-    cursor.execute("DELETE FROM core_sessions WHERE expire_date < NOW()")
11  
-    cursor.execute("DELETE FROM registration_challenges WHERE request_date < NOW() - INTERVAL '1 week'")
  10
+    cursor.execute("DELETE FROM %s WHERE %s < NOW()" % \
  11
+        (db.quote_name('core_sessions'), db.quote_name('expire_date')))
  12
+    cursor.execute("DELETE FROM %s WHERE %s < NOW() - INTERVAL '1 week'" % \
  13
+        (db.quote_name('registration_challenges'), db.quote_name('request_date')))
12 14
     db.commit()
13 15
 
14 16
 if __name__ == "__main__":
4  django/core/db/backends/ado_mssql.py
@@ -149,8 +149,8 @@ def get_relations(cursor, table_name):
149 149
     'NullBooleanField':  'bit',
150 150
     'OneToOneField':     'int',
151 151
     'PhoneNumberField':  'varchar(20)',
152  
-    'PositiveIntegerField': 'int CONSTRAINT [CK_int_pos_%(name)s] CHECK ([%(name)s] > 0)',
153  
-    'PositiveSmallIntegerField': 'smallint CONSTRAINT [CK_smallint_pos_%(name)s] CHECK ([%(name)s] > 0)',
  152
+    'PositiveIntegerField': 'int CONSTRAINT [CK_int_pos_%(column)s] CHECK ([%(column)s] > 0)',
  153
+    'PositiveSmallIntegerField': 'smallint CONSTRAINT [CK_smallint_pos_%(column)s] CHECK ([%(column)s] > 0)',
154 154
     'SlugField':         'varchar(50)',
155 155
     'SmallIntegerField': 'smallint',
156 156
     'TextField':         'text',
4  django/core/db/backends/postgresql.py
@@ -170,8 +170,8 @@ def get_relations(cursor, table_name):
170 170
     'NullBooleanField':  'boolean',
171 171
     'OneToOneField':     'integer',
172 172
     'PhoneNumberField':  'varchar(20)',
173  
-    'PositiveIntegerField': 'integer CHECK (%(name)s >= 0)',
174  
-    'PositiveSmallIntegerField': 'smallint CHECK (%(name)s >= 0)',
  173
+    'PositiveIntegerField': 'integer CHECK (%(column)s >= 0)',
  174
+    'PositiveSmallIntegerField': 'smallint CHECK (%(column)s >= 0)',
175 175
     'SlugField':         'varchar(50)',
176 176
     'SmallIntegerField': 'smallint',
177 177
     'TextField':         'text',
126  django/core/management.py
@@ -19,7 +19,10 @@
19 19
 PROJECT_TEMPLATE_DIR = os.path.join(django.__path__[0], 'conf', '%s_template')
20 20
 
21 21
 def _get_packages_insert(app_label):
22  
-    return "INSERT INTO packages (label, name) VALUES ('%s', '%s');" % (app_label, app_label)
  22
+    from django.core.db import db
  23
+    return "INSERT INTO %s (%s, %s) VALUES ('%s', '%s');" % \
  24
+        (db.quote_name('packages'), db.quote_name('label'), db.quote_name('name'),
  25
+        app_label, app_label)
23 26
 
24 27
 def _get_permission_codename(action, opts):
25 28
     return '%s_%s' % (action, opts.object_name.lower())
@@ -33,12 +36,16 @@ def _get_all_permissions(opts):
33 36
     return perms + list(opts.permissions)
34 37
 
35 38
 def _get_permission_insert(name, codename, opts):
36  
-    return "INSERT INTO auth_permissions (name, package, codename) VALUES ('%s', '%s', '%s');" % \
37  
-        (name.replace("'", "''"), opts.app_label, codename)
  39
+    from django.core.db import db
  40
+    return "INSERT INTO %s (%s, %s, %s) VALUES ('%s', '%s', '%s');" % \
  41
+        (db.quote_name('auth_permissions'), db.quote_name('name'), db.quote_name('package'),
  42
+        db.quote_name('codename'), name.replace("'", "''"), opts.app_label, codename)
38 43
 
39 44
 def _get_contenttype_insert(opts):
40  
-    return "INSERT INTO content_types (name, package, python_module_name) VALUES ('%s', '%s', '%s');" % \
41  
-        (opts.verbose_name, opts.app_label, opts.module_name)
  45
+    from django.core.db import db
  46
+    return "INSERT INTO %s (%s, %s, %s) VALUES ('%s', '%s', '%s');" % \
  47
+        (db.quote_name('content_types'), db.quote_name('name'), db.quote_name('package'),
  48
+        db.quote_name('python_module_name'), opts.verbose_name, opts.app_label, opts.module_name)
42 49
 
43 50
 def _is_valid_dir_name(s):
44 51
     return bool(re.search(r'^\w+$', s))
@@ -64,7 +71,7 @@ def get_sql_create(mod):
64 71
                 data_type = f.get_internal_type()
65 72
             col_type = db.DATA_TYPES[data_type]
66 73
             if col_type is not None:
67  
-                field_output = [f.column, col_type % rel_field.__dict__]
  74
+                field_output = [db.db.quote_name(f.column), col_type % rel_field.__dict__]
68 75
                 field_output.append('%sNULL' % (not f.null and 'NOT ' or ''))
69 76
                 if f.unique:
70 77
                     field_output.append('UNIQUE')
@@ -72,14 +79,16 @@ def get_sql_create(mod):
72 79
                     field_output.append('PRIMARY KEY')
73 80
                 if f.rel:
74 81
                     field_output.append('REFERENCES %s (%s)' % \
75  
-                        (f.rel.to.db_table, f.rel.to.get_field(f.rel.field_name).column))
  82
+                        (db.db.quote_name(f.rel.to.db_table),
  83
+                        db.db.quote_name(f.rel.to.get_field(f.rel.field_name).column)))
76 84
                 table_output.append(' '.join(field_output))
77 85
         if opts.order_with_respect_to:
78  
-            table_output.append('_order %s NULL' % db.DATA_TYPES['IntegerField'])
  86
+            table_output.append('%s %s NULL' % (db.db.quote_name('_order'), db.DATA_TYPES['IntegerField']))
79 87
         for field_constraints in opts.unique_together:
80  
-            table_output.append('UNIQUE (%s)' % ", ".join([opts.get_field(f).column for f in field_constraints]))
  88
+            table_output.append('UNIQUE (%s)' % \
  89
+                ", ".join([db.db.quote_name(opts.get_field(f).column) for f in field_constraints]))
81 90
 
82  
-        full_statement = ['CREATE TABLE %s (' % opts.db_table]
  91
+        full_statement = ['CREATE TABLE %s (' % db.db.quote_name(opts.db_table)]
83 92
         for i, line in enumerate(table_output): # Combine and add commas.
84 93
             full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
85 94
         full_statement.append(');')
@@ -88,13 +97,21 @@ def get_sql_create(mod):
88 97
     for klass in mod._MODELS:
89 98
         opts = klass._meta
90 99
         for f in opts.many_to_many:
91  
-            table_output = ['CREATE TABLE %s (' % f.get_m2m_db_table(opts)]
92  
-            table_output.append('    id %s NOT NULL PRIMARY KEY,' % db.DATA_TYPES['AutoField'])
93  
-            table_output.append('    %s_id %s NOT NULL REFERENCES %s (%s),' % \
94  
-                (opts.object_name.lower(), db.DATA_TYPES[get_rel_data_type(opts.pk)] % opts.pk.__dict__, opts.db_table, opts.pk.column))
95  
-            table_output.append('    %s_id %s NOT NULL REFERENCES %s (%s),' % \
96  
-                (f.rel.to.object_name.lower(), db.DATA_TYPES[get_rel_data_type(f.rel.to.pk)] % f.rel.to.pk.__dict__, f.rel.to.db_table, f.rel.to.pk.column))
97  
-            table_output.append('    UNIQUE (%s_id, %s_id)' % (opts.object_name.lower(), f.rel.to.object_name.lower()))
  100
+            table_output = ['CREATE TABLE %s (' % db.db.quote_name(f.get_m2m_db_table(opts))]
  101
+            table_output.append('    %s %s NOT NULL PRIMARY KEY,' % (db.db.quote_name('id'), db.DATA_TYPES['AutoField']))
  102
+            table_output.append('    %s %s NOT NULL REFERENCES %s (%s),' % \
  103
+                (db.db.quote_name(opts.object_name.lower() + '_id'),
  104
+                db.DATA_TYPES[get_rel_data_type(opts.pk)] % opts.pk.__dict__,
  105
+                db.db.quote_name(opts.db_table),
  106
+                db.db.quote_name(opts.pk.column)))
  107
+            table_output.append('    %s %s NOT NULL REFERENCES %s (%s),' % \
  108
+                (db.db.quote_name(f.rel.to.object_name.lower() + '_id'),
  109
+                db.DATA_TYPES[get_rel_data_type(f.rel.to.pk)] % f.rel.to.pk.__dict__,
  110
+                db.db.quote_name(f.rel.to.db_table),
  111
+                db.db.quote_name(f.rel.to.pk.column)))
  112
+            table_output.append('    UNIQUE (%s, %s)' % \
  113
+                (db.db.quote_name(opts.object_name.lower() + '_id'),
  114
+                db.db.quote_name(f.rel.to.object_name.lower() + '_id')))
98 115
             table_output.append(');')
99 116
             final_output.append('\n'.join(table_output))
100 117
     return final_output
@@ -114,7 +131,7 @@ def get_sql_delete(mod):
114 131
     try:
115 132
         if cursor is not None:
116 133
             # Check whether the table exists.
117  
-            cursor.execute("SELECT 1 FROM django_admin_log LIMIT 1")
  134
+            cursor.execute("SELECT 1 FROM %s LIMIT 1" % db.db.quote_name('django_admin_log'))
118 135
     except:
119 136
         # The table doesn't exist, so it doesn't need to be dropped.
120 137
         db.db.rollback()
@@ -129,12 +146,12 @@ def get_sql_delete(mod):
129 146
         try:
130 147
             if cursor is not None:
131 148
                 # Check whether the table exists.
132  
-                cursor.execute("SELECT 1 FROM %s LIMIT 1" % klass._meta.db_table)
  149
+                cursor.execute("SELECT 1 FROM %s LIMIT 1" % db.db.quote_name(klass._meta.db_table))
133 150
         except:
134 151
             # The table doesn't exist, so it doesn't need to be dropped.
135 152
             db.db.rollback()
136 153
         else:
137  
-            output.append("DROP TABLE %s;" % klass._meta.db_table)
  154
+            output.append("DROP TABLE %s;" % db.db.quote_name(klass._meta.db_table))
138 155
 
139 156
     # Output DROP TABLE statements for many-to-many tables.
140 157
     for klass in mod._MODELS:
@@ -142,25 +159,31 @@ def get_sql_delete(mod):
142 159
         for f in opts.many_to_many:
143 160
             try:
144 161
                 if cursor is not None:
145  
-                    cursor.execute("SELECT 1 FROM %s LIMIT 1" % f.get_m2m_db_table(opts))
  162
+                    cursor.execute("SELECT 1 FROM %s LIMIT 1" % db.db.quote_name(f.get_m2m_db_table(opts)))
146 163
             except:
147 164
                 db.db.rollback()
148 165
             else:
149  
-                output.append("DROP TABLE %s;" % f.get_m2m_db_table(opts))
  166
+                output.append("DROP TABLE %s;" % db.db.quote_name(f.get_m2m_db_table(opts)))
150 167
 
151 168
     app_label = mod._MODELS[0]._meta.app_label
152 169
 
153 170
     # Delete from packages, auth_permissions, content_types.
154  
-    output.append("DELETE FROM packages WHERE label = '%s';" % app_label)
155  
-    output.append("DELETE FROM auth_permissions WHERE package = '%s';" % app_label)
156  
-    output.append("DELETE FROM content_types WHERE package = '%s';" % app_label)
  171
+    output.append("DELETE FROM %s WHERE %s = '%s';" % \
  172
+        (db.db.quote_name('packages'), db.db.quote_name('label'), app_label))
  173
+    output.append("DELETE FROM %s WHERE %s = '%s';" % \
  174
+        (db.db.quote_name('auth_permissions'), db.db.quote_name('package'), app_label))
  175
+    output.append("DELETE FROM %s WHERE %s = '%s';" % \
  176
+        (db.db.quote_name('content_types'), db.db.quote_name('package'), app_label))
157 177
 
158 178
     # Delete from the admin log.
159 179
     if cursor is not None:
160  
-        cursor.execute("SELECT id FROM content_types WHERE package = %s", [app_label])
  180
+        cursor.execute("SELECT %s FROM %s WHERE %s = %%s" % \
  181
+            (db.db.quote_name('id'), db.db.quote_name('content_types'),
  182
+            db.db.quote_name('package')), [app_label])
161 183
         if admin_log_exists:
162 184
             for row in cursor.fetchall():
163  
-                output.append("DELETE FROM django_admin_log WHERE content_type_id = %s;" % row[0])
  185
+                output.append("DELETE FROM %s WHERE %s = %s;" % \
  186
+                    (db.db.quote_name('django_admin_log'), db.db.quote_name('content_type_id'), row[0]))
164 187
 
165 188
     # Close database connection explicitly, in case this output is being piped
166 189
     # directly into a database client, to avoid locking issues.
@@ -206,25 +229,29 @@ def get_sql_initial_data(mod):
206 229
 
207 230
 def get_sql_sequence_reset(mod):
208 231
     "Returns a list of the SQL statements to reset PostgreSQL sequences for the given module."
209  
-    from django.core import meta
  232
+    from django.core import db, meta
210 233
     output = []
211 234
     for klass in mod._MODELS:
212 235
         for f in klass._meta.fields:
213 236
             if isinstance(f, meta.AutoField):
214  
-                output.append("SELECT setval('%s_%s_seq', (SELECT max(%s) FROM %s));" % (klass._meta.db_table, f.column, f.column, klass._meta.db_table))
  237
+                output.append("SELECT setval('%s_%s_seq', (SELECT max(%s) FROM %s));" % \
  238
+                    (klass._meta.db_table, f.column, db.db.quote_name(f.column),
  239
+                    db.db.quote_name(klass._meta.db_table)))
215 240
     return output
216 241
 get_sql_sequence_reset.help_doc = "Prints the SQL statements for resetting PostgreSQL sequences for the given model module name(s)."
217 242
 get_sql_sequence_reset.args = APP_ARGS
218 243
 
219 244
 def get_sql_indexes(mod):
220 245
     "Returns a list of the CREATE INDEX SQL statements for the given module."
  246
+    from django.core.db import db
221 247
     output = []
222 248
     for klass in mod._MODELS:
223 249
         for f in klass._meta.fields:
224 250
             if f.db_index:
225 251
                 unique = f.unique and "UNIQUE " or ""
226 252
                 output.append("CREATE %sINDEX %s_%s ON %s (%s);" % \
227  
-                    (unique, klass._meta.db_table, f.column, klass._meta.db_table, f.column))
  253
+                    (unique, klass._meta.db_table, f.column,
  254
+                    db.quote_name(klass._meta.db_table), db.quote_name(f.column)))
228 255
     return output
229 256
 get_sql_indexes.help_doc = "Prints the CREATE INDEX SQL statements for the given model module name(s)."
230 257
 get_sql_indexes.args = APP_ARGS
@@ -242,7 +269,8 @@ def database_check(mod):
242 269
     app_label = mod._MODELS[0]._meta.app_label
243 270
 
244 271
     # Check that the package exists in the database.
245  
-    cursor.execute("SELECT 1 FROM packages WHERE label = %s", [app_label])
  272
+    cursor.execute("SELECT 1 FROM %s WHERE %s = %%s" % \
  273
+        (db.db.quote_name('packages'), db.db.quote_name('label')), [app_label])
246 274
     if cursor.rowcount < 1:
247 275
 #         sys.stderr.write("The '%s' package isn't installed.\n" % app_label)
248 276
         print _get_packages_insert(app_label)
@@ -256,34 +284,46 @@ def database_check(mod):
256 284
         perms_seen.update(dict(perms))
257 285
         contenttypes_seen[opts.module_name] = 1
258 286
         for codename, name in perms:
259  
-            cursor.execute("SELECT 1 FROM auth_permissions WHERE package = %s AND codename = %s", (app_label, codename))
  287
+            cursor.execute("SELECT 1 FROM %s WHERE %s = %%s AND %s = %%s" % \
  288
+                (db.db.quote_name('auth_permissions'), db.db.quote_name('package'),
  289
+                db.db.quote_name('codename')), (app_label, codename))
260 290
             if cursor.rowcount < 1:
261 291
 #                 sys.stderr.write("The '%s.%s' permission doesn't exist.\n" % (app_label, codename))
262 292
                 print _get_permission_insert(name, codename, opts)
263  
-        cursor.execute("SELECT 1 FROM content_types WHERE package = %s AND python_module_name = %s", (app_label, opts.module_name))
  293
+        cursor.execute("SELECT 1 FROM %s WHERE %s = %%s AND %s = %%s" % \
  294
+            (db.db.quote_name('content_types'), db.db.quote_name('package'),
  295
+            db.db.quote_name('python_module_name')), (app_label, opts.module_name))
264 296
         if cursor.rowcount < 1:
265 297
 #             sys.stderr.write("The '%s.%s' content type doesn't exist.\n" % (app_label, opts.module_name))
266 298
             print _get_contenttype_insert(opts)
267 299
 
268 300
     # Check that there aren't any *extra* permissions in the DB that the model
269 301
     # doesn't know about.
270  
-    cursor.execute("SELECT codename FROM auth_permissions WHERE package = %s", (app_label,))
  302
+    cursor.execute("SELECT %s FROM %s WHERE %s = %%s" % \
  303
+        (db.db.quote_name('codename'), db.db.quote_name('auth_permissions'),
  304
+        db.db.quote_name('package')), (app_label,))
271 305
     for row in cursor.fetchall():
272 306
         try:
273 307
             perms_seen[row[0]]
274 308
         except KeyError:
275 309
 #             sys.stderr.write("A permission called '%s.%s' was found in the database but not in the model.\n" % (app_label, row[0]))
276  
-            print "DELETE FROM auth_permissions WHERE package='%s' AND codename = '%s';" % (app_label, row[0])
  310
+            print "DELETE FROM %s WHERE %s='%s' AND %s = '%s';" % \
  311
+                (db.db.quote_name('auth_permissions'), db.db.quote_name('package'),
  312
+                app_label, db.db.quote_name('codename'), row[0])
277 313
 
278 314
     # Check that there aren't any *extra* content types in the DB that the
279 315
     # model doesn't know about.
280  
-    cursor.execute("SELECT python_module_name FROM content_types WHERE package = %s", (app_label,))
  316
+    cursor.execute("SELECT %s FROM %s WHERE %s = %%s" % \
  317
+        (db.db.quote_name('python_module_name'), db.db.quote_name('content_types'),
  318
+        db.db.quote_name('package')), (app_label,))
281 319
     for row in cursor.fetchall():
282 320
         try:
283 321
             contenttypes_seen[row[0]]
284 322
         except KeyError:
285 323
 #             sys.stderr.write("A content type called '%s.%s' was found in the database but not in the model.\n" % (app_label, row[0]))
286  
-            print "DELETE FROM content_types WHERE package='%s' AND python_module_name = '%s';" % (app_label, row[0])
  324
+            print "DELETE FROM %s WHERE %s='%s' AND %s = '%s';" % \
  325
+                (db.db.quote_name('content_types'), db.db.quote_name('package'),
  326
+                app_label, db.db.quote_name('python_module_name'), row[0])
287 327
 database_check.help_doc = "Checks that everything is installed in the database for the given model module name(s) and prints SQL statements if needed."
288 328
 database_check.args = APP_ARGS
289 329
 
@@ -318,7 +358,9 @@ def init():
318 358
         cursor = db.db.cursor()
319 359
         for sql in get_sql_create(core) + get_sql_create(auth) + get_sql_initial_data(core) + get_sql_initial_data(auth):
320 360
             cursor.execute(sql)
321  
-        cursor.execute("INSERT INTO %s (domain, name) VALUES ('example.com', 'Example site')" % core.Site._meta.db_table)
  361
+        cursor.execute("INSERT INTO %s (%s, %s) VALUES ('example.com', 'Example site')" % \
  362
+            (db.db.quote_name(core.Site._meta.db_table), db.db.quote_name('domain'),
  363
+            db.db.quote_name('name')))
322 364
     except Exception, e:
323 365
         sys.stderr.write("Error: The database couldn't be initialized.\n%s\n" % e)
324 366
         try:
@@ -687,7 +729,7 @@ def createcachetable(tablename):
687 729
     table_output = []
688 730
     index_output = []
689 731
     for f in fields:
690  
-        field_output = [f.column, db.DATA_TYPES[f.get_internal_type()] % f.__dict__]
  732
+        field_output = [db.db.quote_name(f.column), db.DATA_TYPES[f.get_internal_type()] % f.__dict__]
691 733
         field_output.append("%sNULL" % (not f.null and "NOT " or ""))
692 734
         if f.unique:
693 735
             field_output.append("UNIQUE")
@@ -695,9 +737,11 @@ def createcachetable(tablename):
695 737
             field_output.append("PRIMARY KEY")
696 738
         if f.db_index:
697 739
             unique = f.unique and "UNIQUE " or ""
698  
-            index_output.append("CREATE %sINDEX %s_%s ON %s (%s);" % (unique, tablename, f.column, tablename, f.column))
  740
+            index_output.append("CREATE %sINDEX %s_%s ON %s (%s);" % \
  741
+                (unique, tablename, f.column, db.db.quote_name(tablename),
  742
+                db.db.quote_name(f.column)))
699 743
         table_output.append(" ".join(field_output))
700  
-    full_statement = ["CREATE TABLE %s (" % tablename]
  744
+    full_statement = ["CREATE TABLE %s (" % db.db.quote_name(tablename)]
701 745
     for i, line in enumerate(table_output):
702 746
         full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
703 747
     full_statement.append(');')
168  django/core/meta/__init__.py
@@ -57,14 +57,16 @@ def orderfield2column(f, opts):
57 57
         return f
58 58
 
59 59
 def orderlist2sql(order_list, opts, prefix=''):
  60
+    if prefix.endswith('.'):
  61
+        prefix = db.db.quote_name(prefix[:-1]) + '.'
60 62
     output = []
61 63
     for f in handle_legacy_orderlist(order_list):
62 64
         if f.startswith('-'):
63  
-            output.append('%s%s DESC' % (prefix, orderfield2column(f[1:], opts)))
  65
+            output.append('%s%s DESC' % (prefix, db.db.quote_name(orderfield2column(f[1:], opts))))
64 66
         elif f == '?':
65 67
             output.append(db.get_random_function_sql())
66 68
         else:
67  
-            output.append('%s%s ASC' % (prefix, orderfield2column(f, opts)))
  69
+            output.append('%s%s ASC' % (prefix, db.db.quote_name(orderfield2column(f, opts))))
68 70
     return ', '.join(output)
69 71
 
70 72
 def get_module(app_label, module_name):
@@ -785,27 +787,31 @@ def method_save(opts, self):
785 787
     record_exists = True
786 788
     if pk_set:
787 789
         # Determine whether a record with the primary key already exists.
788  
-        cursor.execute("SELECT 1 FROM %s WHERE %s=%%s LIMIT 1" % (opts.db_table, opts.pk.column), [pk_val])
  790
+        cursor.execute("SELECT 1 FROM %s WHERE %s=%%s LIMIT 1" % \
  791
+            (db.db.quote_name(opts.db_table), db.db.quote_name(opts.pk.column)), [pk_val])
789 792
         # If it does already exist, do an UPDATE.
790 793
         if cursor.fetchone():
791 794
             db_values = [f.get_db_prep_save(f.pre_save(getattr(self, f.attname), False)) for f in non_pks]
792  
-            cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % (opts.db_table,
793  
-                ','.join(['%s=%%s' % f.column for f in non_pks]), opts.pk.attname),
  795
+            cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
  796
+                (db.db.quote_name(opts.db_table),
  797
+                ','.join(['%s=%%s' % db.db.quote_name(f.column) for f in non_pks]),
  798
+                db.db.quote_name(opts.pk.attname)),
794 799
                 db_values + [pk_val])
795 800
         else:
796 801
             record_exists = False
797 802
     if not pk_set or not record_exists:
798  
-        field_names = [f.column for f in opts.fields if not isinstance(f, AutoField)]
  803
+        field_names = [db.db.quote_name(f.column) for f in opts.fields if not isinstance(f, AutoField)]
799 804
         placeholders = ['%s'] * len(field_names)
800 805
         db_values = [f.get_db_prep_save(f.pre_save(getattr(self, f.attname), True)) for f in opts.fields if not isinstance(f, AutoField)]
801 806
         if opts.order_with_respect_to:
802  
-            field_names.append('_order')
  807
+            field_names.append(db.db.quote_name('_order'))
803 808
             # TODO: This assumes the database supports subqueries.
804 809
             placeholders.append('(SELECT COUNT(*) FROM %s WHERE %s = %%s)' % \
805  
-                (opts.db_table, opts.order_with_respect_to.column))
  810
+                (db.db.quote_name(opts.db_table), db.db.quote_name(opts.order_with_respect_to.column)))
806 811
             db_values.append(getattr(self, opts.order_with_respect_to.attname))
807  
-        cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % (opts.db_table,
808  
-            ','.join(field_names), ','.join(placeholders)), db_values)
  812
+        cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \
  813
+            (db.db.quote_name(opts.db_table), ','.join(field_names),
  814
+            ','.join(placeholders)), db_values)
809 815
         if opts.has_auto_field:
810 816
             setattr(self, opts.pk.attname, db.get_last_insert_id(cursor, opts.db_table, opts.pk.column))
811 817
     db.db.commit()
@@ -832,12 +838,17 @@ def method_delete(opts, self):
832 838
             for sub_obj in getattr(self, 'get_%s_list' % rel_opts_name)():
833 839
                 sub_obj.delete()
834 840
     for rel_opts, rel_field in opts.get_all_related_many_to_many_objects():
835  
-        cursor.execute("DELETE FROM %s WHERE %s_id=%%s" % (rel_field.get_m2m_db_table(rel_opts),
836  
-            self._meta.object_name.lower()), [getattr(self, opts.pk.attname)])
  841
+        cursor.execute("DELETE FROM %s WHERE %s=%%s" % \
  842
+            (db.db.quote_name(rel_field.get_m2m_db_table(rel_opts)),
  843
+            db.db.quote_name(self._meta.object_name.lower() + '_id')), [getattr(self, opts.pk.attname)])
837 844
     for f in opts.many_to_many:
838  
-        cursor.execute("DELETE FROM %s WHERE %s_id=%%s" % (f.get_m2m_db_table(opts), self._meta.object_name.lower()),
  845
+        cursor.execute("DELETE FROM %s WHERE %s=%%s" % \
  846
+            (db.db.quote_name(f.get_m2m_db_table(opts)),
  847
+            db.db.quote_name(self._meta.object_name.lower() + '_id')),
839 848
             [getattr(self, opts.pk.attname)])
840  
-    cursor.execute("DELETE FROM %s WHERE %s=%%s" % (opts.db_table, opts.pk.column), [getattr(self, opts.pk.attname)])
  849
+    cursor.execute("DELETE FROM %s WHERE %s=%%s" % \
  850
+        (db.db.quote_name(opts.db_table), db.db.quote_name(opts.pk.column)),
  851
+        [getattr(self, opts.pk.attname)])
841 852
     db.db.commit()
842 853
     setattr(self, opts.pk.attname, None)
843 854
     for f in opts.fields:
@@ -854,16 +865,20 @@ def method_delete(opts, self):
854 865
 def method_get_next_in_order(opts, order_field, self):
855 866
     if not hasattr(self, '_next_in_order_cache'):
856 867
         self._next_in_order_cache = opts.get_model_module().get_object(order_by=('_order',),
857  
-            where=['_order > (SELECT _order FROM %s WHERE %s=%%s)' % (opts.db_table, opts.pk.column),
858  
-                '%s=%%s' % order_field.column], limit=1,
  868
+            where=['%s > (SELECT %s FROM %s WHERE %s=%%s)' % \
  869
+                (db.db.quote_name('_order'), db.db.quote_name('_order'),
  870
+                db.db.quote_name(opts.db_table), db.db.quote_name(opts.pk.column)),
  871
+                '%s=%%s' % db.db.quote_name(order_field.column)], limit=1,
859 872
             params=[getattr(self, opts.pk.attname), getattr(self, order_field.attname)])
860 873
     return self._next_in_order_cache
861 874
 
862 875
 def method_get_previous_in_order(opts, order_field, self):
863 876
     if not hasattr(self, '_previous_in_order_cache'):
864 877
         self._previous_in_order_cache = opts.get_model_module().get_object(order_by=('-_order',),
865  
-            where=['_order < (SELECT _order FROM %s WHERE %s=%%s)' % (opts.db_table, opts.pk.column),
866  
-                '%s=%%s' % order_field.column], limit=1,
  878
+            where=['%s < (SELECT %s FROM %s WHERE %s=%%s)' % \
  879
+                (db.db.quote_name('_order'), db.db.quote_name('_order'),
  880
+                db.db.quote_name(opts.db_table), db.db.quote_name(opts.pk.column)),
  881
+                '%s=%%s' % db.db.quote_name(order_field.column)], limit=1,
867 882
             params=[getattr(self, opts.pk.attname), getattr(self, order_field.attname)])
868 883
     return self._previous_in_order_cache
869 884
 
@@ -888,10 +903,13 @@ def method_get_many_to_many(field_with_rel, self):
888 903
     cache_var = '_%s_cache' % field_with_rel.name
889 904
     if not hasattr(self, cache_var):
890 905
         mod = rel.get_model_module()
891  
-        sql = "SELECT %s FROM %s a, %s b WHERE a.%s = b.%s_id AND b.%s_id = %%s %s" % \
892  
-            (','.join(['a.%s' % f.column for f in rel.fields]), rel.db_table,
893  
-            field_with_rel.get_m2m_db_table(self._meta), rel.pk.column,
894  
-            rel.object_name.lower(), self._meta.object_name.lower(), rel.get_order_sql('a'))
  906
+        sql = "SELECT %s FROM %s a, %s b WHERE a.%s = b.%s AND b.%s = %%s %s" % \
  907
+            (','.join(['a.%s' % db.db.quote_name(f.column) for f in rel.fields]),
  908
+            db.db.quote_name(rel.db_table),
  909
+            db.db.quote_name(field_with_rel.get_m2m_db_table(self._meta)),
  910
+            db.db.quote_name(rel.pk.column),
  911
+            db.db.quote_name(rel.object_name.lower() + '_id'),
  912
+            db.db.quote_name(self._meta.object_name.lower() + '_id'), rel.get_order_sql('a'))
895 913
         cursor = db.db.cursor()
896 914
         cursor.execute(sql, [getattr(self, self._meta.pk.attname)])
897 915
         setattr(self, cache_var, [getattr(mod, rel.object_name)(*row) for row in cursor.fetchall()])
@@ -916,10 +934,16 @@ def method_set_many_to_many(rel_field, self, id_list):
916 934
     cursor = db.db.cursor()
917 935
     this_id = getattr(self, self._meta.pk.attname)
918 936
     if ids_to_delete:
919  
-        sql = "DELETE FROM %s WHERE %s_id = %%s AND %s_id IN (%s)" % (m2m_table, self._meta.object_name.lower(), rel.object_name.lower(), ','.join(map(str, ids_to_delete)))
  937
+        sql = "DELETE FROM %s WHERE %s = %%s AND %s IN (%s)" % \
  938
+            (db.db.quote_name(m2m_table),
  939
+            db.db.quote_name(self._meta.object_name.lower() + '_id'),
  940
+            db.db.quote_name(rel.object_name.lower() + '_id'), ','.join(map(str, ids_to_delete)))
920 941
         cursor.execute(sql, [this_id])
921 942
     if ids_to_add:
922  
-        sql = "INSERT INTO %s (%s_id, %s_id) VALUES (%%s, %%s)" % (m2m_table, self._meta.object_name.lower(), rel.object_name.lower())
  943
+        sql = "INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % \
  944
+            (db.db.quote_name(m2m_table),
  945
+            db.db.quote_name(self._meta.object_name.lower() + '_id'),
  946
+            db.db.quote_name(rel.object_name.lower() + '_id'))
923 947
         cursor.executemany(sql, [(this_id, i) for i in ids_to_add])
924 948
     db.db.commit()
925 949
     try:
@@ -965,8 +989,13 @@ def method_set_related_many_to_many(rel_opts, rel_field, self, id_list):
965 989
     m2m_table = rel_field.get_m2m_db_table(rel_opts)
966 990
     this_id = getattr(self, self._meta.pk.attname)
967 991
     cursor = db.db.cursor()
968  
-    cursor.execute("DELETE FROM %s WHERE %s_id = %%s" % (m2m_table, rel.object_name.lower()), [this_id])
969  
-    sql = "INSERT INTO %s (%s_id, %s_id) VALUES (%%s, %%s)" % (m2m_table, rel.object_name.lower(), rel_opts.object_name.lower())
  992
+    cursor.execute("DELETE FROM %s WHERE %s = %%s" % \
  993
+        (db.db.quote_name(m2m_table),
  994
+        db.db.quote_name(rel.object_name.lower() + '_id')), [this_id])
  995
+    sql = "INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % \
  996
+        (db.db.quote_name(m2m_table),
  997
+        db.db.quote_name(rel.object_name.lower() + '_id'),
  998
+        db.db.quote_name(rel_opts.object_name.lower() + '_id'))
970 999
     cursor.executemany(sql, [(this_id, i) for i in id_list])
971 1000
     db.db.commit()
972 1001
 
@@ -975,7 +1004,10 @@ def method_set_related_many_to_many(rel_opts, rel_field, self, id_list):
975 1004
 def method_set_order(ordered_obj, self, id_list):
976 1005
     cursor = db.db.cursor()
977 1006
     # Example: "UPDATE poll_choices SET _order = %s WHERE poll_id = %s AND id = %s"
978  
-    sql = "UPDATE %s SET _order = %%s WHERE %s = %%s AND %s = %%s" % (ordered_obj.db_table, ordered_obj.order_with_respect_to.column, ordered_obj.pk.column)
  1007
+    sql = "UPDATE %s SET %s = %%s WHERE %s = %%s AND %s = %%s" % \
  1008
+        (db.db.quote_name(ordered_obj.db_table), db.db.quote_name('_order'),
  1009
+        db.db.quote_name(ordered_obj.order_with_respect_to.column),
  1010
+        db.db.quote_name(ordered_obj.pk.column))
979 1011
     rel_val = getattr(self, ordered_obj.order_with_respect_to.rel.field_name)
980 1012
     cursor.executemany(sql, [(i, rel_val, j) for i, j in enumerate(id_list)])
981 1013
     db.db.commit()
@@ -983,7 +1015,11 @@ def method_set_order(ordered_obj, self, id_list):
983 1015
 def method_get_order(ordered_obj, self):
984 1016
     cursor = db.db.cursor()
985 1017
     # Example: "SELECT id FROM poll_choices WHERE poll_id = %s ORDER BY _order"
986  
-    sql = "SELECT %s FROM %s WHERE %s = %%s ORDER BY _order" % (ordered_obj.pk.column, ordered_obj.db_table, ordered_obj.order_with_respect_to.column)
  1018
+    sql = "SELECT %s FROM %s WHERE %s = %%s ORDER BY %s" % \
  1019
+        (db.db.quote_name(ordered_obj.pk.column),
  1020
+        db.db.quote_name(ordered_obj.db_table),
  1021
+        db.db.quote_name(ordered_obj.order_with_respect_to.column),
  1022
+        db.db.quote_name('_order'))
987 1023
     rel_val = getattr(self, ordered_obj.order_with_respect_to.rel.field_name)
988 1024
     cursor.execute(sql, [rel_val])
989 1025
     return [r[0] for r in cursor.fetchall()]
@@ -993,7 +1029,8 @@ def method_get_order(ordered_obj, self):
993 1029
 def method_get_next_or_previous(get_object_func, opts, field, is_next, self, **kwargs):
994 1030
     op = is_next and '>' or '<'
995 1031
     kwargs.setdefault('where', []).append('(%s %s %%s OR (%s = %%s AND %s %s %%s))' % \
996  
-        (field.column, op, field.column, opts.pk.column, op))
  1032
+        (db.db.quote_name(field.column), op, db.db.quote_name(field.column),
  1033
+        db.db.quote_name(opts.pk.column), op))
997 1034
     param = str(getattr(self, field.attname))
998 1035
     kwargs.setdefault('params', []).extend([param, param, getattr(self, opts.pk.attname)])
999 1036
     kwargs['order_by'] = [(not is_next and '-' or '') + field.name, (not is_next and '-' or '') + opts.pk.name]
@@ -1080,6 +1117,9 @@ def get_absolute_url(opts, func, self):
1080 1117
     return settings.ABSOLUTE_URL_OVERRIDES.get('%s.%s' % (opts.app_label, opts.module_name), func)(self)
1081 1118
 
1082 1119
 def _get_where_clause(lookup_type, table_prefix, field_name, value):
  1120
+    if table_prefix.endswith('.'):
  1121
+        table_prefix = db.db.quote_name(table_prefix[:-1])+'.'
  1122
+    field_name = db.db.quote_name(field_name)
1083 1123
     try:
1084 1124
         return '%s%s %s %%s' % (table_prefix, field_name, db.OPERATOR_MAPPING[lookup_type])
1085 1125
     except KeyError:
@@ -1160,7 +1200,7 @@ def function_get_values_iterator(opts, klass, **kwargs):
1160 1200
 
1161 1201
     cursor = db.db.cursor()
1162 1202
     _, sql, params = function_get_sql_clause(opts, **kwargs)
1163  
-    select = ['%s.%s' % (opts.db_table, f) for f in fields]
  1203
+    select = ['%s.%s' % (db.db.quote_name(opts.db_table), db.db.quote_name(f)) for f in fields]
1164 1204
     cursor.execute("SELECT " + (kwargs.get('distinct') and "DISTINCT " or "") + ",".join(select) + sql, params)
1165 1205
     while 1:
1166 1206
         rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)
@@ -1181,14 +1221,16 @@ def _fill_table_cache(opts, select, tables, where, old_prefix, cache_tables_seen
1181 1221
         if f.rel and not f.null:
1182 1222
             db_table = f.rel.to.db_table
1183 1223
             if db_table not in cache_tables_seen:
1184  
-                tables.append(db_table)
  1224
+                tables.append(db.db.quote_name(db_table))
1185 1225
             else: # The table was already seen, so give it a table alias.
1186 1226
                 new_prefix = '%s%s' % (db_table, len(cache_tables_seen))
1187  
-                tables.append('%s %s' % (db_table, new_prefix))
  1227
+                tables.append('%s %s' % (db.db.quote_name(db_table), db.db.quote_name(new_prefix)))
1188 1228
                 db_table = new_prefix
1189 1229
             cache_tables_seen.append(db_table)
1190  
-            where.append('%s.%s = %s.%s' % (old_prefix, f.column, db_table, f.rel.get_related_field().column))
1191  
-            select.extend(['%s.%s' % (db_table, f2.column) for f2 in f.rel.to.fields])
  1230
+            where.append('%s.%s = %s.%s' % \
  1231
+                (db.db.quote_name(old_prefix), db.db.quote_name(f.column),
  1232
+                db.db.quote_name(db_table), db.db.quote_name(f.rel.get_related_field().column)))
  1233
+            select.extend(['%s.%s' % (db.db.quote_name(db_table), db.db.quote_name(f2.column)) for f2 in f.rel.to.fields])
1192 1234
             _fill_table_cache(f.rel.to, select, tables, where, db_table, cache_tables_seen)
1193 1235
 
1194 1236
 def _throw_bad_kwarg_error(kwarg):
@@ -1247,11 +1289,15 @@ def _parse_lookup(kwarg_items, opts, table_count=0):
1247 1289
                 # Try many-to-many relationships first...
1248 1290
                 for f in current_opts.many_to_many:
1249 1291
                     if f.name == current:
1250  
-                        rel_table_alias = 't%s' % table_count
  1292
+                        rel_table_alias = db.db.quote_name('t%s' % table_count)
1251 1293
                         table_count += 1
1252  
-                        tables.append('%s %s' % (f.get_m2m_db_table(current_opts), rel_table_alias))
1253  
-                        join_where.append('%s.%s = %s.%s_id' % (current_table_alias, current_opts.pk.column,
1254  
-                            rel_table_alias, current_opts.object_name.lower()))
  1294
+                        tables.append('%s %s' % \
  1295
+                            (db.db.quote_name(f.get_m2m_db_table(current_opts)), rel_table_alias))
  1296
+                        join_where.append('%s.%s = %s.%s' % \
  1297
+                            (db.db.quote_name(current_table_alias),
  1298
+                            db.db.quote_name(current_opts.pk.column),
  1299
+                            rel_table_alias,
  1300
+                            db.db.quote_name(current_opts.object_name.lower() + '_id')))
1255 1301
                         # Optimization: In the case of primary-key lookups, we
1256 1302
                         # don't have to do an extra join.
1257 1303
                         if lookup_list and lookup_list[0] == f.rel.to.pk.name and lookup_type == 'exact':
@@ -1262,9 +1308,13 @@ def _parse_lookup(kwarg_items, opts, table_count=0):
1262 1308
                             param_required = False
1263 1309
                         else:
1264 1310
                             new_table_alias = 't%s' % table_count
1265  
-                            tables.append('%s %s' % (f.rel.to.db_table, new_table_alias))
1266  
-                            join_where.append('%s.%s_id = %s.%s' % (rel_table_alias, f.rel.to.object_name.lower(),
1267  
-                                new_table_alias, f.rel.to.pk.column))
  1311
+                            tables.append('%s %s' % (db.db.quote_name(f.rel.to.db_table),
  1312
+                                db.db.quote_name(new_table_alias)))
  1313
+                            join_where.append('%s.%s = %s.%s' % \
  1314
+                                (db.db.quote_name(rel_table_alias),
  1315
+                                db.db.quote_name(f.rel.to.object_name.lower() + '_id'),
  1316
+                                db.db.quote_name(new_table_alias),
  1317
+                                db.db.quote_name(f.rel.to.pk.column)))
1268 1318
                             current_table_alias = new_table_alias
1269 1319
                             param_required = True
1270 1320
                         current_opts = f.rel.to
@@ -1287,9 +1337,11 @@ def _parse_lookup(kwarg_items, opts, table_count=0):
1287 1337
                             params.extend(f.get_db_prep_lookup(lookup_type, kwarg_value))
1288 1338
                         else:
1289 1339
                             new_table_alias = 't%s' % table_count
1290  
-                            tables.append('%s %s' % (f.rel.to.db_table, new_table_alias))
1291  
-                            join_where.append('%s.%s = %s.%s' % (current_table_alias, f.column, \
1292  
-                                new_table_alias, f.rel.to.pk.column))
  1340
+                            tables.append('%s %s' % \
  1341
+                                (db.db.quote_name(f.rel.to.db_table), db.db.quote_name(new_table_alias)))
  1342
+                            join_where.append('%s.%s = %s.%s' % \
  1343
+                                (db.db.quote_name(current_table_alias), db.db.quote_name(f.column),
  1344
+                                db.db.quote_name(new_table_alias), db.db.quote_name(f.rel.to.pk.column)))
1293 1345
                             current_table_alias = new_table_alias
1294 1346
                             param_required = True
1295 1347
                         current_opts = f.rel.to
@@ -1308,8 +1360,9 @@ def _parse_lookup(kwarg_items, opts, table_count=0):
1308 1360
     return tables, join_where, where, params, table_count
1309 1361
 
1310 1362
 def function_get_sql_clause(opts, **kwargs):
1311  
-    select = ["%s.%s" % (opts.db_table, f.column) for f in opts.fields]
  1363
+    select = ["%s.%s" % (db.db.quote_name(opts.db_table), db.db.quote_name(f.column)) for f in opts.fields]
1312 1364
     tables = [opts.db_table] + (kwargs.get('tables') and kwargs['tables'][:] or [])
  1365
+    tables = [db.db.quote_name(t) for t in tables]
1313 1366
     where = kwargs.get('where') and kwargs['where'][:] or []
1314 1367
     params = kwargs.get('params') and kwargs['params'][:] or []
1315 1368
 
@@ -1328,7 +1381,7 @@ def function_get_sql_clause(opts, **kwargs):
1328 1381
 
1329 1382
     # Add any additional SELECTs passed in via kwargs.
1330 1383
     if kwargs.get('select'):
1331  
-        select.extend(['(%s) AS %s' % (s[1], s[0]) for s in kwargs['select']])
  1384
+        select.extend(['(%s) AS %s' % (db.db.quote_name(s[1]), db.db.quote_name(s[0])) for s in kwargs['select']])
1332 1385
 
1333 1386
     # ORDER BY clause
1334 1387
     order_by = []
@@ -1342,13 +1395,17 @@ def function_get_sql_clause(opts, **kwargs):
1342 1395
             else:
1343 1396
                 col_name = f
1344 1397
                 order = "ASC"
1345  
-            # Use the database table as a column prefix if it wasn't given,
1346  
-            # and if the requested column isn't a custom SELECT.
1347  
-            if "." not in col_name and col_name not in [k[0] for k in kwargs.get('select', [])]:
1348  
-                table_prefix = opts.db_table + '.'
  1398
+            if "." in col_name:
  1399
+                table_prefix, col_name = col_name.split('.', 1)
  1400
+                table_prefix = db.db.quote_name(table_prefix) + '.'
1349 1401
             else:
1350  
-                table_prefix = ''
1351  
-            order_by.append('%s%s %s' % (table_prefix, orderfield2column(col_name, opts), order))
  1402
+                # Use the database table as a column prefix if it wasn't given,
  1403
+                # and if the requested column isn't a custom SELECT.
  1404
+                if "." not in col_name and col_name not in [k[0] for k in kwargs.get('select', [])]:
  1405
+                    table_prefix = db.db.quote_name(opts.db_table) + '.'
  1406
+                else:
  1407
+                    table_prefix = ''
  1408
+            order_by.append('%s%s %s' % (table_prefix, db.db.quote_name(orderfield2column(col_name, opts)), order))
1352 1409
     order_by = ", ".join(order_by)
1353 1410
 
1354 1411
     # LIMIT and OFFSET clauses
@@ -1363,7 +1420,7 @@ def function_get_sql_clause(opts, **kwargs):
1363 1420
 def function_get_in_bulk(opts, klass, *args, **kwargs):
1364 1421
     id_list = args and args[0] or kwargs['id_list']
1365 1422
     assert id_list != [], "get_in_bulk() cannot be passed an empty list."
1366  
-    kwargs['where'] = ["%s.%s IN (%s)" % (opts.db_table, opts.pk.column, ",".join(['%s'] * len(id_list)))]
  1423
+    kwargs['where'] = ["%s.%s IN (%s)" % (db.db.quote_name(opts.db_table), db.db.quote_name(opts.pk.column), ",".join(['%s'] * len(id_list)))]
1367 1424
     kwargs['params'] = id_list
1368 1425
     obj_list = function_get_list(opts, klass, **kwargs)
1369 1426
     return dict([(getattr(o, opts.pk.attname), o) for o in obj_list])
@@ -1384,9 +1441,10 @@ def function_get_date_list(opts, field, *args, **kwargs):
1384 1441
     assert order in ('ASC', 'DESC'), "'order' must be either 'ASC' or 'DESC'"
1385 1442
     kwargs['order_by'] = [] # Clear this because it'll mess things up otherwise.
1386 1443
     if field.null:
1387  
-        kwargs.setdefault('where', []).append('%s.%s IS NOT NULL' % (opts.db_table, field.column))
  1444
+        kwargs.setdefault('where', []).append('%s.%s IS NOT NULL' % \
  1445
+            (db.db.quote_name(opts.db_table), db.db.quote_name(field.column)))
1388 1446
     select, sql, params = function_get_sql_clause(opts, **kwargs)
1389  
-    sql = 'SELECT %s %s GROUP BY 1 ORDER BY 1' % (db.get_date_trunc_sql(kind, '%s.%s' % (opts.db_table, field.column)), sql)
  1447
+    sql = 'SELECT %s %s GROUP BY 1 ORDER BY 1' % (db.get_date_trunc_sql(kind, '%s.%s' % (db.db.quote_name(opts.db_table), db.db.quote_name(field.column))), sql)
1390 1448
     cursor = db.db.cursor()
1391 1449
     cursor.execute(sql, params)
1392 1450
     # We have to manually run typecast_timestamp(str()) on the results, because
25  django/models/auth.py
@@ -91,12 +91,25 @@ def get_group_permissions(self):
91 91
         if not hasattr(self, '_group_perm_cache'):
92 92
             import sets
93 93
             cursor = db.cursor()
94  
-            cursor.execute("""
95  
-                SELECT p.package, p.codename
96  
-                FROM auth_permissions p, auth_groups_permissions gp, auth_users_groups ug
97  
-                WHERE p.id = gp.permission_id
98  
-                    AND gp.group_id = ug.group_id
99  
-                    AND ug.user_id = %s""", [self.id])
  94
+            # The SQL below works out to the following, after DB quoting:
  95
+            # cursor.execute("""
  96
+            #     SELECT p.package, p.codename
  97
+            #     FROM auth_permissions p, auth_groups_permissions gp, auth_users_groups ug
  98
+            #     WHERE p.id = gp.permission_id
  99
+            #         AND gp.group_id = ug.group_id
  100
+            #         AND ug.user_id = %s""", [self.id])
  101
+            sql = """
  102
+                SELECT p.%s, p.%s
  103
+                FROM %s p, %s gp, %s ug
  104
+                WHERE p.%s = gp.%s
  105
+                    AND gp.%s = ug.%s
  106
+                    AND ug.%s = %%s""" % (
  107
+                db.quote_name('package'), db.quote_name('codename'),
  108
+                db.quote_name('auth_permissions'), db.quote_name('auth_groups_permissions'),
  109
+                db.quote_name('auth_users_groups'), db.quote_name('id'),
  110
+                db.quote_name('permission_id'), db.quote_name('group_id'),
  111
+                db.quote_name('group_id'), db.quote_name('user_id'))
  112
+            cursor.execute(sql, [self.id])
100 113
             self._group_perm_cache = sets.Set(["%s.%s" % (row[0], row[1]) for row in cursor.fetchall()])
101 114
         return self._group_perm_cache
102 115
 
29  docs/model-api.txt
@@ -34,15 +34,21 @@ Django will use ``first_name`` and ``last_name`` as the database column names.
34 34
 
35 35
 Each field type, except for ``ForeignKey``, ``ManyToManyField`` and
36 36
 ``OneToOneField``, takes an optional first positional argument -- a
37  
-human-readable name. If the human-readable name isn't given, Django will use
38  
-the machine-readable name, converting underscores to spaces.
  37
+human-readable name. If the human-readable name isn't given, Django will
  38
+automatically create the human-readable name by using the machine-readable
  39
+name, converting underscores to spaces.
39 40
 
40  
-Example::
  41
+In this example, the human-readable name is ``"Person's first name"``::
41 42
 
42 43
     first_name = meta.CharField("Person's first name", maxlength=30)
43 44
 
44  
-For ``ForeignKey``, ``ManyToManyField`` and ``OneToOneField``, use the
45  
-``verbose_name`` keyword argument::
  45
+In this example, the human-readable name is ``"first name"``::
  46
+
  47
+    first_name = meta.CharField(maxlength=30)
  48
+
  49
+``ForeignKey``, ``ManyToManyField`` and ``OneToOneField`` require the first
  50
+argument to be a model class, so use the ``verbose_name`` keyword argument to
  51
+specify the human-readable name::
46 52
 
47 53
     poll = meta.ForeignKey(Poll, verbose_name="the related poll")
48 54
     sites = meta.ManyToManyField(Site, verbose_name="list of sites")
@@ -111,6 +117,11 @@ The following arguments are available to all field types. All are optional.
111 117
     The name of the database column to use for this field. If this isn't given,
112 118
     Django will use the field's name.
113 119
 
  120
+    If your database column name is an SQL reserved word, or contains
  121
+    characters that aren't allowed in Python variable names -- notably, the
  122
+    hyphen -- that's OK. Django quotes column and table names behind the
  123
+    scenes.
  124
+
114 125
 ``db_index``
115 126
     If ``True``, ``django-admin.py sqlindexes`` will output a ``CREATE INDEX``
116 127
     statement for this field.
@@ -700,6 +711,10 @@ Here's a list of all possible ``META`` options. No options are required. Adding
700 711
 
701 712
     If this isn't given, Django will use ``app_label + '_' + module_name``.
702 713
 
  714
+    If your database table name is an SQL reserved word, or contains characters
  715
+    that aren't allowed in Python variable names -- notably, the hyphen --
  716
+    that's OK. Django quotes column and table names behind the scenes.
  717
+
703 718
 ``exceptions``
704 719
     Names of extra exception subclasses to include in the generated module.
705 720
     These exceptions are available from instance methods and from module-level
@@ -732,8 +747,8 @@ Here's a list of all possible ``META`` options. No options are required. Adding
732 747
         module_name = "pizza_orders"
733 748
 
734 749
     If this isn't given, Django will use a lowercased version of the class
735  
-    name, plus "s". This "poor man's pluralization" is intentional: Any other
736  
-    level of magic pluralization would get confusing.
  750
+    name, plus ``"s"``. This "poor man's pluralization" is intentional: Any
  751
+    other level of magic pluralization would get confusing.
737 752
 
738 753
 ``order_with_respect_to``
739 754
     Marks this object as "orderable" with respect to the given field. This is
2  tests/testapp/models/__init__.py
... ...
@@ -1,4 +1,4 @@
1 1
 __all__ = ['basic', 'repr', 'custom_methods', 'many_to_one', 'many_to_many',
2 2
            'ordering', 'lookup', 'get_latest', 'm2m_intermediary', 'one_to_one',
3 3
            'm2o_recursive', 'm2o_recursive2', 'save_delete_hooks', 'custom_pk',
4  
-           'subclassing', 'many_to_one_null', 'custom_columns']
  4
+           'subclassing', 'many_to_one_null', 'custom_columns', 'reserved_names']
47  tests/testapp/models/reserved_names.py
... ...
@@ -0,0 +1,47 @@
  1
+"""
  2
+18. Using SQL reserved names
  3
+
  4
+Need to use a reserved SQL name as a column name or table name? Need to include
  5
+a hyphen in a column or table name? No problem. Django quotes names
  6
+appropriately behind the scenes, so your database won't complain about
  7
+reserved-name usage.
  8
+"""
  9
+
  10
+from django.core import meta
  11
+
  12
+class Thing(meta.Model):
  13
+    when = meta.CharField(maxlength=1, primary_key=True)
  14
+    join = meta.CharField(maxlength=1)
  15
+    like = meta.CharField(maxlength=1)
  16
+    drop = meta.CharField(maxlength=1)
  17
+    alter = meta.CharField(maxlength=1)
  18
+    having = meta.CharField(maxlength=1)
  19
+    where = meta.CharField(maxlength=1)
  20
+    has_hyphen = meta.CharField(maxlength=1, db_column='has-hyphen')
  21
+    class META:
  22
+       db_table = 'select'
  23
+
  24
+    def __repr__(self):
  25
+        return self.when
  26
+
  27
+API_TESTS = """
  28
+>>> t = things.Thing(when='a', join='b', like='c', drop='d', alter='e', having='f', where='g', has_hyphen='h')
  29
+>>> t.save()
  30
+>>> print t.when
  31
+a
  32
+
  33
+>>> u = things.Thing(when='h', join='i', like='j', drop='k', alter='l', having='m', where='n')
  34
+>>> u.save()
  35
+>>> print u.when
  36
+h
  37
+
  38
+>>> things.get_list(order_by=['when'])
  39
+[a, h]
  40
+>>> v = things.get_object(pk='a')
  41
+>>> print v.join
  42
+b
  43
+>>> print v.where
  44
+g
  45
+>>> things.get_list(order_by=['select.when'])
  46
+[a, h]
  47
+"""

0 notes on commit f6bf41e

Please sign in to comment.
Something went wrong with that request. Please try again.