Started adding comparison functions

This commit is contained in:
BLM 2015-07-23 16:29:13 -05:00
parent 339fac17d2
commit 25d23b90d3
4 changed files with 239 additions and 21 deletions

View File

@ -76,12 +76,11 @@ extern "C" {
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_in); PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_in);
PGDLLEXPORT PGDLLEXPORT Datum
Datum phone_number_in(PG_FUNCTION_ARGS) {
phone_number_in(PG_FUNCTION_ARGS)
{
const char *number_str = PG_GETARG_CSTRING(0); const char *number_str = PG_GETARG_CSTRING(0);
//TODO: use international format instead.
ShortPhoneNumber* number = parsePhoneNumber(number_str, "US"); ShortPhoneNumber* number = parsePhoneNumber(number_str, "US");
if(number) { if(number) {
PG_RETURN_POINTER(number); PG_RETURN_POINTER(number);
@ -92,10 +91,8 @@ extern "C" {
PGDLLEXPORT PG_FUNCTION_INFO_V1(parse_phone_number); PGDLLEXPORT PG_FUNCTION_INFO_V1(parse_phone_number);
PGDLLEXPORT PGDLLEXPORT Datum
Datum parse_phone_number(PG_FUNCTION_ARGS) {
parse_phone_number(PG_FUNCTION_ARGS)
{
try { try {
const text* number_text = PG_GETARG_TEXT_P(0); const text* number_text = PG_GETARG_TEXT_P(0);
const text* country_text = PG_GETARG_TEXT_P(1); const text* country_text = PG_GETARG_TEXT_P(1);
@ -112,7 +109,7 @@ extern "C" {
} else { } else {
PG_RETURN_NULL(); PG_RETURN_NULL();
} }
} catch(std::bad_alloc e) { } catch(std::bad_alloc& e) {
reportOutOfMemory(); reportOutOfMemory();
} catch(std::exception& e) { } catch(std::exception& e) {
reportGenericError(e); reportGenericError(e);
@ -121,10 +118,8 @@ extern "C" {
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_out); PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_out);
PGDLLEXPORT PGDLLEXPORT Datum
Datum phone_number_out(PG_FUNCTION_ARGS) {
phone_number_out(PG_FUNCTION_ARGS)
{
try { try {
const ShortPhoneNumber* short_number = (ShortPhoneNumber*)PG_GETARG_POINTER(0); const ShortPhoneNumber* short_number = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
PhoneNumber number = *short_number; PhoneNumber number = *short_number;
@ -154,8 +149,7 @@ extern "C" {
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_recv); PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_recv);
PGDLLEXPORT PGDLLEXPORT Datum
Datum
phone_number_recv(PG_FUNCTION_ARGS) { phone_number_recv(PG_FUNCTION_ARGS) {
try { try {
StringInfo buf = (StringInfo)PG_GETARG_POINTER(0); StringInfo buf = (StringInfo)PG_GETARG_POINTER(0);
@ -176,8 +170,7 @@ extern "C" {
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_send); PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_send);
PGDLLEXPORT PGDLLEXPORT Datum
Datum
phone_number_send(PG_FUNCTION_ARGS) { phone_number_send(PG_FUNCTION_ARGS) {
try { try {
const ShortPhoneNumber *number = (ShortPhoneNumber*)PG_GETARG_POINTER(0); const ShortPhoneNumber *number = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
@ -194,4 +187,101 @@ extern "C" {
PG_RETURN_NULL(); PG_RETURN_NULL();
} }
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_equal);
PGDLLEXPORT Datum
phone_number_equal(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PG_RETURN_BOOL(*number1 == *number2);
} catch(std::exception& e) {
reportGenericError(e);
}
PG_RETURN_NULL();
}
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_not_equal);
PGDLLEXPORT Datum
phone_number_not_equal(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PG_RETURN_BOOL(*number1 != *number2);
} catch(std::exception& e) {
reportGenericError(e);
}
PG_RETURN_NULL();
}
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_less);
PGDLLEXPORT Datum
phone_number_less(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PG_RETURN_BOOL(number1->compare_fast(*number2) < 0);
} catch(std::exception& e) {
reportGenericError(e);
}
PG_RETURN_NULL();
}
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_less_or_equal);
PGDLLEXPORT Datum
phone_number_less_or_equal(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PG_RETURN_BOOL(number1->compare_fast(*number2) <= 0);
} catch(std::exception& e) {
reportGenericError(e);
}
PG_RETURN_NULL();
}
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_greater);
PGDLLEXPORT Datum
phone_number_greater(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PG_RETURN_BOOL(number1->compare_fast(*number2) > 0);
} catch(std::exception& e) {
reportGenericError(e);
}
PG_RETURN_NULL();
}
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_greater_or_equal);
PGDLLEXPORT Datum
phone_number_greater_or_equal(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PG_RETURN_BOOL(number1->compare_fast(*number2) >= 0);
} catch(std::exception& e) {
reportGenericError(e);
}
PG_RETURN_NULL();
}
} }

View File

@ -3,6 +3,8 @@
CREATE TYPE phone_number; CREATE TYPE phone_number;
--Basic function definitions
CREATE FUNCTION phone_number_in(cstring) RETURNS phone_number CREATE FUNCTION phone_number_in(cstring) RETURNS phone_number
LANGUAGE c IMMUTABLE STRICT LANGUAGE c IMMUTABLE STRICT
AS 'pg_libphonenumber', 'phone_number_in'; AS 'pg_libphonenumber', 'phone_number_in';
@ -29,9 +31,111 @@ CREATE TYPE phone_number (
STORAGE = plain STORAGE = plain
); );
--Cast definitions
CREATE CAST (phone_number AS text) CREATE CAST (phone_number AS text)
WITH INOUT; WITH INOUT;
--Operator definitions
CREATE FUNCTION phone_number_equal(phone_number, phone_number) RETURNS bool
LANGUAGE c IMMUTABLE STRICT
AS 'pg_libphonenumber', 'phone_number_equal';
CREATE OPERATOR = (
leftarg = phone_number,
rightarg = phone_number,
procedure = phone_number_equal,
commutator = =,
negator = <>,
restrict = eqsel,
join = eqjoinsel,
hashes = true,
merges = true
);
CREATE FUNCTION phone_number_not_equal(phone_number, phone_number) RETURNS bool
LANGUAGE c IMMUTABLE STRICT
AS 'pg_libphonenumber', 'phone_number_not_equal';
CREATE OPERATOR <> (
leftarg = phone_number,
rightarg = phone_number,
procedure = phone_number_not_equal,
commutator = <>,
negator = =,
restrict = neqsel,
join = neqjoinsel
);
CREATE FUNCTION phone_number_less(phone_number, phone_number) RETURNS bool
LANGUAGE c IMMUTABLE STRICT
AS 'pg_libphonenumber', 'phone_number_less';
CREATE OPERATOR < (
leftarg = phone_number,
rightarg = phone_number,
procedure = phone_number_less,
commutator = >,
negator = >=,
restrict = scalarltsel,
join = scalarltjoinsel
);
CREATE FUNCTION phone_number_less_or_equal(phone_number, phone_number) RETURNS bool
LANGUAGE c IMMUTABLE STRICT
AS 'pg_libphonenumber', 'phone_number_less_or_equal';
CREATE OPERATOR <= (
leftarg = phone_number,
rightarg = phone_number,
procedure = phone_number_less_or_equal,
commutator = >=,
negator = >,
restrict = scalarltsel,
join = scalarltjoinsel
);
CREATE FUNCTION phone_number_greater(phone_number, phone_number) RETURNS bool
LANGUAGE c IMMUTABLE STRICT
AS 'pg_libphonenumber', 'phone_number_greater';
CREATE OPERATOR > (
leftarg = phone_number,
rightarg = phone_number,
procedure = phone_number_greater,
commutator = >,
negator = <=,
restrict = scalargtsel,
join = scalargtjoinsel
);
CREATE FUNCTION phone_number_greater_or_equal(phone_number, phone_number) RETURNS bool
LANGUAGE c IMMUTABLE STRICT
AS 'pg_libphonenumber', 'phone_number_greater_or_equal';
CREATE OPERATOR >= (
leftarg = phone_number,
rightarg = phone_number,
procedure = phone_number_greater_or_equal,
commutator = >=,
negator = <,
restrict = scalargtsel,
join = scalargtjoinsel
);
CREATE OPERATOR CLASS phone_number_ops
DEFAULT FOR TYPE phone_number USING btree AS
OPERATOR 1 <,
OPERATOR 2 <=,
OPERATOR 3 =,
OPERATOR 4 >=,
OPERATOR 5 >,
FUNCTION 1 phone_number_cmp(phone_number, phone_number);
--General functions
CREATE FUNCTION parse_phone_number(text, text) RETURNS phone_number CREATE FUNCTION parse_phone_number(text, text) RETURNS phone_number
LANGUAGE c IMMUTABLE STRICT LANGUAGE c IMMUTABLE STRICT
AS 'pg_libphonenumber', 'parse_phone_number'; AS 'pg_libphonenumber', 'parse_phone_number';

View File

@ -41,3 +41,4 @@ ShortPhoneNumber::operator PhoneNumber() const {
number.set_number_of_leading_zeros(leading_zeros); number.set_number_of_leading_zeros(leading_zeros);
return number; return number;
} }

View File

@ -18,27 +18,50 @@ class ShortPhoneNumber {
public: public:
enum : size_t { enum : size_t {
MAX_COUNTRY_CODE = 999, MAX_COUNTRY_CODE = 999,
MAX_LEADING_ZEROS = 15,
//15 digits //15 digits
MAX_NATIONAL_NUMBER = 999999999999999, MAX_NATIONAL_NUMBER = 999999999999999,
MAX_LEADING_ZEROS = 15,
}; };
enum : size_t { enum : size_t {
COUNTRY_CODE_BITS = 10, COUNTRY_CODE_BITS = 10,
NATIONAL_NUMBER_BITS = 50,
LEADING_ZEROS_BITS = 4, LEADING_ZEROS_BITS = 4,
NATIONAL_NUMBER_BITS = 50,
}; };
enum : size_t { enum : size_t {
COUNTRY_CODE_OFFSET = 0, COUNTRY_CODE_OFFSET = 0,
NATIONAL_NUMBER_OFFSET = COUNTRY_CODE_OFFSET + COUNTRY_CODE_BITS, LEADING_ZEROS_OFFSET = COUNTRY_CODE_OFFSET + COUNTRY_CODE_BITS,
LEADING_ZEROS_OFFSET = NATIONAL_NUMBER_OFFSET + NATIONAL_NUMBER_BITS, NATIONAL_NUMBER_OFFSET = LEADING_ZEROS_OFFSET + LEADING_ZEROS_BITS,
}; };
ShortPhoneNumber(i18n::phonenumbers::PhoneNumber number); ShortPhoneNumber(i18n::phonenumbers::PhoneNumber number);
bool operator == (const ShortPhoneNumber other) const {
return this->_data == other._data;
}
bool operator != (const ShortPhoneNumber other) const {
return !(*this == other);
}
operator i18n::phonenumbers::PhoneNumber() const; operator i18n::phonenumbers::PhoneNumber() const;
/*
* Compares to another PhoneNumber using a fast collation heuristic
*
* May not produce intuitive results for numbers with the same
* country code but different lengths
*
* Returns:
* - <0 (if a < b)
* - 0 (if a == b)
* - >0 (if a > b)
*/
google::protobuf::int64 compare_fast(ShortPhoneNumber other) const {
return other._data - this->_data;
}
google::protobuf::uint32 country_code() const { google::protobuf::uint32 country_code() const {
return getMasked(_data, COUNTRY_CODE_BITS, COUNTRY_CODE_OFFSET); return getMasked(_data, COUNTRY_CODE_BITS, COUNTRY_CODE_OFFSET);
} }