Compare commits

...

19 Commits

Author SHA1 Message Date
jordi fita mas 44ac595b86 Update PostgreSQL version to 15, used in Debian 12 2023-06-15 12:44:41 +02:00
jordi fita mas 7ff09bfa5c Add pkg-config as build dependency 2023-01-25 01:14:38 +01:00
jordi fita mas 851dca13b9 Fix architecture from all to any 2023-01-25 01:07:41 +01:00
jordi fita mas 2cbc3efd7f Add pkg-config dependency 2023-01-24 15:23:28 +01:00
jordi fita mas ecc78c9590 Add Debian packaging 2023-01-24 15:08:30 +01:00
Peter Eisentraut 00241b96b8 CI: Remove Travis, add Cirrus 2022-05-26 17:03:29 +02:00
Peter Eisentraut 7a7849a48a Fix -Wimplicit-fallthrough=3 warning
for PostgreSQL 13
2020-05-21 08:36:08 +02:00
Peter Eisentraut 969031cd25 Travis CI: Fix build script
We need to pass PG_CONFIG to "sudo make install" because sudo clears
the PATH and so it might run the install step against another version.
2020-05-21 08:22:45 +02:00
Peter Eisentraut 9277ca4d9c Travis CI: Update to bionic, add new PostgreSQL versions 2019-12-28 10:28:52 +01:00
Peter Eisentraut e5d25a8fe9 Travis CI: Update setup
Update PGDG repo setup, update to xenial, use inline scripts instead
of external gists.
2019-04-24 11:43:45 +02:00
Peter Eisentraut 437ae00801 Travis CI: Add new PostgreSQL versions 2019-04-23 18:21:16 +02:00
Peter Eisentraut dd3f45945b Add license file
closes #5
2015-12-24 22:43:34 -05:00
Peter Eisentraut 73270357c5 Refine sort order 2015-12-23 22:35:15 -05:00
Peter Eisentraut a9cf856ca0 Add more URLs to tests, mainly for checking sorting 2015-12-23 19:00:57 -05:00
Peter Eisentraut ab90f301b5 Fix typo, causing wrong sorting results 2015-10-08 21:23:45 -04:00
Peter Eisentraut 290dd477f3 Add escape/unescape functions 2015-10-03 00:31:37 -04:00
Peter Eisentraut 817deaaa30 Keep all old extension install scripts around
We need them to test upgrades.
2015-10-02 23:53:32 -04:00
Peter Eisentraut cd80642413 Add hash operator class
The uri = uri operator was marked as HASHES, but no hash function or
hash operator class was defined.  Hash joins would therefore fail.

Bug report and original patch by Grégoire HUBERT (@chanmix51).

closes #3
2015-08-29 16:17:13 -04:00
Peter Eisentraut cf854ebea1 Replace uriIsHostSetA() by local implementation
Even though uriIsHostSetA() is exported by the uriparser library, it is
not in a header file, so it's not part of the official interface, and
its use causes compiler warnings.  So create a local copy and use that.

closes #2
2015-08-27 23:44:40 -04:00
22 changed files with 876 additions and 68 deletions

35
.cirrus.yml Normal file
View File

@ -0,0 +1,35 @@
env:
DEBIAN_FRONTEND: noninteractive
LANG: C
task:
name: Linux (Debian/Ubuntu)
matrix:
- container:
image: ubuntu:20.04
env:
matrix:
- PGVERSION: 14
- PGVERSION: 13
- PGVERSION: 12
- PGVERSION: 11
- PGVERSION: 10
- PGVERSION: 9.6
- PGVERSION: 9.5
- PGVERSION: 9.4
- PGVERSION: 9.3
setup_script:
- apt-get update
- apt-get -y install curl gnupg lsb-release
- curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
- echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list
- apt-get update
- apt-get -y install gcc liburiparser-dev make pkg-config postgresql-$PGVERSION postgresql-server-dev-$PGVERSION
- pg_createcluster --start $PGVERSION test -p 55435 -- -A trust
build_script:
- PATH=/usr/lib/postgresql/$PGVERSION/bin:$PATH
- make all
- make install
test_script:
- PATH=/usr/lib/postgresql/$PGVERSION/bin:$PATH
- PGPORT=55435 make installcheck PGUSER=postgres

1
.gitignore vendored
View File

