From: | Joseph Adams <joeyadams3(dot)14159(at)gmail(dot)com> |
---|---|
To: | PostgreSQL-development <pgsql-hackers(at)postgresql(dot)org> |
Subject: | Working with PostgreSQL enums in C code |
Date: | 2010-05-28 04:07:12 |
Message-ID: | AANLkTinlohONjqxaePe2reJEeI9Z0JA5qThswyfAjTEQ@mail.gmail.com |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Thread: | |
Lists: | pgsql-hackers |
I encountered a situation while implementing JSON support where I
needed to return an enum value from a C function. To clarify, here's
the SQL:
CREATE TYPE json_type_t AS ENUM ('null', 'string', 'number', 'bool',
'object', 'array');
CREATE OR REPLACE FUNCTION json_type(json)
RETURNS json_type_t
AS 'MODULE_PATHNAME','json_get_type'
LANGUAGE C STRICT IMMUTABLE;
I initially tried looking for another function returning an enum in
the PostgreSQL source tree, but I couldn't find any. I guess this is
because enums are a relatively new feature in PostgreSQL.
I learned that to return an enum value from C, one needs to return the
OID of the right row of the pg_enum table. I eventually managed to
write the code below, which is mostly based on the enum_in function in
src/backend/utils/adt/enum.c .
#define PG_RETURN_ENUM(typname, label) return enumLabelToOid(typname, label)
static Oid enumLabelToOid(const char *typname, const char *label)
{
Oid enumtypoid;
HeapTuple tup;
Oid ret;
enumtypoid = TypenameGetTypid(typname);
Assert(OidIsValid(enumtypoid));
tup = SearchSysCache2(ENUMTYPOIDNAME,
ObjectIdGetDatum(enumtypoid),
CStringGetDatum(label));
Assert(HeapTupleIsValid(tup));
ret = HeapTupleGetOid(tup);
ReleaseSysCache(tup);
return ret;
}
Feel free to nitpick the code above, as I'm still learning. Note that
I replaced the more robust validity checks of enum_in with (quicker?)
asserts, with the assumption that correct programs would only pass
valid values to PG_RETURN_ENUM .
The code using the method above can be found here:
http://git.postgresql.org/gitweb?p=json-datatype.git;a=tree;f=contrib/json;h=1dd813da4016b31f35cb39b01c6d5f0999da672e;hb=092fa046f95580dd7906a07370ca401692a1f818
. My testcases passed, so everything seems to work.
I suppose my PG_RETURN_ENUM macro is nice and simple, except for the
fact that the coder has to keep an enum names table in sync with the
SQL code and the C code. However, going the other way around
(PG_GETARG_ENUM) would need access to that enum names table. Hence,
it'd make sense to have macros for defining this table so both
PG_RETURN_ENUM and PG_GETARG_ENUM can reference it.
I believe that these macros would be a useful addition to the
PostgreSQL function manager API, as they would provide a decent way to
receive and return custom enums from C code. Anyone agree/disagree?
Joey Adams
From | Date | Subject | |
---|---|---|---|
Next Message | Sander, Ingo (NSN - DE/Munich) | 2010-05-28 04:26:27 | Re: Streaming Replication: Checkpoint_segment and wal_keep_segments on standby |
Previous Message | Tom Lane | 2010-05-28 04:06:03 | Re: functional call named notation clashes with SQL feature |