view main/database/src/converters.cc @ 11661:1b4e81051b66 octave-forge

Add converter for timestamp.
author i7tiol
date Sat, 27 Apr 2013 19:17:33 +0000
parents f9f1af45e49a
children 2c21253d3341
line wrap: on
line source

/*

Copyright (C) 2012, 2013 Olaf Till <i7tiol@t-online.de>

This program 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 3 of the License, or
(at your option) any later version.

This program 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, see <http://www.gnu.org/licenses/>.

*/

#include <octave/oct.h>
#include <octave/ov-float.h>
#include <octave/ov-uint8.h>

#include <libpq-fe.h>

#include "converters.h"
#include "pq_connection.h"

// remember to adjust OCT_PQ_NUM_CONVERTERS in converters.h

// helper function for debugging
void print_conv (oct_pq_conv_t *c)
{
  printf ("oid: %u, aoid: %u, c: %i, e: %i, nc: %i, n: %s, to_s: %i, to_b: %i, fr_s: %i, fr_b: %i,",
          c->oid, c->aoid, c->is_composite, c->is_enum, c->is_not_constant, c->name.c_str (), c->to_octave_str ? 1 : 0, c->to_octave_bin ? 1 : 0, c->from_octave_str ? 1 : 0, c->from_octave_bin ? 1 : 0);

  printf (", el_oids:");
  for (size_t i = 0; i < c->el_oids.size (); i++)
    printf (" %u", c->el_oids[i]);

  printf ("\n");
}

/* type bool */

int to_octave_str_bool (const octave_pq_connection &conn,
                        const char *c, octave_value &ov, int nb)
{
  bool tp = (*c == 't' ? true : false);

  ov = octave_value (tp);

  return 0;
}

int to_octave_bin_bool (const octave_pq_connection &conn,
                        const char *c, octave_value &ov, int nb)
{
  ov = octave_value (bool (*c));

  return 0;
}

int from_octave_str_bool (const octave_pq_connection &conn,
                          const octave_value &ov, oct_pq_dynvec_t &val)
{
  bool b = ov.bool_value ();

  if (error_state)
    {
      error ("can not convert octave_value to bool value");
      return 1;
    }

  val.push_back (b ? '1' : '0');
  val.push_back ('\0');

  return 0;
}

int from_octave_bin_bool (const octave_pq_connection &conn,
                          const octave_value &ov, oct_pq_dynvec_t &val)
{
  bool b = ov.bool_value ();

  if (error_state)
    {
      error ("can not convert octave_value to bool value");
      return 1;
    }

  val.push_back (char (b));

  return 0;
}

oct_pq_conv_t conv_bool = {0, // 16
                           0, // 1000
                           oct_pq_el_oids_t (),
                           oct_pq_conv_cache_t (),
                           false,
                           false,
                           false,
                           "bool",
                           &to_octave_str_bool,
                           &to_octave_bin_bool,
                           &from_octave_str_bool,
                           &from_octave_bin_bool};

/* end type bool */

/* type oid */

int to_octave_str_oid (const octave_pq_connection &conn,
                       const char *c, octave_value &ov, int nb)
{
  return 1;
}

int to_octave_bin_oid (const octave_pq_connection &conn,
                       const char *c, octave_value &ov, int nb)
{
  ov = octave_value (octave_uint32 (be32toh (*((uint32_t *) c))));

  return 0;
}

int from_octave_str_oid (const octave_pq_connection &conn,
                         const octave_value &ov, oct_pq_dynvec_t &val)
{
  return 1;
}

int from_octave_bin_oid (const octave_pq_connection &conn,
                         const octave_value &ov, oct_pq_dynvec_t &val)
{
  uint32_t oid = ov.uint_value ();

  if (error_state)
    {
      error ("can not convert octave_value to oid value");
      return 1;
    }

  OCT_PQ_PUT(val, uint32_t, htobe32 (oid))

  return 0;
}

oct_pq_conv_t conv_oid = {0, // 26
                          0,
                          oct_pq_el_oids_t (),
                          oct_pq_conv_cache_t (),
                          false,
                          false,
                          false,
                          "oid",
                          &to_octave_str_oid,
                          &to_octave_bin_oid,
                          &from_octave_str_oid,
                          &from_octave_bin_oid};

/* end type oid */

/* type float8 */

int to_octave_str_float8 (const octave_pq_connection &conn,
                          const char *c, octave_value &ov, int nb)
{
  // not implemented

  return 1;
}

int to_octave_bin_float8 (const octave_pq_connection &conn,
                          const char *c, octave_value &ov, int nb)
{
  union
  {
    double d;
    int64_t i;
  }
  swap;

  swap.i = be64toh (*((int64_t *) c));

  ov = octave_value (swap.d);

  return 0;
}

