Vitaliy Serdtsev · Oct 15, 2021 go to post

ClassMethod testvalidator(
  class As %String,
  value As %StringAs %Status
{
 set validator "(out){set out = ##class("class").IsValid("""value""")}"
 xecute (validator,.sc)

 write sc,!  quit sc }

Vitaliy Serdtsev · Oct 15, 2021 go to post

Use $CLASSMETHOD and you won't have such issues:


USER>set sc=$CLASSMETHOD("%Numeric","IsValid","BLAH")

or

ClassMethod testvalidator(class As %Stringvalue As %StringAs %Status
{
 set sc=$CLASSMETHOD(class,"IsValid",value)
 write sc,!
 quit sc
}
Vitaliy Serdtsev · Oct 15, 2021 go to post
Set object ##class(%ZEN.proxyObject).%New()
set object.city "New York"
set object.Target "TEST" 
set object.Details "TEST"
set object.RefCode "123"
set object.Reason "123TTTT"

set string=object.%Serialize()

;write string,!

set anotherObj=##class(%ZEN.proxyObject).%New()
do anotherObj.%ZENDeserialize(string)

write anotherObj.Reason ; ==> 123TTTT
Vitaliy Serdtsev · Oct 11, 2021 go to post

codemode = code:

ClassMethod AddWater(
  s,
  = {$lb("",1,22,333,4444,55555,666666,7777777,88888888,999999999)},
  ""As %String
{
 i=1:1:$l(sr=r_$li(t,$e(s,i)+1)
 r
}

codemode = expression:

ClassMethod AddWater(
  s,
  = {"" r="" i=1:1:$l(st=$e(s,is:t r=r_$tr($j(t,t)," ",t)}) As %String CodeMode = expression ]
{
r
}

Required mapping ISCDC.inc from CACHESYS:

Include ISCDC

Class dc.test Abstract ]
{

ClassMethod AddWater(sAs %String
{
  i=$l(s):-1:1 t=$e(s,i),$e(s,i)=$$DC(t,t)
  s
}

}
Vitaliy Serdtsev · Oct 6, 2021 go to post

Those experienced with encryption systems for databases may have concerns about encryption having dire effects on performance, but, with Caché, these concerns are unfounded. Encryption and decryption have been optimized, and their effects are both deterministic and small for any Caché platform; in fact, there is no added time at all for writing to the database.

Managed Key Encryption: Protecting Data on Disk

InterSystems recommends using its encryption management tools:
  • When built-in hardware instructions are available for encryption-related activities, these activities are considerably faster then when using software-based encryption. The encryption management tools use hardware instructions when they are available.
  • The encryption management tools can use keys stored on a KMIP server.
  • The encryption management tools can run in FIPS mode.
About Encryption Management Operations

High-Performance Encryption for Databases in Financial Services (PDF)

Vitaliy Serdtsev · Oct 4, 2021 go to post

But in new Native API for IRIS there are no proxies, just class methods/functions are called from app and I think, it should be pretty the same as calling this methods/functions from terminal window.
Introduction to the Native API

Using .NET Reverse Proxy Objects

The Native API allows you to create instances of ObjectScript classes on InterSystems IRIS and generate Object Gateway proxy objects for them at runtime. Your .NET application can use proxies to work with ObjectScript objects as easily as if they were native .NET objects.

Vitaliy Serdtsev · Oct 4, 2021 go to post

Yes, most likely this is a feature of the API. Here's what I found about it in the "old" documentation:

In some situations, caching may not be desirable. For example, if an object is opened with Concurrency Level 4 (Exclusive Lock), the lock will not be released until the next server call. To destroy the object immediately, you can call Close() with the optional useCache parameter set to false

Closing Proxy Objects

PS: by the way, for ActiveX, Factory.ForceSync() method serves the same purpose.

Vitaliy Serdtsev · Sep 30, 2021 go to post

I did a test and that's what found out.
It is assumed that the data has already been generated.

COS

Class dc.test Extends %Persistent
{

ClassMethod Checking(CardNo As %StringAs %String
{
  tmp=..%OpenId(CardNo,4)
  "test"
}

}

If executed from the terminal, the lock is removed automatically immediately after the method is completed:

USER>##class(dc.test).Checking("1")
test

C#

// ...
string json = iris.ClassMethodString("dc.test""Checking""1");
 
// here the lock is still present
 
db.ReleaseIRISObjects(); // or iris.ReleaseAllLocks();
 
// here already more is no lock
Vitaliy Serdtsev · Sep 29, 2021 go to post

  1. ProcedureBlock does not apply to your issue at all
  2. you didn't initially indicate that the issue is with C#
  3. use ReleaseIRISObjects

    Example:

    IRISConnection db; IRIS iris; IRISObject person;   // ...   using (person = (IRISObject)iris.ClassMethodObject("Sample.Person""%OpenId""1""4")) {   }   /* or   person = (IRISObject)iris.ClassMethodObject("Sample.Person", "%OpenId", "1", "4") person.Dispose(); person = null; */   db.ReleaseIRISObjects();

Vitaliy Serdtsev · Sep 29, 2021 go to post

And if so?

ClassMethod TestLock() As %Status
{
    New id,obj

    Set id $Order(^ZUser.NewClass1D(""))
    If id "" {
        Set obj ##class(ZUser.NewClass1).%New()
        Do obj.%Save()
    }

    Set id $Order(^ZUser.NewClass1D(""))

    Set obj ##class(ZUser.NewClass1).%OpenId(id, 4)

    ; in case of usage Not ProcedureBlock you should 
    ; kill obj or set obj="" (and all others variables with this object reference) to release the lock

    Return $$$OK
}
Vitaliy Serdtsev · Sep 29, 2021 go to post

COS:

Class dc.DPasarela Extends %RegisteredObject
{

Property STREAM As %Stream.TmpBinary;

Method PostMsg()
{
  s=$tr($j("",$$$MaxStringLength)," ",$c(0))

  i=1:1:5 ..STREAM.Write(s)
}

}

C#

IRISObject STREAM;
MemoryStream stream = new MemoryStream();
string len1, len2;
 
IRISObject pasarela = (IRISObject)iris.ClassMethodObject("dc.DPasarela""%New");
 
pasarela.InvokeVoid("PostMsg");
 
STREAM = (IRISObject) pasarela.Get("STREAM");
 
while (!Convert.ToBoolean(STREAM.GetBool("AtEnd")))
{
	stream.Write(STREAM.InvokeBytes("Read"3641144),03641144);
}
 
len1 = STREAM.GetString("Size"); // 18205720 (3641144*5)
len2 = stream.Length.ToString(); // 18205720 (3641144*5)
 
// =========== AGAIN ===========
 
STREAM.InvokeVoid("MoveToEnd");
 
pasarela.InvokeVoid("PostMsg");
 
stream.SetLength(0);
 
while (!Convert.ToBoolean(STREAM.GetBool("AtEnd")))
{
	stream.Write(STREAM.InvokeBytes("Read"3641144)03641144);
}
 
len1 = STREAM.GetString("Size"); // 36411440 (18205720*2)
len2 = stream.Length.ToString(); // 36411440 (18205720*2)
 
byte[] bytesS = stream.ToArray();
Vitaliy Serdtsev · Sep 29, 2021 go to post

COS:

Class dc.DPasarela Extends %RegisteredObject
{

Property Value As %Numeric;

Property Title As %String;

Property Message As %String;

Property STREAM As %Stream.TmpCharacter;

Method PostMsg(
  SessionId As %String,
  Msg As %String,
  bytesS As %Binary,
  STREAMin As %Stream.TmpCharacter,
  Output STREAMout As %Stream.TmpCharacter)
{
  set ..Value = 5,
      ..Title SessionId,
      ..Message Msg_" "_bytesS
  
  do:$IsObject(STREAMin) ..STREAM.CopyFrom(STREAMin)
  
  set STREAMout=##class(%Stream.TmpCharacter).%New()
  do STREAMout.Write("bla-bla-bla")
}

}

C#:

IRISObject pasarela = (IRISObject)iris.ClassMethodObject("dc.DPasarela""%New");
 
byte[] bytesS = new byte[3]; // In real world this is a BASE64 encoded JSON
bytesS[0] = 233; // é
bytesS[1] = 234; // ê
bytesS[2] = 59; // ;
 
IRISReference refSTREAMout = new IRISReference(null);
 
IRISObject STREAMin = (IRISObject)iris.ClassMethodObject("%Stream.TmpCharacter""%New");
STREAMin.InvokeString("Write","blablabla");
 
pasarela.InvokeVoid("PostMsg""aSession""aMsg", bytesS, STREAMin, refSTREAMout);
 
int aValue = Convert.ToInt32(pasarela.GetLong("Value")); // 5
string aTitle = pasarela.GetString("Title"); // aSession
string aMessage = pasarela.GetString("Message"); // aMsg éê;
string aSTREAMout = ((IRISObject)refSTREAMout.value).InvokeString("Read"); // bla-bla-bla
string aSTREAM = ((IRISObject)pasarela.GetObject("STREAM")).InvokeString("Read"); // blablabla
Vitaliy Serdtsev · Sep 28, 2021 go to post

and second, I would like to read the doc everywhere! For example, I have a 10 hour flight, and want to work. And in case, a server only has a local LAN access, then you have no docu!).
I fully support it. But I'm afraid now, apart from reading the documentation in PDF format, you can forget about local documentation ("DOCBOOK" database) with normal search and navigation. It's a pity..

Vitaliy Serdtsev · Sep 27, 2021 go to post

No. I couldn't find how to do this in the documentation (probably I searched badly), so I don't publish here undocumented features anymore. But you can easily determine this from the source code.

Vitaliy Serdtsev · Sep 27, 2021 go to post

Yes. By default, a strictly defined list of packages/classes is displayed in IRIS for security purposes, but you can change this behavior locally.

Vitaliy Serdtsev · Sep 27, 2021 go to post

Or so:

set tmp ##class(%IO.StringStream).%New()
do tmp.Write("This is my text")

do tmp.Seek(11)

do tmp.Write(" NEW")

do tmp.Rewind()
write tmp.Read(tmp.Size;This is my NEW text
Vitaliy Serdtsev · Sep 23, 2021 go to post

See %SQL.StatementResult:%DisplayFormatted()

Simple sample (for namespace "SAMPLES"):

set st ##class(%SQL.Statement).%New(2,"Sample")
set sql = 3
set sql(1) = "select TOP 5 %ID as id, Name, DOB, Home_State"
set sql(2) = "from Person where Age > 40"
set sql(3) = "order by 2"
do st.%Prepare(.sql)
for type="txt","pdf","csv","html","xml" {
  set rs st.%Execute()
  do rs.%DisplayFormatted(type,"C:\Temp\report")
}

As a result, the following files are generated:

report.csv
report.html
report.pdf
report.txt
report.xml
Vitaliy Serdtsev · Sep 17, 2021 go to post

Instead of

set str=$e(str,1,*-1)

, will be a little faster

set $e(str,*)=""

But this is already saving on matches.

PS: for the sake of interest, I checked on a special version of Caché (very old) with server-side JavaScript (not to be confused with Node.js)

 

Source code

Include %occInclude

Class dc.test Abstract ]
{

ClassMethod MakeStringOnJS(N) [ Language = javascript]
{
  var myval="a", arr=[], stop, str, start=(new Date()).getTime();
  
  for (var i=0;i<N;i++) arr[i]=myval;
  
  str=arr.join();
  
  stop=(new Date()).getTime();
  
  Cache.Console.WriteLine("[JavaScript] execution: ",stop-start,"(ms) len(str): ",str.length);
  
  // Force a Garbage Collection
  Cache.Class.$JavaScript_Runtime.$GarbageCollect();
  
}

ClassMethod MakeStringOnCOS(N)
{
  myval="a",
    str="",
    
    time=$zh
  
  f i=1:1:str=str_myval_","
  
  s $e(str,$l(str))="" ; not supported $e(str,*)

  w $$$FormatText("[COS] execution: %1(ms) len(str): %2",$zh-time*1000,$l(str)),!
}

/// d ##class(dc.test).Test()
ClassMethod Test(10)
{
  ..MakeStringOnJS(N),
    ..MakeStringOnCOS(N)
}

}
USER>##class(dc.test).Test(1800000)
[JavaScript] execution: 99(ms) len(str): 3599999
[COS] execution: 126.683(ms) len(str): 3599999

By the way, the JS code has almost no limit on the string size.

Vitaliy Serdtsev · Sep 17, 2021 go to post
 

An example without complex formulas and very fast

Include %DeepSee

Class dc.test Abstract ]
{

ClassMethod FirstLastDayMonth(
  year 2015,
  month 2)
{
  mm=$$$iscPadZero(month,2),
  
    firstDay=$zdh(year_mm_"01",8),
    lastDay=$zdh(year_mm_$$$iscDaysInMonth(year,month),8),
  
    firstDayName=$zd(firstDay,12,,,,,,,,1),
    lastDayName=$zd(lastDay,12,,,,,,,,1)
    
  w $$$FormatText("firstDay = %1 (%2), lastDay = %3 (%4)",$zd(firstDay),firstDayName,$zd(lastDay),lastDayName),!
}

/// d ##class(dc.test).Test()
ClassMethod Test()
{
  ..FirstLastDayMonth(2015,2),
    ..FirstLastDayMonth(2021,9)
}

}

USER>##class(dc.test).Test()

firstDay = 01.02.2015 (Sunday), lastDay = 28.02.2015 (Saturday)

firstDay = 01.09.2021 (Wednesday), lastDay = 30.09.2021 (Thursday)

Vitaliy Serdtsev · Sep 15, 2021 go to post

Simple sample:

Class dc.test Extends %ZEN.Component.page
{

XData Contents [ XMLNamespace "http://www.intersystems.com/zen" ]
{
<page xmlns="http://www.intersystems.com/zen">
  <tablePane
    id="tp"
    sql="select ID,'Western branch' Branch,{'2021-03-15'&quot;Date&quot;,35 Suma
    union
    select 2,'Eastern branch',{'2020-12-11'},37"
  />
  <button caption="Row unselect" onclick="zenPage.rowUnselect()"/>
</page>
}

ClientMethod rowUnselect() [ Language = javascript ]
{
  var tp=zen('tp');
  row=tp.selectedIndex;

  if (tp.rowSelect && row>=0) {
    var old=tp.enableToggleSelect;

    tp.enableToggleSelect=true;
    tp.selectRow(row);
    tp.enableToggleSelect=old;
  }
}

}
Vitaliy Serdtsev · Sep 15, 2021 go to post

I also will insert my five kopecks.

  • The %Library package also includes stream classes, but those are deprecated. The class library includes additional stream classes, but those are not intended for general use.
    Working with Streams

    I have %Stream.FileCharacter was an order of magnitude faster than %[Library.]File

  • If you rewrite the line-by-line reading to read blocks with further parsing of lines, the speed will more increase by an order of magnitude.
     

    Sample

    Class dc.test Abstract ]
    {
    
    ClassMethod ReadCSVStream(fCSV As %StringAs %String
    {
      stream ##class(%Stream.FileCharacter).%New()
      stream.LinkToFile(fCSV)
    
      time1=$zh
      While 'stream.AtEnd {
        line=stream.ReadLine($$$MaxLocalLength)
      }
      diff=$zh-time1
      
      diff
    }
    
    ClassMethod ReadCSVStreamBlock(fCSV As %StringAs %String
    {
      stream ##class(%Stream.FileCharacter).%New()
      stream.LinkToFile(fCSV)
    
      i=0,time1=$zh
      While 'stream.AtEnd {
        chunks($i(i))=stream.Read($$$MaxLocalLength)
        // do parsing chunk to lines
      }
      diff=$zh-time1
      
      diff
    }
    
    ClassMethod ReadCSVOURC(fCSV As %StringAs %String
    {
      fCSV::1 
      e  q "Missing File"
    
      eof=$zu(68,40,1)
      fCSV
    
      time1=$zh 
      f  {
        line
        q:$zeof
        // do something with line
    
      }
      diff=$zh-time1
    
      fCSV
      d $zu(68,40,eof)
    
      diff
    }
    
    /// d ##class(dc.test).Test()
    ClassMethod Test()
    {
      ptr=0,
        clnm=$classname()
    
      &sql(select %dlist(Nameinto :list
           from %Dictionary.CompiledMethod
           where Parent=:clnm and Name %startswith 'ReadCSV'
           group by Parent
           order by SequenceNumber)
      
      while $listnext(list,ptr,m{
        !,"[",m,"]",?20,"execution: ",$classmethod(clnm,m,"data.csv"),!
      }
    }
    
    }
  • On the Internet, you can find a lot of materials about comparing the speed of reading files (in particular CSV) for different programming languages (Python, C/C++, R, C#, Java, etc.), for example (this is machine translation). Often, those who make such comparisons do not always know all these languages equally well, so sometimes casus happen.
     

    Who do you think in the article above was faster when reading 1e7+ lines: Fortran or C++ ?

    Fortran :)
  • If we approach the issue formally, then the advantage will be given to compiled languages, not interpreted ones, as well as the implementation that uses all the capabilities of the operating system and hardware.