/*
 * debversion: PostgreSQL functions for debversion type
 * Copyright © 2009,2011  Roger Leigh <rleigh@debian.org>
 * schroot 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.
 *
 * schroot 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/>.
 *
 *********************************************************************/

extern "C"
{
#include <postgres.h>
#include <fmgr.h>
#include <access/hash.h>
#include <utils/builtins.h>

#ifdef PG_MODULE_MAGIC
  PG_MODULE_MAGIC;
#endif

  extern Datum debversion_cmp (PG_FUNCTION_ARGS);
  extern Datum debversion_hash (PG_FUNCTION_ARGS);
  extern Datum debversion_eq (PG_FUNCTION_ARGS);
  extern Datum debversion_ne (PG_FUNCTION_ARGS);
  extern Datum debversion_gt (PG_FUNCTION_ARGS);
  extern Datum debversion_ge (PG_FUNCTION_ARGS);
  extern Datum debversion_lt (PG_FUNCTION_ARGS);
  extern Datum debversion_le (PG_FUNCTION_ARGS);
  extern Datum debversion_smaller (PG_FUNCTION_ARGS);
  extern Datum debversion_larger (PG_FUNCTION_ARGS);
}

// apt's apt-pkg/macros.h and PostgreSQL's server/c.h (10+) both define these:
#undef likely
#undef unlikely

#include <apt-pkg/debversion.h>

namespace
{
  int32
  debversioncmp (text *left,
		 text *right)
  {
    int32 result;
    char *lstr, *rstr;

    lstr = text_to_cstring(left);
    rstr = text_to_cstring(right);

    result = debVS.CmpVersion (lstr, rstr);

    pfree (lstr);
    pfree (rstr);

    return (result);
  }
}

extern "C"
{
  PG_FUNCTION_INFO_V1(debversion_cmp);

  Datum
  debversion_cmp(PG_FUNCTION_ARGS)
  {
    text *left  = PG_GETARG_TEXT_PP(0);
    text *right = PG_GETARG_TEXT_PP(1);
    int32 result;

    result = debversioncmp(left, right);

    PG_FREE_IF_COPY(left, 0);
    PG_FREE_IF_COPY(right, 1);

    PG_RETURN_INT32(result);
  }

  PG_FUNCTION_INFO_V1(debversion_hash);

  Datum
  debversion_hash(PG_FUNCTION_ARGS)
  {
    text *txt = PG_GETARG_TEXT_PP(0);
    char *str;
    Datum result;

    str = text_to_cstring(txt);

    result = hash_any((unsigned char *) str, strlen(str));
    pfree(str);

    PG_FREE_IF_COPY(txt, 0);

    PG_RETURN_DATUM(result);
  }

  PG_FUNCTION_INFO_V1(debversion_eq);

  Datum
  debversion_eq(PG_FUNCTION_ARGS)
  {
    text *left  = PG_GETARG_TEXT_PP(0);
    text *right = PG_GETARG_TEXT_PP(1);
    bool  result;

    result = debversioncmp(left, right) == 0;

    PG_FREE_IF_COPY(left, 0);
    PG_FREE_IF_COPY(right, 1);

    PG_RETURN_BOOL(result);
  }

  PG_FUNCTION_INFO_V1(debversion_ne);

  Datum
  debversion_ne(PG_FUNCTION_ARGS)
  {
    text *left  = PG_GETARG_TEXT_PP(0);
    text *right = PG_GETARG_TEXT_PP(1);
    bool  result;

    result = debversioncmp(left, right) != 0;

    PG_FREE_IF_COPY(left, 0);
    PG_FREE_IF_COPY(right, 1);

    PG_RETURN_BOOL(result);
  }

  PG_FUNCTION_INFO_V1(debversion_lt);

  Datum
  debversion_lt(PG_FUNCTION_ARGS)
  {
    text *left  = PG_GETARG_TEXT_PP(0);
    text *right = PG_GETARG_TEXT_PP(1);
    bool  result;

    result = debversioncmp(left, right) < 0;

    PG_FREE_IF_COPY(left, 0);
    PG_FREE_IF_COPY(right, 1);

    PG_RETURN_BOOL(result);
  }

  PG_FUNCTION_INFO_V1(debversion_le);

  Datum
  debversion_le(PG_FUNCTION_ARGS)
  {
    text *left  = PG_GETARG_TEXT_PP(0);
    text *right = PG_GETARG_TEXT_PP(1);
    bool  result;

    result = debversioncmp(left, right) <= 0;

    PG_FREE_IF_COPY(left, 0);
    PG_FREE_IF_COPY(right, 1);

    PG_RETURN_BOOL(result);
  }

  PG_FUNCTION_INFO_V1(debversion_gt);

  Datum
  debversion_gt(PG_FUNCTION_ARGS)
  {
    text *left  = PG_GETARG_TEXT_PP(0);
    text *right = PG_GETARG_TEXT_PP(1);
    bool  result;

    result = debversioncmp(left, right) > 0;

    PG_FREE_IF_COPY(left, 0);
    PG_FREE_IF_COPY(right, 1);

    PG_RETURN_BOOL(result);
  }

  PG_FUNCTION_INFO_V1(debversion_ge);

  Datum
  debversion_ge(PG_FUNCTION_ARGS)
  {
    text *left  = PG_GETARG_TEXT_PP(0);
    text *right = PG_GETARG_TEXT_PP(1);
    bool  result;

    result = debversioncmp(left, right) >= 0;

    PG_FREE_IF_COPY(left, 0);
    PG_FREE_IF_COPY(right, 1);

    PG_RETURN_BOOL(result);
  }

  PG_FUNCTION_INFO_V1(debversion_smaller);

  Datum
  debversion_smaller(PG_FUNCTION_ARGS)
  {
    text *left  = PG_GETARG_TEXT_PP(0);
    text *right = PG_GETARG_TEXT_PP(1);
    text *result;

    result = debversioncmp(left, right) < 0 ? left : right;

    PG_RETURN_TEXT_P(result);
  }

  PG_FUNCTION_INFO_V1(debversion_larger);

  Datum
  debversion_larger(PG_FUNCTION_ARGS)
  {
    text *left  = PG_GETARG_TEXT_PP(0);
    text *right = PG_GETARG_TEXT_PP(1);
    text *result;

    result = debversioncmp(left, right) > 0 ? left : right;

    PG_RETURN_TEXT_P(result);
  }
}