int from_octave_str_float8 (const octave_pq_connection &conn,
                            const octave_value &ov, oct_pq_dynvec_t &val)
{
  // not implemented

  return 1;
}

int from_octave_bin_float8 (const octave_pq_connection &conn,
                            const octave_value &ov, oct_pq_dynvec_t &val)
{
  union
  {
    double d;
    int64_t i;
  }
  swap;

  swap.d = ov.double_value ();

  if (error_state)
    {
      error ("can not convert octave_value to float8 value");
      return 1;
    }

  OCT_PQ_PUT(val, int64_t, htobe64 (swap.i))

  return 0;
}

oct_pq_conv_t conv_float8 = {0, // 701
                             0, // 1022
                             oct_pq_el_oids_t (),
                             oct_pq_conv_cache_t (),
                             false,
                             false,
                             false,
                             "float8",
                             &to_octave_str_float8,
                             &to_octave_bin_float8,
                             &from_octave_str_float8,
                             &from_octave_bin_float8};

/* end type float8 */

/* type float4 */

int to_octave_str_float4 (const octave_pq_connection &conn,
                          const char *c, octave_value &ov, int nb)
{
  // not implemented

  return 1;
}

int to_octave_bin_float4 (const octave_pq_connection &conn,
                          const char *c, octave_value &ov, int nb)
{
  union
  {
    float f;
    int32_t i;
  }
  swap;

  swap.i = be32toh (*((int32_t *) c));

  ov = octave_value (swap.f);

  return 0;
}

int from_octave_str_float4 (const octave_pq_connection &conn,
                            const octave_value &ov, oct_pq_dynvec_t &val)
{
  // not implemented

  return 1;
}

int from_octave_bin_float4 (const octave_pq_connection &conn,
                            const octave_value &ov, oct_pq_dynvec_t &val)
{
  union
  {
    float f;
    int32_t i;
  }
  swap;

  swap.f = ov.float_value ();

  if (error_state)
    {
      error ("can not convert octave_value to float4 value");
      return 1;
    }

  OCT_PQ_PUT(val, int32_t, htobe32 (swap.i))

  return 0;
}

oct_pq_conv_t conv_float4 = {0,
                             0,
                             oct_pq_el_oids_t (),
                             oct_pq_conv_cache_t (),
                             false,
                             false,
                             false,
                             "float4",
                             &to_octave_str_float4,
                             &to_octave_bin_float4,
                             &from_octave_str_float4,
                             &from_octave_bin_float4};

/* end type float4 */

/* type bytea */

int to_octave_str_bytea (const octave_pq_connection &conn,
                         const char *c, octave_value &ov, int nb)
{
  return 1;
}

int to_octave_bin_bytea (const octave_pq_connection &conn,
                         const char *c, octave_value &ov, int nb)
{
  uint8NDArray m (dim_vector (nb, 1));

  uint8_t *p = (uint8_t *) m.fortran_vec ();
  for (octave_idx_type i = 0; i < nb; i++)
    *(p++) = uint8_t (*(c++));

  ov = octave_value (m);

  return 0;
}

int from_octave_str_bytea (const octave_pq_connection &conn,
                           const octave_value &ov, oct_pq_dynvec_t &val)
{
  return 1;
}

int from_octave_bin_bytea (const octave_pq_connection &conn,
                           const octave_value &ov, oct_pq_dynvec_t &val)
{
  uint8NDArray b = ov.uint8_array_value ();

  if (! error_state)
    {
      dim_vector dv = b.dims ();
      if (dv.length () > 2 || (dv(0) > 1 && dv(1) > 1))
        error ("bytea representation must be one-dimensional");
    }

  if (error_state)
    {
      error ("can not convert octave_value to bytea representation");
      return 1;
    }

  octave_idx_type nl = b.numel ();

  for (int i = 0; i < nl; i++)
    val.push_back (b(i).value ());

  return 0;
}

oct_pq_conv_t conv_bytea = {0,
                            0,
                            oct_pq_el_oids_t (),
                            oct_pq_conv_cache_t (),
                            false,
                            false,
                            false,
                            "bytea",
                            &to_octave_str_bytea,
                            &to_octave_bin_bytea,
                            &from_octave_str_bytea,
                            &from_octave_bin_bytea};

/* end type bytea */

/* type text */

int to_octave_str_text (const octave_pq_connection &conn,
                        const char *c, octave_value &ov, int nb)
{
  return 1;
}

int to_octave_bin_text (const octave_pq_connection &conn,
                        const char *c, octave_value &ov, int nb)
{
  std::string s (c, nb);

  ov = octave_value (s);

  return 0;
}

int from_octave_str_text (const octave_pq_connection &conn,
                          const octave_value &ov, oct_pq_dynvec_t &val)
{
  return 1;
}

