postgresql/src/interfaces/ecpg/test/sql/sqlda.pgc
Tom Lane 2e8ed46599 Second try at fixing numeric data passed through an ECPG SQLDA.
In commit ecfd55795, I removed sqlda.c's checks for ndigits != 0 on the
grounds that we should duplicate the state of the numeric value's digit
buffer even when all the digits are zeroes.  However, that still isn't
quite right, because another possible state of the digit buffer is
buf == digits == NULL (this occurs for a NaN).  As the code now stands,
it'll invoke memcpy with a NULL source address and zero bytecount,
which we know a few platforms crash on.  Hence, reinstate the no-copy
short-circuit, but make it test specifically for buf != NULL rather than
some other condition.  In hindsight, the ndigits test (added by commit
f2ae9f9c3) was almost certainly meant to fix the NaN case not the
all-zeroes case as the associated thread alleged.

As before, back-patch to all supported versions.

Discussion: https://postgr.es/m/1803D792815FC24D871C00D17AE95905C71161@g01jpexmbkw24
2018-11-14 11:27:30 -05:00

262 lines
5.6 KiB
Text

#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "ecpg_config.h"
exec sql include ../regression;
exec sql include sqlda.h;
exec sql include pgtypes_numeric.h;
exec sql whenever sqlerror stop;
/* These shouldn't be under DECLARE SECTION */
sqlda_t *inp_sqlda, *outp_sqlda, *outp_sqlda1;
static void
dump_sqlda(sqlda_t *sqlda)
{
int i;
if (sqlda == NULL)
{
printf("dump_sqlda called with NULL sqlda\n");
return;
}
for (i = 0; i < sqlda->sqld; i++)
{
if (sqlda->sqlvar[i].sqlind && *(sqlda->sqlvar[i].sqlind) == -1)
printf("name sqlda descriptor: '%s' value NULL'\n", sqlda->sqlvar[i].sqlname.data);
else
switch (sqlda->sqlvar[i].sqltype)
{
case ECPGt_char:
printf("name sqlda descriptor: '%s' value '%s'\n", sqlda->sqlvar[i].sqlname.data, sqlda->sqlvar[i].sqldata);
break;
case ECPGt_int:
printf("name sqlda descriptor: '%s' value %d\n", sqlda->sqlvar[i].sqlname.data, *(int *)sqlda->sqlvar[i].sqldata);
break;
case ECPGt_long:
printf("name sqlda descriptor: '%s' value %ld\n", sqlda->sqlvar[i].sqlname.data, *(long int *)sqlda->sqlvar[i].sqldata);
break;
#ifdef HAVE_LONG_LONG_INT
case ECPGt_long_long:
printf("name sqlda descriptor: '%s' value %lld\n", sqlda->sqlvar[i].sqlname.data, *(long long int *)sqlda->sqlvar[i].sqldata);
break;
#endif
case ECPGt_double:
printf("name sqlda descriptor: '%s' value %f\n", sqlda->sqlvar[i].sqlname.data, *(double *)sqlda->sqlvar[i].sqldata);
break;
case ECPGt_numeric:
{
char *val;
val = PGTYPESnumeric_to_asc((numeric*)sqlda->sqlvar[i].sqldata, -1);
printf("name sqlda descriptor: '%s' value NUMERIC '%s'\n", sqlda->sqlvar[i].sqlname.data, val);
PGTYPESchar_free(val);
break;
}
}
}
}
int
main (void)
{
exec sql begin declare section;
char *stmt1 = "SELECT * FROM t1";
char *stmt2 = "SELECT * FROM t1 WHERE id = ?";
int rec;
int id;
exec sql end declare section;
char msg[128];
ECPGdebug(1, stderr);
strcpy(msg, "connect");
exec sql connect to REGRESSDB1 as regress1;
strcpy(msg, "set");
exec sql set datestyle to iso;
strcpy(msg, "create");
exec sql create table t1(
id integer,
t text,
d1 numeric,
d2 float8,
c char(10),
big bigint
);
strcpy(msg, "insert");
exec sql insert into t1 values
(1, 'a', 1.0, 1, 'a',1111111111111111111),
(2, null, null, null, null,null),
(3, 'c', 0.0, 3, 'c',3333333333333333333),
(4, 'd', 'NaN', 4, 'd',4444444444444444444),
(5, 'e', 0.001234, 5, 'e',5555555555555555555);
strcpy(msg, "commit");
exec sql commit;
/* SQLDA test for getting all records from a table */
outp_sqlda = NULL;
strcpy(msg, "prepare");
exec sql prepare st_id1 from :stmt1;
strcpy(msg, "declare");
exec sql declare mycur1 cursor for st_id1;
strcpy(msg, "open");
exec sql open mycur1;
exec sql whenever not found do break;
rec = 0;
while (1)
{
strcpy(msg, "fetch");
exec sql fetch 1 from mycur1 into descriptor outp_sqlda;
printf("FETCH RECORD %d\n", ++rec);
dump_sqlda(outp_sqlda);
}
exec sql whenever not found continue;
strcpy(msg, "close");
exec sql close mycur1;
strcpy(msg, "deallocate");
exec sql deallocate prepare st_id1;
free(outp_sqlda);
/* SQLDA test for getting ALL records into the sqlda list */
outp_sqlda = NULL;
strcpy(msg, "prepare");
exec sql prepare st_id2 from :stmt1;
strcpy(msg, "declare");
exec sql declare mycur2 cursor for st_id2;
strcpy(msg, "open");
exec sql open mycur2;
strcpy(msg, "fetch");
exec sql fetch all from mycur2 into descriptor outp_sqlda;
outp_sqlda1 = outp_sqlda;
rec = 0;
while (outp_sqlda1)
{
sqlda_t *ptr;
printf("FETCH RECORD %d\n", ++rec);
dump_sqlda(outp_sqlda1);
ptr = outp_sqlda1;
outp_sqlda1 = outp_sqlda1->desc_next;
free(ptr);
}
strcpy(msg, "close");
exec sql close mycur2;
strcpy(msg, "deallocate");
exec sql deallocate prepare st_id2;
/* SQLDA test for getting one record using an input descriptor */
/*
* Input sqlda has to be built manually
* sqlda_t contains 1 sqlvar_t structure already.
*/
inp_sqlda = (sqlda_t *)malloc(sizeof(sqlda_t));
memset(inp_sqlda, 0, sizeof(sqlda_t));
inp_sqlda->sqln = 1;
inp_sqlda->sqlvar[0].sqltype = ECPGt_int;
inp_sqlda->sqlvar[0].sqldata = (char *)&id;
printf("EXECUTE RECORD 4\n");
id = 4;
outp_sqlda = NULL;
strcpy(msg, "prepare");
exec sql prepare st_id3 FROM :stmt2;
strcpy(msg, "execute");
exec sql execute st_id3 using descriptor inp_sqlda into descriptor outp_sqlda;
dump_sqlda(outp_sqlda);
strcpy(msg, "deallocate");
exec sql deallocate prepare st_id3;
free(inp_sqlda);
free(outp_sqlda);
/* SQLDA test for getting one record using an input descriptor
* on a named connection
*/
exec sql connect to REGRESSDB1 as con2;
/*
* Input sqlda has to be built manually
* sqlda_t contains 1 sqlvar_t structure already.
*/
inp_sqlda = (sqlda_t *)malloc(sizeof(sqlda_t));
memset(inp_sqlda, 0, sizeof(sqlda_t));
inp_sqlda->sqln = 1;
inp_sqlda->sqlvar[0].sqltype = ECPGt_int;
inp_sqlda->sqlvar[0].sqldata = (char *)&id;
printf("EXECUTE RECORD 4\n");
id = 4;
outp_sqlda = NULL;
strcpy(msg, "prepare");
exec sql at con2 prepare st_id4 FROM :stmt2;
strcpy(msg, "execute");
exec sql at con2 execute st_id4 using descriptor inp_sqlda into descriptor outp_sqlda;
dump_sqlda(outp_sqlda);
strcpy(msg, "commit");
exec sql at con2 commit;
strcpy(msg, "deallocate");
exec sql deallocate prepare st_id4;
free(inp_sqlda);
free(outp_sqlda);
strcpy(msg, "disconnect");
exec sql disconnect con2;
/* End test */
strcpy(msg, "drop");
exec sql drop table t1;
strcpy(msg, "commit");
exec sql commit;
strcpy(msg, "disconnect");
exec sql disconnect;
return (0);
}