Vitaliy Serdtsev · Jun 27, 2019 go to post

  w $$MyFunc(1),!,
    $$MyFunc(1,.V)," V=",V,!

MyFunc(p...)   Answer=p_" params"   s:p=2 p(2)="it's all good"   Answer

USER>do ^test 1 params 2 params V=it's all good

Vitaliy Serdtsev · May 21, 2019 go to post

Can be easier:

ClassMethod GetPrivateProp(
  oref,
  propNameAs %String
{
  ##class(%Studio.General).DumpObjectExecute(.arr,oref)
  arr(propName)
}
Vitaliy Serdtsev · May 21, 2019 go to post

Date and Time Constructs

Try this:
SELECT 
LBTS_RowID
,LBTS_CollectedDate
FROM SQLUser.LB_TestSet 
JOIN SQLUser.LB_Transfer ON ($LISTBUILD(LBTS_RowID) %INLIST LBTR_TestSetList)
WHERE LBTS_CollectedDate BETWEEN {'2019-01-01'} AND {'2019-05-10'}

Vitaliy Serdtsev · May 17, 2019 go to post

Try this:

XData Contents [ XMLNamespace "http://www.intersystems.com/zen" ]
{
<page xmlns="http://www.intersystems.com/zen">
  <tableNavigatorBar tablePaneId="tp1"/>
    <tablePane
      id="tp1"
      OnCreateResultSet="CreateRS"
      OnExecuteResultSet="ExecuteRS"
      maxRows="0"
      pageSize="10"
      useSnapshot="true"
    >
    <parameter value="USER1"/>
  </tablePane>
  <tableNavigatorBar tablePaneId="tp2"/>
    <tablePane
      id="tp2"
      OnCreateResultSet="CreateRS"
      OnExecuteResultSet="ExecuteRS"
      maxRows="0"
      pageSize="10"
      useSnapshot="true"
    >
    <parameter value="USER2"/>
  </tablePane>
</page>
}
Vitaliy Serdtsev · May 17, 2019 go to post

For example so:

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

XData Style
{
<style type="text/css">
</style>
}

XData Contents [ XMLNamespace "http://www.intersystems.com/zen" ]
{
<page xmlns="http://www.intersystems.com/zen">
  <tablePane
    OnCreateResultSet="CreateRS"
    OnExecuteResultSet="ExecuteRS"
  >
    <parameter name="ns" value="USER1"/>
  </tablePane>
  <tablePane
    OnCreateResultSet="CreateRS"
    OnExecuteResultSet="ExecuteRS"
  >
    <parameter name="ns" value="USER2"/>
  </tablePane>
</page>
}

Method ExecuteRS(
  myRS As %ResultSet,
  Output pSC As %Status,
  pInfo As %ZEN.Auxiliary.QueryInfoAs %Boolean
{
  myRS.Prepare("select * from xyz")
  myRS.Execute()
  tSC=$$$OK
  q $$$YES
}

Method CreateRS(
  Output tSC As %Status,
  pInfo As %ZEN.Auxiliary.QueryInfoAs %ResultSet
{
  rs=##class(%RemoteResultSet).%New()
  rs.UserName="_system"
  rs.Password="SYS"
  rs.ConnectionString=$$$FormatText("localhost[%1]:%2",##class(%SQL.Manager.API).GetPort(),pInfo.parms(1))
  tSC=$$$OK
  q rs
}

}
Vitaliy Serdtsev · May 17, 2019 go to post

For example so:

Class myapp.jsonProvider Extends %ZEN.Auxiliary.jsonProvider
{

ClassMethod getOrderedProps(
  pClass As %Dictionary.CompiledClass,
  ByRef pList) [ Internal ]
{
  ##super(pClass,.pList)

  key "" key $o(pList(key))  q:""=key
    zk:$lf(^||skipProps,pList(key)) pList(key)
  }
}

}

Class myapp.myclass Extends %RegisteredObject
{

Property property1 As %String;

Property property2 As %String;

Property property3 As %String;

/// d ##class(myapp.myclass).Test()
ClassMethod Test()
{
  myClass = ..%New()
  myClass.property1 "value 1"
  myClass.property2 "value 2"
  myClass.property3 "value 3"
  
  i=$lb("property3"),$lb("property2","property1"{
    ^||skipProps=i
    ##class(myapp.jsonProvider).%WriteJSONStreamFromObject(.tStream,myClass,,,$$$YES,"ed")
    "skip:",$lts(i),?25," -> ",tStream.Read(),!
  }
}

}

USER>##class(myapp.myclass).Test()
skip:property3            -> {"property1":"value 1","property2":"value 2"}
skip:property2,property1  -> {"property3":"value 3"}
Vitaliy Serdtsev · May 8, 2019 go to post

Made a small demo with two options.

Include %occResultSet

Class dc.test Abstract ]
{

ClassMethod MultiRS(As %Integer) [ ReturnResultsetsSqlProc ]
{
  i#2 {
    $$$ResultSet("select 'Name1_1' s1,'Name2_1' s2 union all select 'Name1_2','Name2_2'")
  else {
    $$$ResultSet("select 1 i1,4 i2,3 i3 union all select 2,5,6 union all select 3,6,9")
    $$$ResultSet("select '+1' n union all select '-2' union all select '3.1' union all select '4_4'")
  }
}

Query MyCustomQueryCube(pCubeName As %StringAs %Query SqlProc ]
{
}

ClassMethod MyCustomQueryCubeExecute(
  ByRef qHandle As %Binary,
  pCubeName As %StringAs %Status
{
  qHandle("pCubeName")=pCubeName

  pCubeName="a" {
    N=2 i=1:1:qHandle(N+1-i)=$lb("Name1_"_i,"Name2_"_i)
  }else{
    N=3 i=1:1:qHandle(N+1-i)=$lb(i,i+3,i*3)
  }
  qHandle=N
  q $$$OK
}

ClassMethod MyCustomQueryCubeFetch(
  ByRef qHandle As %Binary,
  ByRef Row As %List,
  ByRef AtEnd As %Integer 0As %Status PlaceAfter = MyCustomQueryCubeExecute ]
{
  qHandle=0 {
    Row=""
    AtEnd=1
  }else{
    Row=qHandle(qHandle)
    qHandle=qHandle-1
  }
  q $$$OK
}

ClassMethod MyCustomQueryCubeClose(ByRef qHandle As %BinaryAs %Status PlaceAfter = MyCustomQueryCubeFetch ]
{
  qHandle
  q $$$OK
}

ClassMethod MyCustomQueryCubeGetInfo(
  ByRef colinfo As %List,
  ByRef parminfo As %List,
  ByRef idinfo As %List,
  ByRef qHandle As %Binary,
  extoption As %Integer 0,
  ByRef extinfo As %ListAs %Status
{
  qHandle("pCubeName")="a" {
    colinfo=$lb($lb("s1",10,"s1"),$lb("s2",10,"s2"))
  }else{
    colinfo=$lb($lb("i1",5,"i1"),$lb("i2",5,"i2"),$lb("i3",5,"i3"))
  }
  parminfo=$lb($lb("pCubeName","10"))
  idinfo=$lb(0,"")
  q $$$OK
}

ClassMethod MyCustomQueryCubeGetODBCInfo(
  ByRef colinfo As %List,
  ByRef parminfo As %List,
  ByRef qHandle As %BinaryAs %Status
{
  qHandle("pCubeName")="a" {
    colinfo=$lb(2,
                  "s1",12,50,0,2,"s1","test","dc","",$c(0,0,0,0,0,0,0,0,0,0,0,0),
                  "s2",12,50,0,2,"s2","test","dc","",$c(0,0,0,0,0,0,0,0,0,0,0,0)
                 )
  }else{
    colinfo=$lb(3,
                  "i1",4,10,0,2,"i1","test","dc","",$c(0,0,0,0,0,0,0,0,0,0,0,0),
                  "i2",4,10,0,2,"i2","test","dc","",$c(0,0,0,0,0,0,0,0,0,0,0,0),
                  "i3",4,10,0,2,"i3","test","dc","",$c(0,0,0,0,0,0,0,0,0,0,0,0)
                 )
  }
  parminfo=$lb(1,12,50,0,2,"pCubeName",1)
  q $$$OK
}

/// d ##class(dc.test).Test()
ClassMethod Test()
{
  try{

    rs=##class(%SQL.Statement).%New()

    $$$ThrowOnError(rs.%PrepareClassQuery("dc.test","MyCustomQueryCube"))
    i="a","b" rs.%Execute(i).%Display()
    
    !!,"=============="
    
    $$$ThrowOnError(rs.%Prepare("call dc.test_MultiRS(?)"))
    i=0,1 rs.%Execute(i).%Display()
    
  }catch(ex){
    "Error "ex.DisplayString(),!
  }
}

}

USER>##class(dc.test).Test()
 
 
Dumping result #1
s1      s2
Name1_1 Name2_1
Name1_2 Name2_2
 
2 Rows(s) Affected
 
Dumping result #1
i1      i2      i3
1       4       3
2       5       6
3       6       9
 
3 Rows(s) Affected
 
==============
 
Dumping result #1
i1      i2      i3
1       4       3
2       5       6
3       6       9
 
3 Rows(s) Affected
 
Dumping result #2
n
+1
-2
3.1
4_4
 
4 Rows(s) Affected
 
Dumping result #1
s1      s2
Name1_1 Name2_1
Name1_2 Name2_2
 
2 Rows(s) Affected
Vitaliy Serdtsev · May 3, 2019 go to post

delim " "abbrv ""
...
set abbrv abbrv $e($PIECE(desc,delim,i),1,2)   // But if I put w abbrv  I can get "Resytorewipa"

Vitaliy Serdtsev · May 3, 2019 go to post

Also I'm curious if we can set up and pass a JSON that easily too? Would be great.

Certainly.

Class dc.test Extends %RegisteredObject
{

ClassMethod MethodTest(args As %DynamicObject)
{
 i $IsObject(args{
   args.%ToJSON(),!
   w:args.%IsDefined("arr"args.arr."2",!
 }else{
   "null",!
 }
}

ClassMethod Test()
{
  ;d ##class(dc.test).Test()
  ..MethodTest(),
    ..MethodTest({}),
    ..MethodTest({"arg1":($zts),"arg6":"hello","arr":["a",10,true,2.5674]})
}

}

Result:

USER>##class(dc.test).Test()
null
{}
{"arg1":"65136,19638.022","arg6":"hello","arr":["a",10,true,2.5674]}
1
Vitaliy Serdtsev · Apr 24, 2019 go to post

First, should be so (AttachFile):

status=msg.AttachFile("F:\MyDir","myFirstFile.pdf",1,,.count)

status=msg.AttachFile("F:\MyDir","mySecondFile.pdf",1,,.count)

Second, you did not specify the error text.

Try the following simple MAC-example, replacing the values with your own:

#include %systemInclude
new

try{

  $$$AddAllRoleTemporaryInTry
  new $namespace
  
  set msg=##class(%Net.MailMessage).%New()

  set msg.Subject="Subject"

  set msg.From="from@domain"

  do msg.To.Insert("to@domain")

  do msg.TextData.Write("Hello!")
  
  $$$ThrowOnError(msg.AttachFile("F:\MyDir","myFirstFile.pdf"))
  $$$ThrowOnError(msg.AttachFile("F:\MyDir","mySecondFile.pdf"))

  set smtp=##class(%Net.SMTP).%New()
  set smtp.smtpserver="123.145.167.189"

  $$$ThrowOnError(smtp.Send(msg))
      
}catch(ex){
  write "Error "ex.DisplayString(),!
}
Vitaliy Serdtsev · Apr 23, 2019 go to post

res=##class(%SQL.Statement).%ExecDirect(,$$$FormatText("CREATE TABLE %1 (TNAMESPACE CHAR(100),TINTERFACE CHAR(100))",$$$quote("xxxxx"_$USERNAME)))

res.%SQLCODE

Vitaliy Serdtsev · Apr 16, 2019 go to post

See examples and try "Run It" in JSON_ARRAYAGG.

E.g.:
  1. SELECT JSON_ARRAYAGG(Home_StateFROM Sample.Person WHERE Home_State %STARTSWITH 'A'
    Result:
    ["AR","AL","AR","AL","AL","AR","AK","AL","AR","AK","AK","AZ","AR","AR","AL"]
  2. SELECT JSON_OBJECT('state':Home_StateFROM Sample.Person WHERE Home_State %STARTSWITH 'A'
    Result:
    {"state":"AR"}
    {"state":"AL"}
    {"state":"AR"}
    {"state":"AL"}
    {"state":"AL"}
    {"state":"AR"}
    {"state":"AK"}
    {"state":"AL"}
    {"state":"AR"}
    {"state":"AK"}
    {"state":"AK"}
    {"state":"AZ"}
    {"state":"AR"}
    {"state":"AR"}
    {"state":"AL"}
  3. SELECT JSON_ARRAYAGG(JSON_OBJECT('state':Home_State)) FROM Sample.Person WHERE Home_State %STARTSWITH 'A'
    Result:
    [{"state":"AR"},{"state":"AL"},{"state":"AR"},{"state":"AL"},{"state":"AL"},{"state":"AR"},{"state":"AK"},{"state":"AL"},{"state":"AR"},{"state":"AK"},{"state":"AK"},{"state":"AZ"},{"state":"AR"},{"state":"AR"},{"state":"AL"}]

Vitaliy Serdtsev · Apr 13, 2019 go to post

Here is a small example:

select JSON_ARRAYAGG(JSON_OBJECT('ID':ID,'Age':Age,'SSN':SSN)) from (select top ID,Age,SSN from sample.person)

Result:

[{"ID":1,"Age":59,"SSN":"502-68-5767"},{"ID":2,"Age":6,"SSN":"169-66-9969"},{"ID":3,"Age":64,"SSN":"868-61-3642"}]
Vitaliy Serdtsev · Apr 10, 2019 go to post

Then it's better:

Method Get() As %String CodeMode = objectgenerator, NoContext]
{
  d:%mode="propertymethod" %code.WriteLine("  q ..Test()")
  q $$$OK
}
Vitaliy Serdtsev · Apr 10, 2019 go to post

NoContext helped. What does it mean?

NoContext
With the same success it is possible to specify NoContext for the class:

Class Test.String Extends %String [ NoContext ]
{

Method Get() As %String CodeMode = objectgenerator ]
{
  %code.WriteLine("  q $this.Test()")
  q $$$OK
}

}

This works too btw:

It doesn't work for me:

MPP5376 : Method or Property 'Test' does not exist in this class.

Vitaliy Serdtsev · Apr 10, 2019 go to post

Try this

Class Test.String Extends %String
{

Method Get() As %String CodeMode = objectgenerator, NoContext ]
{
  %code.WriteLine("  q $this.Test()")
  q $$$OK
}

}
Vitaliy Serdtsev · Apr 8, 2019 go to post

You can do it even easier:

&sql(SELECT {fn TIMESTAMPDIFF(SQL_TSI_HOUR,CURRENT_TIMESTAMP(3),:tx)})

Small example:

&sql(SELECT CURRENT_TIMESTAMP(3),
            {fn TIMESTAMPADD(SQL_TSI_MINUTE,67,CURRENT_TIMESTAMP(3))} into :txBefore,:txAfter)
txBefore," -> ",txAfter,!!

&sql(SELECT {fn TIMESTAMPDIFF(SQL_TSI_HOUR,CURRENT_TIMESTAMP(3),:txAfter)},
            {fn TIMESTAMPDIFF(SQL_TSI_HOUR,:txBefore,:txAfter)} into :r1,:r2)
r1,!,r2

Result:

USER>^test
2019-04-08 08:51:34.916 -> 2019-04-08 09:58:34.916
 
1
1
USER>^test
2019-04-08 08:55:11.907 -> 2019-04-08 10:02:11.907
 
2
2
Vitaliy Serdtsev · Apr 4, 2019 go to post

This setting does not affect users experience. Before enabling, make sure you have Username/Password and/or System_Manager set, otherwise any user will be able to manage your CSP gateway. Everything is described in detail in the link I mentioned above, so I can hardly add anything more than that.

Vitaliy Serdtsev · Apr 4, 2019 go to post

There are two ways to define views, so I'll give you both options:

  1. /// bla-bla-bla:<ul>
    /// <li>Name - Person's name;</li>
    /// <li>SSN - Person's Social Security number. This is validated using pattern match;</li>
    /// <li>DOB - Person's Date of Birth.</li></ul>
    Class view.Person ClassType = view, CompileAfter Sample.PersonDdlAllowedNot ProcedureBlockViewQuery = { select Name,SSN,DOB from Sample.Person} ]
    {
    
    }
  2. /// This sample persistent class represents a person.
    /// <p>Maintenance note: This class is used by some of the bindings samples.
    Class Sample.Person Extends (%Persistent%Populate%XML.Adaptor)
    {
    
    ...
    
    /// bla-bla-bla:<ul>
    /// <li>Name - Person's name;</li>
    /// <li>SSN - Person's Social Security number. This is validated using pattern match;</li>
    /// <li>DOB - Person's Date of Birth.</li></ul>
    Query viewPerson() As %SQLQuery SqlViewSqlViewName viewPerson ]
    {
    select Name,SSN,DOB from Sample.Person
    }
    
    ...
    
    }

Now take a look at these classes from Documatic.

Vitaliy Serdtsev · Mar 20, 2019 go to post

For example, you can export them all to a single file:

SAMPLES>d $system.OBJ.ExportPattern("*.dfi","c:\exportAllDFI.xml",,,"UTF8")

You can get the list as follows (doc):
select Name from %Library.RoutineMgr_StudioOpenDialog('*.dfi')

Vitaliy Serdtsev · Mar 20, 2019 go to post

First, I would not use the input values directly in the query text, but would use Input Host Variables
Second, if it is necessary, it is more elegant to use the following syntax:

Set stmt ##CLASS(%SQL.Statement).%New()
Set query $$$FormatText("Select Val1, Val2 FROM Table WHERE Val1=%1",$$$quote("SomeCondition"))

Ideally these should be :
&SQL(SELECT Val1, Val2
INTO :val1, :val2
FROM Table
WHERE Val1='SomeCondition')

This is and now works:

&SQL(SELECT Val1Val2
               INTO :val1:val2
               FROM "Table"
               WHERE "Val1"='SomeCondition')