From: johnl@informix.com (Jonathan Leffler)
Newsgroups: comp.databases.informix
Date: 13 Sep 1993 15:48:22 -0400

>From: gm0564@swuts.sbc.com (George Ma)
>Subject: datetime data
>Date: 13 Sep 93 14:56:36 GMT
>
>Has any one had experience to retrieve datetime type data into sqlda and then
>to convert it into char string using dttoasc()?
>I tried but dttoasc() failed to provide correct data.
>
>I wonder whether datetime type data has to be FETCHed INTO a host variable of
>type dtime_t but cannot be loaded into sqlda since there is no way to
>initialize dt_qual field if sqlda is used?

1.  Be careful with the version of ESQL/C you are using.  There are bugs in
    rtypemsize() and rtypmalign which are only fixed in 5.00 and above.

2.	The code below is what I use for handling sqlda structures.  This has
  	code for both 5.00 and earlier versions.  It is straight out of a
  	program of mine, so some of the headers may not be available, but it
  	should be a good starting point.  You do not need to initialise the
  	dt_qual field in the allocated data space -- the interface code will
  	sort that out for you.

Yours,
Jonathan Leffler (johnl@informix.com) #include <disclaimer.h>

Notes: MALLOC is a macro which calls a malloc cover function which
guarantees not to return a null pointer.  It is defined in the missing
emalloc.h header. error2 is an error reporting function defined in the
missing stderr.h header.  The missing header describe.h contains the
declarations for the sql_describe() function.  I have previously posted
the esqlc.h headers which contains prototypes for ESQL/C functions.

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
#		"End of shell archive."
# Contents:  describe.ec
# Wrapped by johnl@godzilla on Mon Sep 13 12:04:38 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'describe.ec' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'describe.ec'\"
else
echo shar: Extracting \"'describe.ec'\" \(6561 characters\)
sed "s/^X//" >'describe.ec' <<'END_OF_FILE'
X/*
X@(#)File:           describe.ec
X@(#)Version:        1.6
X@(#)Last changed:   93/05/16
X@(#)Purpose:        Allocate space for SQLDA structure
X@(#)Author:         J Leffler
X@(#)Copyright:      (C) JLSS 1992
X@(#)Product:        :PRODUCT:
X*/
X
X/*TABSTOP=4*/
X/*LINTLIBRARY*/
X
X#include <fcntl.h>
X#include <stdlib.h>
X#include "emalloc.h"
X#include "esqlc.h"
X#include "describe.h"
X#include "stderr.h"
X
X#define FILENAMESIZE	128
X#define DEFAULT_TMPDIR	"/tmp"
X
X#define BLOB_IN_MEMORY	1
X#define BLOB_IN_FILE	2
X
X#ifndef BLOB_LOCATION
X#define BLOB_LOCATION	BLOB_IN_MEMORY
X#endif	/* BLOB_LOCATION */
X
X#if BLOB_LOCATION == BLOB_IN_FILE
Xextern char    *strdup();
X#endif
X
X#ifndef lint
Xstatic char     sccs[] = "@(#)describe.ec	1.6 93/05/16";
X#endif
X
Xchar           *dbtemp()
X{
X	static char    *db_temp;
X
X	if (db_temp == (char *)0)
X	{
X		db_temp = getenv("DBTEMP");
X		if (db_temp == (char *)0)
X			db_temp = DEFAULT_TMPDIR;
X	}
X	return(db_temp);
X}
X
X/*
X** Initialise a Blob data structure ready for use.
X*/
X#ifdef __STDC__
Xvoid            blob_locate(Blob * blob)
X#else
Xvoid            blob_locate(blob)
XBlob           *blob;
X#endif	/* __STDC__ */
X{
X#if BLOB_LOCATION == BLOB_IN_FILE
X	char            tmp[FILENAMESIZE];
X
X	/* Open a file and then delete it, but keep it open. */
X	/* The system cleans it up regardless of how we exit */
X	vstrcpy(tmp, 2, dbtemp(), "/blob.XXXXXX");
X	blob->loc_loctype = LOCFILE;
X	blob->loc_fname = (char *)0;
X	blob->loc_mode = 0666;
X	blob->loc_oflags = LOC_WONLY | LOC_RONLY;
X	blob->loc_size = -1;
X	blob->loc_indicator = 0;
X	mktemp(tmp);
X	blob->loc_fd = open(tmp, 0666, O_RDWR);
X	if (blob->loc_fd < 0)
X		error2("failed to create temporary file", tmp);
X	unlink(tmp);
X#else
X	/* Use memory only */
X	blob->loc_loctype = LOCMEMORY;
X	blob->loc_bufsize = -1;
X	blob->loc_buffer = (char *)0;
X	blob->loc_indicator = 0;
X#endif	/* BLOB_LOCATION == BLOB_IN_FILE */
X#ifdef DEBUG
X	dump_blob(blob);
X#endif	/* DEBUG */
X}
X
X/*
X** Where necessary, convert an SQL* type to a C*TYPE type.
X*/
X#ifdef __STDC__
Xstatic int      rtypctype(int sqltype)
X#else
Xstatic int      rtypctype(sqltype)
Xint             sqltype;
X#endif	/* __STDC__ */
X{
X	int             rtype;
X
X	switch (sqltype)
X	{
X	case SQLCHAR:
X	case SQLVCHAR:
X		rtype = CCHARTYPE;
X		break;
X	default:
X		rtype = sqltype;
X		break;
X	}
X	return(rtype);
X}
X
X#ifdef __STDC__
Xstatic int      rtypcsize(int sqltype, int sqllen)
X#else
Xstatic int      rtypcsize(sqltype, sqllen)
Xint             sqltype;
Xint             sqllen;
X#endif	/* __STDC__ */
X{
X	int             rlen;
X
X	switch (sqltype)
X	{
X	case SQLCHAR:
X		rlen = sqllen + 1;
X		break;
X	case SQLVCHAR:
X		rlen = VCMAX(sqllen) + 1;
X		break;
X	default:
X		rlen = sqllen;
X		break;
X	}
X	return(rlen);
X}
X
X/*
X** Calculate and store the offsets of data in an SQLDA structure.
X** Return the total amount of memory needed.
X** This code assumes that pointers and longs are compatible.
X** It also assumes that the Sqlda structure only contains SQLxxx types.
X**
X** KLUDGE: There are bugs in both rtypmsize and rtypalign in Versions
X** 4.00 & 4.10 which require long and tedious code to circumvent them.
X** rtypmsize fibs about the size of SQLDTIME and SQLINTERVAL
X** (returning sizeof(dec_t) instead of sizeof(dtime_t) and
X** sizeof(intrvl_t)), and doesn't recognise CDTIMETYPE, CINVTYPE,
X** SQLBYTES, SQLTEXT, and CLOCATORTYPE at all, returning size 0.
X** rtypalign fibs about the alignment requirements of CDTIMETYPE,
X** CINVTYPE, SQLBYTES, SQLTEXT, and CLOCATORTYPE, saying they can be
X** byte-aligned when they cannot necessarily be byte-aligned.
X**
X** These bugs have all been fixed in Version 5.00.
X**
X** Additionally, in Version 4.00 and 4.10, if the type in the SQLDA
X** structure is left as SQLCHAR or SQLVCHAR and the length field is
X** not modified, then the string types are truncated.  This is a pain
X** since the size allocated allows for a terminating null.  The
X** routines rtypcsize and rtypctype have been invented to allow for
X** these anomalies.
X*/
X#ifdef __STDC__
Xstatic long     sql_descsize(Sqlda * sqlda)
X#else
Xstatic long     sql_descsize(sqlda)
XSqlda          *sqlda;			/* InOut: SQL dynamic allocation structure */
X#endif	/* __STDC__ */
X{
X	Sqlva          *col;
X	int             offset;
X	int             i;
X
X	offset = 0;
X	for (col = sqlda->sqlvar, i = 0; i < sqlda->sqld; col++, i++)
X	{
X#ifdef ESQLC_5_00
X		static char sqlver[] = "@(#)ESCL/C Version 5.00";
X		int             size;
X		size = rtypmsize(col->sqltype, col->sqllen);
X		offset = rtypalign(offset, col->sqltype);
X		col->sqldata = (char *)offset;
X		col->sqllen  = rtypcsize(col->sqltype, col->sqllen);
X		col->sqltype = rtypctype(col->sqltype);
X		offset += size;
X#else
X		static char sqlver[] = "@(#)ESCL/C Version 4.00 or 4.10";
X		int             m_type;	/* Memory (alignment) type */
X		int             m_size;	/* Memory size */
X
X		m_type = col->sqltype;
X		switch (col->sqltype)
X		{
X		case SQLINT:
X		case SQLSERIAL:
X		case SQLSMINT:
X		case SQLSMFLOAT:
X		case SQLFLOAT:
X		case SQLMONEY:
X		case SQLDECIMAL:
X		case SQLDATE:
X		case SQLVCHAR:
X		case SQLCHAR:
X			m_size = rtypmsize(col->sqltype, col->sqllen);
X			break;
X		case SQLDTIME:
X			m_type = CDECIMALTYPE;
X			m_size = sizeof(dtime_t);
X			break;
X		case SQLINTERVAL:
X			m_type = CDECIMALTYPE;
X			m_size = sizeof(intrvl_t);
X			break;
X		case SQLBYTES:
X		case SQLTEXT:
X			m_size = sizeof(Blob);
X			break;
X		default:
X			err_report(ERR_ERR, ERR_STAT, "Unknown type found in sqlda %d\n",
X					   col->sqltype);
X			break;
X		}
X		offset = (int)rtypalign((char *)offset, m_type);
X		col->sqldata = (char *)offset;
X		col->sqllen  = rtypcsize(col->sqltype, col->sqllen);
X		col->sqltype = rtypctype(col->sqltype);
X		offset += m_size;
X#endif	/* ESQLC_5_00 */
X	}
X	return(offset);
X}
X
X/*
X** Allocate the memory for the data described by an SQLDA structure.
X** This code assumes that pointers and longs are compatible.
X*/
X#ifdef __STDC__
Xchar           *sql_describe(Sqlda * sqlda)
X#else
Xchar           *sql_describe(sqlda)
XSqlda          *sqlda;			/* InOut: SQL dynamic allocation structure */
X#endif	/* __STDC__ */
X{
X	Sqlva          *col;
X	char           *buffer;
X	long            size;
X	long            offset;
X	int             i;
X
X	/* Step 1 -- calculate memory required */
X	size = sql_descsize(sqlda);
X
X	/* Step 2 -- allocate memory */
X	buffer = (char *)MALLOC(size);
X
X	/* Step 3 -- fix up pointers */
X	offset = (long)buffer;
X	col = sqlda->sqlvar;
X	for (i = 0; i < sqlda->sqld; i++, col++)
X	{
X		col->sqldata += offset;
X		if (col->sqltype == CLOCATORTYPE ||
X			col->sqltype == SQLTEXT ||
X			col->sqltype == SQLBYTES)
X			blob_locate((Blob *)col->sqldata);
X	}
X
X	return(buffer);
X}
END_OF_FILE
if test 6561 -ne `wc -c <'describe.ec'`; then
    echo shar: \"'describe.ec'\" unpacked with wrong size!
fi
# end of 'describe.ec'
fi
echo shar: End of shell archive.
exit 0
