Jon Willeke · Mar 27, 2025 go to post

@Murray Oldfield posted "Decoding Intel processor models reported by Windows" a while back. Perhaps the wmic command is along the lines of what you're looking for. The properties that look of interest include  name, description, caption, and processorid:

C:\>wmic cpu get name
Name
Intel(R) Xeon(R) Gold 6248 CPU @ 2.50GHz
C:\>wmic cpu get caption
Caption
Intel64 Family 6 Model 85 Stepping 7
C:\>wmic cpu get processorid
ProcessorId
BFEBFBFF00050657

I don't know if any of these alone is enough to determine whether the processor supports AVX and/or BMI, but it should be enough to find specifications for the processor.

Jon Willeke · Jun 28, 2024 go to post

To be clear, the recommendation is to add "-d", not "d". "d" displays output (the default); "-d" suppresses output. If that is indeed the bug you're running into, it is fixed in newer wheels.

Jon Willeke · Jun 20, 2024 go to post

This is another case in which you're going to be happier using one of the newer wheels that comes with 2023.1.2. You're likely getting some kind of error on the server that the old 1.0.0 wheel cannot report back to you cleanly.

One thing you might try, if for some reason you're stuck on 1.0.0, is to add "-d" to the qspec argument. There's a really old bug/limitation, and I don't remember whether it was fixed on the client or server side, having to do with unexpected writes by a class method. "-d" would suppress that.

Jon Willeke · Jun 20, 2024 go to post

If I understand correctly, you want the Status property of a given task. In that case, this is going to be similar to your other question about fetching the gmheap property, except that you'll call a slightly different method to open the object:

task = native.classMethodValue('%SYS.Task', '%OpenId', id)
task.get('Status')

Since you're able to call RunNow(), I assume that you know the ID of the task. The same idea will work for the Error property.

If you're stuck with the ancient 1.0.0 wheel for some reason, you'll have to write helper class methods of your own.

Jon Willeke · Jun 20, 2024 go to post

1.0.0 is very old. 2023.1.2 shipped with the 3.2.0 and 4.1.0 wheels in the dev/python directory. You're going to be happier using one of them, which support the answer I gave originally. A big difference between the two is that 3.2.0 is pure Python, whereas 4.1.0 includes platform-specific binaries like 1.0.0 did.

Jon Willeke · Jun 14, 2024 go to post

What version of IRIS are you using, and what version of the Native API wheel? This works for me in 2024.1.0 using both 3.2.0 and 4.2.0.

Jon Willeke · Jun 13, 2024 go to post

It's not a dumb idea, but I would balance the risk you're introducing against the value. Refactor if you're already in the code, but if it ain't broke ...

The main thing to look out for is that the control flow is different. One pitfall of try-catch is that a try block is a context for quit, so if you have a quit command in a loop, then introduce a try-catch block, the quit may no longer do what you expect:

for i=1:1:10 {
    if i>4 {
        quit
    }
}

for i=1:1:10 {
    try {
        if i>4 {
            quit  // oops
        }
    } catch {}
}

Otherwise, I find try-catch easier to visualize than $ztrap. Unfortunately, there is no finally block.

Looking through some of my old code, I see a lot of $ztrap for restoring the previous namespace on error. A lot of those can now be replaced with new $namespace.

Jon Willeke · Jun 13, 2024 go to post

You're trying to call gmheap as a class method, but it's a property. Here's one way to do it:

cfg = native.classMethodValue('Config.config', 'Open')
cfg.get('gmheap')

Jon Willeke · Aug 7, 2023 go to post

This is an important point. Depending on the size of each node, this $order loop could be touching virtually every block in the global. If you read the 4GB test global after setting it, you're reading from a warm buffer pool, whereas the 40GB production global is less likely to be buffered—hence the greater than 10x difference in time.

I don't have a good suggestion for how to make this loop run faster. $prefetchon might help a little. Rather, depending on why you need to perform this operation, I'd either cache the record count (which could then become a hot spot of its own), or maintain an index global (possibly a bitmap).

Jon Willeke · Jun 9, 2023 go to post

If you're downloading from evaluation.intersystems.com, take another look. I see a radio button for "Red Hat 9" that does not appear in a screenshot that John Murray posted last week, so this may have been fixed since you last checked.

