Refine sort order

This commit is contained in:
Peter Eisentraut 2015-12-23 22:35:15 -05:00
parent a9cf856ca0
commit 73270357c5
2 changed files with 116 additions and 13 deletions

View File

@ -330,22 +330,22 @@ SELECT DISTINCT b FROM test ORDER BY b;
/ /
/foobar /foobar
foobar foobar
HTTP://www.EXAMPLE.com/
eXAMPLE://a/./b/../b/%63/%7bfoo%7d eXAMPLE://a/./b/../b/%63/%7bfoo%7d
ftp://ftp.gnu.org/gnu/bison ftp://ftp.gnu.org/gnu/bison
http://[1080::8:800:200C:417A]/foo
http://admin:password@192.168.0.1 http://admin:password@192.168.0.1
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://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:591/
http://www.postgresql.org:80/ 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://foobar@review.openstack.org:29418/openstack/nova.git
ssh://review.openstack.org:29418/openstack/nova.git 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
(21 rows) (21 rows)

121
uri.c
View File

@ -170,6 +170,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)
@ -177,15 +187,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);
@ -324,6 +333,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)
{ {
@ -338,14 +397,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)
{ {
@ -361,7 +458,13 @@ _uri_cmp(Datum a, Datum b)
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);