#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 [email protected].
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