int from_octave_bin_text (const octave_pq_connection &conn,
                          const octave_value &ov, oct_pq_dynvec_t &val)
{
  std::string s = ov.string_value ();

  if (error_state)
    {
      error ("can not convert octave_value to string");
      return 1;
    }

  octave_idx_type l = s.size ();

  for (int i = 0; i < l; i++)
    val.push_back (s[i]);

  return 0;
}

oct_pq_conv_t conv_text = {0,
                           0,
                           oct_pq_el_oids_t (),
                           oct_pq_conv_cache_t (),
                           false,
                           false,
                           false,
                           "text",
                           &to_octave_str_text,
                           &to_octave_bin_text,
                           &from_octave_str_text,
                           &from_octave_bin_text};

/* end type text */

/* type varchar */

oct_pq_conv_t conv_varchar = {0,
                              0,
                              oct_pq_el_oids_t (),
                              oct_pq_conv_cache_t (),
                              false,
                              false,
                              false,
                              "varchar",
                              &to_octave_str_text,
                              &to_octave_bin_text,
                              &from_octave_str_text,
                              &from_octave_bin_text};

/* end type varchar */

/* type bpchar */

oct_pq_conv_t conv_bpchar = {0,
                             0,
                             oct_pq_el_oids_t (),
                             oct_pq_conv_cache_t (),
                             false,
                             false,
                             false,
                             "bpchar",
                             &to_octave_str_text,
                             &to_octave_bin_text,
                             &from_octave_str_text,
                             &from_octave_bin_text};

/* end type bpchar */

/* type name */

oct_pq_conv_t conv_name = {0,
                           0,
                           oct_pq_el_oids_t (),
                           oct_pq_conv_cache_t (),
                           false,
                           false,
                           false,
                           "name",
                           &to_octave_str_text,
                           &to_octave_bin_text,
                           &from_octave_str_text,
                           &from_octave_bin_text};

/* end type name */

/* type int2 */

int to_octave_str_int2 (const octave_pq_connection &conn,
                        const char *c, octave_value &ov, int nb)
{
  return 1;
}

int to_octave_bin_int2 (const octave_pq_connection &conn,
                        const char *c, octave_value &ov, int nb)
{
  ov = octave_value (octave_int16 (int16_t (be16toh (*((int16_t *) c)))));

  return 0;
}

int from_octave_str_int2 (const octave_pq_connection &conn,
                          const octave_value &ov, oct_pq_dynvec_t &val)
{
  return 1;
}

int from_octave_bin_int2 (const octave_pq_connection &conn,
                          const octave_value &ov, oct_pq_dynvec_t &val)
{
  int16_t i2 = ov.int_value ();

  if (error_state)
    {
      error ("can not convert octave_value to int2 value");
      return 1;
    }

  OCT_PQ_PUT(val, int16_t, htobe16 (i2))

  return 0;
}

oct_pq_conv_t conv_int2 = {0, // 26
                           0,
                           oct_pq_el_oids_t (),
                           oct_pq_conv_cache_t (),
                           false,
                           false,
                           false,
                           "int2",
                           &to_octave_str_int2,
                           &to_octave_bin_int2,
                           &from_octave_str_int2,
                           &from_octave_bin_int2};


/* end type int2 */

/* type int4 */

int to_octave_str_int4 (const octave_pq_connection &conn,
                        const char *c, octave_value &ov, int nb)
{
  return 1;
}

int to_octave_bin_int4 (const octave_pq_connection &conn,
                        const char *c, octave_value &ov, int nb)
{
  ov = octave_value (octave_int32 (int32_t (be32toh (*((int32_t *) c)))));

  return 0;
}

int from_octave_str_int4 (const octave_pq_connection &conn,
                          const octave_value &ov, oct_pq_dynvec_t &val)
{
  return 1;
}

int from_octave_bin_int4 (const octave_pq_connection &conn,
                          const octave_value &ov, oct_pq_dynvec_t &val)
{
  int32_t i4 = ov.int_value ();

  if (error_state)
    {
      error ("can not convert octave_value to int4 value");
      return 1;
    }

  OCT_PQ_PUT(val, int32_t, htobe32 (i4))

  return 0;
}

oct_pq_conv_t conv_int4 = {0,
                           0,
                           oct_pq_el_oids_t (),
                           oct_pq_conv_cache_t (),
                           false,
                           false,
                           false,
                           "int4",
                           &to_octave_str_int4,
                           &to_octave_bin_int4,
                           &from_octave_str_int4,
                           &from_octave_bin_int4};


/* end type int4 */

/* type int8 */

int to_octave_str_int8 (const octave_pq_connection &conn,
                        const char *c, octave_value &ov, int nb)
{
  return 1;
}

int to_octave_bin_int8 (const octave_pq_connection &conn,
                        const char *c, octave_value &ov, int nb)
{
  ov = octave_value (octave_int64 (int64_t (be64toh (*((int64_t *) c)))));

  return 0;
}

