Skip to content

File csql_result_format.c

File List > cubrid > src > executables > csql_result_format.c

Go to the documentation of this file

/*
 * Copyright 2008 Search Solution Corporation
 * Copyright 2016 CUBRID Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

/*
 * csql_result_format.c : string formatting function
 */

#ident "$Id$"

#include "config.h"

#include <float.h>
#include <time.h>

#include "csql.h"
#include "cnv.h"
#include "memory_alloc.h"
#include "language_support.h"
#include "string_opfunc.h"
#include "unicode_support.h"
#include "string_buffer.hpp"
#include "db_value_printer.hpp"

#include "dbtype.h"

#if defined (SUPPRESS_STRLEN_WARNING)
#define strlen(s1)  ((int) strlen(s1))
#endif /* defined (SUPPRESS_STRLEN_WARNING) */

#ifndef UX_CHAR
#define UX_CHAR wchar_t
#endif

#define CMSB(x) ((x) & 0x80)
    /* Checks if MSB of the character value is ON/OFF */
#define FORMERBYTE(x)   ((UX_CHAR)(((unsigned)(x) & 0xff00) >> 8))
#define LATTERBYTE(x)   ((UX_CHAR)((x) & 0xff))

#define COMMAS_OFFSET(COND, N)   ((COND) == TRUE ? ((N) / 3) : 0)

#define TIME_STRING_MAX         20

#define OID_LENGTH      15

#define COMMA_CHAR      ','

#define SHORT_TO_INT(short_val)          ((int)short_val)
#define OBJECT_SYMBOL_MAX             512

#define DATE_ABREV_NAME_LENGTH       3
#define DATE_TEMP_BUFFER_LENGTH 50

/*
 * double, float, numeric type conversion profile
 */
typedef struct db_type_double_profile DB_TYPE_DOUBLE_PROFILE;
typedef struct db_type_double_profile DB_TYPE_FLOAT_PROFILE;
typedef struct db_type_double_profile DB_TYPE_NUMERIC_PROFILE;

struct db_type_double_profile
{
  char format;          /* Use the following macros */
  int fieldwidth;       /* the width of the entire return string */
  int precision;        /* how many places after the decimal point */
  bool leadingsign;     /* whether or not to print '+' for positive numbers */
  bool leadingzeros;        /* whether or not to print leading zeros */
  bool trailingzeros;       /* whether or not to print trailing zeros */
  bool commas;          /* whether or not to print commas */
};

/* double conversion 'format' macros */
#define DOUBLE_FORMAT_SCIENTIFIC   'e'
#define DOUBLE_FORMAT_DECIMAL      'f'
#define DOUBLE_FORMAT_GENERAL      'g'

static DB_TYPE_DOUBLE_PROFILE default_double_profile = {
  DOUBLE_FORMAT_SCIENTIFIC, 0, DBL_DIG, false, false, true, false
};

static DB_TYPE_FLOAT_PROFILE default_float_profile = {
  DOUBLE_FORMAT_SCIENTIFIC, 0, FLT_DIG, false, false, true, false
};

static DB_TYPE_NUMERIC_PROFILE default_numeric_profile = {
  DOUBLE_FORMAT_DECIMAL, -1, -1, false, false, true, true
};

/*
 * integer, short type conversion profile
 */
typedef struct db_type_integer_profile DB_TYPE_BIGINT_PROFILE;
typedef struct db_type_integer_profile DB_TYPE_INTEGER_PROFILE;
typedef struct db_type_integer_profile DB_TYPE_SHORT_PROFILE;

struct db_type_integer_profile
{
  char format;          /* Use the following macros */
  int fieldwidth;       /* the width of the entire return string */
  bool leadingsymbol;       /* whether or not to print the leading symbol */
  bool leadingzeros;        /* whether or not to print leading zeros */
  bool commas;          /* whether or not to print commas */
};

/* integer conversion 'format' macros */
#define INT_FORMAT_UNSIGNED_DECIMAL     'u'
#define INT_FORMAT_SIGNED_DECIMAL       'd'
#define INT_FORMAT_OCTAL                'o'
#define INT_FORMAT_HEXADECIMAL          'x'
#define INT_FORMAT_CHARACTER            'c'

static DB_TYPE_BIGINT_PROFILE default_bigint_profile = {
  INT_FORMAT_SIGNED_DECIMAL, 0, false, false, false
};

static DB_TYPE_INTEGER_PROFILE default_int_profile = {
  INT_FORMAT_SIGNED_DECIMAL, 0, false, false, false
};

static DB_TYPE_SHORT_PROFILE default_short_profile = {
  INT_FORMAT_SIGNED_DECIMAL, 0, false, false, false
};


/*
 * monetary type conversion profile
 */

typedef struct
{
  int fieldwidth;       /* the width of the entire return string */
  int decimalplaces;        /* how many places after the decimal point */
  bool leadingsign;     /* whether or not to print + symbol */
  bool currency_symbol;     /* whether or not to print currency symbol */
  bool leadingzeros;        /* whether or not to print leading zeros */
  bool trailingzeros;       /* whether or not to print trailing zeros */
  bool commas;          /* whether or not to print commas */
} DB_TYPE_MONETARY_PROFILE;

static DB_TYPE_MONETARY_PROFILE default_monetary_profile = {
  0, 2, false, true, false, true, true
};


/*
 * DB_TIME type conversion profile
 */

typedef struct
{
  const char *format;       /* Use the following macros */
} DB_TYPE_TIME_PROFILE;

/* DB_TIME conversion 'format' macros */
#define TIME_FORMAT_TWELVE_HOUR                 "%I:%M:%S %p"
#define TIME_FORMAT_TWELVE_HOUR_W_TIMEZONE      "%I:%M:%S %p %Z"
#define TIME_FORMAT_TWENTY_FOUR_HOUR            "%H:%M:%S"
#define TIME_FORMAT_TWENTY_FOUR_HOUR_W_TIMEZONE "%H:%M:%S %Z"

static DB_TYPE_TIME_PROFILE default_time_profile = {
  TIME_FORMAT_TWELVE_HOUR
};


/*
 * DB_DATE type conversion profile
 */

typedef struct
{
  int format;           /* Use the following enumeration value */
} DB_TYPE_DATE_PROFILE;

/* DB_DATE conversion 'format' enumeration */
enum
{
  DATE_FORMAT_FULL_TEXT,    /* standard US text format. "September 15, 2008" */
  DATE_FORMAT_ABREV_TEXT,   /* abbreviated US text format. "Sept. 15, 2008" */
  DATE_FORMAT_FULL_TEXT_W_DAY,  /* standard US format with day name. "Thursday, March 20, 2008" */
  DATE_FORMAT_ABREV_TEXT_W_DAY, /* abbreviated US format with day name. "Thu, Mar 20, 2008" */
  DATE_FORMAT_FULL_EURO_TEXT,   /* standard European text format. "10. June 2008" */
  DATE_FORMAT_ABREV_EURO_TEXT,  /* abbreviated European format "15. Sep 1990" */
  DATE_FORMAT_YYMMDD,       /* YY/MM/DD format "08/06/10" */
  DATE_FORMAT_MMDDYY,       /* MM/DD/YY format "06/10/08" */
  DATE_FORMAT_DDMMYY,       /* DD/MM/YY format "10/06/08" */
  DATE_FORMAT_MMDDYYYY      /* MM/DD/YYYY format "06/10/2008" */
};

