Refine sort order
This commit is contained in:
parent
a9cf856ca0
commit
73270357c5
|
@ -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)
|
||||||
|
|
||||||
|
|
119
uri.c
119
uri.c
|
@ -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,7 +397,7 @@ 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);
|
||||||
|
@ -346,6 +405,44 @@ cmp_text_range(UriTextRangeA a, UriTextRangeA b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
Loading…
Reference in New Issue