Jon Willeke · Oct 25, 2021 go to post

Can you elaborate on what it would mean to support Parquet? The diagram appears to have come from this post:

https://blog.openbridge.com/how-to-be-a-hero-with-powerful-parquet-google-and-amazon-f2ae0f35ee04

In that context, the query run time refers to acting on the file directly with something like Amazon Athena. Do you have in mind importing the file (which is what an IRIS user would currently do with CSV), or somehow querying the file directly?

Jon Willeke · Oct 25, 2021 go to post

Since Caché 2016.1, the %SYSTEM.Process class contains a TimeZone() method that lets you alter the value of the TZ environment variable, thereby changing the local time:

https://docs.intersystems.com/irislatest/csp/documatic/%25CSP.Documatic.cls?&LIBRARY=%25SYS&CLASSNAME=%25SYSTEM.Process#TimeZone

Depending on your situation, you can either change the current process, or isolate the change by jobbing off a background process.

Once the time zone is set appropriately, you can use dformat -3 of the $zdatetime and $zdatetimeh functions to convert between UTC and local. It would be cleaner if the time zone were an explicit argument, rather than implicit part of the environment.

Jon Willeke · Aug 10, 2021 go to post

No, the VALIDATE MODEL statement does not do cross validation. It calculates validation metrics for the given trained model and dataset. As described in the "Model Selection Process" section of the documentation, however, the TRAIN MODEL statement does this to some extent for classification models when using the AutoML provider:

These scoring metrics are then computed for each model using Monte Carlo cross validation, with three training/testing splits of 70%/30%, to determine the best model.

I also believe that the DataRobot provider incorporates cross validation into its training. I'm not sure about H2O.

Jon Willeke · Aug 10, 2021 go to post

This new error is indeed a breaking change in InterSystems IRIS 2019.3, as described in the 2020.1 release notes. Since I unfortunately can't link to them at the moment, I'll quote the relevant section from the upgrade compatibility checklist:

3.2.26 System — Class Compiler Validates Global Name Length Limit

This release adds compiler validation to ensure that the global names defined for DataLocation, IdLocation, IndexLocation, StreamLocation, CounterLocation, and VersionLocation are all within the global name length supported by the system (currently 31 characters). In previous releases, these global names were silently truncated to 31 characters. This could cause collisions between global names in the same class. These collisions would cause what appears to be references to separate globals to actually reference the same global.

During class compilation, an error will be reported if any of the global names used for the class are longer than the supported length. For example:

Compiling class %UnitTest.Result.TestInstance

ERROR #9101: Global name 'UnitTest.Result.TestInstanceStream' for 'StreamLocation' is too long, must be no more than 31 characters in length. [ConstructAddresses+60^%ocsExtentCache:BUILDSYS] > ERROR #5030: An error occurred while compiling class '%UnitTest.Result.TestInstance' [compile+59^%occClass:BUILDSYS]

This change will most likely result in classes that need to be modified upon upgrade. This more commonly occurs on systems that were converted from Caché or Ensemble using the in-place conversion if the classes were first defined using %CacheStorage and the class names were fairly long. (first in 2019.3)

I don't believe that you can disable this validation.

Jon Willeke · Jun 2, 2021 go to post

The Python documentation is pretty good. I haven't been too impressed by the Python books I've looked at. I didn't get much out of Learning Python, and even less out of Programming Python. Effective Python is okay, but not great. If I have a favorite, it's Fluent Python by Luciano Ramalho, although it probably shouldn't be your first book on the subject. A second edition is underway; you may need a Safari subscription to read it.

Jon Willeke · May 13, 2021 go to post

Unless pg_bulkload or SimpleMover are doing some kind of magic, I don't see any evidence of indexes in the GitHub repo. gaia_source.pgsql contains a single CREATE TABLE statement, and gaia_source.irissql contains a list of field names.

I don't think the repo is sufficient to reproduce your results.

Jon Willeke · May 13, 2021 go to post

This line also looks suspect:

set tID = tSeg.GetValueAt(pField_"("_tRepCount_")"_"."_pSubField)

Do you want tRep, instead of tRepCount?

Jon Willeke · May 12, 2021 go to post

Am I reading this right: 99 GB and not a single index? The IRIS numbers are incredible under those circumstances, but surely one would put some effort into the schema before issuing non-trivial queries against a large data set. There's a lot of low-hanging fruit here, at least for PostgreSQL.

Jon Willeke · May 12, 2021 go to post

Are you looking for something like this?

select top 1 contacttype
from table_name
order by datefrom desc
Jon Willeke · Mar 4, 2021 go to post

That file uses the irisnative library, but I can't find the library itself.

Jon Willeke · Mar 3, 2021 go to post

I can't seem to find the irisnative library. Is it in the vscode-intersystems-iris repo, and I'm just missing it?

Jon Willeke · Mar 1, 2021 go to post

I don't know whether this is documented, but you can use array accessors in the property expression. To create a property for the productID of the first entry in the OrderContent array, you should be able to use an expression like this in a %CreateProperty() call: $.OrderContent[0].productID.

Unfortunately, this doesn't address the general case of searching an array. I don't think you can create a collection property in DocDB, nor do the %FindDocuments() operators seem to be of much use. You might try poking around in your generated class to see if you can use an existing property as a template for creating your own computed property that aggregates the productID. If that works, you may still find the %FindDocuments() operators to be inadequate, but the property would then be accessible to SQL queries.

Jon Willeke · Feb 3, 2021 go to post

One thing to keep in mind with mode -2 is that the range of valid dates varies by platform. I think Windows is the most limited right now, throwing an ILLEGAL VALUE error for dates prior to 1970.

Jon Willeke · Jan 21, 2021 go to post

I took the spec. from your reply to Dmitriy's question, changed "query" to "path", smooshed it into one line, then pasted it into a terminal:

USER>s swagger={...}

USER>s status=##class(%REST.API).CreateApplication("neerav",swagger)

USER>zw status
... /* ERROR #8722: Path parameter country is not used in url /Demo of route with GETDemo in class: neerav.spec

I then changed "/Demo" to "/Demo/{country}":

USER>s swagger={ "swagger":"2.0","info":{ "title":"O","version":"1" },"schemes":["http","https"],"consumes":["application/json]"],"produces":["application/json]"],"paths":{ "/Demo/{country}":{ "get":{ "summary":"Get Demo ","description":"Demo ","operationId":"GETDemo","x-ISC_CORS":true,"consumes":["application/json]","text/html]"],"produces":["application/json]","text/html]"],"parameters":[{ "name":"country","type":"string","in":"path","description":"Country Name","allowEmptyValue": true } ],"responses":{ "200":{ "description":"Returns Country","schema": { "type":"string" } } } } } } }

USER>s status=##class(%REST.API).CreateApplication("neerav",swagger)

USER>zw status
status=1

I'm curious to know in what version this previously worked. I get the same error in 2019.1.2.

Jon Willeke · Jan 21, 2021 go to post

For a "path" parameter, there has to be a corresponding placeholder in the path string. I got this to work with "path" instead of "query" by changing "/Demo" to "/Demo/{country}", which generated a "/Demo/:country" route in the URL map.

Jon Willeke · Nov 8, 2020 go to post

I wasn't sure whether the Caché ODBC driver works with IRIS. Even if it does now, it's not guaranteed to do so in the future. I did find that the C++ binding SDK appears to include everything you need to generate proxy classes. You just need to call Generator::gen_classes() in generator.cpp.

Again, everything I've described is an unsupported hack. If a C++ binding application is holding up an upgrade from Caché to IRIS, let your Support or Sales Engineering rep. know.

Jon Willeke · Nov 8, 2020 go to post

You are correct that callin is not a replacement for the C++ binding. Callin is a lower-level API that only works for a local instance. The C++ binding has two flavors: the light C++ binding (LCB), which depends on callin, and the full C++ binding, which depends on the ODBC driver.

It's not clear to me from your questions how you're currently using C++. Do you actually have an existing C++ binding application, or are you writing something new with a requirement to use C++? I suggest that you get in touch with your friendly InterSystems representative in Support or Sales Engineering to help you find the best path forward.

That said, I was curious about whether the C++ binding from Caché can be used with InterSystems IRIS. Although I've never used this API on purpose, I was able to get it working after a fashion with a few modifications. I presume this is not supported by InterSystems, and I would hesitate to use it in production. The following overview describes my experiment using the C++ binding SDK from a Caché 2018.1.4 kit for lnxrhx64 with the Community edition of IRIS 2020.3.0 in a container. Apologies for any copy-paste mistakes. I started this on a lark, and didn't take very good notes.

I installed g++, make, and vim in the container:

$ docker exec -it --user root cppbind bash
root:/home/irisowner# apt update && apt install -y g++ make vim
...

I extracted cppsdk-lnxrhx64.tar.gz, and found that the C++ binding uses dlsym() and dlopen() to call entry points in the ODBC driver library. (Search for the init_pfn macro in odbc_common.cpp.) These are still present in the IRIS library, as you can see with the nm command:

$ docker exec -it cppbind bash
irisowner:~$ nm /usr/irissys/bin/libirisodbciw35.so |grep cpp_
000000000005cf90 T cpp_binding_alloc_messenger
000000000005dd40 T cpp_binding_clear_odbc_cache
...

I changed the ODBCLIBNAME symbol in libcppbind.mak from the libcacheodbciw Caché driver library to the libirisodbciw35 IRIS driver library.

I changed the Caché "CacheUni" symbols to the IRIS "ServerUni" symbols. For those three symbols, instead of

*((void**)(&(func))) = dlsym(dll_handle, #func);

You want something like this, where name is the new name of the symbol in the IRIS driver:

*((void**)(&(func))) = dlsym(dll_handle, #name);

I did the same for the ODBC 2.x SQLColAttributesW() function, which has been replaced by the ODBC 3.x SQLColAttributeW() function.

I fixed an apparent bug in obj_types.h by marking get_cs_handle() const and cs_handle mutable. I didn't spend much time investigating, so I'm not certain that this is the best fix.

I then built the C++ binding:

irisowner:~/dev/cpp/src/modules/cpp/lnxrhx64$ make libcppbind.so

It appears that the cpp_generator utility is only shipped as a binary, which obviously doesn't have any of these changes, so it won't work with an IRIS driver library. However, I was able to do a simple test using Dyn_obj:

#include <iostream>
#include "cppbind.h"

using namespace InterSystems;

int
main()
{
    auto conn = tcp_conn::connect(
        "localhost[1972]:USER", "_system", "SYS");
    Database db{conn};
    d_string res;
    Dyn_obj::run_class_method(&db, L"%SYSTEM.Util", L"CreateGUID",
        nullptr, 0, &res);
    std::cout << res.value() << std::endl;

    return 0;
}

I compiled and ran the test program like so:

$ docker exec -it cppbind bash
irisowner:~$ g++ -o cppbindtest cppbindtest.cpp -I dev/cpp/include \
    -L dev/cpp/src/kit/lnxrhx64/release/bin -lcppbind
irisowner:~$ export LD_LIBRARY_PATH=/home/irisowner/dev/cpp/src/kit/lnxrhx64/release/bin:/usr/irissys/bin
irisowner:~$ ./cppbindtest 
7325F26A-21E2-11EB-BB36-0242AC110002
Jon Willeke · Oct 2, 2020 go to post

I don't know what the TRACE macro does, but I would add that you have a couple of ways to visualize the contents of a dynamic object:

USER>read json
{"foo":"bar"}
USER>s object={}.%FromJSON(json)

USER>do object.%ToJSON()
{"foo":"bar"}
USER>write object.%ToJSON()     
{"foo":"bar"}
USER>zwrite object
object={"foo":"bar"}  ; <DYNAMIC OBJECT>

If object.%Get("forename") or object.forename returns "", you can try object.%IsDefined("forename") to see whether that property is in fact defined.

Jon Willeke · Oct 1, 2020 go to post

I would not say that try-catch is slow. If you reach the end of a try block, it simply branches over the catch block. This is a very cheap operation. In the nominal case (i.e., no error or exception), the cost of a try block is probably less than setting a %Status variable, and it would take several try blocks to match the cost of setting $zt once.

The catch block does almost all of the work. It instantiates the exception object, unwinds the stack, etc. I don't know offhand how catch compares to $zt, but the performance of the exceptional cases is usually not as important.

Jon Willeke · Sep 28, 2020 go to post

RAII isn't a well established pattern in ObjectScript, so you frequently end up duplicating code in the main block and the catch block that could otherwise live in a finally block. Besides "resources", clean-up code may restore state of any kind--globals, files, the current namespace, etc.