static DB_TYPE_DATE_PROFILE default_date_profile = {
  DATE_FORMAT_MMDDYYYY
};

/* object conversion 'format' enumeration */
enum
{
  OBJECT_FORMAT_OID,
  OBJECT_FORMAT_CLASSNAME
};

/*
 * set type conversion profile
 */

typedef struct
{
  char begin_notation;      /* what character to use to denote begin of set '\0' for no character */
  char end_notation;        /* what character to use to denote end of set '\0' for no character */
  int max_entries;      /* max no. of entries to display, (-1 for all) */
} DB_TYPE_SET_PROFILE;

static DB_TYPE_SET_PROFILE default_set_profile = {
  '{', '}', -1
};


/*
 * string type conversion profile
 */

typedef struct
{
  char string_delimiter;    /* the character to use for a string delimiter ('\0' for none). */
} DB_TYPE_STRING_PROFILE;

static DB_TYPE_STRING_PROFILE default_string_profile = {
  '\''
};

/* TODO: locale ?*/
static const char *day_of_week_names[] = {
  "Sunday",
  "Monday",
  "Tuesday",
  "Wednesday",
  "Thursday",
  "Friday",
  "Saturday"
};

static const char *month_of_year_names[] = {
  "January",
  "February",
  "March",
  "April",
  "May",
  "June",
  "July",
  "August",
  "September",
  "October",
  "November",
  "December"
};

static void add_commas (char *string);
static void strip_trailing_zeros (char *numeric_string);
static char *double_to_string (double double_value, int field_width, int precision, const bool leading_sign,
                   const char *leading_str, const char *trailing_str, bool leading_zeros,
                   bool trailing_zeros, bool commas, char conversion);
#if defined (ENABLE_UNUSED_FUNCTION)
static char *time_as_string (DB_TIME * time_value, const char *conversion);
#endif
static char *date_as_string (DB_DATE * date_value, int format);
static char *bigint_to_string (DB_BIGINT int_value, int field_width, bool leading_zeros, bool leading_symbol,
                   bool commas, char conversion);
static char *object_to_string (DB_OBJECT * object, int format);
static char *numeric_to_string (DB_VALUE * value, bool commas);
static char *bit_to_string (DB_VALUE * value, char string_delimiter, bool plain_string);
static char *set_to_string (DB_VALUE * value, char begin_notation, char end_notation, int max_entries,
                const CSQL_ARGUMENT * csql_arg);
static char *duplicate_string (const char *string);
static int get_object_print_format (void);

/*
 * add_commas() - counts the digits in this string and adds the commas
 *   return: none
 *   string(in/out): string to add commas to
 */
static void
add_commas (char *string)
{
  int i, num_of_digits, last_digit, num_of_commas, string_len;

  if (string == NULL)
    {
      return;
    }

  num_of_digits = last_digit = num_of_commas = 0;
  string_len = strlen (string);

  /*
   * First count the digits before the decimal place
   */
  for (i = 0; i < string_len; i++)
    {
      /* checking for CMSB is necessary for internationalization */
      if (!(CMSB (string[i])) && isdigit (string[i]))
    {
      if (num_of_digits)
        {
          last_digit = i;   /* keep track of last digit found */
        }
      num_of_digits++;  /* increment total number of digits found */
    }
      else
    {
      if (num_of_digits)    /* check to see if any found yet, if not keep checking */
        {
          break;        /* otherwise stop */
        }
    }
    }

  /*
   * If no digits, exit
   */
  if (!num_of_digits)
    return;

  /*
   * Calculate the number of commas we are going to insert
   */
  num_of_commas = num_of_digits / 3;
  if (!(num_of_digits % 3))
    {
      num_of_commas--;
    }

  /*
   * Add them if necessary
   */
  if (num_of_commas)
    {
      char *temp;
      int src_idx, dest_idx;

      src_idx = string_len;
      dest_idx = string_len + num_of_commas;

      temp = string;

      temp[dest_idx--] = '\0';
      src_idx--;

      /* Checks for a decimal point to avoid double-free core dumps in the scenarios described below
       *  select cast(23421.234 as numeric(7,0));  
       */
      if (string[last_digit + 1] == '.')
    {
      do
        {
          temp[dest_idx--] = string[src_idx--];
        }
      while (string[src_idx] != '.');
      temp[dest_idx--] = string[src_idx--];
    }

      for (i = 0; num_of_commas; i++)
    {
      if (i && !(i % 3) && num_of_commas)
        {
          temp[dest_idx--] = COMMA_CHAR;
          --num_of_commas;
        }
      if (src_idx && dest_idx)
        {
          temp[dest_idx--] = string[src_idx--];
        }
    }
    }
}

/*
 * strip_trailing_zeros() - Strip the trailing zeros from the end of a numeric string
 *   return: none
 *   numeric_string(in/out): the numeric string to strip trailing zeros from
 *
 * Note: Strip the trailing zeros from the end of a numeric string.
 *       This function will only strip them from a string with
 *       a decimal place.  The numeric string can either be in
 *       decimal notation or scientific notation. The string can
 *       also have trailing characters (e.g., 123.45 DM).
 */
static void
strip_trailing_zeros (char *numeric_string)
{
  char *prefix;
  size_t remainder_len;

  if (numeric_string == NULL)
    {
      return;
    }

  /*
   * First check to see if this is even necessary
   */
  if ((prefix = strchr (numeric_string, '.')) == NULL)
    {
      return;
    }

  /*
   * Now count the number of trailing zeros
   */

  if ((remainder_len = strcspn (prefix + 1, "0123456789")) == 0)
    {
      /* No trailing characters */
      char *remainder = numeric_string + strlen (numeric_string);

      while (remainder-- > prefix)
    {
      if (*remainder == '0')
        {
          *remainder = '\0';
        }
      else
        {
          break;
        }
    }
    }
  else
    {
      int num_of_trailing_zeros = 0;
      char *remainder = numeric_string + remainder_len;
      char *end = numeric_string + strlen (numeric_string);

      while (remainder-- > prefix)
    {
      if (*remainder == '0')
        {
          num_of_trailing_zeros++;
        }
      else
        {
          break;
        }
    }

      while ((remainder++ + num_of_trailing_zeros) < end)
    {
      *remainder = *(remainder + num_of_trailing_zeros);
    }
    }
}

