Robert Cemper · Nov 12, 2020 go to post

To get rid of xmlns: attribute In your SOAPservice class you may try

Paramter NAMESPACE = "";
Robert Cemper · Nov 11, 2020 go to post

With MS SQL it's even easier as you can directly run ClassMethods/Procedures  written in TSQL

Robert Cemper · Nov 10, 2020 go to post

Besides the functionality and speed that you mentioned already,
there come other factors to my mind. Just a few from the hip:

  • Portability: Moving a Caché/IRIS DB from one system to the other is as easy as a file copy. And this goes across most actual operating platforms on local HW or in the cloud, from Win to *X and back
  • Flexibility: Splitting or extending your DB if you run out of disk space has no impact on the applications. Vertical or horizontally scaling is a standard feature
  • Connectivity: especially with IRIS you have a huge range of adapters and interfaces available that allow access not only by SQL but also by Objects without any need to separate the data accessed from each other.
  • Openness: You need a private SQL Function or SQL Procedure because Standards don't fit?   No problem: Just add your self modeled ClassMethod and you have it done for both SQL and Object access.  

As I mentioned already in a different place: The only limit is your own imagination.  
 

Robert Cemper · Nov 10, 2020 go to post

There is my related question Multi Language Sort  and the new extension may cover some very simple cases.

@Vitaliy Serdtsev provided an excellent solution as reply to the problem
including a detailed example of how to cover solve the issues I found
with basic features already available in Caché since almost ever(?).

Robert Cemper · Nov 9, 2020 go to post

with error trapping

/// Set value to %session.Data 
ClassMethod setValue(params...) As %Status
{
 try {
   set var=$name(%session.Data)
   for i=1:1:params-1 set var=$name(@var@(params(i)))
   set @var=$g(params(params))
   set status=$$$OK
  }
  catch { set status=$system.Status.Error(710)
  }
  quit status 
 }
Robert Cemper · Nov 9, 2020 go to post

it doesn' trap this cases yet

do ..setValue("key1", "key2", , "key4", "val")
do ..setValue("key1", "key2", "", "key4", "val")
Robert Cemper · Nov 9, 2020 go to post

did you mean that ?

/// Set value to %session.Data 
ClassMethod setValue(params...) As %Status
{
quit:params<2 0
set var="%session.Data("
for i=1:1:params-1 set var=var_"params("_i_"),"
set $e(var,*)=")"
set @var=params(params)
quit $$$OK
}
Robert Cemper · Nov 9, 2020 go to post
/// Set value to %session.Data 
ClassMethod setValue(params...) As %Status
{
 quit:params<2 0
 set var="%session.Data("
 for i=1:1:params-1 set var=var_""""_params(i)_""","
 set $e(var,*)=")"
 set @var=params(params)
 quit $$$OK
}
Robert Cemper · Nov 6, 2020 go to post

The scope and the dimension of possibilities are much wider with IRIS than it was with Caché.
Very generally speaking: There is nothing in Caché that you can't do with IRIS.
The only thing you might miss eventually, are some ancient compatibility hooks back to the previous millennium. wink
Also, support of some outdated operating system versions is gone

Robert Cemper · Nov 6, 2020 go to post

Very generally speaking: There is nothing in Caché that you can't do with IRIS.
The only thing you might miss eventually, are some ancient compatibility hooks back to the previous millennium. wink

Robert Cemper · Nov 5, 2020 go to post

In general YES.
I did it myself with preIRIS  Caché.
Data and Tables and Views and Triggers are not demanding.
Migrating Stored Procedures could take a little bit more effort.
But the ability to transform Stored Procedures to Class Methods should allow also to solve tricky situations.