int from_octave_str_int8 (const octave_pq_connection &conn,
                          const octave_value &ov, oct_pq_dynvec_t &val)
{
  return 1;
}

int from_octave_bin_int8 (const octave_pq_connection &conn,
                          const octave_value &ov, oct_pq_dynvec_t &val)
{
  int64_t i8 = ov.int64_scalar_value ();

  if (error_state)
    {
      error ("can not convert octave_value to int8 value");
      return 1;
    }

  OCT_PQ_PUT(val, int64_t, htobe64 (i8))

  return 0;
}

oct_pq_conv_t conv_int8 = {0,
                           0,
                           oct_pq_el_oids_t (),
                           oct_pq_conv_cache_t (),
                           false,
                           false,
                           false,
                           "int8",
                           &to_octave_str_int8,
                           &to_octave_bin_int8,
                           &from_octave_str_int8,
                           &from_octave_bin_int8};


/* end type int8 */

/* type money */

oct_pq_conv_t conv_money = {0,
                            0,
                            oct_pq_el_oids_t (),
                            oct_pq_conv_cache_t (),
                            false,
                            false,
                            false,
                            "money",
                            &to_octave_str_int8,
                            &to_octave_bin_int8,
                            &from_octave_str_int8,
                            &from_octave_bin_int8};

/* end type money */

// helpers for time types

static inline octave_value time_8byte_to_octave (const char *c, bool int_dt)
{
  if (int_dt)
    {
      return octave_value (octave_int64 (int64_t (be64toh (*((int64_t *) c)))));
    }
  else
    {
      union
      {
        double d;
        int64_t i;
      }
      swap;

      swap.i = be64toh (*((int64_t *) c));

      return octave_value (swap.d);
    }
}

static inline int time_8byte_from_octave (const octave_value &ov,
                                          oct_pq_dynvec_t &val,
                                          bool int_dt)
{
  if (int_dt)
    {
      // don't convert automatically because of possible overflow
      if (ov.is_float_type ())
        {
          error ("floating point octave_value provided for 8-byte time value, but postgresql is configured for int64");
          return 1;
        }

      int64_t i8 = ov.int64_scalar_value ();

      if (error_state)
        {
          error ("can not convert octave_value to int64 time value");
          return 1;
        }

      OCT_PQ_PUT(val, int64_t, htobe64 (i8))

      return 0;
    }
  else
    {
      // don't convert automatically because of possible loss of accuracy
      if (ov.is_integer_type ())
        {
          error ("integer type octave_value provided for 8-byte time value, but postgresql is configured for double");
          return 1;
        }

      union
      {
        double d;
        int64_t i;
      }
      swap;

      swap.d = ov.double_value ();

      if (error_state)
        {
          error ("can not convert octave_value to double time value");
          return 1;
        }

      OCT_PQ_PUT(val, int64_t, htobe64 (swap.i))

      return 0;
    }
}

// end helpers for time types

/* type timestamp */

int to_octave_str_timestamp (const octave_pq_connection &conn,
                             const char *c, octave_value &ov, int nb)
{
  return 1;
}

int to_octave_bin_timestamp (const octave_pq_connection &conn,
                             const char *c, octave_value &ov, int nb)
{
  ov = time_8byte_to_octave (c, conn.integer_datetimes);

  return 0;
}

int from_octave_str_timestamp (const octave_pq_connection &conn,
                               const octave_value &ov, oct_pq_dynvec_t &val)
{
  return 1;
}

int from_octave_bin_timestamp (const octave_pq_connection &conn,
                               const octave_value &ov, oct_pq_dynvec_t &val)
{
  return (time_8byte_from_octave (ov, val, conn.integer_datetimes));
}

oct_pq_conv_t conv_timestamp = {0,
                                0,
                                oct_pq_el_oids_t (),
                                oct_pq_conv_cache_t (),
                                false,
                                false,
                                false,
                                "timestamp",
                                &to_octave_str_timestamp,
                                &to_octave_bin_timestamp,
                                &from_octave_str_timestamp,
                                &from_octave_bin_timestamp};

/* end type timestamp */

oct_pq_conv_t *t_conv_ptrs[OCT_PQ_NUM_CONVERTERS] = {&conv_bool,
                                                     &conv_oid,
                                                     &conv_float8,
                                                     &conv_float4,
                                                     &conv_text,
                                                     &conv_varchar,
                                                     &conv_bpchar,
                                                     &conv_name,
                                                     &conv_bytea,
                                                     &conv_int2,
                                                     &conv_int4,
                                                     &conv_int8,
                                                     &conv_money,
                                                     &conv_timestamp};

oct_pq_conv_ptrs_t conv_ptrs (OCT_PQ_NUM_CONVERTERS, t_conv_ptrs);