Line data Source code
1 : #include "postgres.h"
2 :
3 : #include "fmgr.h"
4 : #include "hstore/hstore.h"
5 : #include "miscadmin.h"
6 : #include "plperl.h"
7 :
8 3 : PG_MODULE_MAGIC_EXT(
9 : .name = "hstore_plperl",
10 : .version = PG_VERSION
11 : );
12 :
13 : /* Linkage to functions in hstore module */
14 : typedef HStore *(*hstoreUpgrade_t) (Datum orig);
15 : static hstoreUpgrade_t hstoreUpgrade_p;
16 : typedef int (*hstoreUniquePairs_t) (Pairs *a, int32 l, int32 *buflen);
17 : static hstoreUniquePairs_t hstoreUniquePairs_p;
18 : typedef HStore *(*hstorePairs_t) (Pairs *pairs, int32 pcount, int32 buflen);
19 : static hstorePairs_t hstorePairs_p;
20 : typedef size_t (*hstoreCheckKeyLen_t) (size_t len);
21 : static hstoreCheckKeyLen_t hstoreCheckKeyLen_p;
22 : typedef size_t (*hstoreCheckValLen_t) (size_t len);
23 : static hstoreCheckValLen_t hstoreCheckValLen_p;
24 :
25 : /* Static asserts verify that typedefs above match original declarations */
26 : StaticAssertVariableIsOfType(&hstoreUpgrade, hstoreUpgrade_t);
27 : StaticAssertVariableIsOfType(&hstoreUniquePairs, hstoreUniquePairs_t);
28 : StaticAssertVariableIsOfType(&hstorePairs, hstorePairs_t);
29 : StaticAssertVariableIsOfType(&hstoreCheckKeyLen, hstoreCheckKeyLen_t);
30 : StaticAssertVariableIsOfType(&hstoreCheckValLen, hstoreCheckValLen_t);
31 :
32 :
33 : /*
34 : * Module initialize function: fetch function pointers for cross-module calls.
35 : */
36 : void
37 3 : _PG_init(void)
38 : {
39 3 : hstoreUpgrade_p = (hstoreUpgrade_t)
40 3 : load_external_function("$libdir/hstore", "hstoreUpgrade",
41 : true, NULL);
42 3 : hstoreUniquePairs_p = (hstoreUniquePairs_t)
43 3 : load_external_function("$libdir/hstore", "hstoreUniquePairs",
44 : true, NULL);
45 3 : hstorePairs_p = (hstorePairs_t)
46 3 : load_external_function("$libdir/hstore", "hstorePairs",
47 : true, NULL);
48 3 : hstoreCheckKeyLen_p = (hstoreCheckKeyLen_t)
49 3 : load_external_function("$libdir/hstore", "hstoreCheckKeyLen",
50 : true, NULL);
51 3 : hstoreCheckValLen_p = (hstoreCheckValLen_t)
52 3 : load_external_function("$libdir/hstore", "hstoreCheckValLen",
53 : true, NULL);
54 3 : }
55 :
56 :
57 : /* These defines must be after the module init function */
58 : #define hstoreUpgrade hstoreUpgrade_p
59 : #define hstoreUniquePairs hstoreUniquePairs_p
60 : #define hstorePairs hstorePairs_p
61 : #define hstoreCheckKeyLen hstoreCheckKeyLen_p
62 : #define hstoreCheckValLen hstoreCheckValLen_p
63 :
64 :
65 5 : PG_FUNCTION_INFO_V1(hstore_to_plperl);
66 :
67 : Datum
68 7 : hstore_to_plperl(PG_FUNCTION_ARGS)
69 : {
70 7 : dTHX;
71 7 : HStore *in = PG_GETARG_HSTORE_P(0);
72 : int i;
73 7 : int count = HS_COUNT(in);
74 7 : char *base = STRPTR(in);
75 7 : HEntry *entries = ARRPTR(in);
76 : HV *hv;
77 :
78 7 : hv = newHV();
79 :
80 20 : for (i = 0; i < count; i++)
81 : {
82 : const char *key;
83 : SV *value;
84 :
85 13 : key = pnstrdup(HSTORE_KEY(entries, base, i),
86 13 : HSTORE_KEYLEN(entries, i));
87 13 : value = HSTORE_VALISNULL(entries, i) ? newSV(0) :
88 7 : cstr2sv(pnstrdup(HSTORE_VAL(entries, base, i),
89 7 : HSTORE_VALLEN(entries, i)));
90 :
91 13 : (void) hv_store(hv, key, strlen(key), value, 0);
92 : }
93 :
94 7 : return PointerGetDatum(newRV((SV *) hv));
95 : }
96 :
97 :
98 6 : PG_FUNCTION_INFO_V1(plperl_to_hstore);
99 :
100 : Datum
101 7 : plperl_to_hstore(PG_FUNCTION_ARGS)
102 : {
103 7 : dTHX;
104 7 : SV *in = (SV *) PG_GETARG_POINTER(0);
105 : HV *hv;
106 : HE *he;
107 : int32 buflen;
108 : int32 i;
109 : int32 pcount;
110 : HStore *out;
111 : Pairs *pairs;
112 :
113 : /* Dereference references recursively. */
114 13 : while (SvROK(in))
115 : {
116 : /*
117 : * It's possible for circular references to make this an infinite
118 : * loop. Checking for such a situation seems like much more trouble
119 : * than it's worth, but let's provide a way to break out of the loop.
120 : */
121 6 : CHECK_FOR_INTERRUPTS();
122 6 : in = SvRV(in);
123 : }
124 :
125 : /* Now we must have a hash. */
126 7 : if (SvTYPE(in) != SVt_PVHV)
127 2 : ereport(ERROR,
128 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
129 : errmsg("cannot transform non-hash Perl value to hstore")));
130 5 : hv = (HV *) in;
131 :
132 5 : pcount = hv_iterinit(hv);
133 :
134 5 : pairs = palloc_array(Pairs, pcount);
135 :
136 5 : i = 0;
137 18 : while ((he = hv_iternext(hv)))
138 : {
139 13 : char *key = sv2cstr(HeSVKEY_force(he));
140 13 : SV *value = HeVAL(he);
141 :
142 13 : pairs[i].key = pstrdup(key);
143 13 : pairs[i].keylen = hstoreCheckKeyLen(strlen(pairs[i].key));
144 13 : pairs[i].needfree = true;
145 :
146 13 : if (!SvOK(value))
147 : {
148 4 : pairs[i].val = NULL;
149 4 : pairs[i].vallen = 0;
150 4 : pairs[i].isnull = true;
151 : }
152 : else
153 : {
154 9 : pairs[i].val = pstrdup(sv2cstr(value));
155 9 : pairs[i].vallen = hstoreCheckValLen(strlen(pairs[i].val));
156 9 : pairs[i].isnull = false;
157 : }
158 :
159 13 : i++;
160 : }
161 :
162 5 : pcount = hstoreUniquePairs(pairs, pcount, &buflen);
163 5 : out = hstorePairs(pairs, pcount, buflen);
164 5 : PG_RETURN_POINTER(out);
165 : }
|