/*
 * double_to_string() - convert double value to string
 *   return: formatted string
 *   double_value(in): double value to convert
 *   field_width(in): the overall fieldwidth
 *   precision(in): the number of places after the decimal point
 *   leading_sign(in): true if leading sign '+' should be forced to show
 *   leading_str(in): the leading symbols to show, NULL if none desired
 *   trailing_str(in): the traling symbols to show, NULL if none desired
 *   leading_zeros(in): whether or not to show leading zeros
 *   trailing_zeros(in): whether or not to show trailing zeros
 *   commas(in): whether or not to show commas (every three digits)
 *   conversion(in): conversion format character, scientific or decimal
 */
static char *
double_to_string (double double_value, int field_width, int precision, const bool leading_sign, const char *leading_str,
          const char *trailing_str, bool leading_zeros, bool trailing_zeros, bool commas, char conversion)
{
  char numeric_conversion_string[1024];
  char precision_string[16];
  char format_string[32];
  int i, overall_fieldwidth;

  if (field_width < 0)
    {
      field_width = 0;
    }

  overall_fieldwidth = field_width;

  if (precision < 0)
    {
      precision = 0;
    }

  snprintf (precision_string, sizeof (precision_string) - 1, ".%u", (int) precision);

  i = 0;

  format_string[i++] = '%';

  if ((double_value < (double) 0) || (leading_sign == true))
    {
      format_string[i++] = '+';
      if (overall_fieldwidth)
    {
      overall_fieldwidth++;
    }
    }

  if (leading_zeros == true)
    {
      format_string[i++] = '0';
    }

  if ((trailing_zeros == true) && (precision))
    {
      format_string[i++] = '#';
    }

  format_string[i++] = '*';
  format_string[i] = 0;


  strcat ((char *) format_string, (char *) precision_string);
  i = strlen (format_string);
  format_string[i++] = conversion;
  format_string[i] = 0;
  if ((overall_fieldwidth > 0) && (conversion == DOUBLE_FORMAT_SCIENTIFIC))
    {
      overall_fieldwidth += 4;
    }

  if (!sprintf ((char *) numeric_conversion_string, (char *) format_string, (int) field_width, double_value))
    {
      return (NULL);
    }
  else
    {
      char *return_string;
      int actual_fieldwidth = strlen (numeric_conversion_string);
      int leading_size = (leading_str != NULL) ? strlen (leading_str) : 0;
      int trailing_size = (trailing_str != NULL) ? strlen (trailing_str) : 0;

      if ((size_t) (leading_size + actual_fieldwidth + 1) > sizeof (numeric_conversion_string))
    {
      return NULL;
    }
      if (leading_size > 0)
    {
      memmove (numeric_conversion_string + leading_size, numeric_conversion_string, actual_fieldwidth);
      memcpy (numeric_conversion_string, leading_str, leading_size);

      numeric_conversion_string[actual_fieldwidth + leading_size] = '\0';
      actual_fieldwidth += leading_size;
    }
#if defined(HPUX)
      /* workaround for HP's broken printf */
      if (strstr (numeric_conversion_string, "+.+") || strstr (numeric_conversion_string, "++"))
    sprintf (numeric_conversion_string, "Inf");
      if (strstr (numeric_conversion_string, "-.-") || strstr (numeric_conversion_string, "--"))
    sprintf (numeric_conversion_string, "-Inf");
#endif

      if (trailing_zeros == false)
    {
      strip_trailing_zeros (numeric_conversion_string);
      actual_fieldwidth = strlen (numeric_conversion_string);
    }

      if ((size_t) (trailing_size + actual_fieldwidth + 1) > sizeof (numeric_conversion_string))
    {
      return NULL;
    }

      if (trailing_size > 0)
    {
      memcpy (numeric_conversion_string + actual_fieldwidth, trailing_str, trailing_size);
      numeric_conversion_string[actual_fieldwidth + trailing_size] = '\0';
      actual_fieldwidth += trailing_size;
    }

      if (field_width == 0)
    {
      if ((return_string =
           (char *) malloc (actual_fieldwidth + COMMAS_OFFSET (commas, actual_fieldwidth) + 1)) == NULL)
        {
          return (NULL);
        }
      (void) strcpy (return_string, numeric_conversion_string);
    }
      else
    {
      if ((return_string =
           (char *) malloc (overall_fieldwidth + COMMAS_OFFSET (commas, actual_fieldwidth) + 1)) == NULL)
        {
          return (NULL);
        }
      if (actual_fieldwidth <= overall_fieldwidth)
        {
          return_string = strcpy (return_string, numeric_conversion_string);
        }
      else
        {
          return_string[overall_fieldwidth] = numeric_conversion_string[actual_fieldwidth];
          while (overall_fieldwidth)
        {
          return_string[--overall_fieldwidth] = numeric_conversion_string[--actual_fieldwidth];
        }
        }
    }
      if (commas == true)
    {
      add_commas (return_string);
    }
      return (return_string);
    }
}

#if defined (ENABLE_UNUSED_FUNCTION)
/*
 * time_as_string() - convert time value to string
 *   return: formatted string
 *   time_value(in): time value to convert
 *   conversion(in): conversion format string
 */
static char *
time_as_string (DB_TIME * time_value, const char *conversion)
{
  char temp_string[TIME_STRING_MAX];

  if (time_value == NULL)
    {
      return NULL;
    }

  if (!db_strftime (temp_string, (int) TIME_STRING_MAX, conversion, (DB_DATE *) NULL, time_value))
    {
      return (NULL);
    }
  return (duplicate_string (temp_string));

}
#endif

/*
 * date_as_string() - convert date value to string
 *   return: formatted string
 *   date_value(in): date value to convert
 *   format(in): conversion format type
 */
static char *
date_as_string (DB_DATE * date_value, int format)
{
  char temp_buffer[DATE_TEMP_BUFFER_LENGTH];
  int month, day, year;

  if (date_value == NULL)
    {
      return (NULL);
    }

  db_date_decode (date_value, &month, &day, &year);
  switch (format)
    {
    case DATE_FORMAT_MMDDYYYY:
      {
    (void) sprintf (temp_buffer, "%02d/%02d/%04d", month, day, year);
      }
      break;
    case DATE_FORMAT_FULL_TEXT:
      (void) sprintf (temp_buffer, "%s %d, %04d", month_of_year_names[month - 1], day, year);
      break;
    case DATE_FORMAT_ABREV_TEXT:
      {
    char month_name[DATE_ABREV_NAME_LENGTH + 1];
    (void) strncpy (month_name, month_of_year_names[month - 1], DATE_ABREV_NAME_LENGTH);
    month_name[DATE_ABREV_NAME_LENGTH] = '\0';
    (void) sprintf (temp_buffer, "%s %d, %04d", month_name, day, year);
      }
      break;
    case DATE_FORMAT_FULL_TEXT_W_DAY:
      {
    int dayofweek = db_date_weekday (date_value);
    if (dayofweek < 0 || dayofweek > 6)
      {
        return (NULL);
      }
    (void) sprintf (temp_buffer, "%s, %s %d, %04d", day_of_week_names[dayofweek], month_of_year_names[month - 1],
            day, year);
      }
      break;
    case DATE_FORMAT_ABREV_TEXT_W_DAY:
      {
    char day_name[DATE_ABREV_NAME_LENGTH + 1];
    char month_name[DATE_ABREV_NAME_LENGTH + 1];

    int dayofweek = db_date_weekday (date_value);
    if (dayofweek < 0 || dayofweek > 6)
      {
        return (NULL);
      }
    (void) strncpy (day_name, day_of_week_names[dayofweek], DATE_ABREV_NAME_LENGTH);
    day_name[DATE_ABREV_NAME_LENGTH] = '\0';
    (void) strncpy (month_name, month_of_year_names[month - 1], DATE_ABREV_NAME_LENGTH);
    month_name[DATE_ABREV_NAME_LENGTH] = '\0';
    (void) sprintf (temp_buffer, "%s, %s %d, %04d", day_name, month_name, day, year);
      }
      break;
    case DATE_FORMAT_FULL_EURO_TEXT:
      (void) sprintf (temp_buffer, "%d. %s %04d", day, month_of_year_names[month - 1], year);
      break;
    case DATE_FORMAT_ABREV_EURO_TEXT:
      {
    char month_name[DATE_ABREV_NAME_LENGTH + 1];
    (void) strncpy (month_name, month_of_year_names[month - 1], DATE_ABREV_NAME_LENGTH);
    month_name[DATE_ABREV_NAME_LENGTH] = '\0';
    (void) sprintf (temp_buffer, "%d. %s %04d", day, month_name, year);
      }
      break;
    case DATE_FORMAT_YYMMDD:
      {
    (void) sprintf (temp_buffer, "%02d/%02d/%02d", year % 100, month, day);
      }
      break;
    case DATE_FORMAT_MMDDYY:
      {
    (void) sprintf (temp_buffer, "%02d/%02d/%02d", month, day, year % 100);
      }
      break;
    case DATE_FORMAT_DDMMYY:
      {
    (void) sprintf (temp_buffer, "%02d/%02d/%02d", day, month, year % 100);
      }
      break;
    default:
      /* invalid format type */
      temp_buffer[0] = '\0';
      break;
    }
  return (duplicate_string (temp_buffer));
}

/*
 * int_to_string() - convert integer value to string
 *   return: formatted string
 *   int_value(in): integer value to convert
 *   field_width(in): the desired field width
 *   leading_zeros(in): whether or not to show leading zeros
 *   leading_symbol(in): whether or not to show the leading symbol
 *   commas(in): whether or not to display commas
 *   conversion(in): conversion format charactern
 */
static char *
bigint_to_string (DB_BIGINT int_value, int field_width, bool leading_zeros, bool leading_symbol, bool commas,
          char conversion)
{
  char numeric_conversion_string[1024];
  char format_string[10];
  char long_decimal = 'l';
  int i = 0;
  int overall_fieldwidth;

  if (field_width < 0)
    {
      field_width = 0;
    }

  overall_fieldwidth = field_width;
  format_string[i++] = '%';

  if (leading_zeros == true)
    {
      format_string[i++] = '0';
    }

  if (leading_symbol == true)
    {
      format_string[i++] = '#';
      if (overall_fieldwidth)
    {
      switch (conversion)
        {
        case INT_FORMAT_SIGNED_DECIMAL:
          {
        if (overall_fieldwidth && (int_value < 0))
          {
            overall_fieldwidth++;
          }
        break;
          }
        case INT_FORMAT_HEXADECIMAL:
          {
        if (overall_fieldwidth)
          {
            overall_fieldwidth += 2;
          }
        break;
          }
        default:
          break;
        }
    }
    }

  if (int_value < 0)
    {
      format_string[i++] = '+';
    }

  format_string[i++] = '*';

  format_string[i++] = long_decimal;
  format_string[i++] = long_decimal;
  format_string[i++] = conversion;
  format_string[i++] = (char) 0;

  if (!sprintf (numeric_conversion_string, (char *) format_string, (int) field_width, int_value))
    {
      return (NULL);
    }
  else
    {
      char *return_string;
      int actual_fieldwidth = strlen (numeric_conversion_string);

      if (field_width == 0)
    {
      if ((return_string =
           (char *) malloc (actual_fieldwidth + COMMAS_OFFSET (commas, actual_fieldwidth) + 1)) == NULL)
        {
          return (NULL);
        }
      (void) strcpy (return_string, (const char *) &numeric_conversion_string[0]);
    }
      else
    {
      if ((return_string =
           (char *) malloc (overall_fieldwidth + COMMAS_OFFSET (commas, actual_fieldwidth) + 1)) == NULL)
        {
          return (NULL);
        }
      if (actual_fieldwidth <= overall_fieldwidth)
        {
          return_string = strcpy (return_string, numeric_conversion_string);
        }
      else
        {
          return_string[overall_fieldwidth] = numeric_conversion_string[actual_fieldwidth];
          while (overall_fieldwidth)
        {
          return_string[--overall_fieldwidth] = numeric_conversion_string[--actual_fieldwidth];
        }
        }
    }
      if (commas == true)
    {
      add_commas (return_string);
    }
      return (return_string);
    }
}

/*
 * object_to_string() - convert object to string
 *   return: formatted string
 *   object(in): object value to convert
 *   format(in): conversion format type
 */
static char *
object_to_string (DB_OBJECT * object, int format)
{
  if (object == NULL)
    return NULL;

  if (format == OBJECT_FORMAT_OID)
    {
      char temp_string[OBJECT_SYMBOL_MAX];

      if (!db_print_mop (object, temp_string, OBJECT_SYMBOL_MAX))
    {
      return (NULL);
    }
      return (duplicate_string (temp_string));
    }
  else
    {
      char *name;

      name = (char *) db_get_class_name (object);
      if (name == NULL)
    {
      return (NULL);
    }
      else
    {
      return (duplicate_string (name));
    }
    }
}

/*
 * numeric_to_string() - convert numeric value to string
 *   return:  formatted string
 *   value(in): numeric value to convert
 *   commas(in): whether or not to display commas
 */
static char *
numeric_to_string (DB_VALUE * value, bool commas)
{
  char str_buf[NUMERIC_MAX_STRING_SIZE];
  char *return_string;
  int comma_length = 0;
  int str_length = 0;

  do
    {
      /* Force-disable commas to preserve legacy behavior.
       * TODO: Once the comma display requirement is finalized, update default_numeric_profile.commas and delete this block.
       */
      commas = false;
    }
  while (0);

  numeric_db_value_print (value, str_buf);

  comma_length = COMMAS_OFFSET (commas, DB_VALUE_PRECISION (value));
  str_length = strlen (str_buf) + 1;    // include '\0'


  return_string = (char *) malloc (str_length + comma_length + 1);
  if (return_string == NULL)
    {
      return (NULL);
    }

  memcpy (return_string, str_buf, str_length);

  if (commas == true)
    {
      add_commas (return_string);
    }

  return return_string;
}

/*
 * bit_to_string() - convert bit value to string
 *   return: formatted string
 *   value(in): bit value to convert
 */
static char *
bit_to_string (DB_VALUE * value, char string_delimiter, bool plain_string)
{
  char *temp_string;
  char *return_string;
  int max_length;

  /*
   * Allocate string length based on precision plus the the leading
   * introducer plus quotes, and NULL terminator.  Precision / 4 (rounded up)
   * represents the number of bytes needed to represent the bit string in
   * hexadecimal.
   */
  max_length = ((db_get_string_length (value) + 3) / 4) + 4;
  temp_string = (char *) malloc (max_length);
  if (temp_string == NULL)
    {
      return (NULL);
    }

  if (db_bit_string (value, "%X", temp_string, max_length) != CSQL_SUCCESS)
    {
      free_and_init (temp_string);
      return (NULL);        /* Should never get here */
    }

  return_string =
    string_to_string (temp_string, string_delimiter, 'X', strlen (temp_string), NULL, plain_string, false);
  free_and_init (temp_string);

  return (return_string);
}

/*
 * set_to_string() - convert set value to string
 *   return: formatted string
 *   value(in): set value to convert
 *   begin_notation(in): character to use to denote begin of set
 *   end_notation(in): character to use to denote end of set
 *   max_entries(in): maximum number of entries to convert. -1 for all
 *   plain_string(in): refine string for plain output
 *   output_type(in): query output or loaddb output
 *   column_enclosure(in): column enclosure for query output
 */
static char *
set_to_string (DB_VALUE * value, char begin_notation, char end_notation, int max_entries,
           const CSQL_ARGUMENT * csql_arg)
{
  int cardinality, total_string_length, i;
  char **string_array;
  char *return_string = NULL;
  DB_VALUE element;
  int set_error;
  DB_SET *set;

  set = db_get_set (value);
  if (set == NULL)
    {
      return (NULL);
    }

  /* pre-fetch any objects in the set, this will prevent multiple server calls during set rendering */
  db_fetch_set (set, DB_FETCH_READ, 0);

  /* formerly we filtered out deleted elements here, now just use db_set_size to get the current size, including NULL &
   * deleted elements */
  cardinality = db_set_size (set);

  if (cardinality < 0)
    {
      return (NULL);
    }
  else if (cardinality == 0)
    {
      char temp_buffer[4];

      i = 0;
      if (begin_notation != '\0')
    {
      temp_buffer[i++] = begin_notation;
    }
      if (end_notation != '\0')
    {
      temp_buffer[i++] = end_notation;
    }
      temp_buffer[i] = '\0';
      return (duplicate_string ((const char *) &(temp_buffer[0])));
    }

  if (max_entries != -1 && max_entries < cardinality)
    {
      cardinality = max_entries;
    }
  string_array = (char **) malloc ((cardinality + 2) * sizeof (char *));
  if (string_array == NULL)
    {
      return (NULL);
    }

  memset (string_array, 0, (cardinality + 2) * sizeof (char *));

  total_string_length = cardinality * 2;
  for (i = 0; i < cardinality; i++)
    {
      set_error = db_set_get (set, i, &element);
      if (set_error != NO_ERROR)
    {
      goto finalize;
    }
      string_array[i] = csql_db_value_as_string (&element, NULL, csql_arg);
      db_value_clear (&element);
      if (string_array[i] == NULL)
    {
      string_array[i] = duplicate_string ("NULL");
      if (string_array[i] == NULL)
        {
          goto finalize;
        }
    }
      total_string_length += strlen (string_array[i]);
    }               /* for (i = 0; i < cardinality... */

  return_string = (char *) malloc (total_string_length + 4);
  if (return_string == NULL)
    {
      goto finalize;
    }

  if (begin_notation != '\0')
    {
      (void) sprintf (return_string, "%c%s", begin_notation, string_array[0]);
    }
  else
    {
      (void) strcpy (return_string, string_array[0]);
    }

  for (i = 1; i < cardinality; i++)
    {
      (void) strcat (return_string, ", ");
      (void) strcat (return_string, string_array[i]);
    }
  if (end_notation != '\0')
    {
      int len = strlen (return_string);

      return_string[len++] = end_notation;
      return_string[len] = '\0';
    }

finalize:
  for (i = 0; i < cardinality; i++)
    {
      if (string_array[i] == NULL)
    {
      break;
    }
      free_and_init (string_array[i]);
    }
  free_and_init (string_array);

  return return_string;
}

/*
 * duplicate_string() - Return an allocated copy of the string
 *   return: new string
 *   string(in): string value
 */
static char *
duplicate_string (const char *string)
{

  char *new_string;

  if (string == NULL)
    {
      return NULL;
    }

  new_string = (char *) malloc (strlen (string) + 1);
  if (new_string)
    {
      strcpy (new_string, string);
    }

  return (new_string);

}

/*
 * csql_string_to_plain_string() - Refine the string and return it
 *   return: refined plain string
 *   string_value(in): source string to duplicate
 *   length(in): length of the source string
 *   result_length(out): : length of output string
 *
 *   note: replace newline and tab with escaped string
 */
char *
csql_string_to_plain_string (const char *string_value, int length, int *result_length)
{
  char *return_string;
  char *ptr;
  char *con_buf_ptr = NULL;
  int con_buf_size = 0;
  int num_found = 0;
  int i;

  if (string_value == NULL)
    {
      return NULL;
    }

  ptr = (char *) string_value;
  while (*ptr != '\0')
    {
      if (*ptr == '\t' || *ptr == '\n' || *ptr == '\\')
    {
      num_found++;
    }
      ptr++;
    }

  if (num_found == 0)
    {
      if (result_length != NULL)
    {
      *result_length = length;
    }
      return duplicate_string (string_value);
    }

  return_string = (char *) malloc (length + num_found + 1);
  if (return_string == NULL)
    {
      return NULL;
    }

  ptr = return_string;
  for (i = 0; i < length; i++)
    {
      if (string_value[i] == '\t')
    {
      ptr += sprintf (ptr, "\\t");
    }
      else if (string_value[i] == '\n')
    {
      ptr += sprintf (ptr, "\\n");
    }
      else if (string_value[i] == '\\')
    {
      ptr += sprintf (ptr, "\\\\");
    }
      else
    {
      *(ptr++) = string_value[i];
    }
    }
  *ptr = '\0';

  if (csql_text_utf8_to_console != NULL
      && (*csql_text_utf8_to_console) (return_string, strlen (return_string), &con_buf_ptr, &con_buf_size) == NO_ERROR)
    {
      if (con_buf_ptr != NULL)
    {
      free (return_string);
      return_string = con_buf_ptr;
      ptr = con_buf_ptr + con_buf_size;
    }
    }

  if (result_length)
    {
      *result_length = CAST_STRLEN (ptr - return_string);
    }

  return return_string;
}

/*
 * string_to_string() - Copy the string and return it
 *   return: formatted string
 *   string_value(in): source string to duplicate
 *   string_delimiter(in): delimiter to surround string with (0 if none)
 *   string_introducer(in): introducer for the string (0 if none)
 *   length(in): length of the source string
 *   result_length(out): : length of output string
 *   plain_string(in): refine string for plain output
 *   change_single_quote(in): refine string for query output
 */
char *
string_to_string (const char *string_value, char string_delimiter, char string_introducer, int length,
          int *result_length, bool plain_string, bool change_single_quote)
{
  char *return_string;
  char *ptr;
  char *con_buf_ptr = NULL;
  int con_buf_size = 0;
  int num_found = 0, i = 0;

  if (plain_string == true)
    {
      return csql_string_to_plain_string (string_value, length, result_length);
    }

  if (string_delimiter == '\0')
    {
      return (duplicate_string (string_value));
    }

  if (string_value == NULL)
    {
      return NULL;
    }

  if (change_single_quote == true)
    {
      ptr = (char *) string_value;

      while (*ptr != '\0')
    {
      if (*ptr == '\'')
        {
          num_found++;
        }
      ptr++;
    }
    }

  if ((return_string = (char *) malloc (length + 4 + num_found)) == NULL)
    {
      return (NULL);
    }

  ptr = return_string;
  if (string_introducer)
    {
      *ptr++ = string_introducer;
    }
  *ptr++ = string_delimiter;

  if (change_single_quote == true)
    {
      for (i = 0; i < length; i++)
    {
      if (string_value[i] == '\'')
        {
          *(ptr++) = string_value[i];
          *(ptr++) = '\'';
        }
      else
        {
          *(ptr++) = string_value[i];
        }
    }
      *(ptr++) = string_delimiter;
      *ptr = '\0';
    }
  else
    {
      memcpy (ptr, string_value, length);
      ptr[length] = string_delimiter;
      ptr = ptr + length + 1;
      *ptr = '\0';
    }

  if (csql_text_utf8_to_console != NULL
      && (*csql_text_utf8_to_console) (return_string, strlen (return_string), &con_buf_ptr, &con_buf_size) == NO_ERROR)
    {
      if (con_buf_ptr != NULL)
    {
      free (return_string);
      return_string = con_buf_ptr;
      ptr = con_buf_ptr + con_buf_size;
    }
    }

  if (result_length)
    {
      *result_length = CAST_STRLEN (ptr - return_string);
    }
  return return_string;
}


#define MAX_DOUBLE_STRING 512
/*
 * convert double value to string for only oracle_number_compat
 */
static char *
conv_double_to_string (char *double_str, int *length)
{
  char return_str[MAX_DOUBLE_STRING] = { '-', '0', '.', '\0', };
  int exp_num, offset, p, sign = 0;

  char *dot, *exp, *sp = return_str + 1;

  dot = strchr (double_str, '.');
  exp = strchr (double_str, 'e');

  if (!exp)
    {
      *length = strlen (double_str);
      return strdup (double_str);
    }

  if (double_str[0] == '-')
    {
      double_str = double_str + 1;  /* for skip the sign */
      sign = -1;
    }
  exp_num = atoi (exp + 1);

  if (exp_num > 0)
    {
      if (dot)
    {
      memcpy (sp, double_str, offset = (int) (dot - double_str));
      memcpy (sp + offset, dot + 1, p = (int) (exp - dot) - 1);
      memset (sp + offset + p, '0', exp_num - (int) (exp - dot) + 1);
    }
      else
    {
      memcpy (sp, double_str, p = (int) (exp - double_str));
      memset (sp + p, '0', exp_num);
    }
    }
  else
    {
      exp_num = -exp_num;
      memset (sp + 2, '0', offset = exp_num - 1);
      if (dot)
    {
      memcpy (sp + 2 + offset, double_str, p = (int) (dot - double_str));
      memcpy (sp + 2 + offset + p, dot + 1, (int) (exp - dot) - 1);
    }
      else
    {
      memcpy (sp + 2 + offset, double_str, (int) (exp - double_str));
    }
    }

  *length = (sign < 0) ? strlen (return_str) : strlen (return_str + 1);

  return (sign < 0) ? strdup (return_str) : strdup (return_str + 1);
}

/*
 * csql_db_value_as_string() - convert DB_VALUE to string
 *   return: formatted string
 *   value(in): value to convert
 *   length(out): length of output string
 *   plain_output(in): refine string for plain output
 *   output_type(in): query output or loaddb output
 *   column_enclosure(in): column enclosure for query output
 */
char *
csql_db_value_as_string (DB_VALUE * value, int *length, const CSQL_ARGUMENT * csql_arg)
{
  char *result = NULL;
  char *json_body = NULL;
  int len = 0;
  char double_format = default_double_profile.format;
  bool trailingzeros = true;

  bool plain_string = csql_arg->plain_output;
  char column_enclosure = csql_arg->column_enclosure;

  static bool oracle_compat_number = prm_get_bool_value (PRM_ID_ORACLE_COMPAT_NUMBER_BEHAVIOR);
  char string_delimiter = csql_arg->column_enclosure;
  bool change_single_quote = (bool) (csql_arg->column_enclosure == '\'');

  CSQL_OUTPUT_TYPE output_type;

  if (csql_arg->query_output == true)
    {
      output_type = CSQL_QUERY_OUTPUT;
    }
  else if (csql_arg->loaddb_output == true)
    {
      output_type = CSQL_LOADDB_OUTPUT;
    }
  else
    {
      output_type = CSQL_UNKNOWN_OUTPUT;
      string_delimiter = default_string_profile.string_delimiter;
      change_single_quote = false;
    }

  /* oracle compatible */
  if (oracle_compat_number)
    {
      /* try to convert numeric */
      if (DB_VALUE_TYPE (value) == DB_TYPE_FLOAT || DB_VALUE_TYPE (value) == DB_TYPE_DOUBLE)
    {
      char double_str[MAX_DOUBLE_STRING];

      double_format = DOUBLE_FORMAT_GENERAL;
      trailingzeros = false;

      if (DB_VALUE_TYPE (value) == DB_TYPE_FLOAT)
        {
          sprintf (double_str, "%.7g", db_get_float (value));
        }
      else
        {
          sprintf (double_str, "%.16g", db_get_double (value));
        }

      result = conv_double_to_string (double_str, length);

      return result;
    }
    }

  if (value == NULL)
    {
      return (NULL);
    }

  switch (DB_VALUE_TYPE (value))
    {
    case DB_TYPE_BIGINT:
      result =
    bigint_to_string (db_get_bigint (value), default_bigint_profile.fieldwidth, default_bigint_profile.leadingzeros,
              default_bigint_profile.leadingsymbol, default_bigint_profile.commas,
              default_bigint_profile.format);
      if (result)
    {
      len = strlen (result);
    }
      break;
    case DB_TYPE_INTEGER:
      result =
    bigint_to_string (db_get_int (value), default_int_profile.fieldwidth, default_int_profile.leadingzeros,
              default_int_profile.leadingsymbol, default_int_profile.commas, default_int_profile.format);
      if (result)
    {
      len = strlen (result);
    }
      break;
    case DB_TYPE_SHORT:
      result =
    bigint_to_string (SHORT_TO_INT (db_get_short (value)), default_short_profile.fieldwidth,
              default_short_profile.leadingzeros, default_short_profile.leadingsymbol,
              default_short_profile.commas, default_short_profile.format);
      if (result)
    {
      len = strlen (result);
    }
      break;
    case DB_TYPE_FLOAT:
      result =
    double_to_string ((double) db_get_float (value), default_float_profile.fieldwidth,
              default_float_profile.precision, default_float_profile.leadingsign, nullptr, nullptr,
              default_float_profile.leadingzeros, trailingzeros, default_float_profile.commas,
              double_format);
      if (result)
    {
      len = strlen (result);
    }
      break;
    case DB_TYPE_DOUBLE:
      result =
    double_to_string (db_get_double (value), default_double_profile.fieldwidth,
              default_double_profile.precision, default_double_profile.leadingsign, nullptr, nullptr,
              default_double_profile.leadingzeros, trailingzeros, default_double_profile.commas,
              double_format);
      if (result)
    {
      len = strlen (result);
    }
      break;
    case DB_TYPE_NUMERIC:
      result = numeric_to_string (value, default_numeric_profile.commas);
      if (result)
    {
      len = strlen (result);
    }
      break;
    case DB_TYPE_VARCHAR:
    case DB_TYPE_CHAR:
      {
    int bytes_size, decomp_size;
    bool need_decomp = false;
    const char *str;
    char *decomposed = NULL;

    str = db_get_char (value);
    bytes_size = db_get_string_size (value);
    if (bytes_size > 0 && db_get_string_codeset (value) == INTL_CODESET_UTF8)
      {
        need_decomp =
          unicode_string_need_decompose (str, bytes_size, &decomp_size, lang_get_generic_unicode_norm ());
      }

    if (need_decomp)
      {
        decomposed = (char *) malloc (decomp_size * sizeof (char));
        if (decomposed != NULL)
          {
        unicode_decompose_string (str, bytes_size, decomposed, &decomp_size, lang_get_generic_unicode_norm ());

        str = decomposed;
        bytes_size = decomp_size;
          }
        else
          {
        return NULL;
          }
      }

    result =
      string_to_string (str, string_delimiter, '\0', bytes_size, &len, csql_arg->plain_output, change_single_quote);

    if (decomposed != NULL)
      {
        free_and_init (decomposed);
      }

      }
      break;
    case DB_TYPE_VARBIT:
    case DB_TYPE_BIT:
      result = bit_to_string (value, string_delimiter, plain_string);
      if (result)
    {
      len = strlen (result);
    }
      break;
    case DB_TYPE_OBJECT:
      result = object_to_string (db_get_object (value), get_object_print_format ());
      if (result == NULL)
    {
      result = duplicate_string ("NULL");
    }
      if (result)
    {
      len = strlen (result);
    }
      break;
    case DB_TYPE_VOBJ:
      result = object_to_string (db_get_object (value), get_object_print_format ());
      if (result == NULL)
    {
      result = duplicate_string ("NULL");
    }
      if (result)
    {
      len = strlen (result);
    }
      break;
    case DB_TYPE_JSON:
      json_body = db_get_json_raw_body (value);
      result = duplicate_string (json_body);
      db_private_free (NULL, json_body);
      if (result)
    {
      if (output_type == CSQL_QUERY_OUTPUT || output_type == CSQL_LOADDB_OUTPUT)
        {
          char *new_result;

          new_result =
        string_to_string (result, column_enclosure, '\0', strlen (result), &len, false, change_single_quote);

          if (new_result)
        {
          free (result);
          result = new_result;
        }
        }
      len = strlen (result);
    }
      break;
    case DB_TYPE_SET:
    case DB_TYPE_MULTISET:
    case DB_TYPE_SEQUENCE:
      result =
    set_to_string (value, default_set_profile.begin_notation, default_set_profile.end_notation,
               default_set_profile.max_entries, csql_arg);
      if (result)
    {
      len = strlen (result);
    }
      break;
    case DB_TYPE_TIME:
      {
    char buf[TIME_BUF_SIZE];
    if (db_time_to_string (buf, sizeof (buf), db_get_time (value)))
      {
        if (output_type == CSQL_QUERY_OUTPUT || output_type == CSQL_LOADDB_OUTPUT)
          {
        result = string_to_string (buf, column_enclosure, '\0', strlen (buf), &len, false, false);
          }
        else
          {
        result = duplicate_string (buf);
          }
      }
    if (result)
      {
        len = strlen (result);
      }
    break;
      }
    case DB_TYPE_MONETARY:
      {
    char *leading_str = NULL;
    char *trailing_str = NULL;
    DB_MONETARY *monetary_val = db_get_monetary (value);
    DB_CURRENCY currency = monetary_val->type;

    if (default_monetary_profile.currency_symbol)
      {
        if (intl_get_currency_symbol_position (currency) == 1)
          {
        trailing_str = intl_get_money_symbol_console (currency);
          }
        else
          {
        leading_str = intl_get_money_symbol_console (currency);
          }
      }

    if (db_get_monetary (value) == NULL)
      {
        result = NULL;
      }
    else
      {
        result = double_to_string (monetary_val->amount, default_monetary_profile.fieldwidth,
                       default_monetary_profile.decimalplaces, default_monetary_profile.leadingsign,
                       leading_str, trailing_str, default_monetary_profile.leadingzeros,
                       default_monetary_profile.trailingzeros, default_monetary_profile.commas,
                       DOUBLE_FORMAT_DECIMAL);
      }

    if (result)
      {
        len = strlen (result);
      }
      }
      break;
    case DB_TYPE_DATE:
      /* default format for all locales */
      result = date_as_string (db_get_date (value), default_date_profile.format);
      if (result)
    {
      if (output_type == CSQL_QUERY_OUTPUT || output_type == CSQL_LOADDB_OUTPUT)
        {
          char *new_result;

          new_result = string_to_string (result, column_enclosure, '\0', strlen (result), &len, false, false);

          if (new_result)
        {
          free (result);
          result = new_result;
        }
        }
      len = strlen (result);
    }
      break;
    case DB_TYPE_TIMESTAMP:
      {
    char buf[TIMESTAMP_BUF_SIZE];
    if (db_utime_to_string (buf, sizeof (buf), db_get_timestamp (value)))
      {
        if (output_type == CSQL_QUERY_OUTPUT || output_type == CSQL_LOADDB_OUTPUT)
          {
        result = string_to_string (buf, column_enclosure, '\0', strlen (buf), &len, false, false);
          }
        else
          {
        result = duplicate_string (buf);
          }
      }

    if (result)
      {
        len = strlen (result);
      }
      }
      break;
    case DB_TYPE_TIMESTAMPTZ:
      {
    char buf[TIMESTAMPTZ_BUF_SIZE];
    DB_TIMESTAMPTZ *ts_tz = db_get_timestamptz (value);
    if (db_timestamptz_to_string (buf, sizeof (buf), &(ts_tz->timestamp), &(ts_tz->tz_id)))
      {
        if (output_type == CSQL_QUERY_OUTPUT || output_type == CSQL_LOADDB_OUTPUT)
          {
        result = string_to_string (buf, column_enclosure, '\0', strlen (buf), &len, false, false);
          }
        else
          {
        result = duplicate_string (buf);
          }
      }

    if (result)
      {
        len = strlen (result);
      }
      }
      break;
    case DB_TYPE_TIMESTAMPLTZ:
      {
    char buf[TIMESTAMPTZ_BUF_SIZE];

    if (db_timestampltz_to_string (buf, sizeof (buf), db_get_timestamp (value)))
      {
        if (output_type == CSQL_QUERY_OUTPUT || output_type == CSQL_LOADDB_OUTPUT)
          {
        result = string_to_string (buf, column_enclosure, '\0', strlen (buf), &len, false, false);
          }
        else
          {
        result = duplicate_string (buf);
          }
      }

    if (result)
      {
        len = strlen (result);
      }
      }
      break;
    case DB_TYPE_DATETIME:
      {
    char buf[DATETIME_BUF_SIZE];
    if (db_datetime_to_string (buf, sizeof (buf), db_get_datetime (value)))
      {
        if (output_type == CSQL_QUERY_OUTPUT || output_type == CSQL_LOADDB_OUTPUT)
          {
        result = string_to_string (buf, column_enclosure, '\0', strlen (buf), &len, false, false);
          }
        else
          {
        result = duplicate_string (buf);
          }
      }

    if (result)
      {
        len = strlen (result);
      }
      }
      break;
    case DB_TYPE_DATETIMETZ:
      {
    char buf[DATETIMETZ_BUF_SIZE];
    DB_DATETIMETZ *dt_tz = db_get_datetimetz (value);
    if (db_datetimetz_to_string (buf, sizeof (buf), &(dt_tz->datetime), &(dt_tz->tz_id)))
      {
        if (output_type == CSQL_QUERY_OUTPUT || output_type == CSQL_LOADDB_OUTPUT)
          {
        result = string_to_string (buf, column_enclosure, '\0', strlen (buf), &len, false, false);
          }
        else
          {
        result = duplicate_string (buf);
          }
      }

    if (result)
      {
        len = strlen (result);
      }
      }
      break;
    case DB_TYPE_DATETIMELTZ:
      {
    char buf[DATETIMETZ_BUF_SIZE];

    if (db_datetimeltz_to_string (buf, sizeof (buf), db_get_datetime (value)))
      {
        if (output_type == CSQL_QUERY_OUTPUT || output_type == CSQL_LOADDB_OUTPUT)
          {
        result = string_to_string (buf, column_enclosure, '\0', strlen (buf), &len, false, false);
          }
        else
          {
        result = duplicate_string (buf);
          }
      }

    if (result)
      {
        len = strlen (result);
      }
      }
      break;
    case DB_TYPE_NULL:
      result = duplicate_string ("NULL");
      if (result)
    {
      len = strlen (result);
    }
      break;

    case DB_TYPE_BLOB:
    case DB_TYPE_CLOB:
      {
    DB_ELO *elo = db_get_elo (value);

    if (elo != NULL)
      {
        result = duplicate_string (elo->locator);
      }

    if (result != NULL)
      {
        len = strlen (result);
      }
      }
      break;

    case DB_TYPE_ENUMERATION:
      {
    int bytes_size, decomp_size;
    bool need_decomp = false;
    const char *str;
    char *decomposed = NULL;

    if (output_type == CSQL_LOADDB_OUTPUT)
      {
        result = bigint_to_string (SHORT_TO_INT (db_get_enum_short (value)), default_short_profile.fieldwidth,
                       default_short_profile.leadingzeros, default_short_profile.leadingsymbol,
                       default_short_profile.commas, default_short_profile.format);
        if (result)
          {
        len = strlen (result);
          }
        break;
      }

    if (db_get_enum_short (value) == 0 && db_get_enum_string (value) == NULL)
      {
        /* ENUM special error value */
        str = "";
        bytes_size = 0;
      }
    else
      {
        str = db_get_enum_string (value);
        bytes_size = db_get_enum_string_size (value);
      }
    if (bytes_size > 0 && db_get_enum_codeset (value) == INTL_CODESET_UTF8)
      {
        need_decomp =
          unicode_string_need_decompose ((char *) str, bytes_size, &decomp_size, lang_get_generic_unicode_norm ());
      }

    if (need_decomp)
      {
        decomposed = (char *) malloc (decomp_size * sizeof (char));
        if (decomposed != NULL)
          {
        unicode_decompose_string ((char *) str, bytes_size, decomposed, &decomp_size,
                      lang_get_generic_unicode_norm ());

        str = decomposed;
        bytes_size = decomp_size;
          }
        else
          {
        return NULL;
          }
      }

    result = string_to_string (str, string_delimiter, '\0', bytes_size, &len, plain_string, change_single_quote);
    if (decomposed != NULL)
      {
        free_and_init (decomposed);
      }
      }
      break;

    case DB_TYPE_MIDXKEY:
      {
    if (csql_arg->midxkey_print)
      {
        string_buffer sb;

        sb.clear ();
        db_sprint_value (value, sb);

        /*  Make sure it has the same format as the result of using cast().
         *  '{1, 'abc'}'  or  '{1, ''abc''}'  (depends on change_single_quote)
         */
        result =
          string_to_string (sb.get_buffer (), string_delimiter, '\0', sb.len (), &len, plain_string,
                change_single_quote);
        sb.clear ();
        break;      /* escape switch */
      }
      }
      [[fallthrough]];

    default:
      {
    char temp_buffer[256];

    (void) sprintf (temp_buffer, "<%s>", db_get_type_name (DB_VALUE_TYPE (value)));
    result = duplicate_string (temp_buffer);
    if (result)
      {
        len = strlen (result);
      }
      }
    }

  if (length)
    {
      *length = len;
    }
  return result;
}

static int
get_object_print_format (void)
{
  return prm_get_bool_value (PRM_ID_OBJECT_PRINT_FORMAT_OID) ? OBJECT_FORMAT_OID : OBJECT_FORMAT_CLASSNAME;
}