Eduard Lebedyuk · Feb 16, 2023 go to post

I usually follow these steps when I have two similar but distinct codebases:

  1. Create a new repo.
  2. Export everything from the LIVE server into the repo. Commit.
  3. Export everything from the TEST server into the repo. Commit.

Commit from step (3) would have all the differences between LIVE and TEST. I assume the code on TEST is newer, so that should be a later commit, but it you want to, you can swap the export order.

Before making a commit (3) you might want to remove trivial differences such as whitespaces, etc. Also Gitlab has a compare mode for commits which automatically ignores whitespace differences.

Eduard Lebedyuk · Feb 10, 2023 go to post

1. Try running:

 cd <IRIS>\bin
 ./irispython "C:\InterSystems\IRIS\lib\python\Scripts\pywin32_postinstall.py" -install

It might fix your error.

If that does not help, add win32 folder to path explitictly and try import again:

import sys
sys.path.append("<IRIS>\Mgr\python\win32")
import win32api
Eduard Lebedyuk · Feb 9, 2023 go to post

While testing, I see I can easily set %session.Data to hold data I want to preserve.  

No problem! I thought you were having issues with that part.

how, on my next API call can I use that session  

You just need to supply the cookies CSPSESSIONID and CSPWSERVERID. With that you'll have the same session. In browsers (and I think in postman) that's automatic, so you don't have to do anything. It should work out of the box as long as you have UseSession set to 1.

Eduard Lebedyuk · Feb 8, 2023 go to post

From the documentation (even better docs):

1. Open the spec class.

2. Add

Parameter UseSession As BOOLEAN = 1;

3. Recompile the spec class.

4. Now your disp class has the same parameter and you can use sessions in your impl class.

If you need a larger change than adding a parameter to a dispatcher class, do this (docs):

1. Create a custom subclass of %CSP.REST, i.e. test.REST.
2. Modify your swagger spec by adding x-ISC_DispatchParent:

  "info":{
    "version":"1.0.0",
    "x-ISC_DispatchParent":"test.REST",

3. Recompile.

Now your disp class extends test.REST and you can modify anything there.

Eduard Lebedyuk · Feb 6, 2023 go to post

Pythonic way is to use with. In that case close is automatic as soon as we get outsude of the context:

ClassMethod ReadFileUsingPython(pFile As %String) [ Language = python ]
{
  from datetime import datetime
  import iris
  time1 = datetime.timestamp(datetime.now())
  print(time1)
  if pFile=="":
    raise Exception("filename is required.")

  with open(pFile,"r", encoding="utf-8", errors="ignore") as file:
    log = iris.cls('otw.log.Log')
    for line in file:
      status = log.ImportLine(line)

  time2 = datetime.timestamp(datetime.now())
  print(time2)
  print("Execution time: ",(time2-time1))
}
Eduard Lebedyuk · Feb 5, 2023 go to post

Also you can simplify your code:

ClassMethod ReadFileUsingPython(pFile As %String) [ Language = python ]
{
  from datetime import datetime
  import iris
  time1 = datetime.timestamp(datetime.now())
  print(time1)
  if pFile=="":
    raise Exception("filename is required.")

  file = open(pFile,"r", encoding="utf-8", errors="ignore")
  log = iris.cls('otw.log.Log')
  for line in file:
    status = log.ImportLine(line)

  time2 = datetime.timestamp(datetime.now())
  print(time2)
  print("Execution time: ",(time2-time1))
}
Eduard Lebedyuk · Feb 3, 2023 go to post

Download Caché 2018.1.7 from the WRC - it will be able to mount CACHE.DAT from Caché 2012.1 or restore a backup from it.

Eduard Lebedyuk · Feb 2, 2023 go to post

Do you have this line:

   <!-- Get info about pivot variables-->
   <Route Url="/PivotVariables/:Cube" Method="GET" Call="WritePivotVariablesForCube"/>

in the UrlMap of the MDX2JSON.REST class?

Eduard Lebedyuk · Jan 27, 2023 go to post

Interrupt causes rollback, try this code:

Class User.Del Extends (%Persistent, %Populate) [ Final ]
{

ClassMethod HangBool(seconds, id) As %Boolean [ SqlProc ]
{
    hang seconds
    quit $$$YES
}

/// do ##class(User.Del).Test()
ClassMethod Test()
{
    do ..%KillExtent()
    do ..Populate(10,,,,$$$NO)
    
    set start = $zh 
    &sql(DELETE FROM Del WHERE Del_HangBool(1, id)=1)
    set end = $zh
    w "Delete took: ", end-start,!
}
}

Regardless of when you send the interrupt, the ^User.DelD global would have 10 records.

Eduard Lebedyuk · Jan 27, 2023 go to post

For cross-namespace queries the easiest way is to map packages/globals but that might not be a recommended approach for an audit table.

You can do this:

  1. In your production namespace create a new table with the same structure as your audit select query backed by PPG storage.
  2. Switch to the audit namespace.
  3. Run audit query, iterate the results and write them into the PPG.
  4. Switch into a production namespace.
  5. Run query against your PPG table, joining any local tables.
Eduard Lebedyuk · Jan 26, 2023 go to post

Audit event has a namespace property, filter by that.

Same for timestamp, audit event timestamp and production class compilation timestamp are probably close to each other.

Eduard Lebedyuk · Jan 26, 2023 go to post

Enable %Ensemble/%Production/ModifyConfiguration in System Audit Events:

After that you should see these events:

Eduard Lebedyuk · Jan 26, 2023 go to post

Audit table contains all production item changes you can query it once every X minutes/hours to get new changes.

Eduard Lebedyuk · Jan 26, 2023 go to post

%objlasterror is %Status which is a binary format. You can store it in a property of a %Status type and use ODBC mode for SQL queries, or use $system.Status.DisplayError(sc) to get/store the display value.

Eduard Lebedyuk · Jan 25, 2023 go to post

Try to export the project with one deployed class. Open exported xml and check if the class is there and deployed.

Eduard Lebedyuk · Jan 25, 2023 go to post

Use args... to supply a variable number of parameters:

ClassMethod DoCleverStuf(args...) As %Status [ CodeMode = objectgenerator ]
{
    do %code.WriteLine("    For i=1:1:args {")
    do %code.WriteLine("        Write args(i)")
    do %code.WriteLine("    }")
    do %code.WriteLine("    Set tSC = $$$OK")
    ...
}

can I generate a whole method at compile time?

You can use projections to do that. Here's an example.

Eduard Lebedyuk · Jan 23, 2023 go to post

Only the pyramid characters count, having (or not having) white spaces at the end is not important.

Test cases do have them, but if you shorten the solution and it outputs the pyramid without white spaces after the hashtag that's great too.

Eduard Lebedyuk · Jan 20, 2023 go to post

I get a syntax error when I do:

Are you doing this in console/terminal? Macros are not available there.

To check if you got an error in a terminal execute:

if sc=1 {w "OK"} else {w $system.Status.DisplayError(sc)}
Eduard Lebedyuk · Jan 20, 2023 go to post

Assuming you have a sync mirror established, adding new db to mirror is as simple as:

  1. Create DB on Primary.
  2. Run SYS.Mirror:AddDatabase. It returns %Status, check that it's ok with $$$ISOK(sc). It should be equal to 1.
  3. Dismount database on Primary (using SYS.Database:DismountDatabase) OR Freeze IRIS (Backup.General:ExternalFreeze).
  4. Copy IRIS.DAT to Backup.
  5. Mount database on Primary (using SYS.Database:MountDatabase) OR Thaw IRIS (Backup.General:ExternalThaw).
  6. Mount database on Backup.
  7. Activate database on Backup (SYS.Mirror:ActivateMirroredDatabase).
  8. Catchup database on Backup (SYS.Mirror:CatchupDB).

Please note that some methods accept db name, most accept db directory, and others db sfn. Please keep that in mind.