Domains versus arrays versus typmods
От | Tom Lane |
---|---|
Тема | Domains versus arrays versus typmods |
Дата | |
Msg-id | 10055.1287526446@sss.pgh.pa.us обсуждение исходный текст |
Ответы |
Re: Domains versus arrays versus typmods
(Robert Haas <robertmhaas@gmail.com>)
|
Список | pgsql-hackers |
In bug #5717, Richard Huxton complains that a domain declared likeCREATE DOMAIN mynums numeric(4,2)[1]; doesn't work properly, ie, the typmod isn't enforced in places where it reasonably ought to be. I dug into this a bit, and found that there are more worms in this can than I first expected. In the first place, plpgsql seems a few bricks shy of a load, in that its code to handle assignment to an array element doesn't appear to be considering arrays with typmod at all: it just passes typmod -1 to exec_simple_cast_value() in the PLPGSQL_DTYPE_ARRAYELEM case in exec_assign_value(). Nonetheless, if you try a case like declare x numeric(4,2)[1];begin x[1] := $1; you'll find the typmod *is* enforced. It turns out that the reason that it works is that after constructing the modified array value, exec_assign_value() calls itself recursively to do the actual assignment to the array variable --- and that call sees that the array variable has a typmod, so it applies the cast *at the array level*, ie it disassembles the array, re-coerces each element, and builds a new array. So it's horridly inefficient but it works. That could and should be improved, but it seems to be just a matter of local changes in pl_exec.c, and it's only an efficiency hack anyway. The big problem is that none of this happens when the variable is declared as a domain, and I believe that that is a significantly more wide-ranging issue. The real issue as I see it is that it's possible to subscript an array without realizing that the array's type is really a domain that incorporates a typmod specification. This happens because of a hack we did to simplify implementation of domains over arrays: we expose the array element type as typelem of the domain as well. For example, given Richard's declaration we have regression=# select typname,oid,typelem,typbasetype,typtypmod from pg_type where typname = 'mynums';typname | oid | typelem| typbasetype | typtypmod ---------+-------+---------+-------------+-----------mynums | 92960 | 1700 | 1231 | 262150 (1 row) If we were to wrap another domain around that, we'd have regression=# create domain mynums2 as mynums; CREATE DOMAIN regression=# select typname,oid,typelem,typbasetype,typtypmod from pg_type where typname = 'mynums2';typname | oid | typelem| typbasetype | typtypmod ---------+-------+---------+-------------+-----------mynums2 | 92976 | 1700 | 92960 | -1 (1 row) and at this point it's completely unobvious from inspection of the pg_type entry that any typmod needs to be applied when subscripting. So I'm suspicious that there are a boatload of bugs related to this kind of domain declaration, not just the one case in plpgsql. I think that what we ought to do about it is to stop exposing typelem in domains' pg_type rows. If you want to subscript a domain value, you should have to drill down to its base type with getBaseTypeAndTypmod, which would also give you the correct typmod to apply. If we set typelem to zero in domain pg_type rows, it shouldn't take too long to find any places that are missing this consideration --- the breakage will be obvious rather than subtle. This catalog definitional change obviously shouldn't be back-patched, but possibly the ensuing code changes could be, since the typelem change is just to expose where things are wrong and wouldn't be a prerequisite for corrected code to behave correctly. Or we could decide that this is a corner case we're not going to try to fix in back branches. It's been wrong since day 0, so there's certainly an argument that it's not important enough to risk back-patching. Comments? regards, tom lane
В списке pgsql-hackers по дате отправления: