[python-sybase] Re: Your test program (sp_test.py) output

Bradley Feldman bradley at relevantevidence.com
Thu, 17 Mar 2005 23:09:10 -0800


That patch worked for me.  I'm getting the output parm back now!  =
Hooray!

*Bradley

-----Original Message-----
From: python-sybase-admin@www.object-craft.com.au
[mailto:python-sybase-admin@www.object-craft.com.au] On Behalf Of Dave =
Cole
Sent: Thursday, March 17, 2005 10:38 PM
To: python-sybase@object-craft.com.au
Subject: [python-sybase] Re: Your test program (sp_test.py) output


I keep forgetting to send to the mailing list :-(.

Bradley Feldman wrote:
> Dave:
>=20
> If I run your test program (slightly modded for my environment) on=20
> FreeTDS/MS SQL, here's what I get as output:
>=20
> {'@num': 12345, '@result': <DataBufType object at 0x2a95596770>}=20
> [54321, <DataBufType object at 0x2a95596940>]
>=20
> Attached is the debug trace.  Let me know what you discover.

Extremely odd.

The parts of the log to do with calling the stored procedure are:

Cursor.callproc
ct_cmd_alloc(conn0, &cmd) -> CS_SUCCEED, cmd3

Allocated a command structure to send a command to the server.

ct_command(cmd3, CS_RPC_CMD, "sp_test_output", CS_NULLTERM, CS_UNUSED)
-> CS_SUCCEED

Start constructing the command; use an RPC command telling the server to
  execute a stored procedure.

ct_param(cmd3, &databuf0->fmt=3D[name:"@result" type:CS_INT_TYPE
status:CS_RETURN format:CS_FMT_UNUSED count:1 maxlength:4 scale:0
precision:0], databuf0->buff, 4, 0) -> CS_SUCCEED

Tell the command that we want to bind a buffer to receive a return =
parameter
(status =3D=3D CS_RETURN) called @result.

ct_param(cmd3, &databuf1->fmt=3D[name:"@num" type:CS_INT_TYPE
status:CS_INPUTVALUE format:CS_FMT_UNUSED count:1 maxlength:4 scale:0
precision:0], databuf1->buff, 4, 0) -> CS_SUCCEED

Tell the command that we have an input parameter called '@num'.  The =
value
is already in the associated buffer.

ct_send(cmd3) -> CS_SUCCEED

Send the command to the server.

ct_results(cmd3, &result) -> CS_SUCCEED, CS_STATUS_RESULT

Server says that there is some status returned.  We fetch this and =
discard
it.

ct_res_info(cmd3, CS_NUMDATA, &value, CS_UNUSED, NULL) -> CS_SUCCEED, 1
ct_describe(cmd3, 1, &fmt) -> CS_SUCCEED, datafmt0=3D[name:"" =
type:CS_INT_TYPE
status:CS_FALSE format:CS_FMT_UNUSED count:1 maxlength:4 scale:0
precision:0] ct_bind(cmd3, 1, &datafmt0->fmt=3D[name:"" type:CS_INT_TYPE
status:CS_FALSE format:CS_FMT_UNUSED count:1 maxlength:4 scale:0
precision:0], databuf2->buff,
databuf2->copied, databuf2->indicator) -> CS_SUCCEED, databuf2
_fetch_rows
ct_fetch(cmd3, CS_UNUSED, CS_UNUSED, CS_UNUSED, &rows_read) -> =
CS_SUCCEED, 1
_fetch_rows ct_fetch(cmd3, CS_UNUSED, CS_UNUSED, CS_UNUSED, &rows_read) =
->
CS_END_DATA, 0

Status result has been fetched.  The next logs are where we get the
parameter results.

ct_results(cmd3, &result) -> CS_SUCCEED, CS_PARAM_RESULT

Server tells us to begin fetching the parameter result set.

ct_res_info(cmd3, CS_NUMDATA, &value, CS_UNUSED, NULL) -> CS_SUCCEED, 1

There is one return parameter.

ct_describe(cmd3, 1, &fmt) -> CS_SUCCEED, datafmt1=3D[name:"@result"
type:CS_INT_TYPE status:CS_FALSE format:CS_FMT_UNUSED count:1 =
maxlength:4
scale:0 precision:0]

It is called '@result' (which is what we expected).  The *really* =
strange
thing here is that the status is not CS_RETURN!!!  When I run it here =
the
status *is* CS_RETURN.  The upshot of this is that the result is ignored =
by
the code in Sybase.py

I think that a fix for this that should work all of the time is to =
change
_FetchNowParams._param_result():

     def _param_result(self):
         bufs =3D _row_bind(self._cmd, 1)
         while 1:
             status, rows_read =3D self._cmd.ct_fetch()
             if status =3D=3D CS_SUCCEED:
                 pass
             elif status =3D=3D CS_END_DATA:
                 break
             elif status in (CS_ROW_FAIL, CS_FAIL, CS_CANCELED):
                 self._raise_error(Error, 'ct_fetch')
             pos =3D -1
             for buf in bufs:
                 if buf.status & CS_RETURN:
                     if type(self._params) is type({}):
                         self._params[buf.name] =3D =
_column_value(buf[0])
                     else:
                         while 1:
                             pos +=3D 1
                             param =3D self._params[pos]
                             if (type(param) is DataBufType
                                 and param.status & CS_RETURN):
                                 break
                         self._params[pos] =3D _column_value(buf[0])

If you just remove the test for buf.status & CS_RETURN it should do the
right thing.

     def _param_result(self):
         bufs =3D _row_bind(self._cmd, 1)
         while 1:
             status, rows_read =3D self._cmd.ct_fetch()
             if status =3D=3D CS_SUCCEED:
                 pass
             elif status =3D=3D CS_END_DATA:
                 break
             elif status in (CS_ROW_FAIL, CS_FAIL, CS_CANCELED):
                 self._raise_error(Error, 'ct_fetch')
             pos =3D -1
             for buf in bufs:
                 if type(self._params) is type({}):
                     self._params[buf.name] =3D _column_value(buf[0])
                 else:
                     while 1:
                         pos +=3D 1
                         param =3D self._params[pos]
                         if (type(param) is DataBufType
                             and param.status & CS_RETURN):
                             break
                     self._params[pos] =3D _column_value(buf[0])

Let me know how it goes.

- Dave

--=20
http://www.object-craft.com.au

_______________________________________________
Python-sybase mailing list Python-sybase@www.object-craft.com.au
https://www.object-craft.com.au/cgi-bin/mailman/listinfo/python-sybase