Thread: typmod is always -1

typmod is always -1

From
Pavel Stehule
Date:
Hello

I am playing with custom typmod. I did simple wrapper over varchar type.

PG_FUNCTION_INFO_V1(mvarcharin);

Datum
mvarcharin(PG_FUNCTION_ARGS)
{
elog(NOTICE, ">>>>>>>>%d", PG_GETARG_INT32(2));       return DirectFunctionCall3(varchar,
           DirectFunctionCall3(varcharin, 
    PG_GETARG_DATUM(0),
    PG_GETARG_DATUM(1),
    Int32GetDatum(-1)),                                           PG_GETARG_DATUM(2),/* original typmod */
                            BoolGetDatum(true));/* explit casting, quite truncate */ 
}


CREATE TYPE mvarchar (       INPUT = mvarcharin,       OUTPUT = mvarcharout,       LIKE = pg_catalog.varchar,
typmod_in= pg_catalog.varchartypmodin,       typmod_out = pg_catalog.varchartypmodout 
);

I have a problem - every call of mvarcharin is with typmod = -1.

postgres=# create table x(a mvarchar(3));
CREATE TABLE
Time: 29,930 ms
postgres=# \d x         Table "public.x"
┌────────┬─────────────┬───────────┐
│ Column │ Type        │ Modifiers │
├────────┴─────────────┴───────────┤
│ a      │ mvarchar(3) │           │
└──────────────────────────────────┘


postgres=# INSERT INTO x values('abcdef');
NOTICE:  >>>>>>>>-1
INSERT 0 1
Time: 2,244 ms
postgres=#

can somebody navigate me?

regards
Pavel Stehule

Re: typmod is always -1

From
Tom Lane
Date:
Pavel Stehule <pavel.stehule@gmail.com> writes:
> I have a problem - every call of mvarcharin is with typmod = -1.

Sure your typmod_in function works?

Also, there are a bunch of scenarios where we rely on a cast function to
apply the typmod rather than passing it to the input function initially.
I'm not sure if the particular case you're checking here falls into that
category, but you definitely should have a "length conversion cast"
function in pg_cast if you expect to do anything useful with typmod.
        regards, tom lane


Re: typmod is always -1

From
Pavel Stehule
Date:
2009/3/17 Tom Lane <tgl@sss.pgh.pa.us>:
> Pavel Stehule <pavel.stehule@gmail.com> writes:
>> I have a problem - every call of mvarcharin is with typmod = -1.
>
> Sure your typmod_in function works?
>
> Also, there are a bunch of scenarios where we rely on a cast function to
> apply the typmod rather than passing it to the input function initially.
> I'm not sure if the particular case you're checking here falls into that
> category, but you definitely should have a "length conversion cast"
> function in pg_cast if you expect to do anything useful with typmod.

thank you. It is it.

What I understand, this behave is little bit confusing and undocumented :(

regards
Pavel Stehule

>
>                        regards, tom lane
>


typmod is always -1

From
Chapman Flack
Date:
nothing like resurrecting a really old thread ...

> Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com> writes:
>> I have a problem - every call of mvarcharin is with typmod = -1.

2009/3/17 Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>:
> Also, there are a bunch of scenarios where we rely on a cast function to
> apply the typmod rather than passing it to the input function initially.
> I'm not sure if the particular case you're checking here falls into that
> category,

Is it possible to name any case that *does not* fall into that category?

I'm in the same boat ... I have an input function I want to test, and so
far I have failed to think of *any* sql construct that causes it to be
invoked with other than -1 for the typmod.

> but you definitely should have a "length conversion cast"
> function in pg_cast if you expect to do anything useful with typmod.

Ok, that's good to know (and I didn't until now). But back to the
input and recv functions, which are both documented to have 3-arg
forms that get typmods ... how would one test them?  Is there any
sql syntax that can be written to make them get passed a typmod?

If I just write them with assert(typmod == -1), will anyone ever
see a failure?

-Chap



Re: typmod is always -1

From
Tom Lane
Date:
Chapman Flack <chap@anastigmatix.net> writes:
> I'm in the same boat ... I have an input function I want to test, and so
> far I have failed to think of *any* sql construct that causes it to be
> invoked with other than -1 for the typmod.

COPY was the first case a quick grep came across.
        regards, tom lane



Re: typmod is always -1

From
Chapman Flack
Date:
On 03/17/16 09:35, Tom Lane wrote:
> Chapman Flack <chap@anastigmatix.net> writes:
>> I'm in the same boat ... I have an input function I want to test, and so
>> far I have failed to think of *any* sql construct that causes it to be
>> invoked with other than -1 for the typmod.
> 
> COPY was the first case a quick grep came across.

Thanks, that does make a working test. Given a table with a typmod'd
column, COPY FROM exercises the 'input' function with a typmod != -1,
and COPY FROM (FORMAT BINARY) likewise exercises the 'receive' function.

While I'm here, I guess I should check the sense I am getting of what
can and can't be workable semantics for type modifiers.

It seems that a typmod can only be used restrict the set of possible
values of the unmodified type (as clearly seen in the language "length
conversion cast", since certainly a typmod allowing { string | length < N }
is doing nothing but enforcing a subset of { string }. Each element of
the subset is still a valid element of the whole set (naturally, boring)
*and has to be represented the same way* (interesting): the representation
mustn't do clever things that you would need to know the typmod in order to
interpret, because most uses of a value are without access to the typmod.

So, the generalization of "length conversion cast" could be something like
"typmod application cast" and the only things a typmod application cast can
do to a value V are:

1. pass V unchanged if it is in the subset implied by the typmod
2. silently pass some V' that is in that subset and "close to" V  in some sense (longest initial substring shorter than
N,nearest  numeric value with no more than N precision digits, etc.)
 
3. fail

with sometimes the choice of (2) or (3) depending on whether the cast
is explicit or not.

All in all, very like a domain, except a domain can only do (1) or (3),
not (2).

Differences in representation, like short strings getting 1-byte headers,
are only possible as a consequence of a lower layer doing that consistently
to all values that happen to be short, and not as an effect of a typmod.

Am I getting it about right?

-Chap



Re: typmod is always -1

From
Tom Lane
Date:
Chapman Flack <chap@anastigmatix.net> writes:
> It seems that a typmod can only be used restrict the set of possible
> values of the unmodified type (as clearly seen in the language "length
> conversion cast", since certainly a typmod allowing { string | length < N }
> is doing nothing but enforcing a subset of { string }. Each element of
> the subset is still a valid element of the whole set (naturally, boring)
> *and has to be represented the same way* (interesting): the representation
> mustn't do clever things that you would need to know the typmod in order to
> interpret, because most uses of a value are without access to the typmod.

You do need to be able to interpret values of the type without having
separate access to the typmod, but I don't think it follows that it's as
restrictive as you say.  One easy way around that is to store the typmod
in the value.

Practical uses might include compressing the data in different ways
depending on typmod.  I'm drawing a blank on other compelling examples
though I'm sure there are some.  Have you looked at PostGIS?  I'm pretty
sure some of their types make use of typmod in nontrivial ways.
        regards, tom lane



Re: typmod is always -1

From
Jim Nasby
Date:
On 3/17/16 7:40 PM, Tom Lane wrote:
> Chapman Flack <chap@anastigmatix.net> writes:
>> It seems that a typmod can only be used restrict the set of possible
>> values of the unmodified type (as clearly seen in the language "length
>> conversion cast", since certainly a typmod allowing { string | length < N }
>> is doing nothing but enforcing a subset of { string }. Each element of
>> the subset is still a valid element of the whole set (naturally, boring)
>> *and has to be represented the same way* (interesting): the representation
>> mustn't do clever things that you would need to know the typmod in order to
>> interpret, because most uses of a value are without access to the typmod.
>
> You do need to be able to interpret values of the type without having
> separate access to the typmod, but I don't think it follows that it's as
> restrictive as you say.  One easy way around that is to store the typmod
> in the value.
>
> Practical uses might include compressing the data in different ways
> depending on typmod.  I'm drawing a blank on other compelling examples
> though I'm sure there are some.  Have you looked at PostGIS?  I'm pretty
> sure some of their types make use of typmod in nontrivial ways.

If you want a non-trivial use of typmod, take a look at the (work in 
progress) variant type I created[1]. It allows you pass names of 
"registered variants" in via typmod. The idea behind that is to restrict 
what types you can actually store in a particular variant field (though 
you can also disallow a registered variant from being used in a table 
definition).

I did run into some cases where Postgres ignored typmod, so I special 
case the default typmod (-1) to a registered variant that's disabled.

[1] 
https://github.com/BlueTreble/variant/blob/master/doc/variant.md#variant-modifier
-- 
Jim Nasby, Data Architect, Blue Treble Consulting, Austin TX
Experts in Analytics, Data Architecture and PostgreSQL
Data in Trouble? Get it in Treble! http://BlueTreble.com