Eduard Lebedyuk · Mar 27, 2019 go to post

$zf(-100) has different signature:

set cmd = """C:\Program Files (x86)\WinRAR\Rar.exe"""
set args(1) = "x"
set args(2) = path _ "*.dbf"
set args(3) = pathToExt
set sc = $ZF(-100,"/SHELL", cmd,.args)
Eduard Lebedyuk · Mar 26, 2019 go to post

If you're on pre 2019.1 you can use %ZEN.Auxiliary.jsonProvider and %ZEN.Auxiliary.altJSONProvider to convert arbitrary object to and from JSON.

If you're on 2019.1 you can use %JSON.Adaptor class which is similar to %XML.Adaptor.

Eduard Lebedyuk · Mar 26, 2019 go to post

Error shows that it's access/user error:

ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT

    1808 (0x710)

    The account used is a computer account. Use your global user account or local user account to access this server.

Eduard Lebedyuk · Mar 26, 2019 go to post

Cache runs as a service under SYSTEM account.

Check that this user has access to a network drive.

Eduard Lebedyuk · Mar 26, 2019 go to post

This applies to properties of a class correct? Not just methods?

Correct.

You have several solutions:

  1. Application level control. You have one table Term { Name, Type} and on the application level you decide for edits to go or not based on type. It is the fastest solution, but you need to write a application code and remember to check for type.
  2. Class-level control as described by you.
  3. Row-level security. Control access row by row.
Eduard Lebedyuk · Mar 25, 2019 go to post

The easiest way is to use JSON_OBJECT for everything. Fastest would be just writing to device from resultset. Combine these approaches to get the performance you need (add this code to Parent class and call Test method):


Query Display() As %SQLQuery
{
SELECT
    JSON_OBJECT(
        'ID':%ID,
        'Name': Name,
        'Description': Description,
        'Children':    Example.Parent_GetChildrenInfo(%ID)
    )
FROM Example.Parent
}

/// do ##class(Example.Parent).Test()
ClassMethod Test(count = 0)
{
    if count>0 {
        do ##class(Example.Child).%KillExtent()
        do ..%KillExtent()
        
        
        do ##class(Example.Child).Populate(count,,,,$$$NO)
        do ..Populate(count,,,,$$$NO)
    }
    
    do ..DisplayFunc().%Display()
}

ClassMethod GetChildrenInfo(id) As %String [ SqlProc ]
{
    #define CRLF                             $c(13,10)
    #define ZENJSISNUM(%val)                ($IsValidNum(%val)&&(%val=+(%val)))
    #define ZENJSNUM(%num)                    $fnumber(%num,"LON")
    #; JSON utility macros that use the JSON translation table instead of the JS translation table
    #define ZENJSTABLE(%format)                ("JS"_$S(%format["u":"ML",1:""))
    #define ZENJSONTABLE(%format)            ("JSON"_$S((%format["u"):"ML",1:""))
    #define ZENJSONESCAPE(%str,%format)        $S(%format["s":$ZCVT(%str,"O",$$$ZENJSONTABLE(%format)),1:$Replace($ZCVT(%str,"O",$$$ZENJSTABLE(%format)),"\'","'"))
    #define ZENJSONSTR(%str,%format)        (""""_$$$ZENJSONESCAPE(%str,%format)_"""")
    #define ZENJSONPROP(%prop,%format)        $$$ZENJSONSTR(%prop,%format)
    #define ZENJSONVALUE(%val,%format)        $S($$$ZENJSISNUM(%val):$$$ZENJSNUM(%val),$C(0)=(%val)||$ListValid(%val):"""""",1:$$$ZENJSONSTR(%val,%format))
    #define ZENJSONPAIR(%pr,%val,%format)    $$$ZENJSONPROP(%pr,%format)_":"_$$$ZENJSONVALUE(%val,%format)
    
    set out = "["   
    
    
    set ids = ..ChildrenGetStored(id)
    set ptr=0
    set separator=0
    while $listnext(ids,ptr,value) {
        set value = $lg(value)
        set:separator out = out _ ","

        set out = out _  "{"
        set out = out _  $$$ZENJSONPAIR("Name",##class(Example.Child).NameGetStored(value),"") _","
        set out = out _  $$$ZENJSONPAIR("Description",##class(Example.Child).DescriptionGetStored(value),"")
        set out = out _  "}"
        set separator = 1
    }
    
    set out = out _  "]"
    
    quit out
}
Eduard Lebedyuk · Mar 21, 2019 go to post

I once separated one Ensemble database (with code and data) into two databases (one db for code, one db for data) on a running system.

It was not difficult actually:

  1. Exported code from one database
  2. Created new database.
  3. Imported code into new database.
  4. In a namespace switched code database from old database to a newly created one.
  5. Deleted classes from old database.

But in my situation the code itself didn't change.

Eduard Lebedyuk · Mar 20, 2019 go to post

Another check. Properties can't be SQL reserved words. I often name properties "Date", etc. only to forget that they can't be used in SQL as is only quoted, so I need to go to Class view and rename them to something else.

Eduard Lebedyuk · Mar 20, 2019 go to post

The main check we need is parametrization. SQL should not be concattenated from user input, but user input should be passed as an argument.

Eduard Lebedyuk · Mar 20, 2019 go to post

Well, what do you want to do with that list? Depending on your use case, the solution may differ.

For example to get a list of dashboards execute this query:

SELECT *
FROM %DeepSee_Dashboard.Definition

And to get a list of Pivots execute this one:

SELECT *
FROM %DeepSee_Dashboard.Pivot

And in MDX2JSON project I need to get a list of dashboards visible to the current user.  I use custom result set for that (because user may have access to dashes but not to SQL).

Eduard Lebedyuk · Mar 14, 2019 go to post

The easiest way would be to configure web server on customersdomain.com to act as a reverse proxy. In this case it would proxy requests to yourownserver.com or wherever you need.

Another way is to install CSP Gateway on a customersdomain.com. After that connect CSP Gateway to your Cache/Ensemble/InterSystems IRIS instance on yourownserver.com. And connect web server on customersdomain.com to CSP Gateway on customersdomain.com.

Advantage of this approach is that static would be served directly from customersdomain.com server.

Eduard Lebedyuk · Mar 14, 2019 go to post

Can you try restarting the instance?

CSP absolutely should work.

Also check this post about clearing cached elements from webserver.

Eduard Lebedyuk · Mar 13, 2019 go to post

I never use return unless I really do want to exit from the method while inside some inner loop. So mainly I use quit.

Eduard Lebedyuk · Mar 12, 2019 go to post

-Creating SSL/TLS configurations in S1's Healthshare portal (also tried with a %SuperServer... but where and how could I use them ? I haven't found it)

Your SSL configuration should be called %SuperServer. Currently it's called AccDirSsl. You need to create new/rename existing configuration to %SuperServer.

Also, can you show a screen from the Portal’s System-wide Security Parameters page (System Administration > Security > System Security > System-wide Security Parameters)? For the Superserver SSL/TLS Support choice, you should select Enabled (not Required).

Also does HS OS user has access to C:\chr11614pem? I'd try to copy certificates/keys to HS temp directory and modify paths in config accordingly.

Eduard Lebedyuk · Mar 11, 2019 go to post

From docs. RETURN and QUIT differ when issued from within a FOR, DO WHILE, or WHILE flow-of-control structure, or a TRY or CATCH block.

  • You can use RETURN to terminate execution of a routine at any point, including from within a FOR, DO WHILE, or WHILE loop or nested loop structure. RETURN always exits the current routine, returning to the calling routine or terminating the program if there is no calling routine. RETURN always behaves the same, regardless of whether it is issued from within a code block. This includes a TRY block or a CATCH block.
  • In contrast, QUIT exits only the current structure when issued from within a FOR loop, a DO WHILE loop, a WHILE loop, or a TRY or CATCH block. QUIT exits the structure block and continues execution of the current routine with the next command outside of that structure block. QUIT exits the current routine when issued outside of a block structure or from within an IF, ELSEIF, or ELSE code block.
Eduard Lebedyuk · Mar 11, 2019 go to post

If you already have HL7 message inside Ensemble you can use  Caché SQL Gateway which provides access from Caché to external databases via JDBC and ODBC. You can use SQL Gateway (probably in ODBC mode) to update SQL Server table(s).