Once upon a time, when the grass was greener and the sky was bluer, there was even an add-in application Caché RoseLinkPDF.
- Log in to post comments
Once upon a time, when the grass was greener and the sky was bluer, there was even an add-in application Caché RoseLinkPDF.
Here is what is in the documentation for Caché:
Disable Query Timeout — Optional. If selected, causes the ODBC client driver to ignore the value of the ODBC query timeout setting. The ODBC query timeout setting specifies how long a client should wait for a specific operation to finish. If an operation does not finish within the specified time, it is automatically cancelled. The ODBC API provides functions to set this timeout value programmatically. Some ODBC applications, however, hard-code this value. If you are using an ODBC application that does not allow you to set the timeout value and the timeout value is too small, you can use the Disable Query Timeout option to disable timeouts. java.sql Exceptions The following exceptions are listed here for completeness, but are not required and are never used: ... SQLTimeoutException ...
You can empirically verify all your considerations by calling a custom stored procedure from Microsoft SQL Server, for example:
Class dc.a [ Abstract ]
{
Query DbgSqlProc(
qMaxRows = 10,
qTimeWait As %SmallInt = 3) As %Query(ROWSPEC = "nrow:%Integer,name:%String") [ SqlProc ]
{
}
ClassMethod DbgSqlProcExecute(
ByRef qHandle As %Binary,
qMaxRows = 10,
qTimeWait As %SmallInt = 3) As %Status
{
#define Log(%s) Set ^dbgSqlProc(qHandle("id"),%s)=$ZDateTime($NOW(),1,1,6)
Set qHandle("id")=$Increment(^dbgSqlProc)
Set qHandle("qMaxRows")=qMaxRows
Set qHandle("qTimeWait")=qTimeWait
$$$Log("1_Execute")
For i=1:1:qMaxRows Set qHandle(i)=$ListBuild(i,"name"_i)
Set qHandle=0
; Hang qHandle("qTimeWait")*3
Quit $$$OK
}
ClassMethod DbgSqlProcFetch(
ByRef qHandle As %Binary,
ByRef Row As %List,
ByRef AtEnd As %Integer = 0) As %Status [ PlaceAfter = DbgSqlProcExecute ]
{
$$$Log("2_Fetch")
If qHandle>qHandle("qMaxRows") {
Set Row=""
Set AtEnd=1
}else{
Set Row=qHandle($Increment(qHandle))
Hang qHandle("qTimeWait")
}
Quit $$$OK
}
ClassMethod DbgSqlProcClose(ByRef qHandle As %Binary) As %Status [ PlaceAfter = DbgSqlProcExecute ]
{
$$$Log("3_Close")
Quit $$$OK
}
}
Example of a call: select * from dc.a_DbgSqlProc(11,5)
Well, of course it works. See loads data from 'C:\data\sales.csv' above.
Not quite so (see RowID Hidden?).
ALLOWIDENTITYINSERT is needed for other purposes:
Set Up Delegated Authentication
Have you enabled delegated authentication for services and applications, in particular for %Service_WebGateway?
dc.onetomany.PKG
Class dc.onetomany.products Extends %Persistent
{
Parameter ALLOWIDENTITYINSERT = 1;
Property name As %VarString [ SqlColumnNumber = 2 ];
Property listpriceusd As %BigInt [ SqlColumnNumber = 3 ];
Property description As %VarString [ SqlColumnNumber = 4 ];
}
Class dc.onetomany.sales Extends %Persistent
{
Parameter ALLOWIDENTITYINSERT = 1;
Property companyid As %BigInt [ SqlColumnNumber = 2 ];
Property productid As %BigInt [ SqlColumnNumber = 3 ];
Property saledate As %Date [ SqlColumnNumber = 4 ];
Property saleamountusd As %BigInt [ SqlColumnNumber = 5 ];
}
Class dc.onetomany.companies Extends %Persistent
{
Parameter ALLOWIDENTITYINSERT = 1;
Property name As %VarString [ SqlColumnNumber = 2 ];
Property industry As %VarString [ SqlColumnNumber = 3 ];
Property description As %VarString [ SqlColumnNumber = 4 ];
Property website As %VarString [ SqlColumnNumber = 5 ];
Query CompaniesBySales() As %SQLQuery(CONTAINID = 1, ROWSPEC = "id:%Integer,name:%String,industry:%String,description:%String,website:%String,totalsales:%Numeric") [ SqlName = CompaniesBySales, SqlProc ]
{
SELECT c.id,
c.name,
c.industry,
c.description,
c.website,
SUM(s.saleamountusd) AS totalsales
FROM dc_onetomany.sales s
JOIN dc_onetomany.companies c ON c.id = s.companyid
GROUP BY c.id, c.name, c.industry, c.description, c.website
ORDER BY totalsales DESC
}
Query CompanySalesTotal(companyid As %Integer) As %SQLQuery(CONTAINID = 1, ROWSPEC = "companyid:%Integer,totalsales:%Numeric") [ SqlName = CompanySalesTotal, SqlProc ]
{
SELECT :companyid AS companyid,
COALESCE(SUM(s.saleamountusd), 0) AS totalsales
FROM dc_onetomany.sales s
WHERE s.companyid = :companyid
}
/// d ##class(dc.onetomany.companies).Test()
ClassMethod Test()
{
d ##class(dc.onetomany.sales).%KillExtent()
d ##class(dc.onetomany.companies).%KillExtent()
d ##class(dc.onetomany.products).%KillExtent()
&sql(LOAD DATA FROM FILE 'C:\data\companies.csv'
INTO dc_onetomany.companies(id,name,industry,description,website)
USING {"from":{"file":{"header":true}}})
&sql(LOAD DATA FROM FILE 'C:\data\products.csv'
INTO dc_onetomany.products(id,name,listPriceUSD,description)
USING {"from":{"file":{"header":true}}})
&sql(LOAD DATA FROM FILE 'C:\data\sales.csv'
INTO dc_onetomany.sales(ID,companyId,productId,saleDate,saleAmountUSD)
VALUES (saleId,companyId,productId,saleDate,saleAmountUSD)
USING {"from":{"file":{"header":true}}})
s rs = ##class(%ResultSet).%New("dc.onetomany.companies:CompanySalesTotal")
d rs.Execute(103)
d rs.Next()
w rs.Get("totalsales")," <- 17000",!
s rs = ##class(%ResultSet).%New("dc.onetomany.companies:CompanySalesTotal")
d rs.Execute(104)
d rs.Next()
w rs.Get("totalsales")," <- 7000",!
s c=##class(dc.onetomany.companies).%New()
s c.name="my name 111"
d c.%Save()
w "current ID = ",c.%Id(),!
&sql(insert into dc_onetomany.companies(ID,name) values(500,'my name 500'))
w "current ID = ",%ROWID,!
&sql(insert into dc_onetomany.companies(name) values('my name 501'))
w "current ID = ",%ROWID,!
}
}USER>d ##class(dc.onetomany.companies).Test() 17000 <- 17000 7000 <- 7000 current ID = 111 current ID = 500 current ID = 501
Interestingly, if I try your examples, I can recreate the ambiguity error, but then get an error when attempting to specify the full param specificationWhat is your version of IRIS and .NET? I have IRIS 2025.3CE and .NET 8.0/Framework 4.6.2 - the examples above work flawlessly and give respectively 1, 0, 1 as indicated in the comments.
This is also possible:
USER>s gw = $System.external.getDotNetGateway()
USER>w gw.invoke("System.Convert","ToBoolean(System.UInt64)",123)
1
USER>
Since you manage the ID yourself, in the general case it may not necessarily be a simple counter, but, for example, a Fibonacci sequence. If the source code of the class or table is available, it is better to see how the ID is generated in it. If there is no source code, and you are sure that this is a simple counter, then in my opinion it would be easier to make a standard ID and let IRIS manage it itself.
var irisReference = new IRISReference(""); iris.ClassMethodStatusCode("TestClasses.TestClass", "Method1", irisReference); var pReturn = (IRISObject)irisReference.value; var list = (IRISObject)pReturn.Get("Entries"); for (var i = 1; i <= list.InvokeLong("Count"); i++) { var entry = (IRISObject)list.InvokeObject("GetAt", i); Console.WriteLine(entry.GetString("Username"));}
gateway.new() calls a constructor, but the System.Convert class has no constructors.
To call a static method, use gateway.invoke(), but keep in mind that if you call the following code, an error will occur "Unable to resolve method overloading ambiguity":
write netGate.invoke("System.Convert","ToBoolean",123)To avoid it, specify the name of the method with the full specification of the parameters, for example:
s gw = $System.external.getDotNetGateway()
w gw.invoke("System.Convert","ToBoolean(int)",123),! ; -> 1
w gw.invoke("System.Convert","ToBoolean(string)","false"),! ; -> 0
w gw.invoke("System.Convert","ToBoolean(string)","true"),! ; -> 1
PS: see Mapping Specification (pay special attention to the sections "Overloaded Methods" and "Restrictions")
By the way, what do you think this statement does? Note the %OpenId(20) at the end instead of %New().
#dim a,b,c As Sample.Person = ##class(Sample.Person).%OpenId(20)
Confusing. How about this statement?
#dim a,b,c As Sample.Company = ##class(Sample.Person).%New()
Do you get 3 companies or 3 persons? Does it try to "cast" persons as companies? Do you get an error at compile time or run time? Would it work if Sample.Company extends Sample.Person? More confusion...
There is no confusion. Here's another example where the class may not even exist and yet the code compiles without errors and according to the documentation. test.MAC
#dim a,b,c As %Boolean = ##class(bla.bla).%OpenId(20) #dim a,b,c As bla.bla.bla123 = ##class(bla.bla).%OpenId(20)
--> test.INT
Set (a,b,c)=##class(bla.bla).%OpenId(20) Set a=##class(bla.bla).%OpenId(20),b=##class(bla.bla).%OpenId(20),c=##class(bla.bla).%OpenId(20)
The only thing is that in this case Studio Assist will not work.
A good thing to know is, that there isn't actually a thing as 'during compile time' in ObjectScript.Do you think that the documentation contains an error?
##function Evaluates an ObjectScript function at compile time.#execute Executes a line of ObjectScript at compile time.
##expression Evaluates an ObjectScript expression at compile time.
There are nuances ;)
According to the documentation, the following two lines will give different results at the runtime:
#dim a,b,c = ##class(Sample.Person).%New() ; all the variables are assigned the same initial value #dim a,b,c As Sample.Person = ##class(Sample.Person).%New() ; each variable is assigned a separate OREF
IRIS 2025.3.CE
ClassMethod test() [ Language = python ]
{
import iris
ns
= iris.system.Process.NameSpace()
try:
iris.system.Process.SetNamespace('%SYS')
passenger = iris.SYS.Stats.Dashboard.Sample()
print(passenger.GloRefsPerSec)
finally:
iris.system.Process.SetNamespace(ns)
}
PS: Do I need a separate python iris connection for each Namespace?
- For each alphabetic character, determine its zero-based index in the lowercase alphabet (a-z).
- Preserve non-alphabetic characters unchanged.
For clarify: does alphabetical characters include only the English letters a-z, A-Z, or all Unicode characters including "ªµºÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéyêëìíîïðñtóôõöøùúûüýþÿ" ?
What should be the correct result for the string "Hello World µÝ Привет Мир!" ?
Your task is to implement this encryption efficientlyWhat does "efficiently" mean?
The condition of the Code Golf competition has always been to write the shortest code, not the fastest (see Code Golf Index)
My current code size is 74 (where alphabetical characters only a-z,A-Z).
size = 74
ClassMethod Encode(m) As %String
{
f j=65,97{f i=0:1:25 s m=$tr(m,$c(j+i),i#2)} q $re($e(m,1,*-1))_$e(m,*)
}"Hello World µÝ Привет Мир!" -> "риМ тевирП Ýµ 11100 01101!"
PS: why is the correct result in the testNumbers method 321 and not 213?
Caché/IRIS already has ready-made macros: $$$FormatText(), $$$FormatTextHTML(), $$$FormatTextJS()
, which may be useful to you and which use #def1arg.
ISO/IEC 19075-6:2021 (see Chapter 6.4)
Wow!
By the way, if you remove the second brackets, the query works:
SELECT 1 WHERE ('') = '_㉸^'It requires Java 17, and InterSystems IRIS Enterprise (it uses many connections).
Do I understand correctly that with the built-in Community Edition license, the SQLancer tool cannot be fully used?
One of the options for Caché 2018.1:
set xmlStream=##class(%Stream.FileBinary).%New() set xmlStream.Filename="C:\test_from.xml" set jsonStream=##class(%Stream.FileBinary).%New() set jsonStream.Filename="C:\test_to.json" #dim d As %Document.Object = ##class(%Document.Object).XML(xmlStream) do d.%ToJSONStream(.jsonStream) do jsonStream.%Save()
For i = 1:1:maxRow {
Set cel = pySheet.cell(i,y)
If cel."is_date" {
Set val = cel.value.date().isoformat() ; ODBC Date
Set MolDatum = $zdh(val,3) ; LOGICAL Date
Write $zd(MolDatum),! ; DISPLAY Date
}
}Class dc.test [ Abstract ]
{
ClassMethod Test()
{
#dim ex As %Exception.AbstractException
#dim xDataStream As %Stream.Object
#dim mydoc As %XML.XPATH.Document
try{
set xDataStream=##class(%Dictionary.CompiledXData).IDKEYOpen(..%ClassName(1),"ClinicalDocXData").Data
$$$ThrowOnError
(##class(%XML.XPATH.Document).CreateFromStream(xDataStream, .mydoc,,,,,"s urn:hl7-org:v3"))
$$$ThrowOnError(mydoc.EvaluateExpression("//s:entry/s:Id", "text()", .tRes))
for i =1:1:tRes.Count() {
write tRes.GetAt(i).Value,!
}
}
catch(ex) {
write "Error ", ex.DisplayString(),!
}
}
XData ClinicalDocXData
{
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<MainDocument xmlns="urn:hl7-org:v3">
<realmCode code="IT"/>
<title>kjbkjkjbkjb</title>
<effectiveTime value="20090905150716"/>
<versionNumber value="1"/>
<component>
<body>mhvjhjkvhj</body>
<component>
<section>content</section>
<ID>5</ID>
<title>Certificato</title>
<text/>
<entry>
<Id>5</Id>
</entry>
<entry>
<Id>6</Id>
</entry>
</component>
</component>
</MainDocument>
}
}
Result:USER>do ##class(dc.test).Test() 5 6
TEST.TEST.cls
Class TEST.TEST Extends %Persistent
{
Property userActionone As %Boolean [ SqlColumnNumber = 2 ];
Property userActiontwo As %Boolean [ SqlColumnNumber = 3 ];
Property userActionthree As %Boolean [ SqlColumnNumber = 4 ];
Property userActionfour As %Boolean [ SqlColumnNumber = 5 ];
Property userActionfive As %Boolean [ SqlColumnNumber = 6 ];
Property userActionsix As %Boolean [ SqlColumnNumber = 7 ];
Property userActionseven As %Boolean [ SqlColumnNumber = 8 ];
Property userActioneigth As %Boolean [ SqlColumnNumber = 9 ];
Property userActionnine As %Boolean [ SqlColumnNumber = 10 ];
Property userActionten As %Boolean [ SqlColumnNumber = 11 ];
Property userActioneleven As %Boolean [ SqlColumnNumber = 12 ];
Property userActiontwelve As %Boolean [ SqlColumnNumber = 13 ];
Property userActionthirteen As %Boolean [ SqlColumnNumber = 14 ];
Property userActionfourteen As %Boolean [ SqlColumnNumber = 15 ];
ClassMethod Fill()
{
&sql(truncate table TEST.TEST)
&sql(insert into TEST.TEST
(userActionone,
userActiontwo,
userActionthree,
userActionfour,
userActionfive,
userActionsix,
userActionseven,
userActioneigth,
userActionnine,
userActionten,
userActioneleven,
userActiontwelve,
userActionthirteen,
userActionfourteen)
select 0,0,0,0,0,0,0,0,0,0,0,0,0,0
union all
select 1,0,0,0,0,0,0,0,0,0,0,0,0,0
union all
select 0,1,0,0,0,0,0,0,0,0,0,0,0,0
union all
select 0,0,1,0,0,0,0,0,0,0,0,0,0,0
union all
select 0,0,0,1,0,0,0,0,0,0,0,0,0,0
union all
select 0,0,0,0,1,0,0,0,0,0,0,0,0,0
union all
select 0,0,0,0,0,1,0,0,0,0,0,0,0,0
union all
select 0,0,0,0,0,0,1,0,0,0,0,0,0,0
union all
select 0,0,0,0,0,0,0,1,0,0,0,0,0,0
union all
select 0,0,0,0,0,0,0,0,1,0,0,0,0,0
union all
select 0,0,0,0,0,0,0,0,0,1,0,0,0,0
union all
select 0,0,0,0,0,0,0,0,0,0,1,0,0,0
union all
select 0,0,0,0,0,0,0,0,0,0,0,1,0,0
union all
select 0,0,0,0,0,0,0,0,0,0,0,0,1,0
union all
select 0,0,0,0,0,0,0,0,0,0,0,0,0,1
)
}
}That's what I get:
PS: Have you tried rebuilding the cube?
As you can see, the author asked two questions:
I answered the second question, and the other participants answered the first.What would be the best practices for these use cases?
- In some cases, it's necessary to manipulate data from one namespace to another. For example, a routine in the "N1" namespace needs data from the "N2" namespace.
- In the same context, how could I make a persistent class global for all namespaces? The only way I know is by putting it in %SYS.
Both.Just for understanding. Will the result change if the conditions are reversed? For example:
$SELECT( %source.userActionfourteen=1:"User action fourteen", %source.userActionthirteen=1:"User action thirteen", %source.userActiontwelve=1:"User action twelve", %source.userActioneleven=1:"User action eleven", %source.userActionten=1:"User action ten", %source.userActionnine=1:"User action nine", %source.userActioneigth=1:"User action eigth", %source.userActionseven=1:"User action seven", %source.userActionsix=1:"User action six", %source.userActionfive=1:"User action five", %source.userActionfour=1:"User action four", %source.userActionthree=1:"User action three", %source.userActiontwo=1:"User action two", %source.userActionone=1:"User action one", 1:"Other")
I agree.
$CASE(1, %source.userActionone:"User action one", %source.userActiontwo:"User action two", %source.userActionthree:"User action three", %source.userActionfour:"User action four", %source.userActionfive:"User action five", %source.userActionsix:"User action six", %source.userActionseven:"User action seven", %source.userActioneigth:"User action eigth", %source.userActionnine:"User action nine", %source.userActionten:"User action ten", %source.userActioneleven:"User action eleven", %source.userActiontwelve:"User action twelve", %source.userActionthirteen:"User action thirteen", %source.userActionfourteen:"User action fourteen", :"Other")
But the result will still be only one value, even if all %source.userActionXXX=1.
What result should $select return if the conditions %source.userActionone=1 AND %source.userActiontwo=1 are true ?
&sql(DECLARE C2 CURSOR FOR SELECT name INTO :name FROM person where name = :namevar)See Host Variables