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.
Vitaliy Serdtsev · Aug 20, 2021 go to post

Why not use numeric codes?

$ascii("á") = 225

set s1=$zconvert("Fl&aacute;vio","I","HTML"),     s2=$zconvert("Fl&#225;vio","I","HTML")     write s1,$select(s1=s2:" = ",1:" <> "),s2

Vitaliy Serdtsev · Apr 30, 2021 go to post

How do you count "Count"? Why is "Northwest" 1 instead of 2 for 2021?


For now so:
select v.Branchnvl(sum(%FOREACH(v.Branch)),0) "Count" from 
  (
  select 'Northwest' Branch,$listbuild('Northern','Western'Branches union
  select 'Oriental',$listbuild('Eastern'union
  select 'Southern',$listbuild('Southern')
  ) v
left join
  (select replace(%exact(Branch),' branch',''Branch,count(%FOREACH(Branch)) from yourtable where year("Date")=2021 group by Branchm
on m.Branch %inlist v.Branches
group by v.Branch

Vitaliy Serdtsev · Apr 29, 2021 go to post

You are implicitly using %Library.SqlQuery:Func() method, in which, as @Robert Cemper rightly pointed out, $get() is used.

You can do it differently:

Query GetInfo(pObject AS Kurro.MyClassAs %SQLQuery(CONTAINID 1ROWSPEC "IdList:%String,IdProcess:%String,Duration:%String") [ SqlProc ]
{
    SELECT IdListIdProcessDuration
    FROM Kurro.MyClass
    WHERE KeyProcess :pObject.KeyProcess
    AND CodeSpecialist :pObject.CodeSpecialist
    AND CodeProvider :pObject.CodeProvider
    AND CodeCenter :pObject.CodeCenter
    AND "Date" :pObject.Date
}

set obj=##class(Kurro.MyClass).%New() set obj.KeyProcess="1033004-1#" set obj.CodeSpecialist "surgery" set obj.CodeProvider "PR002" set obj.CodeCenter "CENTER-01" set obj.Date $ZDATETIME($ZDATETIMEH("2021-04-30 15:45:00",3,1),3,1)

set st=##class(%SQL.Statement).%New() set sc=st.%PrepareClassQuery("Kurro.MyClass","GetInfo")   if $$$ISERR(sc{write "%PrepareClassQuery failed:" do $System.Status.DisplayError(scquit} set result=st.%Execute(obj) do result.%Display()

Vitaliy Serdtsev · Apr 29, 2021 go to post

I don't quite understand what you want to get.

If in the forehead, then so:

Select v.valueIdm.name 
 From (Select valueId Union Select Union Select Union Select Union Select 5) v
     left Join otherTable m
        on m.id v.valueId

But you can achieve the same thing more easily through IN or %INLIST.

Vitaliy Serdtsev · Apr 16, 2021 go to post

You can easily do this by replacing two values in the registry.
Just checked on Caché & IRIS: SMP and Terminal (##class(%SYS.System).GetInstanceName()) displays the new instance name.
Upgrade/Deinstall work fine too.

If desired, you can also replace the service names (private Apache, etc.).

Vitaliy Serdtsev · Apr 15, 2021 go to post

You don't need to grant rights to the users whose properties you want to get.

Access rights (resource %DB_CACHESYS:R) you need to give the user from which your GetUserInfo method will run.

Vitaliy Serdtsev · Apr 14, 2021 go to post

There's clearly something wrong with the settings here. What web server do you use, did you configure something in the CSP Gateway? Is the error reproduced when accessing (edit&compile) pages from USER/SAMPLES (of course, if you have them installed)?

Vitaliy Serdtsev · Apr 13, 2021 go to post

If you use Studio to edit/compile *.csp files, check the following parameters:

  • Enable service status check (Recommended) (yes)
  • Studio is active application (2–60 sec) (5)
  • Studio is background application (30–600 sec) (60)
  • Automatically reload document when it is modified on the server and it has not been edited in Studio (yes)
And also see Caché Launcher (Cube) settings : Web Server IP Address / CSP Server Instance


I tried to simply edit the file in Studio (csp/samples/redirect.csp) and with an external editor FAR Manager ([CACHEROOT]\CSP\samples\redirect.csp) For simplicity, I changed the comment in the header. I tested everything both locally and remotely.

So, I change it in Studio - the changes are immediately visible in FAR, I change it in FAR - the changes are immediately visible in Studio. Or in another way: I change it locally - the changes are immediately visible on the remote machine, I change it on the remote machine - the changes are immediately visible locally.

In other words, there is no and cannot be any desynchronization, since the work is always done with the same file on the server, see Saving a CSP File.

Vitaliy Serdtsev · Apr 12, 2021 go to post

Important:
Jobbed Process Permissions are Platform-dependentRunning Programs or System Commands with $ZF(-100)

So that we speak the same language, I made a simple example using Using the Work Queue Manager

Class dc.test Abstract ]
{

ClassMethod MyJob(SDIR As %String)
{
  FILE=##class(%File).NormalizeFilename("DIRLIST.TXT",SDIR)

  q:##class(%File).GetFileSize(FILE)>0

  ##class(%File).Delete(FILE)

  X=$ZF(-1,$$$FormatText("DIR %1 >> %2",$$$quote(##class(%File).NormalizeDirectory(SDIR)),$$$quote(FILE)))
}

/// d ##class(dc.test).test()
ClassMethod test()
{
  N=4
  queue=$system.WorkMgr.Initialize(,.sc,N)
  i=1:1:queue.Queue("##class(dc.test).MyJob","C:\Temp\test "_i)
  queue.WaitForComplete()
}

}

I copied different files to the following directories:

C:\Temp\test 1
C:\Temp\test 2
C:\Temp\test 3
C:\Temp\test 4

After calling ##class(dc.test).test() , everything worked out as expected: DIRLIST.TXT were created in the corresponding directories each with its own content.

Vitaliy Serdtsev · Apr 12, 2021 go to post

You can still avoid code duplication.
To do this, you need to make a function, and already use it in query.

For example:

/// Linked Funds via Person->Fund link
ClassMethod LinkedFundsByPerson(personId As %IntegerAs %Boolean SqlName CUSTOM_MyQuerySqlProc ]
{
  &sql(SELECT NULL FROM QUASAR_Core_Client.Client AS Client
      INNER JOIN QUASAR_KYC_Fund.Fund AS Fund ON Client.Number=Fund.InternalReference
      LEFT JOIN QUASAR_GDPR_Close_Fund.FundClosure As FundClosure ON Client.Number=FundClosure.ID
    WHERE Client.ClientMarketIndicator='C'
    AND Client.Number IN
    (
    SELECT Client
    FROM QUASAR_KYC_Person.FundLink
    WHERE Person->InternalReference=:personId
    )
  )
  QUIT ''%ROWCOUNT
}

SELECT * FROM TableA WHERE CUSTOM_MyQuery(ID)>0
Vitaliy Serdtsev · Apr 12, 2021 go to post

You can't pass IDENTIFIER to class query, but only LITERALS. This is akin to error 5262:

Cannot project query with parameters '%1' as view

Here is a simple demo of this issue:

Class dc.test Extends %Persistent
{

Property As %Integer;

Query LinkedFundsByPerson(As %IntegerAs %SQLQuery(ROWSPEC "p:%Integer") [ SqlName CUSTOM_MyQuerySqlProc ]
{
SELECT FROM dc.test
where ID IN
(
SELECT ID
FROM dc.test
WHERE p=:p
)
}

ClassMethod test()
{
  &sql(SELECT * FROM dc.test WHERE EXISTS (SELECT * FROM dc.CUSTOM_MyQuery(ID)))
}

}