[OGo-Developer] OGo, PostgreSQL 8.3, & INT casting

Adam Tauno Williams developer@opengroupware.org
Sat, 16 Feb 2008 16:02:35 -0500


PostgreSQL 8.3, and I think some builds of 8.2.x, not longer performing
automatic casting of INT to TEXT when INTs are compared to character
types. <http://www.postgresql.org/docs/8.3/static/release-8-3.html>
This causes at least ACL processing in OGo to die with -

ERROR:  IN types character varying and integer cannot be matched

 - because a query like -

SELECT DISTINCT B.company_id  FROM person AS B WHERE (( ( B.firstname
ILIKE '%%yser%%' ) OR ( B.name ILIKE '%%yser%%' ) ))  AND (( B.owner_id
= 10100 ) OR ( ( B.is_private = 0 OR B.is_private IS NULL ) AND (  ( 0 =
( SELECT COUNT(*) FROM object_acl WHERE object_id = B.company_id ) OR 0
< ( SELECT COUNT(*) FROM object_acl WHERE object_id = B.company_id AND
action = 'allowed' AND permissions LIKE '%r%' AND ( auth_id = 10100 OR
auth_id IN ( 9981, 9991, 10003, 11530, 55000, 77210, 142730, 142780,
142850, 393280, 423400, 445160, 949410, 949540, 955770, 970730, 970990,
1096320, 9153790, 9153880, 9154000, 10597021, 10735169 ) ) ) )  ) )) AND
(B.is_template_user IS NULL OR B.is_template_user = 0) AND (B.db_status
<> 'archived') LIMIT 50

 - is generated where object_acl.auth_id [a CHAR(255)] is IN'd with an
integer list.   Altering this query to -

  ... auth_id::INT IN ( 9981, 9991, ....)

- fixes this.  On the other hand I think a better fix is just to make
auth_id an integer column.  I've never seen this column be anything but
an integer [object id] and integer comparison and integer set comparison
is faster than processing text types.

I've done -
OGo=# ALTER TABLE object_acl ADD auth_id_int INT;
OGo=# UPDATE object_acl SET auth_id_int = auth_id::INT;
OGo=# ALTER TABLE object_acl DROP auth_id;
OGo=# ALTER TABLE object_acl ADD auth_id INT;
OGo=# UPDATE object_acl SET auth_id = auth_id_int;
OGo=# ALTER TABLE object_acl DROP auth_id_int;
OGo=# VACUUM ANALYZE object_acl;

This fixes the issue and everything still seems to work fine.

The "original" object_acl table is -

CREATE TABLE object_acl (
  object_acl_id int not null,
  sort_key      int not null,
  action        varchar(10) not null,
  object_id     varchar(255) not null,
  auth_id       varchar(255),
  permissions   varchar(50));
 
To me it just seems like having object_id and auth_id as VARCHAR(255) is
pointless.

I've also proceeded to change object_id to an INT -

OGo=# ALTER TABLE object_acl ADD object_id_int INT;
OGo=# UPDATE object_acl SET object_id_int = object_id::INT;
OGo=# ALTER TABLE object_acl DROP object_id;
OGo=# ALTER TABLE object_acl ADD object_id INT;
OGo=# UPDATE object_acl SET object_id = object_id_int;
OGo=# ALTER TABLE object_acl DROP object_id_int;
OGo=# VACUUM ANALYZE object_acl;

 - leaving me with a table of - 

    Column     |         Type          | Modifiers 
 object_acl_id | integer               | not null
 sort_key      | integer               | not null
 action        | character varying(10) | not null
 permissions   | character varying(50) | 
 auth_id       | integer               | 
 object_id     | integer               | 

Everything still works.  

However, the OGoModel represents these data-types as VARCHAR(255), so
maybe my fix isn't appropriate.

<snip>
        {
          name           = "authId";
          columnName     = "auth_id";
          externalType   = "VARCHAR(255)";
          valueClassName = "NSString";
          allowsNull     = Y;
          width          = 255;
        },
        {
          name           = "objectAclId";
          columnName     = "object_acl_id";
          externalType   = "INT";
          valueClassName = "NSNumber";
          valueType      = i;
        },
        {
          name           = "objectId";
          columnName     = "object_id";
          externalType   = "VARCHAR(255)";
          valueClassName = "NSString";
          width          = 255;
        },
</snap>

I haven't tried modifying the model to use INT/NSNumber yet.  Personally
I think just storing INTs is better [and faster],  but maybe the
object_acl has some [edge / undocumented] functionality I'm not aware
of?