#35336: Adding GeneratedField fails with ProgrammingError when using When on
CharField
-------------------------------------+-------------------------------------
     Reporter:  Adrian Garcia        |                    Owner:  Simon
                                     |  Charette
         Type:  Bug                  |                   Status:  assigned
    Component:  Database layer       |                  Version:  5.0
  (models, ORM)                      |
     Severity:  Release blocker      |               Resolution:
     Keywords:  postgres,            |             Triage Stage:  Accepted
  generatedfield, contains           |
    Has patch:  1                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  1
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Changes (by Simon Charette):

 * has_patch:  0 => 1
 * needs_better_patch:  0 => 1

Comment:

 > Out of curiosity, why does this issue only present itself when adding a
 field? Does Django handle SQL generation differently for table creation vs
 field addition?

 I'm still laying down the details
 [https://github.com/django/django/pull/18027 in this MR] but the short
 answer is yes.

 The DBAPI `Cursor.execute` method can be used in two ways when dealing
 with parameters. Either `(sql: str, params: [])` which will delegate
 parametrization to the library or `(sql: str, params: None)` which won't
 attempt to parametrize the SQL. This is an important difference and
 requires special care when dealing with `%` literals in parameters as it's
 the symbol use for parametrization placeholders by most libraries.

 Well some backend simply don't support parametrization in some DDL
 statements such as `GENERATED` columns declaration, in other words you
 can't do

 {{{#!python
 cursor.execute(
     "ALTER TABLE invoice ADD COLUMN discount_display text GENERATED ALWAYS
 discount || %s;",
     ["%"]
 )
 }}}

 So you must do

 {{{#!python
 cursor.execute(
     "ALTER TABLE invoice ADD COLUMN discount_display text GENERATED ALWAYS
 AS discount || '%';", None
 )
 }}}

 Well in the case of `SchemaEditor.create_model` we liberally do one or the
 other and in your case, because you don't have any other field with a
 `db_default` assuming your use Postgres, it does the right thing.

 In the case of `SchemaEditor.add_field` however we always do `params:
 list`, which forces parametrization, and thus

 {{{#!python
 cursor.execute(
     "ALTER TABLE testmodel ADD COLUMN contains_heck text GENERATED ALWAYS
 AS UPPER(description) LIKE '%HECK%';", []
 )
 }}}

 Crashes as there is an attempt to interpolate the two `%` while `params`
 is empty.

 The schema migration has historically use parametrizable DDL in the past
 when possible but this has become increasingly complex as more and more
 features were added (indexes, constraints, `db_default`, `GeneratedField`)
 to a point where I don't think we can continue doing so but the tricky
 part is that we can't make such a change in a bug fix release without
 risking to introduce further problems. This is made even worst by the fact
 that objects as `Index` and `Constraint` subclasses return already
 interpolated SQL (their `as_sql` methods return `"CHECK UPPER(description)
 LIKE '%HECK%'"` instead of `("CHECK UPPER(description) LIKE %s",
 "%HECK%")` so even if we wanted to use it entirely to the backend until
 the last minute by using `quote_value` ourselves we can't as by that point
 we have a mixture of interpolated and non-interpolated SQL.
-- 
Ticket URL: <https://code.djangoproject.com/ticket/35336#comment:3>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/0107018e85bd49fd-1ec7c223-0d2b-42a0-b93a-b156e26d2245-000000%40eu-central-1.amazonses.com.

Reply via email to