Normalized line endings; tweaked error reporting to show exception class

names
This commit is contained in:
BLM 2015-07-14 15:32:22 -05:00
parent 790a1cb56a
commit 610a66220f
1 changed files with 159 additions and 156 deletions

View File

@ -1,156 +1,159 @@
#include <exception> #include <exception>
#include <string> #include <string>
#define I18N_PHONENUMBERS_USE_BOOST #define I18N_PHONENUMBERS_USE_BOOST
#include "phonenumbers/phonenumberutil.h" #include "phonenumbers/phonenumberutil.h"
extern "C" { extern "C" {
#include "postgres.h" #include "postgres.h"
#include "libpq/pqformat.h" #include "libpq/pqformat.h"
#include "fmgr.h" #include "fmgr.h"
} }
using namespace i18n::phonenumbers; using namespace i18n::phonenumbers;
PhoneNumberUtil *phoneUtil = PhoneNumberUtil::GetInstance(); PhoneNumberUtil *phoneUtil = PhoneNumberUtil::GetInstance();
//Utility functions for error handling //Utility functions for error handling
void reportOutOfMemory() { void reportOutOfMemory() {
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY))); (errcode(ERRCODE_OUT_OF_MEMORY)));
} }
void reportParsingError(const char* phone_number, const char* msg = "") { void reportParsingError(const char* phone_number, const char* msg = "") {
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("unable to parse '%s' as a phone number", phone_number), errmsg("unable to parse '%s' as a phone number", phone_number),
errdetail("%s", msg))); errdetail("%s", msg)));
} }
void reportGenericError(std::exception& exception) { void reportGenericError(std::exception& exception) {
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
errmsg("%s", exception.what()))); errmsg("%s", typeid(exception).name()),
} errdetail("%s", exception.what())));
}
//TODO: handle non-exception thrown types? (shouldn't happen, but you never know...)
//TODO: handle non-exception thrown types? (shouldn't happen, but you never know...)
extern "C" {
#ifdef PG_MODULE_MAGIC extern "C" {
PG_MODULE_MAGIC; #ifdef PG_MODULE_MAGIC
#endif PG_MODULE_MAGIC;
#endif
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_in);
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_in);
PGDLLEXPORT
Datum PGDLLEXPORT
phone_number_in(PG_FUNCTION_ARGS) Datum
{ phone_number_in(PG_FUNCTION_ARGS)
const char *str = PG_GETARG_CSTRING(0); {
PhoneNumber *number; const char *str = PG_GETARG_CSTRING(0);
PhoneNumber *number;
number = (PhoneNumber*)palloc0(sizeof(PhoneNumber));
//TODO: can this be removed? (palloc normally handles this, right?) number = (PhoneNumber*)palloc0(sizeof(PhoneNumber));
if(number == nullptr) { //TODO: can this be removed? (palloc normally handles this, right?)
reportOutOfMemory(); if(number == nullptr) {
PG_RETURN_NULL(); reportOutOfMemory();
} PG_RETURN_NULL();
}
try {
using PNU = i18n::phonenumbers::PhoneNumberUtil; try {
PNU::ErrorType error; using PNU = i18n::phonenumbers::PhoneNumberUtil;
error = phoneUtil->Parse(str, "US", number); PNU::ErrorType error;
switch(error) { error = phoneUtil->Parse(str, "US", number);
case PNU::NO_PARSING_ERROR: switch(error) {
//The number was parsed correctly; return it. case PNU::NO_PARSING_ERROR:
PG_RETURN_POINTER(number); //The number was parsed correctly; return it.
break; PG_RETURN_POINTER(number);
case PNU::NOT_A_NUMBER: break;
reportParsingError(str, "String does not appear to contain a phone number."); case PNU::NOT_A_NUMBER:
break; reportParsingError(str, "String does not appear to contain a phone number.");
case PNU::INVALID_COUNTRY_CODE_ERROR: break;
reportParsingError(str, "Invalid country code"); case PNU::INVALID_COUNTRY_CODE_ERROR:
break; reportParsingError(str, "Invalid country code");
//TODO: handle more error cases specifically. break;
default: //TODO: handle more error cases specifically.
//We have some generic parsing error. default:
reportParsingError(str); //We have some generic parsing error.
} reportParsingError(str);
//TODO: check number validity. }
} catch(std::bad_alloc& e) { //TODO: check number validity.
reportOutOfMemory(); } catch(std::bad_alloc& e) {
} catch (std::exception& e) { reportOutOfMemory();
reportGenericError(e); } catch (std::exception& e) {
} reportGenericError(e);
}
//If we get here, we couldn't return a valid number.
PG_RETURN_NULL(); //If we get here, we couldn't return a valid number.
} PG_RETURN_NULL();
}
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_out);
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_out);
PGDLLEXPORT
Datum PGDLLEXPORT
phone_number_out(PG_FUNCTION_ARGS) Datum
{ phone_number_out(PG_FUNCTION_ARGS)
PhoneNumber *number = (PhoneNumber*)PG_GETARG_POINTER(0); {
std::string formatted; PhoneNumber *number = (PhoneNumber*)PG_GETARG_POINTER(0);
char *result; std::string formatted;
char *result;
try {
phoneUtil->Format(*number, PhoneNumberUtil::INTERNATIONAL, &formatted); formatted.resize(20, ' ');
} catch(std::bad_alloc& e) {
reportOutOfMemory(); try {
} catch (std::exception& e) { phoneUtil->Format(*number, PhoneNumberUtil::INTERNATIONAL, &formatted);
reportGenericError(e); } catch(std::bad_alloc& e) {
} reportOutOfMemory();
} catch (std::exception& e) {
//Copy the formatted number to a C-style string. reportGenericError(e);
//We must use the PostgreSQL allocator, not new/malloc. }
size_t len = formatted.length();
ereport(INFO, //Copy the formatted number to a C-style string.
(errcode(ERRCODE_SUCCESSFUL_COMPLETION), //We must use the PostgreSQL allocator, not new/malloc.
errmsg("Length: %zu", len))); size_t len = formatted.length();
result = (char*)palloc(len + 1); ereport(INFO,
if(result == nullptr) { (errcode(ERRCODE_SUCCESSFUL_COMPLETION),
reportOutOfMemory(); errmsg("Length: %zu", len)));
PG_RETURN_NULL(); result = (char*)palloc(len + 1);
} if(result == nullptr) {
memcpy(result, formatted.data(), len); reportOutOfMemory();
result[len] = '\0'; PG_RETURN_NULL();
}
PG_RETURN_CSTRING(result); memcpy(result, formatted.data(), len);
} result[len] = '\0';
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_recv); PG_RETURN_CSTRING(result);
}
PGDLLEXPORT
Datum PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_recv);
phone_number_recv(PG_FUNCTION_ARGS)
{ PGDLLEXPORT
StringInfo buf = (StringInfo)PG_GETARG_POINTER(0); Datum
PhoneNumber *result; phone_number_recv(PG_FUNCTION_ARGS)
{
//TODO: error handling? StringInfo buf = (StringInfo)PG_GETARG_POINTER(0);
result = (PhoneNumber*)palloc0(sizeof(PhoneNumber)); PhoneNumber *result;
result->set_country_code(pq_getmsgint(buf, 4));
result->set_national_number(pq_getmsgint64(buf)); //TODO: error handling?
PG_RETURN_POINTER(result); result = (PhoneNumber*)palloc0(sizeof(PhoneNumber));
} result->set_country_code(pq_getmsgint(buf, 4));
result->set_national_number(pq_getmsgint64(buf));
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_send); PG_RETURN_POINTER(result);
}
PGDLLEXPORT
Datum PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_send);
phone_number_send(PG_FUNCTION_ARGS)
{ PGDLLEXPORT
PhoneNumber *number = (PhoneNumber*)PG_GETARG_POINTER(0); Datum
StringInfoData buf; phone_number_send(PG_FUNCTION_ARGS)
{
pq_begintypsend(&buf); PhoneNumber *number = (PhoneNumber*)PG_GETARG_POINTER(0);
pq_sendint(&buf, number->country_code(), 4); StringInfoData buf;
pq_sendint64(&buf, number->national_number());
PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); pq_begintypsend(&buf);
} pq_sendint(&buf, number->country_code(), 4);
} pq_sendint64(&buf, number->national_number());
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
}