Re: Sending dbnumeric in dbrpcparam

Frediano Ziglio <[email protected]>
Newsgroups gmane.comp.db.tds.freetds
Message-ID <[email protected]>
2009/6/2 James K. Lowden <[email protected]>:
> Damien Churchill wrote:
>> >> Here is the code that I've tried: http://pastebin.com/f69a761d7
>> >
>> > http://manuals.sybase.com/onlinebooks/group-cnarc/cng1110e/dblib/@Generic__BookTextView/34413;pt=39614
>> >
>> >        "The value of type indicates the datatype of *value. See
>> > "Types" for more information. For types that have no C equivalent,
>> > such as SYBDATETIME, SYBMONEY, SYBNUMERIC, or SYBDECIMAL, use
>> > dbconvert_ps to initialize *value."
>>
>> Hmm, I gave this a try and it still fails with the same error.
>
> Um, that's not possible?  The advice is to convert your numeric value to a
> "known" type -- a C string, say -- and bind your parameter to that
> (intermediate) buffer.  Line 63 becomes:
>
> ret = dbrpcparam(dbproc, "@idecimal", 0, SYBCHAR, -1, strlen(tmp), (BYTE
> *)tmp);
>
> At that point, it's just a plain-vanilla RPC call.
>
>> Would this only work with Sybase perhaps?
>
> It should work regardless of TDS protocol.  The server interaction is
> different, but the API (and its limitations) are the same.
>
> FWIW, there's no technical reason dbrpcparam couldn't deal directly with
> these types.  It's not specified by the vendors, but it's a reasonable
> extension.  In case you want to try your hand at it.
>
> HTH.
>

I tried to add test to our unittests (attached) and it seems that
client library doesn't fill correctly needed informations for numeric
(precision and scale). I did also a small change to dblib. However I
would check if DBDECIMAL declaration is different between Sybase and
Microsoft. It seems for instance that Sybase use big endian order
while MS use little endian.

freddy77

_______________________________________________
FreeTDS mailing list
[email protected]
http://lists.ibiblio.org/mailman/listinfo/freetds
numeric_test.diff (application/octet-stream, 4.2 KB)
Index: freetds83/src/dblib/rpc.c
===================================================================
--- freetds83.orig/src/dblib/rpc.c
+++ freetds83/src/dblib/rpc.c
@@ -429,6 +429,12 @@ param_info_alloc(TDSSOCKET * tds, DBREMO
 				pcol->column_size = p->datalen;
 			}
 		}
+		if (temp_value && is_numeric_type(temp_type)) {
+			DBDECIMAL *dec = (DBDECIMAL*) temp_value;
+			pcol->column_prec = dec->precision;
+			pcol->column_scale = dec->scale;
+			temp_datalen = tds_numeric_bytes_per_prec[dec->precision];
+		}
 		pcol->on_server.column_size = pcol->column_size;
 
 		pcol->column_output = p->status;
Index: freetds83/src/dblib/unittests/Makefile.am
===================================================================
--- freetds83.orig/src/dblib/unittests/Makefile.am
+++ freetds83/src/dblib/unittests/Makefile.am
@@ -10,7 +10,7 @@ TESTS		=	t0001$(EXEEXT) t0002$(EXEEXT) t
 			bcp$(EXEEXT) thread$(EXEEXT) text_buffer$(EXEEXT)\
 			done_handling$(EXEEXT) timeout$(EXEEXT) \
 			hang$(EXEEXT) null$(EXEEXT) null2$(EXEEXT) \
-			setnull$(EXEEXT)
+			setnull$(EXEEXT) numeric$(EXEEXT)
 check_PROGRAMS	=	$(TESTS)
 
 SQL_DIST = 	bcp.sql dbmorecmds.sql done_handling.sql rpc.sql \
@@ -53,6 +53,7 @@ hang_SOURCES	=	hang.c common.c common.h
 null_SOURCES	=	null.c common.c common.h
 null2_SOURCES	=	null2.c common.c common.h
 setnull_SOURCES	=	setnull.c common.c common.h
+numeric_SOURCES =	numeric.c common.c common.h
 
 AM_CPPFLAGS	= 	-DFREETDS_SRCDIR=\"$(srcdir)\" -I$(top_srcdir)/include
 if MINGW32
Index: freetds83/src/dblib/unittests/.cvsignore
===================================================================
--- freetds83.orig/src/dblib/unittests/.cvsignore
+++ freetds83/src/dblib/unittests/.cvsignore
@@ -45,4 +45,5 @@ hang
 null
 null2
 setnull
+numeric
 
Index: freetds83/src/dblib/unittests/numeric.sql
===================================================================
--- /dev/null
+++ freetds83/src/dblib/unittests/numeric.sql
@@ -0,0 +1,12 @@
+IF OBJECT_ID('testDecimal') IS NOT NULL DROP PROC testDecimal
+go
+CREATE PROCEDURE testDecimal
+  @idecimal NUMERIC(20,10)
+AS
+BEGIN
+	SELECT @idecimal
+END
+go
+IF OBJECT_ID('testDecimal') IS NOT NULL DROP PROC testDecimal
+go
+
Index: freetds83/src/dblib/unittests/numeric.c
===================================================================
--- /dev/null
+++ freetds83/src/dblib/unittests/numeric.c
@@ -0,0 +1,88 @@
+#define MSDBLIB 1
+#include "common.h"
+
+int
+main(int argc, char **argv)
+{
+	LOGINREC *login;
+	DBPROCESS *dbproc;
+	DBNUMERIC *numeric;
+	RETCODE ret;
+
+	read_login_info(argc, argv);
+
+	login = dblogin();
+
+	DBSETLUSER(login, USER);
+	DBSETLPWD(login, PASSWORD);
+	DBSETLAPP(login, "numeric");
+	dbsetmaxprocs(25);
+	DBSETLHOST(login, SERVER);
+
+	dbproc = dbopen(login, SERVER);
+	if (strlen(DATABASE))
+		dbuse(dbproc, DATABASE);
+
+	sql_cmd(dbproc);
+	dbsqlexec(dbproc);
+	while (dbresults(dbproc) != NO_MORE_RESULTS) {
+		/* nop */
+	}
+
+	sql_cmd(dbproc);
+	dbsqlexec(dbproc);
+	while (dbresults(dbproc) != NO_MORE_RESULTS) {
+		/* nop */
+	}
+
+	ret = dbcmd(dbproc,
+		    "SET ARITHABORT ON;"
+		    "SET CONCAT_NULL_YIELDS_NULL ON;"
+		    "SET ANSI_NULLS ON;"
+		    "SET ANSI_NULL_DFLT_ON ON;"
+		    "SET ANSI_PADDING ON;"
+		    "SET ANSI_WARNINGS ON;"
+		    "SET ANSI_NULL_DFLT_ON ON;"
+		    "SET CURSOR_CLOSE_ON_COMMIT ON;"
+		    "SET QUOTED_IDENTIFIER ON");
+	printf("%d\n", ret);
+	ret = dbsqlexec(dbproc);
+	printf("%d\n", ret);
+
+	ret = dbcancel(dbproc);
+	printf("%d\n", ret);
+
+	ret = dbrpcinit(dbproc, "testDecimal", 0);
+	printf("%d\n", ret);
+
+	numeric = (DBDECIMAL *) malloc(sizeof(DBDECIMAL));
+	numeric->scale = 5;
+	numeric->precision = 6;
+#ifdef DBNTWIN32
+	numeric->sign = 0;
+	numeric->val[0] = 1;
+	numeric->val[1] = 2;
+	numeric->val[2] = 3;
+	numeric->val[3] = 4;
+	numeric->val[4] = 5;
+#else
+	numeric->array[0] = 5;
+	numeric->array[1] = 1;
+	numeric->array[2] = 2;
+	numeric->array[3] = 3;
+	numeric->array[4] = 4;
+	numeric->array[5] = 5;
+#endif
+
+	ret = dbrpcparam(dbproc, "@idecimal", 0, SYBDECIMAL, -1, sizeof(DBDECIMAL), (BYTE *) numeric);
+	printf("%d\n", ret);
+	ret = dbrpcsend(dbproc);
+	printf("%d\n", ret);
+	ret = dbsqlok(dbproc);
+	printf("%d\n", ret);
+
+	sql_cmd(dbproc);
+
+	printf("Succeed: %d\n", SUCCEED);
+	return 0;
+}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.