@ -1,4 +1,3 @@
*.o *.o
*.so *.so
/results/ /results/
/*--*.sql

View File

@ -1,14 +0,0 @@
language: c
before_install:
- wget https://gist.github.com/petere/5893799/raw/apt.postgresql.org.sh
- wget https://gist.github.com/petere/6023944/raw/pg-travis-test.sh
- sudo sh ./apt.postgresql.org.sh
install:
- sudo apt-get install -qq liburiparser-dev
env:
- PGVERSION=9.1
- PGVERSION=9.2
- PGVERSION=9.3
- PGVERSION=9.4
script:
- bash ./pg-travis-test.sh

19
LICENSE.md Normal file
View File

@ -0,0 +1,19 @@
© 2015 Peter Eisentraut <peter@eisentraut.org>
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose, without fee, and without a written
agreement is hereby granted, provided that the above copyright notice
and this paragraph and the following two paragraphs appear in all
copies.
IN NO EVENT SHALL THE AUTHORS BE LIABLE TO ANY PARTY FOR DIRECT,
INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
DOCUMENTATION, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS
IS" BASIS, AND THE AUTHORS HAVE NO OBLIGATIONS TO PROVIDE MAINTENANCE,
SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

View File

@ -1,12 +1,10 @@
PG_CONFIG = pg_config PG_CONFIG = pg_config
PKG_CONFIG = pkg-config PKG_CONFIG = pkg-config
extension_version = 0
EXTENSION = uri EXTENSION = uri
MODULE_big = uri MODULE_big = uri
OBJS = uri.o OBJS = uri.o
DATA_built = uri--$(extension_version).sql DATA = uri--0.sql uri--1.sql uri--0--1.sql
ifeq (no,$(shell $(PKG_CONFIG) liburiparser || echo no)) ifeq (no,$(shell $(PKG_CONFIG) liburiparser || echo no))
$(warning liburiparser not registed with pkg-config, build might fail) $(warning liburiparser not registed with pkg-config, build might fail)
@ -15,11 +13,8 @@ endif
PG_CPPFLAGS += $(shell $(PKG_CONFIG) --cflags-only-I liburiparser) PG_CPPFLAGS += $(shell $(PKG_CONFIG) --cflags-only-I liburiparser)
SHLIB_LINK += $(shell $(PKG_CONFIG) --libs liburiparser) SHLIB_LINK += $(shell $(PKG_CONFIG) --libs liburiparser)
REGRESS = init test REGRESS = init test escape
REGRESS_OPTS = --inputdir=test REGRESS_OPTS = --inputdir=test
PGXS := $(shell $(PG_CONFIG) --pgxs) PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS) include $(PGXS)
uri--$(extension_version).sql: uri.sql
cat $^ >$@

View File

@ -126,3 +126,22 @@ Other functions:
without normalization. If you want to consider distinct URIs without normalization. If you want to consider distinct URIs
without regard for mostly irrelevant syntax differences, pass them without regard for mostly irrelevant syntax differences, pass them
through this function. through this function.
- `uri_escape(text, space_to_plus boolean DEFAULT false, normalize_breaks boolean DEFAULT false) returns text`
Percent-encodes all reserved characters from the text. This can
be useful for constructing URIs from strings.
If `space_to_plus` is true, then spaces are replaced by plus
signs. If `normalize_breaks` is true, then line breaks are
converted to CR LF pairs (and subsequently percent-encoded). Note
that these two conversions come from the HTML standard for
encoding form data but are not part of the specification for URIs.
- `uri_unescape(text, plus_to_space boolean DEFAULT false, break_conversion boolean DEFAULT false) returns text`
Decodes all percent-encodings in the text.
If `plus_to_space` is true, then plus signs are converted to
spaces. If `break_conversion` is true, then CR LF pairs are
converted to simple newlines (`\n`).

23
debian/changelog vendored Normal file
View File

@ -0,0 +1,23 @@
pguri (1.20151224-4) bookworm; urgency=medium
* Update PostgreSQL version to 15
-- jordi fita mas <jordi@tandem.blog> Thu, 15 Jun 2023 10:44:11 +0000
pguri (1.20151224-3) bullseye; urgency=medium
* Fix architecture from all to any
-- jordi fita mas <jordi@tandem.blog> Wed, 25 Jan 2023 00:07:13 +0000
pguri (1.20151224-2) bullseye; urgency=medium
* Add pkg-config dependency
-- jordi fita mas <jordi@tandem.blog> Tue, 24 Jan 2023 14:21:22 +0000
pguri (1.20151224-1) bullseye; urgency=medium
* Add Debian packaging
-- jordi fita mas <jordi@tandem.blog> Tue, 24 Jan 2023 13:07:39 +0000

35
debian/control vendored Normal file
View File

@ -0,0 +1,35 @@
Source: pguri
Section: database
Priority: optional
Maintainer: jordi fita mas <jordi@tandem.blog>
Build-Depends:
debhelper-compat (= 13),
postgresql-all (>= 217~),
liburiparser-dev,
pkg-config
Standards-Version: 4.6.0
Vcs-Browser: https://github.com/petere/pguri
Vcs-Git: https://github.com/petere/pguri.git
Homepage: https://github.com/petere/pguri
Rules-Requires-Root: no
Package: postgresql-15-pguri
Architecture: any
Depends:
${shlibs:Depends},
${misc:Depends},
postgresql-15
description: uri type for PostgreSQL
This is an extension for PostgreSQL that provides a uri data type. Advantages
over using plain text for storing URIs include:
.
* URI syntax checking,
* functions for extracting URI components, and
* human-friendly sorting.
.
The actual URI parsing is provided by the uriparser library, which supports
URI syntax as per RFC 3986.
.
Note that this might not be the right data type to use if you want to store
user-provided URI data, such as HTTP referrers, since they might contain
arbitrary junk.

35
debian/control.in vendored Normal file
View File

@ -0,0 +1,35 @@
Source: pguri
Section: database
Priority: optional
Maintainer: jordi fita mas <jordi@tandem.blog>
Build-Depends:
debhelper-compat (= 13),
postgresql-all (>= 217~),
liburiparser-dev,
pkg-config
Standards-Version: 4.6.0
Vcs-Browser: https://github.com/petere/pguri
Vcs-Git: https://github.com/petere/pguri.git
Homepage: https://github.com/petere/pguri
Rules-Requires-Root: no
Package: postgresql-PGVERSION-pguri
Architecture: any
Depends:
${shlibs:Depends},
${misc:Depends},
postgresql-PGVERSION
description: uri type for PostgreSQL
This is an extension for PostgreSQL that provides a uri data type. Advantages
over using plain text for storing URIs include:
.
* URI syntax checking,
* functions for extracting URI components, and
* human-friendly sorting.
.
The actual URI parsing is provided by the uriparser library, which supports
URI syntax as per RFC 3986.
.
Note that this might not be the right data type to use if you want to store
user-provided URI data, such as HTTP referrers, since they might contain
arbitrary junk.

29
debian/copyright vendored Normal file
View File

@ -0,0 +1,29 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Source: https://github.com/petere/pguri
Upstream-Name: pguri
Upstream-Contact: peter@eisentraut.org
Files: *
Copyright: 2015 Peter Eisentraut
License:
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose, without fee, and without a written agreement is
hereby granted, provided that the above copyright notice and this paragraph and
the following two paragraphs appear in all copies.
.
IN NO EVENT SHALL THE AUTHORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE AUTHORS HAVE
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.
THE AUTHORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE
AUTHORS HAVE NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
ENHANCEMENTS, OR MODIFICATIONS.
Files: debian/*
Copyright: 2023 jordi fita mas
License:
This debian package is distributed under the same license as the source
package.

1
debian/pgversions vendored Normal file
View File

@ -0,0 +1 @@
13+

6
debian/rules vendored Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/make -f
include /usr/share/postgresql-common/pgxs_debian_control.mk
%:
dh $@ --with pgxs_loop

1
debian/source/format vendored Normal file
View File

@ -0,0 +1 @@
3.0 (quilt)

99
test/expected/escape.out Normal file
View File

@ -0,0 +1,99 @@
SELECT uri_escape('foobar');
uri_escape
------------
foobar
(1 row)
SELECT uri_escape(':/?#[]@!$&''()*+,;=');
uri_escape
--------------------------------------------------------
%3A%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D
(1 row)
SELECT uri_escape('foo bar');
uri_escape
------------
foo%20bar
(1 row)
SELECT uri_escape('foo bar', space_to_plus := false);
uri_escape
------------
foo%20bar
(1 row)
SELECT uri_escape('foo bar', space_to_plus := true);
uri_escape
------------
foo+bar
(1 row)
SELECT uri_escape(E'foo\nbar');
uri_escape
------------
foo%0Abar
(1 row)
SELECT uri_escape(E'foo\nbar', normalize_breaks := false);
uri_escape
------------
foo%0Abar
(1 row)
SELECT uri_escape(E'foo\nbar', normalize_breaks := true);
uri_escape
--------------
foo%0D%0Abar
(1 row)
SELECT uri_unescape('foobar');
uri_unescape
--------------
foobar
(1 row)
SELECT uri_unescape('%3A%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D');
uri_unescape
--------------------
:/?#[]@!$&'()*+,;=
(1 row)
SELECT uri_unescape('foo+bar');
uri_unescape
--------------
foo+bar
(1 row)
SELECT uri_unescape('foo+bar', plus_to_space := false);
uri_unescape
--------------
foo+bar
(1 row)
SELECT uri_unescape('foo+bar', plus_to_space := true);
uri_unescape
--------------
foo bar
(1 row)
SELECT uri_unescape('foo%0D%0Abar');
uri_unescape
--------------
foo +
bar
(1 row)
SELECT uri_unescape('foo%0D%0Abar', break_conversion := false);
uri_unescape
--------------
foo +
bar
(1 row)
SELECT uri_unescape('foo%0D%0Abar', break_conversion := true);
uri_unescape
--------------
foo\r +
bar
(1 row)

View File

@ -4,10 +4,14 @@ CREATE TABLE test (a serial, b uri);
INSERT INTO test (b) INSERT INTO test (b)
VALUES ('http://www.postgresql.org/'), VALUES ('http://www.postgresql.org/'),
('http://www.postgresql.org/docs/devel/static/xfunc-sql.html#XFUNC-SQL-FUNCTION-ARGUMENTS'), ('http://www.postgresql.org/docs/devel/static/xfunc-sql.html#XFUNC-SQL-FUNCTION-ARGUMENTS'),
('http://www.postgresql.org:591/'),
('http://www.postgresql.org:80/'),
('https://duckduckgo.com/?q=postgresql&ia=about'), ('https://duckduckgo.com/?q=postgresql&ia=about'),
('ftp://ftp.gnu.org/gnu/bison'), ('ftp://ftp.gnu.org/gnu/bison'),
('mailto:foo@example.com'), ('mailto:foo@example.com'),
('ssh://username@review.openstack.org:29418/openstack/nova.git'), ('ssh://username@review.openstack.org:29418/openstack/nova.git'),
('ssh://foobar@review.openstack.org:29418/openstack/nova.git'),
('ssh://review.openstack.org:29418/openstack/nova.git'),
('http://admin:password@192.168.0.1'), ('http://admin:password@192.168.0.1'),
('http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html'), ('http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html'),
('http://[1080::8:800:200C:417A]/foo'), ('http://[1080::8:800:200C:417A]/foo'),
@ -26,22 +30,26 @@ SELECT * FROM test;
----+----------------------------------------------------------------------------------------- ----+-----------------------------------------------------------------------------------------
1 | http://www.postgresql.org/ 1 | http://www.postgresql.org/
2 | http://www.postgresql.org/docs/devel/static/xfunc-sql.html#XFUNC-SQL-FUNCTION-ARGUMENTS 2 | http://www.postgresql.org/docs/devel/static/xfunc-sql.html#XFUNC-SQL-FUNCTION-ARGUMENTS
3 | https://duckduckgo.com/?q=postgresql&ia=about 3 | http://www.postgresql.org:591/
4 | ftp://ftp.gnu.org/gnu/bison 4 | http://www.postgresql.org:80/
5 | mailto:foo@example.com 5 | https://duckduckgo.com/?q=postgresql&ia=about
6 | ssh://username@review.openstack.org:29418/openstack/nova.git 6 | ftp://ftp.gnu.org/gnu/bison
7 | http://admin:password@192.168.0.1 7 | mailto:foo@example.com
8 | http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html 8 | ssh://username@review.openstack.org:29418/openstack/nova.git
9 | http://[1080::8:800:200C:417A]/foo 9 | ssh://foobar@review.openstack.org:29418/openstack/nova.git
10 | http://host: 10 | ssh://review.openstack.org:29418/openstack/nova.git
11 | 11 | http://admin:password@192.168.0.1
12 | / 12 | http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html
13 | foobar 13 | http://[1080::8:800:200C:417A]/foo
14 | /foobar 14 | http://host:
15 | HTTP://www.EXAMPLE.com/ 15 |
16 | http://www.ex%41mple.com/ 16 | /
17 | eXAMPLE://a/./b/../b/%63/%7bfoo%7d 17 | foobar
(17 rows) 18 | /foobar
19 | HTTP://www.EXAMPLE.com/
20 | http://www.ex%41mple.com/
21 | eXAMPLE://a/./b/../b/%63/%7bfoo%7d
(21 rows)
-- error cases -- error cases
SELECT uri 'http://host:port/'; SELECT uri 'http://host:port/';
@ -86,6 +94,30 @@ uri_path_array | {docs,devel,static,xfunc-sql.html}
uri_query | _null_ uri_query | _null_
uri_fragment | XFUNC-SQL-FUNCTION-ARGUMENTS uri_fragment | XFUNC-SQL-FUNCTION-ARGUMENTS
-[ RECORD 3 ]--+---------------------------------------------------------------------------------------- -[ RECORD 3 ]--+----------------------------------------------------------------------------------------
uri | http://www.postgresql.org:591/
uri_normalize | http://www.postgresql.org:591/
uri_scheme | http
uri_userinfo | _null_
uri_host | www.postgresql.org
uri_host_inet | _null_
uri_port | 591
uri_path | /
uri_path_array | {""}
uri_query | _null_
uri_fragment | _null_
-[ RECORD 4 ]--+----------------------------------------------------------------------------------------
uri | http://www.postgresql.org:80/
uri_normalize | http://www.postgresql.org:80/
uri_scheme | http
uri_userinfo | _null_
uri_host | www.postgresql.org
uri_host_inet | _null_
uri_port | 80
uri_path | /
uri_path_array | {""}
uri_query | _null_
uri_fragment | _null_
-[ RECORD 5 ]--+----------------------------------------------------------------------------------------
uri | https://duckduckgo.com/?q=postgresql&ia=about uri | https://duckduckgo.com/?q=postgresql&ia=about
uri_normalize | https://duckduckgo.com/?q=postgresql&ia=about uri_normalize | https://duckduckgo.com/?q=postgresql&ia=about
uri_scheme | https uri_scheme | https
@ -97,7 +129,7 @@ uri_path | /
uri_path_array | {""} uri_path_array | {""}
uri_query | q=postgresql&ia=about uri_query | q=postgresql&ia=about
uri_fragment | _null_ uri_fragment | _null_
-[ RECORD 4 ]--+---------------------------------------------------------------------------------------- -[ RECORD 6 ]--+----------------------------------------------------------------------------------------
uri | ftp://ftp.gnu.org/gnu/bison uri | ftp://ftp.gnu.org/gnu/bison
uri_normalize | ftp://ftp.gnu.org/gnu/bison uri_normalize | ftp://ftp.gnu.org/gnu/bison
uri_scheme | ftp uri_scheme | ftp
@ -109,7 +141,7 @@ uri_path | /gnu/bison
uri_path_array | {gnu,bison} uri_path_array | {gnu,bison}
uri_query | _null_ uri_query | _null_
uri_fragment | _null_ uri_fragment | _null_
-[ RECORD 5 ]--+---------------------------------------------------------------------------------------- -[ RECORD 7 ]--+----------------------------------------------------------------------------------------
uri | mailto:foo@example.com uri | mailto:foo@example.com
uri_normalize | mailto:foo@example.com uri_normalize | mailto:foo@example.com
uri_scheme | mailto uri_scheme | mailto
@ -121,7 +153,7 @@ uri_path | foo@example.com
uri_path_array | {foo@example.com} uri_path_array | {foo@example.com}
uri_query | _null_ uri_query | _null_
uri_fragment | _null_ uri_fragment | _null_
-[ RECORD 6 ]--+---------------------------------------------------------------------------------------- -[ RECORD 8 ]--+----------------------------------------------------------------------------------------
uri | ssh://username@review.openstack.org:29418/openstack/nova.git uri | ssh://username@review.openstack.org:29418/openstack/nova.git
uri_normalize | ssh://username@review.openstack.org:29418/openstack/nova.git uri_normalize | ssh://username@review.openstack.org:29418/openstack/nova.git
uri_scheme | ssh uri_scheme | ssh
@ -133,7 +165,31 @@ uri_path | /openstack/nova.git
uri_path_array | {openstack,nova.git} uri_path_array | {openstack,nova.git}
uri_query | _null_ uri_query | _null_
uri_fragment | _null_ uri_fragment | _null_
-[ RECORD 7 ]--+---------------------------------------------------------------------------------------- -[ RECORD 9 ]--+----------------------------------------------------------------------------------------
uri | ssh://foobar@review.openstack.org:29418/openstack/nova.git
uri_normalize | ssh://foobar@review.openstack.org:29418/openstack/nova.git
uri_scheme | ssh
uri_userinfo | foobar
uri_host | review.openstack.org
uri_host_inet | _null_
uri_port | 29418
uri_path | /openstack/nova.git
uri_path_array | {openstack,nova.git}
uri_query | _null_
uri_fragment | _null_
-[ RECORD 10 ]-+----------------------------------------------------------------------------------------
uri | ssh://review.openstack.org:29418/openstack/nova.git
uri_normalize | ssh://review.openstack.org:29418/openstack/nova.git
uri_scheme | ssh
uri_userinfo | _null_
uri_host | review.openstack.org
uri_host_inet | _null_
uri_port | 29418
uri_path | /openstack/nova.git
uri_path_array | {openstack,nova.git}
uri_query | _null_
uri_fragment | _null_
-[ RECORD 11 ]-+----------------------------------------------------------------------------------------
uri | http://admin:password@192.168.0.1 uri | http://admin:password@192.168.0.1
uri_normalize | http://admin:password@192.168.0.1 uri_normalize | http://admin:password@192.168.0.1
uri_scheme | http uri_scheme | http
@ -145,7 +201,7 @@ uri_path |
uri_path_array | {} uri_path_array | {}
uri_query | _null_ uri_query | _null_
uri_fragment | _null_ uri_fragment | _null_
-[ RECORD 8 ]--+---------------------------------------------------------------------------------------- -[ RECORD 12 ]-+----------------------------------------------------------------------------------------
uri | http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html uri | http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html
uri_normalize | http://[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:80/index.html uri_normalize | http://[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:80/index.html
uri_scheme | http uri_scheme | http
@ -157,7 +213,7 @@ uri_path | /index.html
uri_path_array | {index.html} uri_path_array | {index.html}
uri_query | _null_ uri_query | _null_
uri_fragment | _null_ uri_fragment | _null_
-[ RECORD 9 ]--+---------------------------------------------------------------------------------------- -[ RECORD 13 ]-+----------------------------------------------------------------------------------------
uri | http://[1080::8:800:200C:417A]/foo uri | http://[1080::8:800:200C:417A]/foo
uri_normalize | http://[1080:0000:0000:0000:0008:0800:200c:417a]/foo uri_normalize | http://[1080:0000:0000:0000:0008:0800:200c:417a]/foo
uri_scheme | http uri_scheme | http
@ -169,7 +225,7 @@ uri_path | /foo
uri_path_array | {foo} uri_path_array | {foo}
uri_query | _null_ uri_query | _null_
uri_fragment | _null_ uri_fragment | _null_
-[ RECORD 10 ]-+---------------------------------------------------------------------------------------- -[ RECORD 14 ]-+----------------------------------------------------------------------------------------
uri | http://host: uri | http://host:
uri_normalize | http://host: uri_normalize | http://host:
uri_scheme | http uri_scheme | http
@ -181,7 +237,7 @@ uri_path |
uri_path_array | {} uri_path_array | {}
uri_query | _null_ uri_query | _null_
uri_fragment | _null_ uri_fragment | _null_
-[ RECORD 11 ]-+---------------------------------------------------------------------------------------- -[ RECORD 15 ]-+----------------------------------------------------------------------------------------
uri | uri |
uri_normalize | uri_normalize |
uri_scheme | _null_ uri_scheme | _null_
@ -193,7 +249,7 @@ uri_path |
uri_path_array | {} uri_path_array | {}
uri_query | _null_ uri_query | _null_
uri_fragment | _null_ uri_fragment | _null_
-[ RECORD 12 ]-+---------------------------------------------------------------------------------------- -[ RECORD 16 ]-+----------------------------------------------------------------------------------------
uri | / uri | /
uri_normalize | / uri_normalize | /
uri_scheme | _null_ uri_scheme | _null_
@ -205,7 +261,7 @@ uri_path | /
uri_path_array | {} uri_path_array | {}
uri_query | _null_ uri_query | _null_
uri_fragment | _null_ uri_fragment | _null_
-[ RECORD 13 ]-+---------------------------------------------------------------------------------------- -[ RECORD 17 ]-+----------------------------------------------------------------------------------------
uri | foobar uri | foobar
uri_normalize | foobar uri_normalize | foobar
uri_scheme | _null_ uri_scheme | _null_
@ -217,7 +273,7 @@ uri_path | foobar
uri_path_array | {foobar} uri_path_array | {foobar}
uri_query | _null_ uri_query | _null_
uri_fragment | _null_ uri_fragment | _null_
-[ RECORD 14 ]-+---------------------------------------------------------------------------------------- -[ RECORD 18 ]-+----------------------------------------------------------------------------------------
uri | /foobar uri | /foobar
uri_normalize | /foobar uri_normalize | /foobar
uri_scheme | _null_ uri_scheme | _null_
@ -229,7 +285,7 @@ uri_path | /foobar
uri_path_array | {foobar} uri_path_array | {foobar}
uri_query | _null_ uri_query | _null_
uri_fragment | _null_ uri_fragment | _null_
-[ RECORD 15 ]-+---------------------------------------------------------------------------------------- -[ RECORD 19 ]-+----------------------------------------------------------------------------------------
uri | HTTP://www.EXAMPLE.com/ uri | HTTP://www.EXAMPLE.com/
uri_normalize | http://www.example.com/ uri_normalize | http://www.example.com/
uri_scheme | HTTP uri_scheme | HTTP
@ -241,7 +297,7 @@ uri_path | /
uri_path_array | {""} uri_path_array | {""}
uri_query | _null_ uri_query | _null_
uri_fragment | _null_ uri_fragment | _null_
-[ RECORD 16 ]-+---------------------------------------------------------------------------------------- -[ RECORD 20 ]-+----------------------------------------------------------------------------------------
uri | http://www.ex%41mple.com/ uri | http://www.ex%41mple.com/
uri_normalize | http://www.example.com/ uri_normalize | http://www.example.com/
uri_scheme | http uri_scheme | http
@ -253,7 +309,7 @@ uri_path | /
uri_path_array | {""} uri_path_array | {""}
uri_query | _null_ uri_query | _null_
uri_fragment | _null_ uri_fragment | _null_
-[ RECORD 17 ]-+---------------------------------------------------------------------------------------- -[ RECORD 21 ]-+----------------------------------------------------------------------------------------
uri | eXAMPLE://a/./b/../b/%63/%7bfoo%7d uri | eXAMPLE://a/./b/../b/%63/%7bfoo%7d
uri_normalize | example://a/b/c/%7Bfoo%7D uri_normalize | example://a/b/c/%7Bfoo%7D
uri_scheme | eXAMPLE uri_scheme | eXAMPLE
@ -273,19 +329,34 @@ SELECT DISTINCT b FROM test ORDER BY b;
/ /
/foobar /foobar
HTTP://www.EXAMPLE.com/
eXAMPLE://a/./b/../b/%63/%7bfoo%7d
foobar foobar
eXAMPLE://a/./b/../b/%63/%7bfoo%7d
ftp://ftp.gnu.org/gnu/bison ftp://ftp.gnu.org/gnu/bison
http://admin:password@192.168.0.1
http://[1080::8:800:200C:417A]/foo http://[1080::8:800:200C:417A]/foo
http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html
http://admin:password@192.168.0.1
http://host: http://host:
http://www.ex%41mple.com/ http://www.ex%41mple.com/
HTTP://www.EXAMPLE.com/
http://www.postgresql.org/ http://www.postgresql.org/
http://www.postgresql.org/docs/devel/static/xfunc-sql.html#XFUNC-SQL-FUNCTION-ARGUMENTS http://www.postgresql.org/docs/devel/static/xfunc-sql.html#XFUNC-SQL-FUNCTION-ARGUMENTS
http://www.postgresql.org:80/
http://www.postgresql.org:591/
https://duckduckgo.com/?q=postgresql&ia=about https://duckduckgo.com/?q=postgresql&ia=about
mailto:foo@example.com mailto:foo@example.com
ssh://review.openstack.org:29418/openstack/nova.git
ssh://foobar@review.openstack.org:29418/openstack/nova.git
ssh://username@review.openstack.org:29418/openstack/nova.git ssh://username@review.openstack.org:29418/openstack/nova.git
(17 rows) (21 rows)
CREATE TABLE test2 (x text, y uri);
INSERT INTO test2 VALUES ('foo', 'http://www.postgresql.org/');
-- check hashing (issue petere/pguri#3)
SET enable_nestloop = off;
SET enable_mergejoin = off;
SELECT * FROM test JOIN test2 ON b = y AND a = 1;
a | b | x | y
---+----------------------------+-----+----------------------------
1 | http://www.postgresql.org/ | foo | http://www.postgresql.org/
(1 row)

21
test/sql/escape.sql Normal file
View File

@ -0,0 +1,21 @@
SELECT uri_escape('foobar');
SELECT uri_escape(':/?#[]@!$&''()*+,;=');
SELECT uri_escape('foo bar');
SELECT uri_escape('foo bar', space_to_plus := false);
SELECT uri_escape('foo bar', space_to_plus := true);
SELECT uri_escape(E'foo\nbar');
SELECT uri_escape(E'foo\nbar', normalize_breaks := false);
SELECT uri_escape(E'foo\nbar', normalize_breaks := true);
SELECT uri_unescape('foobar');
SELECT uri_unescape('%3A%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D');
SELECT uri_unescape('foo+bar');
SELECT uri_unescape('foo+bar', plus_to_space := false);
SELECT uri_unescape('foo+bar', plus_to_space := true);
SELECT uri_unescape('foo%0D%0Abar');
SELECT uri_unescape('foo%0D%0Abar', break_conversion := false);
SELECT uri_unescape('foo%0D%0Abar', break_conversion := true);

View File

@ -7,10 +7,14 @@ CREATE TABLE test (a serial, b uri);
INSERT INTO test (b) INSERT INTO test (b)
VALUES ('http://www.postgresql.org/'), VALUES ('http://www.postgresql.org/'),
('http://www.postgresql.org/docs/devel/static/xfunc-sql.html#XFUNC-SQL-FUNCTION-ARGUMENTS'), ('http://www.postgresql.org/docs/devel/static/xfunc-sql.html#XFUNC-SQL-FUNCTION-ARGUMENTS'),
('http://www.postgresql.org:591/'),
('http://www.postgresql.org:80/'),
('https://duckduckgo.com/?q=postgresql&ia=about'), ('https://duckduckgo.com/?q=postgresql&ia=about'),
('ftp://ftp.gnu.org/gnu/bison'), ('ftp://ftp.gnu.org/gnu/bison'),
('mailto:foo@example.com'), ('mailto:foo@example.com'),
('ssh://username@review.openstack.org:29418/openstack/nova.git'), ('ssh://username@review.openstack.org:29418/openstack/nova.git'),
('ssh://foobar@review.openstack.org:29418/openstack/nova.git'),
('ssh://review.openstack.org:29418/openstack/nova.git'),
('http://admin:password@192.168.0.1'), ('http://admin:password@192.168.0.1'),
('http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html'), ('http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html'),
('http://[1080::8:800:200C:417A]/foo'), ('http://[1080::8:800:200C:417A]/foo'),
@ -48,3 +52,12 @@ SELECT b AS uri,
\x off \x off
SELECT DISTINCT b FROM test ORDER BY b; SELECT DISTINCT b FROM test ORDER BY b;
CREATE TABLE test2 (x text, y uri);
INSERT INTO test2 VALUES ('foo', 'http://www.postgresql.org/');
-- check hashing (issue petere/pguri#3)
SET enable_nestloop = off;
SET enable_mergejoin = off;
SELECT * FROM test JOIN test2 ON b = y AND a = 1;

22
uri--0--1.sql Normal file
View File

@ -0,0 +1,22 @@
CREATE FUNCTION uri_hash(uri) RETURNS integer
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE OPERATOR CLASS uri_ops_hash
DEFAULT FOR TYPE uri USING hash AS
OPERATOR 1 =,
FUNCTION 1 uri_hash(uri);
CREATE FUNCTION uri_escape(text, space_to_plus boolean DEFAULT false, normalize_breaks boolean DEFAULT false) RETURNS text
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_unescape(text, plus_to_space boolean DEFAULT false, break_conversion boolean DEFAULT false) RETURNS text
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';

View File

225
uri--1.sql Normal file
View File

@ -0,0 +1,225 @@
SET client_min_messages = warning;
CREATE TYPE uri;
CREATE FUNCTION uri_in(cstring) RETURNS uri
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_out(uri) RETURNS cstring
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
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/uri';
CREATE FUNCTION uri_userinfo(uri) RETURNS text
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_host(uri) RETURNS text
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_host_inet(uri) RETURNS inet
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_port(uri) RETURNS integer
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_query(uri) RETURNS text
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_fragment(uri) RETURNS text
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_path(uri) RETURNS text
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_path_array(uri) RETURNS text[]
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_normalize(uri) RETURNS uri
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_lt(uri, uri) RETURNS boolean
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_le(uri, uri) RETURNS boolean
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_eq(uri, uri) RETURNS boolean
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_ne(uri, uri) RETURNS boolean
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_ge(uri, uri) RETURNS boolean
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_gt(uri, uri) RETURNS boolean
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_cmp(uri, uri) RETURNS integer
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_hash(uri) RETURNS integer
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
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);
CREATE OPERATOR CLASS uri_ops_hash
DEFAULT FOR TYPE uri USING hash AS
OPERATOR 1 =,
FUNCTION 1 uri_hash(uri);
CREATE FUNCTION uri_escape(text, space_to_plus boolean DEFAULT false, normalize_breaks boolean DEFAULT false) RETURNS text
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_unescape(text, plus_to_space boolean DEFAULT false, break_conversion boolean DEFAULT false) RETURNS text
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';

196
uri.c
View File

@ -1,4 +1,5 @@
#include <postgres.h> #include <postgres.h>
#include <access/hash.h>
#include <catalog/pg_type.h> #include <catalog/pg_type.h>
#include <fmgr.h> #include <fmgr.h>
#include <lib/stringinfo.h> #include <lib/stringinfo.h>
@ -16,9 +17,11 @@ typedef struct varlena uritype;
#define DatumGetUriP(X) ((uritype *) PG_DETOAST_DATUM(X)) #define DatumGetUriP(X) ((uritype *) PG_DETOAST_DATUM(X))
#define DatumGetUriPP(X) ((uritype *) PG_DETOAST_DATUM_PACKED(X))
#define UriPGetDatum(X) PointerGetDatum(X) #define UriPGetDatum(X) PointerGetDatum(X)
#define PG_GETARG_URI_P(n) DatumGetUriP(PG_GETARG_DATUM(n)) #define PG_GETARG_URI_P(n) DatumGetUriP(PG_GETARG_DATUM(n))
#define PG_GETARG_URI_PP(n) DatumGetUriPP(PG_GETARG_DATUM(n))
#define PG_RETURN_URI_P(x) PG_RETURN_POINTER(x) #define PG_RETURN_URI_P(x) PG_RETURN_POINTER(x)
@ -39,6 +42,7 @@ parse_uri(const char *s, UriUriA *urip)
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type uri at or near \"%s\"", errmsg("invalid input syntax for type uri at or near \"%s\"",
state.errorPos))); state.errorPos)));
break;
default: default:
elog(ERROR, "liburiparser error code %d", state.errorCode); elog(ERROR, "liburiparser error code %d", state.errorCode);
} }
@ -167,6 +171,16 @@ uri_host_inet(PG_FUNCTION_ARGS)
} }
} }
static int
_uri_port_num(UriUriA *urip)
{
if (!urip->portText.first || !urip->portText.afterLast
|| urip->portText.afterLast == urip->portText.first)
return -1;
return strtol(pnstrdup(urip->portText.first, urip->portText.afterLast - urip->portText.first),
NULL, 10);
}
PG_FUNCTION_INFO_V1(uri_port); PG_FUNCTION_INFO_V1(uri_port);
Datum Datum
uri_port(PG_FUNCTION_ARGS) uri_port(PG_FUNCTION_ARGS)
@ -174,15 +188,14 @@ uri_port(PG_FUNCTION_ARGS)
Datum arg = PG_GETARG_DATUM(0); Datum arg = PG_GETARG_DATUM(0);
char *s = TextDatumGetCString(arg); char *s = TextDatumGetCString(arg);
UriUriA uri; UriUriA uri;
const char *p; int num;
parse_uri(s, &uri); parse_uri(s, &uri);
if (!uri.portText.first || !uri.portText.afterLast num = _uri_port_num(&uri);
|| uri.portText.afterLast == uri.portText.first)
PG_RETURN_NULL();
p = pnstrdup(uri.portText.first, uri.portText.afterLast - uri.portText.first);
uriFreeUriMembersA(&uri); uriFreeUriMembersA(&uri);
PG_RETURN_INT32(strtol(p, NULL, 10)); if (num < 0)
PG_RETURN_NULL();
PG_RETURN_INT32(num);
} }
PG_FUNCTION_INFO_V1(uri_query); PG_FUNCTION_INFO_V1(uri_query);
@ -221,6 +234,21 @@ uri_fragment(PG_FUNCTION_ARGS)
PG_RETURN_NULL(); PG_RETURN_NULL();
} }
/*
* Defined in uriparser library, but not exported, so we keep a local version
* here.
*/
static bool
_is_host_set(UriUriA *uri)
{
return (uri != NULL)
&& ((uri->hostText.first != NULL)
|| (uri->hostData.ip4 != NULL)
|| (uri->hostData.ip6 != NULL)
|| (uri->hostData.ipFuture.first != NULL)
);
}
PG_FUNCTION_INFO_V1(uri_path); PG_FUNCTION_INFO_V1(uri_path);
Datum Datum
uri_path(PG_FUNCTION_ARGS) uri_path(PG_FUNCTION_ARGS)
@ -235,7 +263,7 @@ uri_path(PG_FUNCTION_ARGS)
parse_uri(s, &uri); parse_uri(s, &uri);
if (uri.absolutePath || (uriIsHostSetA(&uri) && uri.pathHead)) if (uri.absolutePath || (_is_host_set(&uri) && uri.pathHead))
appendStringInfoChar(&buf, '/'); appendStringInfoChar(&buf, '/');
for (p = uri.pathHead; p; p = p->next) for (p = uri.pathHead; p; p = p->next)
@ -306,6 +334,56 @@ uri_normalize(PG_FUNCTION_ARGS)
PG_RETURN_URI_P((uritype *) cstring_to_text(ret)); PG_RETURN_URI_P((uritype *) cstring_to_text(ret));
} }
static int
strcasecmp_ascii(const char *s1, const char *s2)
{
for (;;)
{
unsigned char ch1 = (unsigned char) *s1++;
unsigned char ch2 = (unsigned char) *s2++;
if (ch1 != ch2)
{
if (ch1 >= 'A' && ch1 <= 'Z')
ch1 += 'a' - 'A';
if (ch2 >= 'A' && ch2 <= 'Z')
ch2 += 'a' - 'A';
if (ch1 != ch2)
return (int) ch1 - (int) ch2;
}
if (ch1 == 0)
break;
}
return 0;
}
static int
strncasecmp_ascii(const char *s1, const char *s2, size_t n)
{
while (n-- > 0)
{
unsigned char ch1 = (unsigned char) *s1++;
unsigned char ch2 = (unsigned char) *s2++;
if (ch1 != ch2)
{
if (ch1 >= 'A' && ch1 <= 'Z')
ch1 += 'a' - 'A';
if (ch2 >= 'A' && ch2 <= 'Z')
ch2 += 'a' - 'A';
if (ch1 != ch2)
return (int) ch1 - (int) ch2;
}
if (ch1 == 0)
break;
}
return 0;
}
static int static int
cmp_text_range(UriTextRangeA a, UriTextRangeA b) cmp_text_range(UriTextRangeA a, UriTextRangeA b)
{ {
@ -320,14 +398,52 @@ cmp_text_range(UriTextRangeA a, UriTextRangeA b)
return 1; return 1;
else else
{ {
int x = strncmp(a.first, b.first, int x = strncasecmp_ascii(a.first, b.first,
Min(a.afterLast - a.first, b.afterLast - b.first)); Min(a.afterLast - a.first, b.afterLast - b.first));
if (x == 0) if (x == 0)
return (a.afterLast - a.first) - (b.afterLast - b.first); return (a.afterLast - a.first) - (b.afterLast - b.first);
return x; return x;
} }
} }
static int
cmp_hosts(UriUriA *uap, UriUriA *ubp)
{
if (!uap->hostText.first)
{
if (!ubp->hostText.first)
return 0;
else
return -1;
}
else if (uap->hostData.ip4)
{
if (!ubp->hostText.first)
return 1;
else if (ubp->hostData.ip4)
return memcmp(uap->hostData.ip4->data,
ubp->hostData.ip4->data,
sizeof(uap->hostData.ip4->data));
else
return -1;
}
else if (uap->hostData.ip6)
{
if (!ubp->hostText.first)
return 1;
else if (ubp->hostData.ip4)
return 1;
else if (ubp->hostData.ip6)
return memcmp(uap->hostData.ip6->data,
ubp->hostData.ip6->data,
sizeof(uap->hostData.ip6->data));
else
return -1;
}
else
return cmp_text_range(uap->hostText, ubp->hostText);
}
static int static int
_uri_cmp(Datum a, Datum b) _uri_cmp(Datum a, Datum b)
{ {
@ -338,12 +454,18 @@ _uri_cmp(Datum a, Datum b)
int res = 0; int res = 0;
parse_uri(sa, &ua); parse_uri(sa, &ua);
parse_uri(sa, &ub); parse_uri(sb, &ub);
if (res == 0) if (res == 0)
res = cmp_text_range(ua.scheme, ub.scheme); res = cmp_text_range(ua.scheme, ub.scheme);
if (res == 0) if (res == 0)
res = cmp_text_range(ua.hostText, ub.hostText); res = cmp_hosts(&ua, &ub);
if (res == 0)
res = _uri_port_num(&ua) - _uri_port_num(&ub);
if (res == 0)
res = cmp_text_range(ua.userInfo, ub.userInfo);
if (res == 0)
res = strcasecmp_ascii(sa, sb);
if (res == 0) if (res == 0)
res = strcmp(sa, sb); res = strcmp(sa, sb);
uriFreeUriMembersA(&ua); uriFreeUriMembersA(&ua);
@ -421,3 +543,55 @@ uri_cmp(PG_FUNCTION_ARGS)
PG_RETURN_INT32(_uri_cmp(arg1, arg2)); PG_RETURN_INT32(_uri_cmp(arg1, arg2));
} }
PG_FUNCTION_INFO_V1(uri_hash);
Datum
uri_hash(PG_FUNCTION_ARGS)
{
uritype *key = PG_GETARG_URI_PP(0);
Datum result;
result = hash_any((unsigned char *) VARDATA_ANY(key),
VARSIZE_ANY_EXHDR(key));
/* Avoid leaking memory for toasted inputs */
PG_FREE_IF_COPY(key, 0);
return result;
}
PG_FUNCTION_INFO_V1(uri_escape);
Datum
uri_escape(PG_FUNCTION_ARGS)
{
text *arg = PG_GETARG_TEXT_PP(0);
bool space_to_plus = PG_GETARG_BOOL(1);
bool normalize_breaks = PG_GETARG_BOOL(2);
size_t chars_required;
char *ret;
chars_required = (VARSIZE(arg) - 4) * (normalize_breaks ? 6 : 3) + 1;
ret = palloc(chars_required);
uriEscapeExA(VARDATA(arg),
VARDATA(arg) + VARSIZE(arg) - 4,
ret,
space_to_plus, normalize_breaks);
PG_RETURN_TEXT_P(cstring_to_text(ret));
}
PG_FUNCTION_INFO_V1(uri_unescape);
Datum
uri_unescape(PG_FUNCTION_ARGS)
{
text *arg = PG_GETARG_TEXT_PP(0);
bool plus_to_space = PG_GETARG_BOOL(1);
bool break_conversion = PG_GETARG_BOOL(2);
char *s = text_to_cstring(arg);
uriUnescapeInPlaceExA(s, plus_to_space, break_conversion);
PG_RETURN_TEXT_P(cstring_to_text(s));
}

View File

@ -1,4 +1,4 @@
comment = 'uri type' comment = 'uri type'
default_version = 0 default_version = 1
module_pathname = '$libdir/uri' module_pathname = '$libdir/uri'
relocatable = true relocatable = true