mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
919 lines
23 KiB
919 lines
23 KiB
/*
|
|
* Portions Copyright (C) 2001-2003 FhG FOKUS
|
|
* Copyright (C) 2003 August.Net Services, LLC
|
|
* Portions Copyright (C) 2005-2008 iptelorg GmbH
|
|
*
|
|
* This file is part of SER, a free SIP server.
|
|
*
|
|
* SER is free software; you can redistribute it and/or modify it under the
|
|
* terms of the GNU General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option) any later
|
|
* version
|
|
*
|
|
* For a license to use the ser software under conditions other than those
|
|
* described here, or to purchase support for this software, please contact
|
|
* iptel.org by e-mail at the following addresses: info@iptel.org
|
|
*
|
|
* SER is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
|
|
/*!
|
|
* \file
|
|
* \brief DB_POSTGRES :: Data field conversion and type checking functions.
|
|
* \ingroup db_postgres
|
|
* Module: \ref db_postgres
|
|
*/
|
|
|
|
#include "pg_fld.h"
|
|
#include "pg_con.h" /* flags */
|
|
#include "pg_mod.h"
|
|
|
|
#include "../../lib/srdb2/db_drv.h"
|
|
#include "../../mem/mem.h"
|
|
#include "../../dprint.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
/**
|
|
* This is the epoch time in time_t format, this value is used to convert
|
|
* timestamp values to/from PostgreSQL format.
|
|
* 2000-01-01 00:00:00 +0000 as the value of time_t in UTC
|
|
*/
|
|
#define PG_EPOCH_TIME ((int64_t)946684800)
|
|
|
|
|
|
/** Frees memory used by a pg_fld structure.
|
|
* This function frees all memory used by a pg_fld structure
|
|
* @param fld Generic db_fld_t* structure being freed.
|
|
* @param payload The postgresql extension structure to be freed
|
|
*/
|
|
static void pg_fld_free(db_fld_t* fld, struct pg_fld* payload)
|
|
{
|
|
db_drv_free(&payload->gen);
|
|
if (payload->name) pkg_free(payload->name);
|
|
pkg_free(payload);
|
|
}
|
|
|
|
|
|
int pg_fld(db_fld_t* fld, char* table)
|
|
{
|
|
struct pg_fld* res;
|
|
|
|
res = (struct pg_fld*)pkg_malloc(sizeof(struct pg_fld));
|
|
if (res == NULL) {
|
|
ERR("postgres: No memory left\n");
|
|
return -1;
|
|
}
|
|
memset(res, '\0', sizeof(struct pg_fld));
|
|
if (db_drv_init(&res->gen, pg_fld_free) < 0) goto error;
|
|
|
|
DB_SET_PAYLOAD(fld, res);
|
|
return 0;
|
|
|
|
error:
|
|
if (res) pkg_free(res);
|
|
return -1;
|
|
}
|
|
|
|
|
|
union ull {
|
|
uint64_t ui64;
|
|
uint32_t ui32[2];
|
|
};
|
|
|
|
static inline uint64_t _htonll(uint64_t in)
|
|
{
|
|
union ull* p = (union ull*)∈
|
|
|
|
return ((uint64_t)htonl(p->ui32[0]) << 32) + (uint64_t)htonl(p->ui32[1]);
|
|
}
|
|
|
|
|
|
static inline uint64_t _ntohll(uint64_t in)
|
|
{
|
|
union ull* p = (union ull*)∈
|
|
return ((uint64_t)ntohl(p->ui32[0]) << 32) + (uint64_t)ntohl(p->ui32[1]);
|
|
}
|
|
|
|
|
|
static inline void db_int2pg_int4(struct pg_params* dst, int i,
|
|
db_fld_t* src)
|
|
{
|
|
struct pg_fld* pfld = DB_GET_PAYLOAD(src);
|
|
pfld->v.int4[0] = htonl(src->v.int4);
|
|
|
|
dst->fmt[i] = 1;
|
|
dst->val[i] = pfld->v.byte;
|
|
dst->len[i] = 4;
|
|
}
|
|
|
|
|
|
static inline void db_int2pg_int2(struct pg_params* dst, int i,
|
|
db_fld_t* src)
|
|
{
|
|
struct pg_fld* pfld = DB_GET_PAYLOAD(src);
|
|
pfld->v.int2[0] = htons(src->v.int4);
|
|
|
|
dst->fmt[i] = 1;
|
|
dst->val[i] = pfld->v.byte;
|
|
dst->len[i] = 2;
|
|
}
|
|
|
|
|
|
static inline void db_int2pg_timestamp(struct pg_params* dst, int i,
|
|
db_fld_t* src, unsigned int flags)
|
|
{
|
|
struct pg_fld* pfld = DB_GET_PAYLOAD(src);
|
|
if (flags & PG_INT8_TIMESTAMP) {
|
|
pfld->v.int8 = ((int64_t)src->v.int4 - PG_EPOCH_TIME) * 1000000;
|
|
} else {
|
|
pfld->v.dbl = (double)src->v.int4 - (double)PG_EPOCH_TIME;
|
|
}
|
|
pfld->v.int8 = _htonll(pfld->v.int8);
|
|
|
|
dst->fmt[i] = 1;
|
|
dst->val[i] = pfld->v.byte;
|
|
dst->len[i] = 8;
|
|
}
|
|
|
|
|
|
static inline void db_int2pg_int8(struct pg_params* dst, int i,
|
|
db_fld_t* src)
|
|
{
|
|
struct pg_fld* pfld = DB_GET_PAYLOAD(src);
|
|
pfld->v.int4[0] = 0;
|
|
pfld->v.int4[1] = htonl(src->v.int4);
|
|
|
|
dst->fmt[i] = 1;
|
|
dst->val[i] = pfld->v.byte;
|
|
dst->len[i] = 8;
|
|
}
|
|
|
|
|
|
static inline void db_int2pg_bool(struct pg_params* dst, int i, db_fld_t* src)
|
|
{
|
|
struct pg_fld* pfld = DB_GET_PAYLOAD(src);
|
|
if (src->v.int4) pfld->v.byte[0] = 1;
|
|
else pfld->v.byte[0] = 0;
|
|
|
|
dst->fmt[i] = 1;
|
|
dst->val[i] = pfld->v.byte;
|
|
dst->len[i] = 1;
|
|
}
|
|
|
|
|
|
static inline void db_int2pg_inet(struct pg_params* dst, int i, db_fld_t* src)
|
|
{
|
|
struct pg_fld* pfld = DB_GET_PAYLOAD(src);
|
|
pfld->v.byte[0] = AF_INET; /* Address family */
|
|
pfld->v.byte[1] = 32; /* Netmask */
|
|
pfld->v.byte[2] = 0; /* is CIDR */
|
|
pfld->v.byte[3] = 4; /* Number of bytes */
|
|
pfld->v.int4[1] = htonl(src->v.int4); /* Actuall IP address */
|
|
|
|
dst->fmt[i] = 1;
|
|
dst->val[i] = pfld->v.byte;
|
|
dst->len[i] = 8;
|
|
}
|
|
|
|
|
|
static inline void db_float2pg_float4(struct pg_params* dst, int i, db_fld_t* src)
|
|
{
|
|
struct pg_fld* pfld = DB_GET_PAYLOAD(src);
|
|
pfld->v.int4[0] = htonl(src->v.int4);
|
|
|
|
dst->fmt[i] = 1;
|
|
dst->val[i] = pfld->v.byte;
|
|
dst->len[i] = 4;
|
|
}
|
|
|
|
|
|
static inline void db_float2pg_float8(struct pg_params* dst, int i, db_fld_t* src)
|
|
{
|
|
struct pg_fld* pfld = DB_GET_PAYLOAD(src);
|
|
pfld->v.dbl = src->v.flt;
|
|
pfld->v.int8 = _htonll(pfld->v.int8);
|
|
|
|
dst->fmt[i] = 1;
|
|
dst->val[i] = pfld->v.byte;
|
|
dst->len[i] = 8;
|
|
}
|
|
|
|
|
|
static inline void db_double2pg_float8(struct pg_params* dst, int i, db_fld_t* src)
|
|
{
|
|
struct pg_fld* pfld = DB_GET_PAYLOAD(src);
|
|
pfld->v.int8 = _htonll(src->v.int8);
|
|
|
|
dst->fmt[i] = 1;
|
|
dst->val[i] = pfld->v.byte;
|
|
dst->len[i] = 8;
|
|
}
|
|
|
|
|
|
static inline void db_double2pg_float4(struct pg_params* dst, int i, db_fld_t* src)
|
|
{
|
|
struct pg_fld* pfld = DB_GET_PAYLOAD(src);
|
|
pfld->v.flt = src->v.dbl;
|
|
pfld->v.int4[0] = htonl(pfld->v.int4[0]);
|
|
|
|
dst->fmt[i] = 1;
|
|
dst->val[i] = pfld->v.byte;
|
|
dst->len[i] = 4;
|
|
}
|
|
|
|
|
|
static inline void db_int2pg_bit(struct pg_params* dst, int i, db_fld_t* src)
|
|
{
|
|
struct pg_fld* pfld = DB_GET_PAYLOAD(src);
|
|
|
|
pfld->v.int4[0] = htonl(32);
|
|
pfld->v.int4[1] = htonl(src->v.int4);
|
|
|
|
dst->fmt[i] = 1;
|
|
dst->val[i] = pfld->v.byte;
|
|
dst->len[i] = 8;
|
|
}
|
|
|
|
|
|
static inline void db_str2pg_string(struct pg_params* dst, int i,
|
|
db_fld_t* src)
|
|
{
|
|
dst->fmt[i] = 1;
|
|
dst->val[i] = src->v.lstr.s;
|
|
dst->len[i] = src->v.lstr.len;
|
|
}
|
|
|
|
|
|
static inline void db_cstr2pg_string(struct pg_params* dst, int i,
|
|
db_fld_t* src)
|
|
{
|
|
dst->fmt[i] = 0;
|
|
dst->val[i] = src->v.cstr;
|
|
}
|
|
|
|
|
|
int pg_fld2pg(struct pg_params* dst, int off, pg_type_t* types,
|
|
db_fld_t* src, unsigned int flags)
|
|
{
|
|
int i;
|
|
struct pg_fld* pfld;
|
|
|
|
if (src == NULL) return 0;
|
|
|
|
for(i = 0; !DB_FLD_EMPTY(src) && !DB_FLD_LAST(src[i]); i++) {
|
|
pfld = DB_GET_PAYLOAD(src + i);
|
|
|
|
/* NULL value */
|
|
if (src[i].flags & DB_NULL) {
|
|
dst->val[off + i] = NULL;
|
|
dst->len[off + i] = 0;
|
|
continue;
|
|
}
|
|
|
|
switch(src[i].type) {
|
|
case DB_INT:
|
|
if (pfld->oid == types[PG_INT2].oid)
|
|
db_int2pg_int2(dst, off + i, src + i);
|
|
else if (pfld->oid == types[PG_INT4].oid)
|
|
db_int2pg_int4(dst, off + i, src + i);
|
|
else if ((pfld->oid == types[PG_TIMESTAMP].oid) ||
|
|
(pfld->oid == types[PG_TIMESTAMPTZ].oid))
|
|
db_int2pg_timestamp(dst, off + i, src + i, flags);
|
|
else if (pfld->oid == types[PG_INT8].oid)
|
|
db_int2pg_int8(dst, off + i, src + i);
|
|
else if (pfld->oid == types[PG_INET].oid)
|
|
db_int2pg_inet(dst, off + i, src + i);
|
|
else if (pfld->oid == types[PG_BOOL].oid)
|
|
db_int2pg_bool(dst, off + i, src + i);
|
|
else if (pfld->oid == types[PG_BIT].oid)
|
|
db_int2pg_bit(dst, off + i, src + i);
|
|
else if (pfld->oid == types[PG_VARBIT].oid)
|
|
db_int2pg_bit(dst, off + i, src + i);
|
|
else goto bug;
|
|
break;
|
|
|
|
case DB_BITMAP:
|
|
if (pfld->oid == types[PG_INT4].oid)
|
|
db_int2pg_int4(dst, off + i, src + i);
|
|
else if (pfld->oid == types[PG_INT8].oid)
|
|
db_int2pg_int8(dst, off + i, src + i);
|
|
else if (pfld->oid == types[PG_BIT].oid)
|
|
db_int2pg_bit(dst, off + i, src + i);
|
|
else if (pfld->oid == types[PG_VARBIT].oid)
|
|
db_int2pg_bit(dst, off + i, src + i);
|
|
else goto bug;
|
|
break;
|
|
|
|
case DB_DATETIME:
|
|
if (pfld->oid == types[PG_INT4].oid)
|
|
db_int2pg_int4(dst, off + i, src + i);
|
|
else if ((pfld->oid == types[PG_TIMESTAMP].oid) ||
|
|
(pfld->oid == types[PG_TIMESTAMPTZ].oid))
|
|
db_int2pg_timestamp(dst, off + i, src + i, flags);
|
|
else if (pfld->oid == types[PG_INT8].oid)
|
|
db_int2pg_int8(dst, off + i, src + i);
|
|
else goto bug;
|
|
break;
|
|
|
|
case DB_FLOAT:
|
|
if (pfld->oid == types[PG_FLOAT4].oid)
|
|
db_float2pg_float4(dst, off + i, src + i);
|
|
else if (pfld->oid == types[PG_FLOAT8].oid)
|
|
db_float2pg_float8(dst, off + i, src + i);
|
|
else goto bug;
|
|
break;
|
|
|
|
case DB_DOUBLE:
|
|
if (pfld->oid == types[PG_FLOAT4].oid)
|
|
db_double2pg_float4(dst, off + i, src + i);
|
|
else if (pfld->oid == types[PG_FLOAT8].oid)
|
|
db_double2pg_float8(dst, off + i, src + i);
|
|
else goto bug;
|
|
break;
|
|
|
|
case DB_STR:
|
|
if (pfld->oid == types[PG_VARCHAR].oid ||
|
|
pfld->oid == types[PG_BYTE].oid ||
|
|
pfld->oid == types[PG_CHAR].oid ||
|
|
pfld->oid == types[PG_TEXT].oid ||
|
|
pfld->oid == types[PG_BPCHAR].oid)
|
|
db_str2pg_string(dst, off + i, src + i);
|
|
else goto bug;
|
|
break;
|
|
|
|
case DB_CSTR:
|
|
if (pfld->oid == types[PG_VARCHAR].oid ||
|
|
pfld->oid == types[PG_BYTE].oid ||
|
|
pfld->oid == types[PG_CHAR].oid ||
|
|
pfld->oid == types[PG_TEXT].oid ||
|
|
pfld->oid == types[PG_BPCHAR].oid)
|
|
db_cstr2pg_string(dst, off + i, src + i);
|
|
else goto bug;
|
|
break;
|
|
|
|
case DB_BLOB:
|
|
if (pfld->oid == types[PG_BYTE].oid)
|
|
db_str2pg_string(dst, off + i, src + i);
|
|
else goto bug;
|
|
break;
|
|
|
|
default:
|
|
BUG("postgres: Unsupported field type %d in field %s\n",
|
|
src[i].type, src[i].name);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
bug:
|
|
BUG("postgres: Error while converting DB API type %d to Postgres Oid %d\n",
|
|
src[i].type, pfld->oid);
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
int pg_check_fld2pg(db_fld_t* fld, pg_type_t* types)
|
|
{
|
|
int i;
|
|
const char* name = "UNKNOWN";
|
|
struct pg_fld* pfld;
|
|
|
|
if (fld == NULL) return 0;
|
|
|
|
for(i = 0; !DB_FLD_EMPTY(fld) && !DB_FLD_LAST(fld[i]); i++) {
|
|
pfld = DB_GET_PAYLOAD(fld + i);
|
|
switch(fld[i].type) {
|
|
case DB_INT:
|
|
if (pfld->oid == types[PG_INT2].oid) continue;
|
|
if (pfld->oid == types[PG_INT4].oid) continue;
|
|
if (pfld->oid == types[PG_INT8].oid) continue;
|
|
if (pfld->oid == types[PG_BOOL].oid) continue;
|
|
if (pfld->oid == types[PG_INET].oid) continue;
|
|
if (pfld->oid == types[PG_TIMESTAMP].oid) continue;
|
|
if (pfld->oid == types[PG_TIMESTAMPTZ].oid) continue;
|
|
if (pfld->oid == types[PG_BIT].oid) continue;
|
|
if (pfld->oid == types[PG_VARBIT].oid) continue;
|
|
break;
|
|
|
|
case DB_BITMAP:
|
|
if (pfld->oid == types[PG_INT4].oid) continue;
|
|
if (pfld->oid == types[PG_INT8].oid) continue;
|
|
if (pfld->oid == types[PG_BIT].oid) continue;
|
|
if (pfld->oid == types[PG_VARBIT].oid) continue;
|
|
break;
|
|
|
|
case DB_FLOAT:
|
|
case DB_DOUBLE:
|
|
if (pfld->oid == types[PG_FLOAT4].oid) continue;
|
|
if (pfld->oid == types[PG_FLOAT8].oid) continue;
|
|
break;
|
|
|
|
case DB_CSTR:
|
|
case DB_STR:
|
|
if (pfld->oid == types[PG_BYTE].oid) continue;
|
|
if (pfld->oid == types[PG_CHAR].oid) continue;
|
|
if (pfld->oid == types[PG_TEXT].oid) continue;
|
|
if (pfld->oid == types[PG_BPCHAR].oid) continue;
|
|
if (pfld->oid == types[PG_VARCHAR].oid) continue;
|
|
break;
|
|
|
|
case DB_BLOB:
|
|
if (pfld->oid == types[PG_BYTE].oid) continue;
|
|
break;
|
|
|
|
case DB_DATETIME:
|
|
if (pfld->oid == types[PG_INT4].oid) continue;
|
|
if (pfld->oid == types[PG_INT8].oid) continue;
|
|
if (pfld->oid == types[PG_TIMESTAMP].oid) continue;
|
|
if (pfld->oid == types[PG_TIMESTAMPTZ].oid) continue;
|
|
break;
|
|
|
|
default:
|
|
BUG("postgres: Unsupported field type %d, bug in postgres module\n",
|
|
fld[i].type);
|
|
return -1;
|
|
}
|
|
|
|
pg_oid2name(&name, types, pfld->oid);
|
|
ERR("postgres: Cannot convert column '%s' of type %s "
|
|
"to PostgreSQL column type '%s'\n",
|
|
fld[i].name, db_fld_str[fld[i].type], name);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int pg_resolve_param_oids(db_fld_t* vals, db_fld_t* match, int n1, int n2, PGresult* types)
|
|
{
|
|
struct pg_fld* pfld;
|
|
int i;
|
|
|
|
if (n1 + n2 != PQnparams(types)) {
|
|
ERR("postgres: Number of command parameters do not match\n");
|
|
return -1;
|
|
}
|
|
|
|
for(i = 0; i < n1; i++) {
|
|
pfld = DB_GET_PAYLOAD(vals + i);
|
|
pfld->oid = PQparamtype(types, i);
|
|
}
|
|
|
|
for(i = 0; i < n2; i++) {
|
|
pfld = DB_GET_PAYLOAD(match + i);
|
|
pfld->oid = PQparamtype(types, n1 + i);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int pg_resolve_result_oids(db_fld_t* fld, int n, PGresult* types)
|
|
{
|
|
struct pg_fld* pfld;
|
|
int i;
|
|
if (fld == NULL) return 0;
|
|
|
|
if (n != PQnfields(types)) {
|
|
ERR("postgres: Result field numbers do not match\n");
|
|
return -1;
|
|
}
|
|
|
|
for(i = 0; i < n; i++) {
|
|
pfld = DB_GET_PAYLOAD(fld + i);
|
|
pfld->oid = PQftype(types, i);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int pg_check_pg2fld(db_fld_t* fld, pg_type_t* types)
|
|
{
|
|
int i;
|
|
const char* name = "UNKNOWN";
|
|
struct pg_fld* pfld;
|
|
|
|
if (fld == NULL) return 0;
|
|
|
|
for(i = 0; !DB_FLD_EMPTY(fld) && !DB_FLD_LAST(fld[i]); i++) {
|
|
pfld = DB_GET_PAYLOAD(fld + i);
|
|
|
|
if (pfld->oid == 0) {
|
|
ERR("postgres: Unknown type fields not supported\n");
|
|
return -1;
|
|
}
|
|
|
|
switch(fld[i].type) {
|
|
case DB_INT:
|
|
if (pfld->oid == types[PG_INT2].oid) continue;
|
|
if (pfld->oid == types[PG_INT4].oid) continue;
|
|
if (pfld->oid == types[PG_INT8].oid) continue;
|
|
if (pfld->oid == types[PG_BOOL].oid) continue;
|
|
if (pfld->oid == types[PG_INET].oid) continue;
|
|
if (pfld->oid == types[PG_TIMESTAMP].oid) continue;
|
|
if (pfld->oid == types[PG_TIMESTAMPTZ].oid) continue;
|
|
if (pfld->oid == types[PG_BIT].oid) continue;
|
|
if (pfld->oid == types[PG_VARBIT].oid) continue;
|
|
break;
|
|
|
|
case DB_BITMAP:
|
|
if (pfld->oid == types[PG_INT2].oid) continue;
|
|
if (pfld->oid == types[PG_INT4].oid) continue;
|
|
if (pfld->oid == types[PG_INT8].oid) continue;
|
|
if (pfld->oid == types[PG_BIT].oid) continue;
|
|
if (pfld->oid == types[PG_VARBIT].oid) continue;
|
|
break;
|
|
|
|
case DB_FLOAT:
|
|
if (pfld->oid == types[PG_FLOAT4].oid) continue;
|
|
break;
|
|
|
|
case DB_DOUBLE:
|
|
if (pfld->oid == types[PG_FLOAT4].oid) continue;
|
|
if (pfld->oid == types[PG_FLOAT8].oid) continue;
|
|
break;
|
|
|
|
case DB_CSTR:
|
|
if (pfld->oid == types[PG_CHAR].oid) continue;
|
|
if (pfld->oid == types[PG_TEXT].oid) continue;
|
|
if (pfld->oid == types[PG_BPCHAR].oid) continue;
|
|
if (pfld->oid == types[PG_VARCHAR].oid) continue;
|
|
if (pfld->oid == types[PG_INT2].oid) continue;
|
|
if (pfld->oid == types[PG_INT4].oid) continue;
|
|
break;
|
|
|
|
case DB_STR:
|
|
case DB_BLOB:
|
|
if (pfld->oid == types[PG_BYTE].oid) continue;
|
|
if (pfld->oid == types[PG_CHAR].oid) continue;
|
|
if (pfld->oid == types[PG_TEXT].oid) continue;
|
|
if (pfld->oid == types[PG_BPCHAR].oid) continue;
|
|
if (pfld->oid == types[PG_VARCHAR].oid) continue;
|
|
if (pfld->oid == types[PG_INT2].oid) continue;
|
|
if (pfld->oid == types[PG_INT4].oid) continue;
|
|
break;
|
|
|
|
case DB_DATETIME:
|
|
if (pfld->oid == types[PG_INT2].oid) continue;
|
|
if (pfld->oid == types[PG_INT4].oid) continue;
|
|
if (pfld->oid == types[PG_TIMESTAMP].oid) continue;
|
|
if (pfld->oid == types[PG_TIMESTAMPTZ].oid) continue;
|
|
break;
|
|
|
|
default:
|
|
BUG("postgres: Unsupported field type %d, bug in postgres module\n",
|
|
fld[i].type);
|
|
return -1;
|
|
}
|
|
|
|
pg_oid2name(&name, types, pfld->oid);
|
|
ERR("postgres: Cannot convert column '%s' of type %s "
|
|
"to DB API field of type %s\n",
|
|
fld[i].name, name, db_fld_str[fld[i].type]);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static inline int pg_int2_2_db_cstr(db_fld_t* fld, char* val, int len)
|
|
{
|
|
struct pg_fld* pfld = DB_GET_PAYLOAD(fld);
|
|
int size, v;
|
|
|
|
v = (int16_t)ntohs(*((int16_t*)val));
|
|
|
|
size = snprintf(pfld->buf, INT2STR_MAX_LEN, "%-d", v);
|
|
if (size < 0 || size >= INT2STR_MAX_LEN) {
|
|
BUG("postgres: Error while converting integer to string\n");
|
|
return -1;
|
|
}
|
|
|
|
fld->v.cstr = pfld->buf;
|
|
return 0;
|
|
}
|
|
|
|
|
|
static inline int pg_int4_2_db_cstr(db_fld_t* fld, char* val, int len)
|
|
{
|
|
struct pg_fld* pfld = DB_GET_PAYLOAD(fld);
|
|
int size, v;
|
|
|
|
v = (int32_t)ntohl(*((int32_t*)val));
|
|
|
|
size = snprintf(pfld->buf, INT2STR_MAX_LEN, "%-d", v);
|
|
if (len < 0 || size >= INT2STR_MAX_LEN) {
|
|
BUG("postgres: Error while converting integer to string\n");
|
|
return -1;
|
|
}
|
|
|
|
fld->v.cstr = pfld->buf;
|
|
return 0;
|
|
}
|
|
|
|
|
|
static inline int pg_int2_2_db_str(db_fld_t* fld, char* val, int len)
|
|
{
|
|
struct pg_fld* pfld = DB_GET_PAYLOAD(fld);
|
|
int size, v;
|
|
|
|
v = (int16_t)ntohs(*((int16_t*)val));
|
|
|
|
size = snprintf(pfld->buf, INT2STR_MAX_LEN, "%-d", v);
|
|
if (size < 0 || size >= INT2STR_MAX_LEN) {
|
|
BUG("postgres: Error while converting integer to string\n");
|
|
return -1;
|
|
}
|
|
|
|
fld->v.lstr.s = pfld->buf;
|
|
fld->v.lstr.len = size;
|
|
return 0;
|
|
}
|
|
|
|
|
|
static inline int pg_int4_2_db_str(db_fld_t* fld, char* val, int len)
|
|
{
|
|
struct pg_fld* pfld = DB_GET_PAYLOAD(fld);
|
|
int size, v;
|
|
|
|
v = (int32_t)ntohl(*((int32_t*)val));
|
|
|
|
size = snprintf(pfld->buf, INT2STR_MAX_LEN, "%-d", v);
|
|
if (size < 0 || size >= INT2STR_MAX_LEN) {
|
|
BUG("postgres: Error while converting integer to string\n");
|
|
return -1;
|
|
}
|
|
|
|
fld->v.lstr.s = pfld->buf;
|
|
fld->v.lstr.len = size;
|
|
return 0;
|
|
}
|
|
|
|
|
|
static inline int pg_int2_2_db_int(db_fld_t* fld, char* val, int len)
|
|
{
|
|
fld->v.int4 = (int16_t)ntohs(*((int16_t*)val));
|
|
return 0;
|
|
}
|
|
|
|
|
|
static inline int pg_int4_2_db_int(db_fld_t* fld, char* val, int len)
|
|
{
|
|
fld->v.int4 = (int32_t)ntohl(*((int32_t*)val));
|
|
return 0;
|
|
}
|
|
|
|
|
|
static inline int pg_int8_2_db_int(db_fld_t* fld, char* val, int len)
|
|
{
|
|
fld->v.int8 = (int64_t)_ntohll(*((int64_t*)val));
|
|
return 0;
|
|
}
|
|
|
|
|
|
static inline int pg_bool2db_int(db_fld_t* fld, char* val, int len)
|
|
{
|
|
fld->v.int4 = val[0];
|
|
return 0;
|
|
}
|
|
|
|
|
|
static inline int pg_inet2db_int(db_fld_t* fld, char* val, int len)
|
|
{
|
|
if (len != 8 || val[2] != 0) {
|
|
ERR("postgres: Unsupported 'inet' format, column %s\n", fld->name);
|
|
return -1;
|
|
}
|
|
|
|
if (val[0] != AF_INET) {
|
|
ERR("postgres: Unsupported address family %d in field %s\n",
|
|
val[0], fld->name);
|
|
return -1;
|
|
}
|
|
|
|
if (val[1] != 32) {
|
|
WARN("postgres: Netmasks shorter than 32-bits not supported, "
|
|
"column %s\n", fld->name);
|
|
}
|
|
|
|
if (val[3] != 4) {
|
|
ERR("postgres: Unsupported IP address size %d in column %s\n",
|
|
val[3], fld->name);
|
|
return -1;
|
|
}
|
|
|
|
fld->v.int4 = (int32_t)ntohl(((int32_t*)val)[1]);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static inline int pg_timestamp2db_int(db_fld_t* fld, char* val, int len,
|
|
unsigned int flags)
|
|
{
|
|
if (flags & PG_INT8_TIMESTAMP) {
|
|
/* int8 format */
|
|
fld->v.int4 = (int64_t)_ntohll(((int64_t*)val)[0]) / (int64_t)1000000 + PG_EPOCH_TIME;
|
|
} else {
|
|
/* double format */
|
|
fld->v.int4 = PG_EPOCH_TIME + _ntohll(((int64_t*)val)[0]);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static inline int pg_bit2db_int(db_fld_t* fld, char* val, int len)
|
|
{
|
|
int size;
|
|
|
|
size = ntohl(*(uint32_t*)val);
|
|
if (size != 32) {
|
|
ERR("postgres: Unsupported bit field size (%d), column %s\n",
|
|
size, fld->name);
|
|
return -1;
|
|
}
|
|
fld->v.int4 = ntohl(((uint32_t*)val)[1]);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static inline int pg_float42db_float(db_fld_t* fld, char* val, int len)
|
|
{
|
|
fld->v.int4 = (uint32_t)ntohl(*(uint32_t*)val);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static inline int pg_float42db_double(db_fld_t* fld, char* val, int len)
|
|
{
|
|
float tmp;
|
|
|
|
tmp = ntohl(*(uint32_t*)val);
|
|
fld->v.dbl = tmp;
|
|
return 0;
|
|
}
|
|
|
|
|
|
static inline int pg_float82db_double(db_fld_t* fld, char* val, int len)
|
|
{
|
|
fld->v.int8 = _ntohll(*(uint64_t*)val);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static inline int pg_string2db_cstr(db_fld_t* fld, char* val, int len)
|
|
{
|
|
fld->v.cstr = val;
|
|
return 0;
|
|
}
|
|
|
|
|
|
static inline int pg_string2db_str(db_fld_t* fld, char* val, int len)
|
|
{
|
|
fld->v.lstr.s = val;
|
|
fld->v.lstr.len = len;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int pg_pg2fld(db_fld_t* dst, PGresult* src, int row,
|
|
pg_type_t* types, unsigned int flags)
|
|
{
|
|
char* val;
|
|
int i, len, ret;
|
|
Oid type;
|
|
|
|
if (dst == NULL || src == NULL) return 0;
|
|
ret = 0;
|
|
|
|
for(i = 0; !DB_FLD_EMPTY(dst) && !DB_FLD_LAST(dst[i]); i++) {
|
|
if (PQgetisnull(src, row, i)) {
|
|
dst[i].flags |= DB_NULL;
|
|
continue;
|
|
} else {
|
|
dst[i].flags &= ~DB_NULL;
|
|
}
|
|
|
|
type = PQftype(src, i);
|
|
val = PQgetvalue(src, row, i);
|
|
len = PQgetlength(src, row, i);
|
|
|
|
switch(dst[i].type) {
|
|
case DB_INT:
|
|
if (type == types[PG_INT2].oid)
|
|
ret |= pg_int2_2_db_int(dst + i, val, len);
|
|
else if (type == types[PG_INT4].oid)
|
|
ret |= pg_int4_2_db_int(dst + i, val, len);
|
|
else if (type == types[PG_INT8].oid)
|
|
ret |= pg_int8_2_db_int(dst + i, val, len);
|
|
else if (type == types[PG_BOOL].oid)
|
|
ret |= pg_bool2db_int(dst + i, val, len);
|
|
else if (type == types[PG_INET].oid)
|
|
ret |= pg_inet2db_int(dst + i, val, len);
|
|
else if ((type == types[PG_TIMESTAMP].oid) ||
|
|
(type == types[PG_TIMESTAMPTZ].oid))
|
|
ret |= pg_timestamp2db_int(dst + i, val, len, flags);
|
|
else if (type == types[PG_BIT].oid)
|
|
ret |= pg_bit2db_int(dst + i, val, len);
|
|
else if (type == types[PG_VARBIT].oid)
|
|
ret |= pg_bit2db_int(dst + i, val, len);
|
|
else goto bug;
|
|
break;
|
|
|
|
case DB_FLOAT:
|
|
if (type == types[PG_FLOAT4].oid)
|
|
ret |= pg_float42db_float(dst + i, val, len);
|
|
else goto bug;
|
|
break;
|
|
|
|
case DB_DOUBLE:
|
|
if (type == types[PG_FLOAT4].oid)
|
|
ret |= pg_float42db_double(dst + i, val, len);
|
|
else if (type == types[PG_FLOAT8].oid)
|
|
ret |= pg_float82db_double(dst + i, val, len);
|
|
else goto bug;
|
|
break;
|
|
|
|
case DB_DATETIME:
|
|
if (type == types[PG_INT2].oid)
|
|
ret |= pg_int2_2_db_int(dst + i, val, len);
|
|
else if (type == types[PG_INT4].oid)
|
|
ret |= pg_int4_2_db_int(dst + i, val, len);
|
|
else if ((type == types[PG_TIMESTAMP].oid) ||
|
|
(type == types[PG_TIMESTAMPTZ].oid))
|
|
ret |= pg_timestamp2db_int(dst + i, val, len, flags);
|
|
else goto bug;
|
|
break;
|
|
|
|
case DB_CSTR:
|
|
if ((type == types[PG_CHAR].oid) ||
|
|
(type == types[PG_TEXT].oid) ||
|
|
(type == types[PG_BPCHAR].oid) ||
|
|
(type == types[PG_VARCHAR].oid))
|
|
ret |= pg_string2db_cstr(dst + i, val, len);
|
|
else if (type == types[PG_INT2].oid)
|
|
ret |= pg_int2_2_db_cstr(dst + i, val, len);
|
|
else if (type == types[PG_INT4].oid)
|
|
ret |= pg_int4_2_db_cstr(dst + i, val, len);
|
|
else goto bug;
|
|
break;
|
|
|
|
case DB_STR:
|
|
case DB_BLOB:
|
|
if ((type == types[PG_BYTE].oid) ||
|
|
(type == types[PG_CHAR].oid) ||
|
|
(type == types[PG_TEXT].oid) ||
|
|
(type == types[PG_BPCHAR].oid) ||
|
|
(type == types[PG_VARCHAR].oid))
|
|
ret |= pg_string2db_str(dst + i, val, len);
|
|
else if (type == types[PG_INT2].oid)
|
|
ret |= pg_int2_2_db_str(dst + i, val, len);
|
|
else if (type == types[PG_INT4].oid)
|
|
ret |= pg_int4_2_db_str(dst + i, val, len);
|
|
else goto bug;
|
|
break;
|
|
|
|
case DB_BITMAP:
|
|
if (type == types[PG_INT2].oid)
|
|
ret |= pg_int2_2_db_int(dst + i, val, len);
|
|
else if (type == types[PG_INT4].oid)
|
|
ret |= pg_int4_2_db_int(dst + i, val, len);
|
|
else if (type == types[PG_INT8].oid)
|
|
ret |= pg_int8_2_db_int(dst + i, val, len);
|
|
else if (type == types[PG_BIT].oid)
|
|
ret |= pg_bit2db_int(dst + i, val, len);
|
|
else if (type == types[PG_VARBIT].oid)
|
|
ret |= pg_bit2db_int(dst + i, val, len);
|
|
else goto bug;
|
|
break;
|
|
|
|
default:
|
|
BUG("postgres: Unsupported field type %d in field %s\n",
|
|
dst[i].type, dst[i].name);
|
|
return -1;
|
|
}
|
|
}
|
|
return ret;
|
|
|
|
bug:
|
|
BUG("postgres: Error while converting Postgres Oid %d to DB API type %d\n",
|
|
type, dst[i].type);
|
|
return -1;
|
|
}
|