pgtypes: Support cidr and inet
This commit is contained in:
parent
b66610e25a
commit
7076714296
3 changed files with 59 additions and 2 deletions
3
FU.xs
3
FU.xs
|
|
@ -1,4 +1,7 @@
|
|||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#undef PERL_IMPLICIT_SYS
|
||||
|
|
|
|||
53
c/pgtypes.c
53
c/pgtypes.c
|
|
@ -326,6 +326,55 @@ SENDFN(array) {
|
|||
|
||||
#undef ARRAY_MAXDIM
|
||||
|
||||
|
||||
RECVFN(inet) { /* Also works for cidr */
|
||||
char tmp[128];
|
||||
if (len < 8) RERR("input data too short");
|
||||
// 0: ip_family, 1: mask_bits, 2: is_cidr, 3: addrsize, 4: address
|
||||
|
||||
if (buf[0] == 2) { /* INET */
|
||||
RLEN(8);
|
||||
if (!inet_ntop(AF_INET, buf+4, tmp, sizeof(tmp)-1)) RERR("%s", strerror(errno));
|
||||
} else if (buf[0] == 3) { /* INET6 */
|
||||
RLEN(20);
|
||||
if (!inet_ntop(AF_INET6, buf+4, tmp, sizeof(tmp)-1)) RERR("%s", strerror(errno));
|
||||
} else RERR("unknown address type");
|
||||
|
||||
if (buf[2] || buf[1] != (buf[0] == 2 ? 32 : (char)128))
|
||||
return newSVpvf("%s/%d", tmp, (unsigned char)buf[1]);
|
||||
return newSVpv(tmp, 0);
|
||||
}
|
||||
|
||||
SENDFN(inet) {
|
||||
char tmp[128];
|
||||
STRLEN len;
|
||||
const char *in = SvPV(val, len);
|
||||
if (len >= sizeof(tmp)) SERR("input too long");
|
||||
char family = strchr(in, ':') ? 3 : 2;
|
||||
char *wr = fustr_write_buf(out, family == 2 ? 8 : 20);
|
||||
unsigned char *mask = (unsigned char*)wr+1;
|
||||
wr[0] = family;
|
||||
*mask = family == 2 ? 32 : 128;
|
||||
wr[2] = ctx->oid == 650;
|
||||
wr[3] = family == 2 ? 4 : 16;
|
||||
|
||||
char *slash = strchr(in, '/');
|
||||
if (slash && slash - in < 100) {
|
||||
memcpy(tmp, in, slash - in);
|
||||
tmp[slash - in] = 0;
|
||||
in = tmp;
|
||||
}
|
||||
if (inet_pton(family == 2 ? AF_INET : AF_INET6, in, wr+4) != 1)
|
||||
SERR("invalid address");
|
||||
|
||||
if (slash) {
|
||||
UV uv = 129;
|
||||
if (!grok_atoUV(slash+1, &uv, NULL) || uv > *mask)
|
||||
SERR("invalid mask");
|
||||
*mask = uv;
|
||||
}
|
||||
}
|
||||
|
||||
#undef SIV
|
||||
#undef RLEN
|
||||
#undef RECVFN
|
||||
|
|
@ -385,7 +434,7 @@ SENDFN(array) {
|
|||
/* 603 box */\
|
||||
/* 604 polygon */\
|
||||
/* 628 line */\
|
||||
/* 650 cidr */\
|
||||
B( 650, "cidr", inet )\
|
||||
A( 629, "_line", 628 )\
|
||||
A( 651, "_cidr", 650 )\
|
||||
B( 700, "float4", float4)\
|
||||
|
|
@ -397,7 +446,7 @@ SENDFN(array) {
|
|||
/* 790 money */\
|
||||
A( 791, "_money", 790 )\
|
||||
/* 829 macaddr */\
|
||||
/* 869 inet */\
|
||||
B( 869, "inet", inet )\
|
||||
A( 1000, "_bool", 16 )\
|
||||
A( 1001, "_bytea", 17 )\
|
||||
A( 1002, "_char", 18 )\
|
||||
|
|
|
|||
|
|
@ -94,6 +94,11 @@ f jsonb => \1;
|
|||
v jsonpath => $_ for ('$."key"', '$."a[*]"?(@ > 2)');
|
||||
f jsonpath => $_ for ('', 'hello world');
|
||||
|
||||
v inet => $_ for ('0.0.0.0', '0.0.0.0/12', '127.0.0.1', '192.168.0.0/16', '2001:4f8:3:ba::/64', '::ffff:1.2.3.0/120', '::');
|
||||
v cidr => '0.0.0.0', '0.0.0.0/32', undef, '0.0.0.0/32';
|
||||
v cidr => '::', '::/128', undef, '::/128';
|
||||
f inet => $_ for ('', [], '0.0.0.0/a', '0.0.0.0/1a', '[::]', '0.0.0.0/33', '::/129', '/1', ':/1');
|
||||
|
||||
v 'int[]', [], undef, '{}';
|
||||
v 'int[]', [1], undef, '{1}';
|
||||
v 'int[]', [1,-3,undef,3], undef, '{1,-3,NULL,3}';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue