Linked Stored Procedure Query in Ensemble 2017.2.1
I have generated a class using the linked procedure wizard however I can't get it to work if the datatype of one of the parameters is VARCHAR(MAX). It works fine if I change it to say VARCHAR(500) and rerun the stored procedure wizard.
I get the following error returned.:
ErrorMsg: SQLState: (07002) NativeError: [0] Message: [Microsoft][ODBC SQL Server Driver]COUNT field incorrect or syntax error
Can anyone see what I am doing wrong? I think it is to do with the way I am using the %Stream.GlobalCharacter? Any help is much appreciated.
Class generated by linked procedure wizard:
Include %occInclude /// Class dbo.spTIETest [ Not ProcedureBlock ] { ClassMethod spTIETest(ObjectName As %String(MAXLEN=200), NamespaceName As %String(MAXLEN=50), CacheVersion As %String(MAXLEN=500), RawData As %Stream.GlobalCharacter) As %Integer [ ProcedureBlock = 1, ReturnResultsets, SqlName = spTIETest, SqlProc ] { if '$isobject($g(%sqlcontext)) s %sqlcontext=##class(%Library.ProcedureContext).%New() s RETURNVALUE=$g(RETURNVALUE) s ObjectName=$g(ObjectName) s NamespaceName=$g(NamespaceName) s CacheVersion=$g(CacheVersion) s RawData=$g(RawData) s hdbc=$$GetConnection^%apiGTW("TestTIEUserProd") if hdbc="" { set %msg=$$$ERROR($$$GTWCConnectionError),%msg=$$GetErrorText^%apiOBJ(%msg) goto setError } s QHandle=$zf(-5,%SQLGateway,5,hdbc) if QHandle="" { set %msg=$$$ERROR($$$GTWCAllocationError),%msg=$$GetErrorText^%apiOBJ(%msg) goto setError } s err=$zf(-5,%SQLGateway,$s(%SQLGateway("-uv"):37,1:3),QHandle,"{?=call dbo.""spTIE_InsertTIE_OBJECT_EXPORT""(?,?,?,?)}") i err g getError s err=$zf(-5,%SQLGateway,62,QHandle,1,4,1,4,10,0,10) s err=$zf(-5,%SQLGateway,62,QHandle,2,1,1,12,200,0,200) s err=$zf(-5,%SQLGateway,9,QHandle,$lb(ObjectName),2) i err g getError s err=$zf(-5,%SQLGateway,62,QHandle,3,1,1,12,50,0,50) s err=$zf(-5,%SQLGateway,9,QHandle,$lb(NamespaceName),3) i err g getError s err=$zf(-5,%SQLGateway,62,QHandle,4,1,1,12,500,0,500) s err=$zf(-5,%SQLGateway,9,QHandle,$lb(CacheVersion),4) i err g getError s err=$zf(-5,%SQLGateway,62,QHandle,5,1,$s(%SQLGateway("-uv")&&$zbitget($zversion(0),1):-8,1:1),12,0,0,-2) s err=$zf(-5,%SQLGateway,4,QHandle) i err=99 s lerr=$zf(-5,%SQLGateway,55,QHandle) s err=$li(lerr) i err=99 s err=$$setStream^%apiGTW(QHandle,RawData,0,1) i err g getError s %ROWCOUNT=$zf(-5,%SQLGateway,31,QHandle) set tConnection = ##class(%Library.SQLGatewayConnection).%New() set tConnection.DLLHandle = %SQLGateway, tConnection.ConnectionHandle = hdbc set rrs = ##class(%SQL.Gateway.ODBCResultSet).%New(tConnection,QHandle) while $Isobject(rrs) { if rrs.%GetMetadata().columnCount do %sqlcontext.AddResultSet(##class(%ResultSet.Static).%New(rrs)) set rrs = tConnection.getNextResultSet(QHandle) } s RETURNVALUE=$li($zf(-5,%SQLGateway,22,QHandle,1)) setError ; If ($g(%sqlcontext)'=$$$NULLOREF) { Set %sqlcontext.%SQLCODE = $g(err) Set %sqlcontext.%Message = $g(%msg) Set %sqlcontext.%ROWCOUNT = $g(%ROWCOUNT) w "ErrorMsg: "_%sqlcontext.%Message,! } s err=$zf(-5,%SQLGateway,16,QHandle) QUIT $g(RETURNVALUE) getError ; set %msg=$li($zf(-5,%SQLGateway,12,hdbc,QHandle)) goto setError } }
Code I am using to call the method from terminal:
Set OBJECT = "UHSM.LPI.LinkedTable.LPIGPPractice" Set NAMESPACE = "WYTTEST" Set CACHEVERSION = "Cache for Windows (x86-64) 2017.2.1 (Build 801U) Wed Dec 6 2017 09:07:51 EST" Set RAWDATA = ##class(%Stream.GlobalCharacter).%New() Do RAWDATA.Write("RawData") Set sc = ##class(dbo.spTIETest)."spTIETest"(OBJECT,NAMESPACE,CACHEVERSION,.RAWDATA)
Thanks,
Graham
What type of database is the stored procedure on? If it is Microsoft have you tried VARCHAR(8000)? MAX does not exist in some SQL languages so sometime you have to limit it down to the number of bytes I believe. Though I might be wrong.
Thanks Scott, It's SQL Server 2016. Yes 8000 works fine but when I change it to be 8001 the class generated by the link procedure wizard changes the parameter to be %Stream.GlobalCharacter instead of %String. It then no longer works.
Thanks Eduard, I am trying to implement your suggestion but not sure how to get the the PutData method to work. Do you have any examples? I have used the BindParameter and SetParameter methods on the first 3 parameters I am passing to the SQL stored procedure but want to use this method to pass the steam (as this appears to be what you need to do for a varchar(max) parameter)
Have you tried to set it back to %String manually?
There should be no issue from Ensemble side
Thanks Robert, When I do this I get the following ODBC error:
ErrorMsg: SQLState: (HY104) NativeError: [0] Message: [Microsoft][ODBC SQL Server Driver]Invalid precision value
I will give Eduard's approach a try and ditch the code generated by the wizard.
1. If you replace:
with:
or with:
What do you get?
2. Also in your original 4-parameter generated code the stream is bound via:
which is equal to
In your new code you bind the stream with:
Is it from some other generated code?
Thanks Eduard,
Your help is much appreciated.
The code generated by the wizard for this parameter is below:
s err=$zf(-5,%SQLGateway,62,QHandle,5,1,$s(%SQLGateway("-uv")&&$zbitget($zversion(0),1):-8,1:1),12,0,0,-2)
s err=$zf(-5,%SQLGateway,4,QHandle)
i err=99 s lerr=$zf(-5,%SQLGateway,55,QHandle) s err=$li(lerr)
i err=99 s err=$$setStream^%apiGTW(QHandle,RawData,0,1)
I then mapped the following:
s err=$zf(-5,%SQLGateway,62,QHandle,5,1,$s(%SQLGateway("-uv")&&$zbitget($zversion(0),1):-8,1:1),12,0,0,-2)
To in my revised code. I am not sure what the -2 or the "$s(%SQLGateway("-uv")&&$zbitget($zversion(0),1):-8,1:1)" means
I then noticed that this generated the following error:
(HY104) NativeError: [0] Message: [Microsoft][ODBC SQL Server Driver]Invalid precision value
I therefore revised it to the following as I am not sure what you need to pass for these parameters for a varchar(max) datatype:
I then tried this code:
However this resulted in the following error:
(HY010) NativeError: [0] Message: [Microsoft][ODBC Driver Manager] Function sequence error
I then tried this code:
set sc = gc.SetParameter(hstmt,$LB("TEXT"),2)
This worked and the value TEXT was stored in the database.
However when I pass another line of text as below the value in the database gets overwritten instead of appended to:
Do you know why this could be? Is it to do with how I have used BindParameter and that I am using SetParameter instead of PutData?
You need to set the whole value at once with SetParameter.
If you mean different procedure calls than you need to debug the procedure itself.
Not sure if this will help but I was having problems to connect to a database in ensemble. I needed to call a store procedure and one of the problems was because of the input variables was a VARCHAR(MAX).
Have a look in case it can help... Post
Thanks, however I still can't get it to work. All I keep getting is the following error:
SQLState: (07002) NativeError: [0] Message: [Microsoft][ODBC SQL Server Driver]COUNT field incorrect or syntax error
I think I must be doing something fundamentally wrong as I am fairly new to object script. Below is my revised code. To simplify things I have created a new stored procedure in a Microsoft SQL Server database with one input parameter of type varchar(max).
Any help would be much appreciated.
Set pDSN="Test dsn"
Set usr="testuser"
Set pwd="testpwd"
Set sc=gc.Connect(pDSN,usr,pwd,0)
Set sc=gc.AllocateStatement(.hstmt)
Set pQuery= "{? =call dbo.""spTIE_TestTable""(?)}"
Set sc=gc.Prepare(hstmt,pQuery)
Set sc=gc.BindParameter(hstmt,1,4,1,4,10,0,10)
Set sc=gc.BindParameter(hstmt,2,1,1,12,0,0,-2)
Set RAWDATA = ##class(%Stream.GlobalCharacter).%New()
Do RAWDATA.Write("RawData")
set temp = RAWDATA.Read(16000)
set sc=gc.SetParameter(hstmt,$LB(gc.PutData(hstmt,.temp)),2)
set sc=gc.Execute(hstmt)
set sc=gc.Disconnect()
The call to
Is roughly equal to:
Examples are available in EnsLib.SQL.Common class:
Maybe remove $zf calls?
Here's sample code:
Check BindParameter method and EnsSQLTypes for SQL types macro definitions. Varchar maybe.
You can also try to call PutData method and similar methods (by passing parts of stream there).