Skip to content

Commit 2adba89

Browse files
committed
[FIX] util.column_type: optionally return the max length of varchar colums
Returning the max length in ff3001a was a good idea, but that changed the API and break a few existing scripts that compared the result to "varchar"[^1]. Now, the sized should be explicitly asked for. Adapt calls that needs it. [^1]: notably, the one that handle the conversion of the translated fields to jsonb. Part-of: #345 Related: odoo/upgrade#8715 Signed-off-by: Christophe Simonis (chs) <[email protected]>
1 parent 6340bad commit 2adba89

File tree

2 files changed

+34
-24
lines changed

2 files changed

+34
-24
lines changed

src/base/tests/test_util.py

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -720,18 +720,21 @@ def test_iter_browse_call_twice(self):
720720
class TestPG(UnitTestCase):
721721
@parametrize(
722722
[
723-
("res_country", "name", "jsonb" if util.version_gte("16.0") else "varchar"), # translated field
724-
("res_country", "code", "varchar(2)"),
725-
("res_currency", "active", "bool"),
726-
("res_country", "create_date", "timestamp"),
727-
("res_currency", "create_uid", "int4"),
728-
("res_country", "name_position", "varchar"),
729-
("res_country", "address_format", "text"),
730-
("res_partner", "does_not_exists", None),
723+
("res_country", "name", False, "jsonb" if util.version_gte("16.0") else "varchar"), # translated field
724+
("res_country", "code", False, "varchar"),
725+
("res_country", "code", True, "varchar(2)"),
726+
("res_currency", "active", False, "bool"),
727+
("res_currency", "active", True, "bool"),
728+
("res_country", "create_date", False, "timestamp"),
729+
("res_currency", "create_uid", False, "int4"),
730+
("res_country", "name_position", False, "varchar"),
731+
("res_country", "name_position", True, "varchar"),
732+
("res_country", "address_format", False, "text"),
733+
("res_partner", "does_not_exists", False, None),
731734
]
732735
)
733-
def test_column_type(self, table, column, expected):
734-
value = util.column_type(self.env.cr, table, column)
736+
def test_column_type(self, table, column, sized, expected):
737+
value = util.column_type(self.env.cr, table, column, sized=sized)
735738
if expected is None:
736739
self.assertIsNone(value)
737740
else:
@@ -762,11 +765,14 @@ def test_alter_column_type(self):
762765
"Some values where not casted correctly via USING",
763766
)
764767

765-
self.assertEqual(util.column_type(cr, "res_partner_bank", "y"), "varchar(4)")
768+
self.assertEqual(util.column_type(cr, "res_partner_bank", "y"), "varchar")
769+
self.assertEqual(util.column_type(cr, "res_partner_bank", "y", sized=True), "varchar(4)")
766770
util.alter_column_type(cr, "res_partner_bank", "y", "varchar")
767771
self.assertEqual(util.column_type(cr, "res_partner_bank", "y"), "varchar")
772+
self.assertEqual(util.column_type(cr, "res_partner_bank", "y", sized=True), "varchar")
768773
util.alter_column_type(cr, "res_partner_bank", "y", "varchar(12)")
769-
self.assertEqual(util.column_type(cr, "res_partner_bank", "y"), "varchar(12)")
774+
self.assertEqual(util.column_type(cr, "res_partner_bank", "y"), "varchar")
775+
self.assertEqual(util.column_type(cr, "res_partner_bank", "y", sized=True), "varchar(12)")
770776

771777
@parametrize(
772778
[

src/util/pg.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -501,15 +501,15 @@ def get_value_or_en_translation(cr, table, column):
501501

502502

503503
def _column_info(cr, table, column):
504+
# -> tuple[str, int | None, bool, bool] | None
504505
_validate_table(table)
505-
# NOTE: usage of both `CONCAT` and `||` in the query below is done on purpose to take advantage of their NULL handling.
506-
# NULLS propagate with `||` and are ignored by `CONCAT`.
507506
cr.execute(
508507
"""
509-
SELECT CONCAT(
510-
COALESCE(bt.typname, t.typname),
511-
'(' || information_schema._pg_char_max_length(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*)) || ')'
512-
) AS udt_name,
508+
SELECT COALESCE(bt.typname, t.typname) AS udt_name,
509+
information_schema._pg_char_max_length(
510+
information_schema._pg_truetypid(a.*, t.*),
511+
information_schema._pg_truetypmod(a.*, t.*)
512+
) AS char_max_length,
513513
NOT (a.attnotnull OR t.typtype = 'd' AND t.typnotnull) AS is_nullable,
514514
( c.relkind IN ('r','p','v','f')
515515
AND pg_column_is_updatable(c.oid::regclass, a.attnum, false)
@@ -589,7 +589,7 @@ def column_exists(cr, table, column):
589589
return _COLUMNS[(table, column)] if (table, column) in _COLUMNS else (_column_info(cr, table, column) is not None)
590590

591591

592-
def column_type(cr, table, column):
592+
def column_type(cr, table, column, sized=False):
593593
"""
594594
Return the type of a column, if it exists.
595595
@@ -598,17 +598,21 @@ def column_type(cr, table, column):
598598
:rtype: SQL type of the column
599599
"""
600600
nfo = _column_info(cr, table, column)
601+
if not nfo:
602+
return None
603+
if sized and nfo[1]:
604+
return "{}({})".format(nfo[0], nfo[1])
601605
return nfo[0] if nfo else None
602606

603607

604608
def column_nullable(cr, table, column):
605609
nfo = _column_info(cr, table, column)
606-
return nfo and nfo[1]
610+
return nfo and nfo[2]
607611

608612

609613
def column_updatable(cr, table, column):
610614
nfo = _column_info(cr, table, column)
611-
return nfo and nfo[2]
615+
return nfo and nfo[3]
612616

613617

614618
def _normalize_pg_type(type_):
@@ -672,7 +676,7 @@ def create_column(cr, table, column, definition, **kwargs):
672676
if definition == "bool" and default is no_def:
673677
default = False
674678

675-
curtype = column_type(cr, table, column)
679+
curtype = column_type(cr, table, column, sized=True)
676680
if curtype:
677681
if curtype != definition:
678682
_logger.error("%s.%s already exists but is %r instead of %r", table, column, curtype, definition)
@@ -738,7 +742,7 @@ def alter_column_type(cr, table, column, type, using=None, where=None, logger=_l
738742
raise ValueError("`where` parameter is only relevant with a non-default `using` parameter")
739743

740744
if not using:
741-
current_type = column_type(cr, table, column)
745+
current_type = column_type(cr, table, column, sized=True)
742746
if current_type and current_type == _normalize_pg_type(type):
743747
logger.info("Column %r of table %r is already defined as %r", column, table, type)
744748
return
@@ -1884,7 +1888,7 @@ def bulk_update_table(cr, table, columns, mapping, key_col="id"):
18841888
cols=ColumnList.from_unquoted(cr, columns),
18851889
cols_values=SQLStr(
18861890
", ".join(
1887-
"(m.value->>{:d})::{}".format(col_idx, column_type(cr, table, col_name))
1891+
"(m.value->>{:d})::{}".format(col_idx, column_type(cr, table, col_name, sized=True))
18881892
for col_idx, col_name in enumerate(columns)
18891893
)
18901894
),

0 commit comments

Comments
 (0)