Eduard Lebedyuk · Nov 27, 2017 go to post

When you  want to have two or more classes pointing to the same storage. Sometimes it can be useful to have one persistent class with full definition and another with only a few properties. I used this approach to test indices building on a test class - it does not affect existing class and it's indices.

Eduard Lebedyuk · Nov 27, 2017 go to post

2.  Write a routine to copy (duplicate) all the data from old classes to new ones. (which is not trivial at some point)

Why is it not trivial? If you're not changing class definition  three merges per class should be enough.

Also check that storage definition in the new class is the same as in old class, only pointing to the new globals.

MANAGEDEXTENT=0 may be easier to do, but it raises the risk of accidentally deleting old globals (what are these globals not corresponding to any class? Let's free some space)

Eduard Lebedyuk · Nov 24, 2017 go to post

I don't think that order of indices in first argument affects anything. They are converted into tBuildFlags which also follows by ASSCII sorting of index names

Eduard Lebedyuk · Nov 16, 2017 go to post

On previous versions you can use ^%GSIZE utility:

do ^%GSIZE
Directory name: c:\intersystems\cache\mgr\mdx2json\ =>
 
All Globals? No => No
Global ^Git("TSH")
Global ^
1 global selected from 54 available globals.
Show details?? No => Yes
Device:
Right margin: 80 =>

directory: c:\intersystems\cache\mgr\mdx2json\
Page: 1                           GLOBAL SIZE                        16 Nov 2017
                                                                        11:49 AM
      Global        Blocks       Bytes Used  Packing   Contig.
      --------    --------  ---------------  -------   -------
      Git("TSH")         1              132      2 %         0
 
 
      TOTAL         Blocks       Bytes Used  Packing   Contig.
      --------    --------  ---------------  -------   -------
                         1              132      2 %         0
                                        <RETURN> to continue or '^' to STOP:
Eduard Lebedyuk · Nov 10, 2017 go to post

I have a Cache-compatible sql script file and each query is separate by white space.

How do you escape white spaces in a query?

 

Anyway, the general approach is:

set file = ##class(%Stream.FileCharacter).%New()
do file.LinkToFile(filename)
while 'file.AtEnd {
  set query = file.ReadLine() // ???
  set rs = ##class(%SQL.Statement).%ExecDirect(, query)
  set sc = rs.%DisplayFormatted(format, outfile)
}

Where:

  • filename - file with queries
  • format - one of  XML, HTML, PDF, TXT or CSV.
  • outfile - file to write results to

I assumed query separation by newline.

Also outfile needs to change between queries as %DisplayFormatted recreates it.

Eduard Lebedyuk · Nov 5, 2017 go to post

Here's some steps you can take to debug this query:

1. Add BREAK after executing query

2. Start BO in a terminal

3. Get to BREAK

4. Execute: write $System.Status.GetErrorText(%objlasterror)

Eduard Lebedyuk · Oct 31, 2017 go to post

You'll need to:

  • write authorization code
  • control current authorization state 
  • check that it all works as expected so  you don't consume more that one license per user

There's no reason to do that, as standard Caché tools, such as Login page provide all required capabilities.

Eduard Lebedyuk · Oct 31, 2017 go to post

Do you mean web-app settings like in the following screenshot?

Yes.

But why not using basic authentication? Can I consider using it?

It's way better to use CLP because this way Caché tracks authorization and licenses and you don't need to think about it in your app.

Here's some recommendations on securing REST + CSP web apps:

  1. All brokers effectively have Parameter UseSession = 1;
  2. REST web application and client web application allow only authenticated (i.e. password) access.
  3. REST web application and client web application have reasonable Session timeout (i.e. 900, 3600).
  4. REST web application and client web application have the same GroupById value.
  5. REST web application and client web application have the same cookie path.

Client web application can have a custom Login Page (or just use default login page, that's okay too).

Eduard Lebedyuk · Oct 27, 2017 go to post

Hello, Amir!

  1. That was just a quick testing in the existing class. For the actual project of course I would write this method in a separate utility class. you are completely right on that. Still, I edited my code to avoid bad examples.
  2. I  need a method to return storage position of property in $lb at runtime, and I also can't modify existing classes to achieve that (for example by generating a method for each class with precomputed property name=storage position values).
  3. Impossible, because 2.

 

That said I do agree that idea with method generators is good, just not applicable in this exact case.

Eduard Lebedyuk · Oct 25, 2017 go to post

Hello, Amir!

Can ECP be configured in the case where one of the server is on the internal network? So server1 can see and get replies from server2 but server2 can't access server1 by itself?

Eduard Lebedyuk · Oct 20, 2017 go to post

You need to parse CSV. Here's how to do that in Caché:

Provided you have this csv:

car,2000,100.51,27.10.2016,
phone,2003,65.8,15.01.2017,

You can import it into class Test.CSV:

1. Generate a persistent class Test.CSV

set rowtype = "name VARCHAR(50),year INTEGER,amount NUMERIC(9,2),date DATE"
set filename = "D:\data.csv"
do ##class(%SQL.Util.Procedures).CSVTOCLASS(2, .rowtype, filename,,,,"Test.CSV")

2. Import file or files

do ##class(Test.CSV).Import(2,filename)

Usually you can't import your CSV right away - the dates are in a different format, etc. You need to modify Import method and property definitions. For example I often:

  • Add FORMAT=4 property parameter for dates to import dates in dd/mm/yyyy format.
  • Find&replace Library.
  • Add this else line in Import method:
if $$$ISOK(tStatus) { set tCounter = tCounter + 1 } else { w $System.Status.GetErrorText(tStatus) return}

If you have a tab separated file, you need to change Import method signature from:

pDelimiter As %String = ","

to:

pDelimiter As %String = {$c(9)}

You may need to additionally modify Import method to accept streams instead of files.

Eduard Lebedyuk · Oct 20, 2017 go to post

Additionally in web app settings specify:

  • Serve Files: Always
  • Serve Files Timeout: 0

Note, that it would disable caching completely.

Eduard Lebedyuk · Oct 17, 2017 go to post

Not sure if choiceGetCount is a public API to do that.

You want to count a number of occurances of a particular node in some path?

Eduard Lebedyuk · Oct 17, 2017 go to post

Simplified example:

set xml = ##class(EnsLib.EDI.XML.Document).%New().ImportFromString("<root><RepeatingElement>Content</RepeatingElement><RepeatingElement>Content</RepeatingElement></root>")