(I'm personally proud that over more than a decade I never lost a benchmark against Oracle)) 

Robert Cemper · Oct 29, 2020 go to post

With your service contract WRC should be able to provide you with a kit for 2015
Once restored the DB should have no problem to upgrade.

Robert Cemper · Oct 25, 2020 go to post

Hi Jeff;

all you have to do is to set the Stream location to a  Global in *TEMP Database.
Example:
 

Ok ... so this actually works:

ClassMethod GetHL7Msg(pId As %String) As %Stream.GlobalCharacter [ SqlName = GetMsg, SqlProc ]
{
    Set tHl7 = ##class(EnsLib.HL7.Message).%OpenId(pId,,.tSC)
    Throw:$$$ISERR(tSC) ..GetErr(-400, "HL7 Message with ID "_pId_" Not Found.")
    Set tMsg = ##class(%Stream.GlobalCharacter).%New()
           SET tMsg.%Location="^mtemp.JEFF"
    Set tSC = tHl7.OutputToLibraryStream(.tMsg)
    Do tHl7.%Close()
    If tSC Set tSC=tMsg.%Save()
    Throw:$$$ISERR(tSC) ..GetErr(-400, $system.Status.GetErrorText(tSC))
    Return tMsg."%%OID"
}

>>>>>

yes

Robert Cemper · Oct 24, 2020 go to post

StreamPrefetch looks related but it is totally related to the .NET end (googled SQL prefetch in .NET), 
while <INVALID OREF> is clearly an issue @Ensemble end.
I'm not too deep in the external ODBC  world but I assume that collecting the resultset and
transmitting it to .NET  [ %SYS.SQLStreamSRV ] could happen asynchronously in different processes.
So I doubted %Stream.TempCharacter which is bound to a process private Global  vs. a standard Global visible also to other processes. And only the final %Save nails it down.
I wonder if you experience the same problem if you run your query from
terminal prompt: do $system.SQL.Shell()  
This can signal if the ODBC connection plays a role at all.

Robert Cemper · Oct 24, 2020 go to post

Jeff,
if this is still happening I suggest contacting WRC. 
They have access to the sources and more diagnostic tools.

Robert Cemper · Oct 24, 2020 go to post

%SYS.SQLStreamSRV.obj  is a deployed routine / class so we can't look into its details.
<INVALID OREF> expects a (stream) Object, but it doesn't exist.
So an additional check might be required.  Or you force some content for testing.
 

ClassMethod GetHL7Msg(pId As %String) As %Stream.TmpCharacter [ SqlName = GetMsg, SqlProc ]
{
    Set tHl7 = ##class(EnsLib.HL7.Message).%OpenId(pId,,.tSC)
    Throw:$$$ISERR(tSC) ..GetErr(-400, "HL7 Message with ID "_pId_" Not Found.")
    Set tMsg = ##class(%Stream.GlobalCharacter).%New()
    Set tSC = tHl7.OutputToLibraryStream(.tMsg)

     ;;  Throw:$$$ISERR(tSC) ..GetErr(-400, "HL7 Message with ID "_pId_" failed.") 
         IF 'tMsg.Size DO tMsg.Write("*** no message for ID:"-pId_" ***")
         SET tSC=tMsg.%Save()

    Do tHl7.%Close()
    Return tMsg
}

So you should have always a Stream Object

Robert Cemper · Oct 24, 2020 go to post

So my next try would be to add %Save  of the Stream Object before closing  tHl7

ClassMethod GetHL7Msg(pId As %String) As %Stream.TmpCharacter [ SqlName = GetMsg, SqlProc ]
{
    Set tHl7 = ##class(EnsLib.HL7.Message).%OpenId(pId,,.tSC)
    Throw:$$$ISERR(tSC) ..GetErr(-400, "HL7 Message with ID "_pId_" Not Found.")
    Set tMsg = ##class(%Stream.GlobalCharacter).%New()
    Set tSC = tHl7.OutputToLibraryStream(.tMsg)

        IF tSC SET tSC=tMsg.%Save()          

    Do tHl7.%Close()
    Return tMsg
}
Robert Cemper · Oct 23, 2020 go to post

to understand what is happening:
Do you get the same error using ?

Set tMsg = ##class(%Stream.GlobalCharacter).%New() 
Robert Cemper · Oct 18, 2020 go to post

this would be a typical exercise to use XSLT support

but for this simple case using $FIND Function in a loop may do it as well.

set a="<Name>ABC</Name><RollNo>45</RollNo><Name>XYZ</Name><RollNo>66</RollNo><Name>xyz</Name>RollNo>89</RollNo>"
set p=1
for  {
      set f=$find(a,"<RollNo>",p) quit:'f
      set t=$find(a,"<",f-1) quit:'t  set p=t-2
      set $e(a,f,p)="**"
     }
Robert Cemper · Oct 10, 2020 go to post

"there is no real advantage to having a temp table unless you are worried about storage."

"That is not as simple as the Microsoft code"

Both observations are correct.
Though there is an implementation of TSQL that mentions SELECT ... INTO explicitly
But you have to declare that your context is TSQL

but this not Cache SQL anymore as initially inquired