First commit
This commit is contained in:
commit
67a513742a
|
@ -0,0 +1 @@
|
|||
*.out -whitespace
|
|
@ -0,0 +1,25 @@
|
|||
PG_CONFIG = pg_config
|
||||
PKG_CONFIG = pkg-config
|
||||
|
||||
extension_version = 0
|
||||
|
||||
EXTENSION = pguri
|
||||
MODULE_big = pguri
|
||||
OBJS = pguri.o
|
||||
DATA_built = pguri--$(extension_version).sql
|
||||
|
||||
ifeq (no,$(shell $(PKG_CONFIG) liburiparser || echo no))
|
||||
$(warning liburiparser not registed with pkg-config, build might fail)
|
||||
endif
|
||||
|
||||
PG_CPPFLAGS += $(shell $(PKG_CONFIG) --cflags-only-I liburiparser)
|
||||
SHLIB_LINK += $(shell $(PKG_CONFIG) --libs liburiparser)
|
||||
|
||||
REGRESS = init test
|
||||
REGRESS_OPTS = --inputdir=test
|
||||
|
||||
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
||||
include $(PGXS)
|
||||
|
||||
pguri--$(extension_version).sql: pguri.sql
|
||||
cat $^ >$@
|
|
@ -0,0 +1,3 @@
|
|||
`uri` type for PostgreSQL
|
||||
|
||||
https://twitter.com/pvh/status/567395527357001728
|
|
@ -0,0 +1,365 @@
|
|||
#include <postgres.h>
|
||||
#include <catalog/pg_type.h>
|
||||
#include <fmgr.h>
|
||||
#include <utils/array.h>
|
||||
#include <utils/builtins.h>
|
||||
#include <utils/inet.h>
|
||||
|
||||
#include <uriparser/Uri.h>
|
||||
|
||||
|
||||
PG_MODULE_MAGIC;
|
||||
|
||||
|
||||
typedef struct varlena uritype;
|
||||
|
||||
|
||||
#define DatumGetUriP(X) ((uritype *) PG_DETOAST_DATUM(X))
|
||||
#define UriPGetDatum(X) PointerGetDatum(X)
|
||||
|
||||
#define PG_GETARG_URI_P(n) DatumGetUriP(PG_GETARG_DATUM(n))
|
||||
#define PG_RETURN_URI_P(x) PG_RETURN_POINTER(x)
|
||||
|
||||
|
||||
static void
|
||||
parse_uri(const char *s, UriUriA *urip)
|
||||
{
|
||||
UriParserStateA state;
|
||||
|
||||
state.uri = urip;
|
||||
uriParseUriA(&state, s);
|
||||
|
||||
switch (state.errorCode)
|
||||
{
|
||||
case URI_SUCCESS:
|
||||
return;
|
||||
case URI_ERROR_SYNTAX:
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||
errmsg("invalid input syntax for type uri at or near \"%s\"",
|
||||
state.errorPos)));
|
||||
default:
|
||||
elog(ERROR, "liburiparser error code %d", state.errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(uri_in);
|
||||
Datum
|
||||
uri_in(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *s = PG_GETARG_CSTRING(0);
|
||||
uritype *vardata;
|
||||
UriUriA uri;
|
||||
|
||||
parse_uri(s, &uri);
|
||||
uriFreeUriMembersA(&uri);
|
||||
|
||||
vardata = (uritype *) cstring_to_text(s);
|
||||
PG_RETURN_URI_P(vardata);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(uri_out);
|
||||
Datum
|
||||
uri_out(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum arg = PG_GETARG_DATUM(0);
|
||||
|
||||
PG_RETURN_CSTRING(TextDatumGetCString(arg));
|
||||
}
|
||||
|
||||
static text *
|
||||
uri_text_range_to_text(UriTextRangeA r)
|
||||
{
|
||||
if (!r.first || !r.afterLast)
|
||||
return NULL;
|
||||
|
||||
return cstring_to_text_with_len(r.first, r.afterLast - r.first);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(uri_scheme);
|
||||
Datum
|
||||
uri_scheme(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum arg = PG_GETARG_DATUM(0);
|
||||
char *s = TextDatumGetCString(arg);
|
||||
UriUriA uri;
|
||||
text *result;
|
||||
|
||||
parse_uri(s, &uri);
|
||||
result = uri_text_range_to_text(uri.scheme);
|
||||
uriFreeUriMembersA(&uri);
|
||||
if (result)
|
||||
PG_RETURN_TEXT_P(result);
|
||||
else
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(uri_userinfo);
|
||||
Datum
|
||||
uri_userinfo(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum arg = PG_GETARG_DATUM(0);
|
||||
char *s = TextDatumGetCString(arg);
|
||||
UriUriA uri;
|
||||
text *result;
|
||||
|
||||
parse_uri(s, &uri);
|
||||
result = uri_text_range_to_text(uri.userInfo);
|
||||
uriFreeUriMembersA(&uri);
|
||||
if (result)
|
||||
PG_RETURN_TEXT_P(result);
|
||||
else
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(uri_host);
|
||||
Datum
|
||||
uri_host(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum arg = PG_GETARG_DATUM(0);
|
||||
char *s = TextDatumGetCString(arg);
|
||||
UriUriA uri;
|
||||
text *result;
|
||||
|
||||
parse_uri(s, &uri);
|
||||
result = uri_text_range_to_text(uri.hostText);
|
||||
uriFreeUriMembersA(&uri);
|
||||
if (result)
|
||||
PG_RETURN_TEXT_P(result);
|
||||
else
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(uri_host_inet);
|
||||
Datum
|
||||
uri_host_inet(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum arg = PG_GETARG_DATUM(0);
|
||||
char *s = TextDatumGetCString(arg);
|
||||
UriUriA uri;
|
||||
text *result;
|
||||
|
||||
parse_uri(s, &uri);
|
||||
if (uri.hostData.ip4)
|
||||
{
|
||||
unsigned char *data = uri.hostData.ip4;
|
||||
char *tmp = psprintf("%u.%u.%u.%u", data[0], data[1], data[2], data[3]);
|
||||
uriFreeUriMembersA(&uri);
|
||||
PG_RETURN_INET_P(DirectFunctionCall1(inet_in, CStringGetDatum(tmp)));
|
||||
}
|
||||
else if (uri.hostData.ip6)
|
||||
{
|
||||
unsigned char *data = uri.hostData.ip6;
|
||||
char *tmp = psprintf("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
|
||||
data[0], data[1], data[2], data[3],
|
||||
data[4], data[5], data[6], data[7],
|
||||
data[8], data[9], data[10], data[11],
|
||||
data[12], data[13], data[14], data[15]);
|
||||
uriFreeUriMembersA(&uri);
|
||||
PG_RETURN_INET_P(DirectFunctionCall1(inet_in, CStringGetDatum(tmp)));
|
||||
}
|
||||
else
|
||||
{
|
||||
uriFreeUriMembersA(&uri);
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(uri_port);
|
||||
Datum
|
||||
uri_port(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum arg = PG_GETARG_DATUM(0);
|
||||
char *s = TextDatumGetCString(arg);
|
||||
UriUriA uri;
|
||||
text *result;
|
||||
|
||||
parse_uri(s, &uri);
|
||||
result = uri_text_range_to_text(uri.portText);
|
||||
uriFreeUriMembersA(&uri);
|
||||
if (result)
|
||||
PG_RETURN_TEXT_P(result);
|
||||
else
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(uri_query);
|
||||
Datum
|
||||
uri_query(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum arg = PG_GETARG_DATUM(0);
|
||||
char *s = TextDatumGetCString(arg);
|
||||
UriUriA uri;
|
||||
text *result;
|
||||
|
||||
parse_uri(s, &uri);
|
||||
result = uri_text_range_to_text(uri.query);
|
||||
uriFreeUriMembersA(&uri);
|
||||
if (result)
|
||||
PG_RETURN_TEXT_P(result);
|
||||
else
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(uri_fragment);
|
||||
Datum
|
||||
uri_fragment(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum arg = PG_GETARG_DATUM(0);
|
||||
char *s = TextDatumGetCString(arg);
|
||||
UriUriA uri;
|
||||
text *result;
|
||||
|
||||
parse_uri(s, &uri);
|
||||
result = uri_text_range_to_text(uri.fragment);
|
||||
uriFreeUriMembersA(&uri);
|
||||
if (result)
|
||||
PG_RETURN_TEXT_P(result);
|
||||
else
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(uri_path);
|
||||
Datum
|
||||
uri_path(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum arg = PG_GETARG_DATUM(0);
|
||||
char *s = TextDatumGetCString(arg);
|
||||
UriUriA uri;
|
||||
ArrayBuildState *astate = initArrayResult(TEXTOID, CurrentMemoryContext);
|
||||
UriPathSegmentA *pa;
|
||||
|
||||
parse_uri(s, &uri);
|
||||
for (pa = uri.pathHead; pa; pa = pa->next)
|
||||
{
|
||||
text *piece = uri_text_range_to_text(pa->text);
|
||||
astate = accumArrayResult(astate,
|
||||
PointerGetDatum(piece),
|
||||
!piece,
|
||||
TEXTOID,
|
||||
CurrentMemoryContext);
|
||||
}
|
||||
uriFreeUriMembersA(&uri);
|
||||
|
||||
if (astate)
|
||||
PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate,
|
||||
CurrentMemoryContext));
|
||||
else
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
static int
|
||||
cmp_text_range(UriTextRangeA a, UriTextRangeA b)
|
||||
{
|
||||
if (!a.first || !a.afterLast)
|
||||
{
|
||||
if (!b.first || !b.afterLast)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else if (!b.first || !b.afterLast)
|
||||
return 1;
|
||||
else
|
||||
{
|
||||
int x = strncmp(a.first, b.first,
|
||||
Min(a.afterLast - a.first, b.afterLast - b.first));
|
||||
if (x == 0)
|
||||
return (a.afterLast - a.first) - (b.afterLast - b.first);
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_uri_cmp(Datum a, Datum b)
|
||||
{
|
||||
const char *sa = TextDatumGetCString(a);
|
||||
const char *sb = TextDatumGetCString(b);
|
||||
UriUriA ua;
|
||||
UriUriA ub;
|
||||
int res = 0;
|
||||
|
||||
parse_uri(sa, &ua);
|
||||
parse_uri(sa, &ub);
|
||||
|
||||
if (res == 0)
|
||||
res = cmp_text_range(ua.scheme, ub.scheme);
|
||||
if (res == 0)
|
||||
res = cmp_text_range(ua.hostText, ub.hostText);
|
||||
if (res == 0)
|
||||
res = strcmp(sa, sb);
|
||||
uriFreeUriMembersA(&ua);
|
||||
uriFreeUriMembersA(&ub);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(uri_lt);
|
||||
Datum
|
||||
uri_lt(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum *arg1 = PG_GETARG_DATUM(0);
|
||||
Datum *arg2 = PG_GETARG_DATUM(1);
|
||||
|
||||
PG_RETURN_BOOL(_uri_cmp(arg1, arg2) < 0);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(uri_le);
|
||||
Datum
|
||||
uri_le(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum *arg1 = PG_GETARG_DATUM(0);
|
||||
Datum *arg2 = PG_GETARG_DATUM(1);
|
||||
|
||||
PG_RETURN_BOOL(_uri_cmp(arg1, arg2) <= 0);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(uri_eq);
|
||||
Datum
|
||||
uri_eq(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum *arg1 = PG_GETARG_DATUM(0);
|
||||
Datum *arg2 = PG_GETARG_DATUM(1);
|
||||
|
||||
PG_RETURN_BOOL(_uri_cmp(arg1, arg2) == 0);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(uri_ne);
|
||||
Datum
|
||||
uri_ne(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum *arg1 = PG_GETARG_DATUM(0);
|
||||
Datum *arg2 = PG_GETARG_DATUM(1);
|
||||
|
||||
PG_RETURN_BOOL(_uri_cmp(arg1, arg2) != 0);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(uri_ge);
|
||||
Datum
|
||||
uri_ge(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum *arg1 = PG_GETARG_DATUM(0);
|
||||
Datum *arg2 = PG_GETARG_DATUM(1);
|
||||
|
||||
PG_RETURN_BOOL(_uri_cmp(arg1, arg2) >= 0);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(uri_gt);
|
||||
Datum
|
||||
uri_gt(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum *arg1 = PG_GETARG_DATUM(0);
|
||||
Datum *arg2 = PG_GETARG_DATUM(1);
|
||||
|
||||
PG_RETURN_BOOL(_uri_cmp(arg1, arg2) > 0);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(uri_cmp);
|
||||
Datum
|
||||
uri_cmp(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum *arg1 = PG_GETARG_DATUM(0);
|
||||
Datum *arg2 = PG_GETARG_DATUM(1);
|
||||
|
||||
PG_RETURN_INT32(_uri_cmp(arg1, arg2));
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
comment = 'uri type'
|
||||
default_version = 0
|
||||
module_pathname = '$libdir/pguri'
|
||||
relocatable = true
|
|
@ -0,0 +1,189 @@
|
|||
SET client_min_messages = warning;
|
||||
|
||||
|
||||
CREATE TYPE uri;
|
||||
|
||||
CREATE FUNCTION uri_in(cstring) RETURNS uri
|
||||
IMMUTABLE
|
||||
STRICT
|
||||
LANGUAGE C
|
||||
AS '$libdir/pguri';
|
||||
|
||||
CREATE FUNCTION uri_out(uri) RETURNS cstring
|
||||
IMMUTABLE
|
||||
STRICT
|
||||
LANGUAGE C
|
||||
AS '$libdir/pguri';
|
||||
|
||||
CREATE TYPE uri (
|
||||
INTERNALLENGTH = -1,
|
||||
INPUT = uri_in,
|
||||
OUTPUT = uri_out
|
||||
);
|
||||
|
||||
|
||||
CREATE CAST (uri AS text) WITH INOUT AS ASSIGNMENT;
|
||||
CREATE CAST (text AS uri) WITH INOUT AS ASSIGNMENT;
|
||||
|
||||
|
||||
CREATE FUNCTION uri_scheme(uri) RETURNS text
|
||||
IMMUTABLE
|
||||
STRICT
|
||||
LANGUAGE C
|
||||
AS '$libdir/pguri';
|
||||
|
||||
CREATE FUNCTION uri_userinfo(uri) RETURNS text
|
||||
IMMUTABLE
|
||||
STRICT
|
||||
LANGUAGE C
|
||||
AS '$libdir/pguri';
|
||||
|
||||
CREATE FUNCTION uri_host(uri) RETURNS text
|
||||
IMMUTABLE
|
||||
STRICT
|
||||
LANGUAGE C
|
||||
AS '$libdir/pguri';
|
||||
|
||||
CREATE FUNCTION uri_host_inet(uri) RETURNS inet
|
||||
IMMUTABLE
|
||||
STRICT
|
||||
LANGUAGE C
|
||||
AS '$libdir/pguri';
|
||||
|
||||
CREATE FUNCTION uri_port(uri) RETURNS text
|
||||
IMMUTABLE
|
||||
STRICT
|
||||
LANGUAGE C
|
||||
AS '$libdir/pguri';
|
||||
|
||||
CREATE FUNCTION uri_query(uri) RETURNS text
|
||||
IMMUTABLE
|
||||
STRICT
|
||||
LANGUAGE C
|
||||
AS '$libdir/pguri';
|
||||
|
||||
CREATE FUNCTION uri_fragment(uri) RETURNS text
|
||||
IMMUTABLE
|
||||
STRICT
|
||||
LANGUAGE C
|
||||
AS '$libdir/pguri';
|
||||
|
||||
CREATE FUNCTION uri_path(uri) RETURNS text[]
|
||||
IMMUTABLE
|
||||
STRICT
|
||||
LANGUAGE C
|
||||
AS '$libdir/pguri';
|
||||
|
||||
|
||||
CREATE FUNCTION uri_lt(uri, uri) RETURNS boolean
|
||||
IMMUTABLE
|
||||
STRICT
|
||||
LANGUAGE C
|
||||
AS '$libdir/pguri';
|
||||
|
||||
CREATE FUNCTION uri_le(uri, uri) RETURNS boolean
|
||||
IMMUTABLE
|
||||
STRICT
|
||||
LANGUAGE C
|
||||
AS '$libdir/pguri';
|
||||
|
||||
CREATE FUNCTION uri_eq(uri, uri) RETURNS boolean
|
||||
IMMUTABLE
|
||||
STRICT
|
||||
LANGUAGE C
|
||||
AS '$libdir/pguri';
|
||||
|
||||
CREATE FUNCTION uri_ne(uri, uri) RETURNS boolean
|
||||
IMMUTABLE
|
||||
STRICT
|
||||
LANGUAGE C
|
||||
AS '$libdir/pguri';
|
||||
|
||||
CREATE FUNCTION uri_ge(uri, uri) RETURNS boolean
|
||||
IMMUTABLE
|
||||
STRICT
|
||||
LANGUAGE C
|
||||
AS '$libdir/pguri';
|
||||
|
||||
CREATE FUNCTION uri_gt(uri, uri) RETURNS boolean
|
||||
IMMUTABLE
|
||||
STRICT
|
||||
LANGUAGE C
|
||||
AS '$libdir/pguri';
|
||||
|
||||
CREATE FUNCTION uri_cmp(uri, uri) RETURNS integer
|
||||
IMMUTABLE
|
||||
STRICT
|
||||
LANGUAGE C
|
||||
AS '$libdir/pguri';
|
||||
|
||||
CREATE OPERATOR < (
|
||||
LEFTARG = uri,
|
||||
RIGHTARG = uri,
|
||||
COMMUTATOR = >,
|
||||
NEGATOR = >=,
|
||||
RESTRICT = scalarltsel,
|
||||
JOIN = scalarltjoinsel,
|
||||
PROCEDURE = uri_lt
|
||||
);
|
||||
|
||||
CREATE OPERATOR <= (
|
||||
LEFTARG = uri,
|
||||
RIGHTARG = uri,
|
||||
COMMUTATOR = >=,
|
||||
NEGATOR = >,
|
||||
RESTRICT = scalarltsel,
|
||||
JOIN = scalarltjoinsel,
|
||||
PROCEDURE = uri_le
|
||||
);
|
||||
|
||||
CREATE OPERATOR = (
|
||||
LEFTARG = uri,
|
||||
RIGHTARG = uri,
|
||||
COMMUTATOR = =,
|
||||
NEGATOR = <>,
|
||||
RESTRICT = eqsel,
|
||||
JOIN = eqjoinsel,
|
||||
HASHES,
|
||||
MERGES,
|
||||
PROCEDURE = uri_eq
|
||||
);
|
||||
|
||||
CREATE OPERATOR <> (
|
||||
LEFTARG = uri,
|
||||
RIGHTARG = uri,
|
||||
COMMUTATOR = <>,
|
||||
NEGATOR = =,
|
||||
RESTRICT = neqsel,
|
||||
JOIN = neqjoinsel,
|
||||
PROCEDURE = uri_ne
|
||||
);
|
||||
|
||||
CREATE OPERATOR >= (
|
||||
LEFTARG = uri,
|
||||
RIGHTARG = uri,
|
||||
COMMUTATOR = <=,
|
||||
NEGATOR = <,
|
||||
RESTRICT = scalargtsel,
|
||||
JOIN = scalargtjoinsel,
|
||||
PROCEDURE = uri_ge
|
||||
);
|
||||
|
||||
CREATE OPERATOR > (
|
||||
LEFTARG = uri,
|
||||
RIGHTARG = uri,
|
||||
COMMUTATOR = <,
|
||||
NEGATOR = <=,
|
||||
RESTRICT = scalargtsel,
|
||||
JOIN = scalargtjoinsel,
|
||||
PROCEDURE = uri_gt
|
||||
);
|
||||
|
||||
CREATE OPERATOR CLASS uri_ops
|
||||
DEFAULT FOR TYPE uri USING btree AS
|
||||
OPERATOR 1 < ,
|
||||
OPERATOR 2 <= ,
|
||||
OPERATOR 3 = ,
|
||||
OPERATOR 4 >= ,
|
||||
OPERATOR 5 > ,
|
||||
FUNCTION 1 uri_cmp(uri, uri);
|
|
@ -0,0 +1 @@
|
|||
CREATE EXTENSION pguri;
|
|
@ -0,0 +1,178 @@
|
|||
\pset null _null_
|
||||
CREATE TABLE test (a serial, b uri);
|
||||
INSERT INTO test (b)
|
||||
VALUES ('http://www.postgresql.org/'),
|
||||
('http://www.postgresql.org/docs/devel/static/xfunc-sql.html#XFUNC-SQL-FUNCTION-ARGUMENTS'),
|
||||
('https://duckduckgo.com/?q=postgresql&ia=about'),
|
||||
('ftp://ftp.gnu.org/gnu/bison'),
|
||||
('mailto:foo@example.com'),
|
||||
('ssh://username@review.openstack.org:29418/openstack/nova.git'),
|
||||
('http://admin:password@192.168.0.1'),
|
||||
('http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html'),
|
||||
('http://[1080::8:800:200C:417A]/foo'),
|
||||
(''),
|
||||
('foobar');
|
||||
SELECT * FROM test;
|
||||
a | b
|
||||
----+-----------------------------------------------------------------------------------------
|
||||
1 | http://www.postgresql.org/
|
||||
2 | http://www.postgresql.org/docs/devel/static/xfunc-sql.html#XFUNC-SQL-FUNCTION-ARGUMENTS
|
||||
3 | https://duckduckgo.com/?q=postgresql&ia=about
|
||||
4 | ftp://ftp.gnu.org/gnu/bison
|
||||
5 | mailto:foo@example.com
|
||||
6 | ssh://username@review.openstack.org:29418/openstack/nova.git
|
||||
7 | http://admin:password@192.168.0.1
|
||||
8 | http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html
|
||||
9 | http://[1080::8:800:200C:417A]/foo
|
||||
10 |
|
||||
11 | foobar
|
||||
(11 rows)
|
||||
|
||||
-- error cases
|
||||
SELECT uri ':';
|
||||
ERROR: invalid input syntax for type uri at or near ":"
|
||||
LINE 1: SELECT uri ':';
|
||||
^
|
||||
SELECT uri 'foo bar';
|
||||
ERROR: invalid input syntax for type uri at or near " bar"
|
||||
LINE 1: SELECT uri 'foo bar';
|
||||
^
|
||||
\x on
|
||||
SELECT b AS uri,
|
||||
uri_scheme(b),
|
||||
uri_userinfo(b),
|
||||
uri_host(b),
|
||||
uri_host_inet(b),
|
||||
uri_port(b),
|
||||
uri_path(b),
|
||||
uri_query(b),
|
||||
uri_fragment(b)
|
||||
FROM test;
|
||||
-[ RECORD 1 ]-+----------------------------------------------------------------------------------------
|
||||
uri | http://www.postgresql.org/
|
||||
uri_scheme | http
|
||||
uri_userinfo | _null_
|
||||
uri_host | www.postgresql.org
|
||||
uri_host_inet | _null_
|
||||
uri_port | _null_
|
||||
uri_path | {""}
|
||||
uri_query | _null_
|
||||
uri_fragment | _null_
|
||||
-[ RECORD 2 ]-+----------------------------------------------------------------------------------------
|
||||
uri | http://www.postgresql.org/docs/devel/static/xfunc-sql.html#XFUNC-SQL-FUNCTION-ARGUMENTS
|
||||
uri_scheme | http
|
||||
uri_userinfo | _null_
|
||||
uri_host | www.postgresql.org
|
||||
uri_host_inet | _null_
|
||||
uri_port | _null_
|
||||
uri_path | {docs,devel,static,xfunc-sql.html}
|
||||
uri_query | _null_
|
||||
uri_fragment | XFUNC-SQL-FUNCTION-ARGUMENTS
|
||||
-[ RECORD 3 ]-+----------------------------------------------------------------------------------------
|
||||
uri | https://duckduckgo.com/?q=postgresql&ia=about
|
||||
uri_scheme | https
|
||||
uri_userinfo | _null_
|
||||
uri_host | duckduckgo.com
|
||||
uri_host_inet | _null_
|
||||
uri_port | _null_
|
||||
uri_path | {""}
|
||||
uri_query | q=postgresql&ia=about
|
||||
uri_fragment | _null_
|
||||
-[ RECORD 4 ]-+----------------------------------------------------------------------------------------
|
||||
uri | ftp://ftp.gnu.org/gnu/bison
|
||||
uri_scheme | ftp
|
||||
uri_userinfo | _null_
|
||||
uri_host | ftp.gnu.org
|
||||
uri_host_inet | _null_
|
||||
uri_port | _null_
|
||||
uri_path | {gnu,bison}
|
||||
uri_query | _null_
|
||||
uri_fragment | _null_
|
||||
-[ RECORD 5 ]-+----------------------------------------------------------------------------------------
|
||||
uri | mailto:foo@example.com
|
||||
uri_scheme | mailto
|
||||
uri_userinfo | _null_
|
||||
uri_host | _null_
|
||||
uri_host_inet | _null_
|
||||
uri_port | _null_
|
||||
uri_path | {foo@example.com}
|
||||
uri_query | _null_
|
||||
uri_fragment | _null_
|
||||
-[ RECORD 6 ]-+----------------------------------------------------------------------------------------
|
||||
uri | ssh://username@review.openstack.org:29418/openstack/nova.git
|
||||
uri_scheme | ssh
|
||||
uri_userinfo | username
|
||||
uri_host | review.openstack.org
|
||||
uri_host_inet | _null_
|
||||
uri_port | 29418
|
||||
uri_path | {openstack,nova.git}
|
||||
uri_query | _null_
|
||||
uri_fragment | _null_
|
||||
-[ RECORD 7 ]-+----------------------------------------------------------------------------------------
|
||||
uri | http://admin:password@192.168.0.1
|
||||
uri_scheme | http
|
||||
uri_userinfo | admin:password
|
||||
uri_host | 192.168.0.1
|
||||
uri_host_inet | 192.168.0.1
|
||||
uri_port | _null_
|
||||
uri_path | {}
|
||||
uri_query | _null_
|
||||
uri_fragment | _null_
|
||||
-[ RECORD 8 ]-+----------------------------------------------------------------------------------------
|
||||
uri | http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html
|
||||
uri_scheme | http
|
||||
uri_userinfo | _null_
|
||||
uri_host | FEDC:BA98:7654:3210:FEDC:BA98:7654:3210
|
||||
uri_host_inet | fedc:ba98:7654:3210:fedc:ba98:7654:3210
|
||||
uri_port | 80
|
||||
uri_path | {index.html}
|
||||
uri_query | _null_
|
||||
uri_fragment | _null_
|
||||
-[ RECORD 9 ]-+----------------------------------------------------------------------------------------
|
||||
uri | http://[1080::8:800:200C:417A]/foo
|
||||
uri_scheme | http
|
||||
uri_userinfo | _null_
|
||||
uri_host | 1080::8:800:200C:417A
|
||||
uri_host_inet | 1080::8:800:200c:417a
|
||||
uri_port | _null_
|
||||
uri_path | {foo}
|
||||
uri_query | _null_
|
||||
uri_fragment | _null_
|
||||
-[ RECORD 10 ]+----------------------------------------------------------------------------------------
|
||||
uri |
|
||||
uri_scheme | _null_
|
||||
uri_userinfo | _null_
|
||||
uri_host | _null_
|
||||
uri_host_inet | _null_
|
||||
uri_port | _null_
|
||||
uri_path | {}
|
||||
uri_query | _null_
|
||||
uri_fragment | _null_
|
||||
-[ RECORD 11 ]+----------------------------------------------------------------------------------------
|
||||
uri | foobar
|
||||
uri_scheme | _null_
|
||||
uri_userinfo | _null_
|
||||
uri_host | _null_
|
||||
uri_host_inet | _null_
|
||||
uri_port | _null_
|
||||
uri_path | {foobar}
|
||||
uri_query | _null_
|
||||
uri_fragment | _null_
|
||||
|
||||
\x off
|
||||
SELECT DISTINCT b FROM test ORDER BY b;
|
||||
b
|
||||
-----------------------------------------------------------------------------------------
|
||||
|
||||
foobar
|
||||
ftp://ftp.gnu.org/gnu/bison
|
||||
http://[1080::8:800:200C:417A]/foo
|
||||
http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html
|
||||
http://admin:password@192.168.0.1
|
||||
http://www.postgresql.org/
|
||||
http://www.postgresql.org/docs/devel/static/xfunc-sql.html#XFUNC-SQL-FUNCTION-ARGUMENTS
|
||||
https://duckduckgo.com/?q=postgresql&ia=about
|
||||
mailto:foo@example.com
|
||||
ssh://username@review.openstack.org:29418/openstack/nova.git
|
||||
(11 rows)
|
||||
|
|
@ -0,0 +1 @@
|
|||
CREATE EXTENSION pguri;
|
|
@ -0,0 +1,38 @@
|
|||
\pset null _null_
|
||||
|
||||
CREATE TABLE test (a serial, b uri);
|
||||
|
||||
INSERT INTO test (b)
|
||||
VALUES ('http://www.postgresql.org/'),
|
||||
('http://www.postgresql.org/docs/devel/static/xfunc-sql.html#XFUNC-SQL-FUNCTION-ARGUMENTS'),
|
||||
('https://duckduckgo.com/?q=postgresql&ia=about'),
|
||||
('ftp://ftp.gnu.org/gnu/bison'),
|
||||
('mailto:foo@example.com'),
|
||||
('ssh://username@review.openstack.org:29418/openstack/nova.git'),
|
||||
('http://admin:password@192.168.0.1'),
|
||||
('http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html'),
|
||||
('http://[1080::8:800:200C:417A]/foo'),
|
||||
(''),
|
||||
('foobar');
|
||||
|
||||
SELECT * FROM test;
|
||||
|
||||
-- error cases
|
||||
SELECT uri ':';
|
||||
SELECT uri 'foo bar';
|
||||
|
||||
|
||||
\x on
|
||||
SELECT b AS uri,
|
||||
uri_scheme(b),
|
||||
uri_userinfo(b),
|
||||
uri_host(b),
|
||||
uri_host_inet(b),
|
||||
uri_port(b),
|
||||
uri_path(b),
|
||||
uri_query(b),
|
||||
uri_fragment(b)
|
||||
FROM test;
|
||||
\x off
|
||||
|
||||
SELECT DISTINCT b FROM test ORDER BY b;
|
Loading…
Reference in New Issue