Thread: By Passed Domain Constraints

By Passed Domain Constraints

From
Robert Perry
Date:
     I have a database in which I used domains with check constraints  
to keep all the constraints nice and uniform for like columns across  
tables.  My users access and update data primarily through function  
calls that have parameters that of DOMAIN types.
    These constraints work when I call the functions via psql or  
from a PHP client.  But, my pqlib users seem to be able to get bad  
data in.  I have not done any real testing yet to track this down,  
but have looks through the archives and have not been able to spot  
anything.  Anybody else seen something like this?  Am I missing  
something fundamental.
    I have noticed that I can cast the bad data to the domain type,  
but not to a varchar and then the domain type.

i.e.

Select passcode::D_PASSCODE from  
employee_passcode;                      -- will work
Select passcode::varchar::D_PASSCODE from employee_passcode;      --  
properly complains --> ERROR:  value for domain d_passcode violates  
check constraint "d_passcode_check"

    It looks like the data is not checked when passed to the  
function and from their on out since it is already the correct type  
it is not checked again. Has anyone else seen something like this?
    I am using 8.0.1.  On the pqlib side we are calling PQexecParams  
and using NULL for param types for the function calls in question.



Re: By Passed Domain Constraints

From
Tom Lane
Date:
Robert Perry <rlperry@lodestonetechnologies.com> writes:
>      It looks like the data is not checked when passed to the  
> function and from their on out since it is already the correct type  
> it is not checked again. Has anyone else seen something like this?

IIRC, plpgsql does not know anything about domains and does not enforce
domain constraints when assigning to local variables or the function
result.  The same is true of the other PLs, though I think it could only
matter for the function result in those cases (internal variables aren't
of SQL types anyway for them).  You could probably work around this by
writing explicit casts to the domain inside the function, eg
"RETURN x::domain" not just "RETURN x".

I thought the unfinished work for domains was mentioned on the TODO list
but I don't see anything about it right now.
        regards, tom lane


Re: By Passed Domain Constraints

From
Robert Perry
Date:
     I'm sorry Tom, but I am not certain that I understand how this  
known problem applies to my problem.

select * from employee_passcode_update('system',100000, 'DOGGY');
ERROR:  value for domain d_passcode violates check constraint  
"d_passcode_check"
    I call the same function from pqlib using PQexecParams and the  
next thing I know.

select * from employee_passcode where id = 100000;   id   | passcode | mod_user |           timestamp
--------+----------+----------+-------------------------------
100000 | DOGGY    | system   | 2005-07-06 11:37:09.926907-04

Where

\df employee_passcode_update                                       List of functions
Schema |           Name           | Result data type |           
Argument data types
--------+--------------------------+------------------ 
+----------------------------------------
public | employee_passcode_update | d_employee_id    | d_user_name,  
d_employee_id, d_passcode

and

\d employee_passcode   Table "public.employee_passcode"  Column   |     Type      | Modifiers
-----------+---------------+-----------
id        | d_employee_id | not null
passcode  | d_passcode    |
mod_user  | d_user_name   |
timestamp | d_timestamp   |
Indexes:    "employee_passcode_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:    "employee_passcode_mod_user_fkey" FOREIGN KEY (mod_user)  
REFERENCES employee(user_name)
    The same plpgsql function is being called each time.   
Additionally, I believe that the same checks work from php.
    However, if I cast the D_PASSCODE to a varchar and back in the  
function implementation I do get the expected exception when called  
from PQexecParams.  Which is good.  It means I have a work around,  
though I really do not want to updated hundreds of functions to do  
this.  (I suspect that this will be my short term solution) Just  
casting to a D_PASSCODE does nothing.  I am guessing this is because  
p_passcode, my function parameter in question, is already a D_PASSCODE.
    I have also been bitten by the problem you are describing. But,  
that one is a problem even when called from psql if I am not  
mistaken.  Does psql not use pqlib?  Perhaps it is something about  
PQexecParams that is the problem.  I will test in a little while.

Thanks for you help
Robert Perry

On Jul 6, 2005, at 10:35 AM, Tom Lane wrote:

> Robert Perry <rlperry@lodestonetechnologies.com> writes:
>
>>      It looks like the data is not checked when passed to the
>> function and from their on out since it is already the correct type
>> it is not checked again. Has anyone else seen something like this?
>>
>
> IIRC, plpgsql does not know anything about domains and does not  
> enforce
> domain constraints when assigning to local variables or the function
> result.  The same is true of the other PLs, though I think it could  
> only
> matter for the function result in those cases (internal variables  
> aren't
> of SQL types anyway for them).  You could probably work around this by
> writing explicit casts to the domain inside the function, eg
> "RETURN x::domain" not just "RETURN x".
>
> I thought the unfinished work for domains was mentioned on the TODO  
> list
> but I don't see anything about it right now.
>
>             regards, tom lane
>
> ---------------------------(end of  
> broadcast)---------------------------
> TIP 2: you can get off all lists at once with the unregister command
>     (send "unregister YourEmailAddressHere" to  
> majordomo@postgresql.org)
>



Re: By Passed Domain Constraints

From
Tom Lane
Date:
Robert Perry <rlperry@lodestonetechnologies.com> writes:
>      I have also been bitten by the problem you are describing. But,  
> that one is a problem even when called from psql if I am not  
> mistaken.  Does psql not use pqlib?  Perhaps it is something about  
> PQexecParams that is the problem.  I will test in a little while.

[ thinks about it... ]  If you've declared the function input parameter
as a domain type and then write a parameterized query like... function($1) ...
and don't specify any particular datatype for the parameter symbol,
I think the backend will infer the domain type as the parameter type.
Which would also allow bypassing the domain checks.

You could work around this by explicitly specifying the parameter
type as text or varchar or whatever the domain's base type is.
I wonder though if we oughtn't change the backend so that the inferred
type of a parameter symbol is never a domain, but the domain's base
type.  That would force the proper application of CoerceToDomain inside
the constructed query parsetree.
        regards, tom lane


Re: By Passed Domain Constraints

From
Robert Perry
Date:
Tom
    Thank you very much.  This sounds like my problem exactly.   I  
personally, feel that the change you have described is the right way  
to go for PostgreSQL. But, since the thing that I expected to work  
does not and would with your suggested change I guess that my opinion  
is pretty predictable.
    B.T.W.  Using PQexec instead of PQexecParams also solves my  
problem.  But, that is not a surprise either given your assessment of  
the problem.  Since all of the C++ code in my project ends up calling  
a single function that calls PQexecParams (this was done to  
centralize the conversion of PostgreSQL exceptions to out own  
internal exception classes) I think it is going to be easier for us  
to make this function dynamically build a non parameterized query.   
But, I still appreciate your advice on a work around and I am holding  
it as my plan B.

Thanks again
Robert Perry

On Jul 6, 2005, at 12:05 PM, Tom Lane wrote:

> Robert Perry <rlperry@lodestonetechnologies.com> writes:
>
>>      I have also been bitten by the problem you are describing. But,
>> that one is a problem even when called from psql if I am not
>> mistaken.  Does psql not use pqlib?  Perhaps it is something about
>> PQexecParams that is the problem.  I will test in a little while.
>>
>
> [ thinks about it... ]  If you've declared the function input  
> parameter
> as a domain type and then write a parameterized query like
>     ... function($1) ...
> and don't specify any particular datatype for the parameter symbol,
> I think the backend will infer the domain type as the parameter type.
> Which would also allow bypassing the domain checks.
>
> You could work around this by explicitly specifying the parameter
> type as text or varchar or whatever the domain's base type is.
> I wonder though if we oughtn't change the backend so that the inferred
> type of a parameter symbol is never a domain, but the domain's base
> type.  That would force the proper application of CoerceToDomain  
> inside
> the constructed query parsetree.
>
>             regards, tom lane
>
> ---------------------------(end of  
> broadcast)---------------------------
> TIP 3: if posting/reading through Usenet, please send an appropriate
>        subscribe-nomail command to majordomo@postgresql.org so that  
> your
>        message can get through to the mailing list cleanly
>



Re: [HACKERS] By Passed Domain Constraints

From
Christopher Kings-Lynne
Date:
> You could work around this by explicitly specifying the parameter
> type as text or varchar or whatever the domain's base type is.
> I wonder though if we oughtn't change the backend so that the inferred
> type of a parameter symbol is never a domain, but the domain's base
> type.  That would force the proper application of CoerceToDomain inside
> the constructed query parsetree.

Remember we have similar weirdness when returning domain types from 
stored procs :(

Chris