Louis Lu · 三月 16, 2022 转到文章

不知道你在哪里找文档找了一个星期,可以直接去docs.intersytems.com,选择你要对应的版本,然后再查找框里输入jdbc url, 比如我在最新的InterSystems IRIS for health 2021.2的文档中查到:

jdbc:IRIS://<host>:<port>/<namespace>/<logfile>:<eventclass>:<nodelay>:<ssl>

比如:

jdbc:IRIS://127.0.0.1:1972/User

原文在这里:https://docs.intersystems.com/irisforhealth20212/csp/docbook/DocBook.UI.Page.cls?KEY=BJAVA_connecting#BJAVA_connecting_url

Louis Lu · 三月 16, 2022 转到文章

既然是再研究,何不试试我们最新的InterSystems IRIS。如果以前研究过Caché 会发现,IRIS 还是同样的架构、同样的开发语言、同样的global存储,只是人机交互更流畅、性能更快,增加更多扩展,机器学习、python、丰富的外部BI工具适配、容器化部署、API管理等等等等,都等着你探索。

要想体验就在社区主页左边,选择下载InterSystems IRIS。

WRC可以说是我们对客户的支持中心,所以只面对我们的客户开放注册。

Louis Lu · 三月 25, 2022 转到文章

试试扩展函数,里面使用%Ensemble获取,同时还有%System中可以获取更多系统信息。

再在rule中使用这个扩展函数。

Class utils.functions Extends Ens.Rule.FunctionSet
{

ClassMethod GetSess()
{
	s s=%Ensemble("SessionId")
	&SQL(Select SourceConfigName into :sess from Ens.MessageHeader where ID=:s)
	Quit sess
}
}
Louis Lu · 九月 25, 2022 转到文章

直接用%XML.Reader,可以通过设置它的 SAXSchemaSpec 参数指定 schema。

读取xml就可以了。

USER>set reader  = ##class(%XML.Reader).%New()
 
USER>set reader.SAXSchemaSpec = "c:\tmp\a.xsd"
 
USER>set sc = reader.OpenString(XMLstr)
 
USER>do$System.OBJ.DisplayError(sc)
Louis Lu · 九月 26, 2022 转到文章

Message Router的主要功能是消息路由,可以根据传递消息的不同内容将消息发送给不同的目标。

它不能用于监视task schedule任务执行的情况。

如果要通过代码监视任务执行情况可以:

set rs=##class(%ResultSet).%New("%SYS.Task.History:TaskHistoryForDay")
 set startH=$ZDH("02/01/2017")
 set endH=$ZDH("02/28/2017")
 do rs.Execute(startH,endH)
 ;do rs.Execute()     ;; or take all hisotrieswhile rs.Next() {
  write rs.Get("Task Name"),":",rs.Get("Result"),!
 }
Louis Lu · 十一月 17, 2022 转到文章

可以通过下面网址直接打开SOAP 向导页:

{serverurl}/isc/studio/templates/%25ZEN.Template.AddInWizard.SOAPWizard.cls?Namespace={namespace}

比如:http://localhost:52779/isc/studio/templates/%25ZEN.Template.AddInWizard…

也可以在VSCode里添加用户自定义的快捷键:

"objectscript.conn": {
    "links": {
        "Portal Explorer": "${serverUrl}/csp/sys/exp/%25CSP.UI.Portal.ClassList.zen?$NAMESPACE=${ns}",
        "SOAPWizard": "${serverUrl}/isc/studio/templates/%25ZEN.Template.AddInWizard.SOAPWizard.cls?$NAMESPACE=${ns}"
    },
}

参考文档:https://intersystems-community.github.io/vscode-objectscript/configuration/#server-actions-menu

另:BPL,DTL一般直接在浏览器中进行编辑,完全不需要VSCode。

Louis Lu · 十二月 5, 2022 转到文章

使用Python Binding,参见文档 https://cedocs.intersystems.com/ens20162/csp/docbook/DocBook.UI.Page.cls?KEY=GBPY_intro

例如一些基本的操作:

  • 创建数据库连接
       conn = intersys.pythonbind.connection()
       conn.connect_now(url,user,password, None)
       database = intersys.pythonbind.database(conn)
  • 打开存在的对象
       person =  database.openid("Sample.Person",str(id),-1,-1)
  • 创建新的对象
       person =  database.create_new("Sample.Person", None)
  • 设置对象属性或者取值
       person.set("Name","Doe, Joe A")
       name = person.get("Name")
  • 运行一个方法
       answer = person.run_obj_method("Addition",[17,20])
  • 保存对象
       person.run_obj_method("%Save",[])
  • 获取保存对象的id 
       id = person.run_obj_method("%Id",[])
  • 执行一个查询 
       sqlstring ="SELECT ID, Name, DOB, SSN \
                   FROM SAMPLE.PERSON \
                   WHERE Name %STARTSWITH ?"
       query = intersys.pythonbind.query(database)
       query.prepare(sqlstring)
       query.set_par(1,"A")
       query.execute();
       while 1:
          cols = query.fetch([None])
          if len(cols) == 0: break
          print cols

同时可以在安装目录的/dev/Python/samples/ 下查看更多例子,比如

  • CPTest6.py — Process the result set of a ByName query.
  • CPTest7.py — Process the result set of a dynamic SQL query.
Louis Lu · 一月 4, 2023 转到文章

如果是运行在IRIS下,可以参考使用JSON Adaptor,详细文档可以参考这里

比如要使用包含下划线_的字段,可以使用%JSONFIELDNAME  定义

更多有关%JSON.Adaptor 类定义可以参考这里

Louis Lu · 二月 8, 2023 转到文章

可以试试在Mirror配置里面选中使用传输的压缩模式,具体文档看这里

也就是从主机传输到备机、异步镜像成员的内容是压缩后的,这样可以大大较少网络占用。

还有建议将Mirror镜像成员之间传输数据使用的网络和使用数据的外部应用网络区分开,如果使用了ECP配置更加需要注意,如下图区分了1.给用户和其他系统接入使用的网络。2.为ECP通讯使用的私有网以及3.为Mirror通讯的私有网:

Mirror members are on one private LAN, app servers on another for the mirror and on a campus network for external connections

更多Mirror架构以及网络配置建议可以参考官方文档,这里

Louis Lu · 四月 25, 2023 转到文章

建议在Unix上使用JDBCGateway,因为目前只有iODBC支持Unicode

下面是示例代码使用JDBCGateway

#dim%JDBCGatewayAs%Net.Remote.Java.JDBCGatewayset conn = $system.SQLGateway.GetJDBCConnection("TestConn")
 if (conn = "") quit0set cmd = "select c1,c2,c3 from wrc943403 where c1 = ?"set st = %JDBCGateway.prepareStatement(conn, cmd)
 do%JDBCGateway.setString(st,1,9) // assign c1 to 9set res = %JDBCGateway.execQuery(st)
 if (res) {
   set error = %JDBCGateway.getErrorText()
   write"error = ",error,!
   quit
 }
 while%JDBCGateway.next(st) {
   set c1 = %JDBCGateway.getString(st,1)
   set c2 = %JDBCGateway.getString(st,2)
   write"c1=",c1,!
   write"c2=",c2,!
 }
 write$system.SQLGateway.DropConnection("TestConn")
 quit
Louis Lu · 五月 29, 2023 转到文章

这个具体要看代码Fetch2函数的第4行是什么,有可能是在query中使用了Unicode字符,可以尝试使用PrepareW替代Prepare函数,也有可能某些函数仅支持$CHAR(0) 到 $CHAR(255),比如Base64 encoding。

或者在安装的时候需要选择Unicode而不是8-bit的安装参数。

具体原因需要根据源代码分析。

Louis Lu · 五月 29, 2023 转到文章

可以将Java Gateway Service的日志打开,设置方法是在Production管理页面选中该组件上,在设置中设置日志文件(包括路径和文件名称)。如果问题再次出现,我们可以对日志文件进行分析,开启之后请注意该文件的大小增长。

另外,linux的Dynamic TCP port范围是32768~60999,可通过下面的命令进行查询,例如(在RedHat7.9下),

sysctl net.ipv4.ip_local_port_range

net.ipv4.ip_local_port_range = 32768 60999

在这个范围内的tcp端口号可能会被系统动态分配给其他进程使用,所以建议咱们更改一个不在此范围内的端口号。

Louis Lu · 五月 29, 2023 转到文章

是的使用了索引,主要过程为:通过IndexBGRQ,将BGRQ对应的ROWId写入 临时文件A

再遍历临时文件A中的RowID,查询DataMaster中的内容。

Louis Lu · 五月 29, 2023 转到文章

可参考文档:https://docs.intersystems.com/ens201817/csp/docbook/DocBook.UI.Page.cls…

提供以下方法/工具分析sql性能:

SQL运行时统计:生成查询执行的性能统计。

索引分析器:显示当前命名空间中所有查询的各种索引分析器报告。这显示了Caché SQL要如何执行查询,让你对索引的使用情况有一个整体的了解。这个索引分析可能表明,你应该添加一个或多个索引来提高性能。

显示计划:显示SQL查询的最佳(默认)执行计划。

备选显示计划:显示一个SQL查询的可用备选执行计划,并附有统计数据。

索引优化选项:可用FROM子句来管理所有的条件,或者用%NOINDEX作为单个条件的前导。

并行查询处理 :可用%PARALLEL关键字的FROM子句选项,允许多处理器系统在各处理器之间划分查询执行。

Louis Lu · 五月 29, 2023 转到文章

这个函数是java调用IRIS上的方法或者routine。

比如有一个routine的名字是NativeRoutine,routine中有一个方法的名字是fnString,方法调用的参数是"World"

那么从Java调用就可以:

String stringVal = irisjv.functionString("fnString",routineName,"World");

详细文档可以参考:https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI.Page.cls?KEY=BJAVNAT_call

Louis Lu · 八月 6, 2024 转到文章
Include EnsConstants

/// Get Settings from Production and Create DefaultSettingsClass CONNECTORSPKG.Utility.DefaultSettings
{

/// List productionsClassMethod ListProductions(printAs%Boolean = 1, namespace As%String = {$NAMESPACE}) As%String
{
    new$NAMESPACEset$NAMESPACE = namespace
    set production = ""ifprint
    {
        write"Productions in namespace " _ namespace _ ":",!
    }

    set prdRS = ##class(%ResultSet).%New("Ens.Config.Production:ProductionStatus")
    do prdRS.Execute()

    while (prdRS.Next())
    {
        set status = prdRS.Data("Status")

        if status = "Running"
        {
            set production = prdRS.Data("Production")
        }

        ifprint
        {
            write prdRS.Data("Production")," (",status,")",!
        }
    }

    return production
}

/// Export to settingsfileClassMethod Export() As%Status
{
    return##class(Ens.Config.DefaultSettings).%Export("/home/irisowner/systemdefaults/Ens.Config.DefaultSettings.esd", "MONDRIAAN.FoundationProduction")
}

/// Export from settingsfileClassMethod Import() As%Status
{
    set sc = ##class(Ens.Config.DefaultSettings).%Import("/home/irisowner/systemdefaults/Ens.Config.DefaultSettings.esd", .count, .idsimported)

    write"Imported ",count," settings",!

    return sc
}

/// Connectors actionClassMethod SettingsFromProduction(removeFromProduction As%Boolean = 0, updateSettings As%Boolean = 1) As%Status
{
    return..GetSettingsFromProduction("CONNECTORSPKG.FoundationProduction", "*:HTTPServer,SSLConfig;CONNECTORSPKG.BO.GenericHTTP.Operation:HttpMethod,AcceptHeader,ContentType,URL,AuthorizationType,Credentials,CustomAuthorizationHeader,AlertOnError,ReplyCodeActions", removeFromProduction, updateSettings)
}

/// Get settings From ProductionClassMethod GetSettingsFromProduction(production As%String = {..ListProductions(0, $NAMESPACE)}, filter As%String = "", removeFromProduction As%Boolean = 0, updateSettings As%Boolean = 1) As%Status
{
    write"Settings in production '",production _ "':",!
    set xdataId = production _ "||ProductionDefinition"set xdata = ##class(%Dictionary.XDataDefinition).%OpenId(xdataId, , .sc)

    if$$$ISERR(sc)
    {
        write"Failed to open XData block '" _ xdataId,"': ",$SYSTEM.Status.GetErrorText(sc),!
        return sc
    }

    set tProduction = ##class(Ens.Config.Production).%OpenId(production,,.sc)

    if$$$ISERR(sc)
    {
        write"Failed to open production '",production,"': ",$SYSTEM.Status.GetErrorText(sc),"; settings will not be removed from the production",!
        set removeFromProduction = 0
    }

    set sc = ##class(%XML.TextReader).ParseStream(xdata.Data, .textreader)
    #dim textreader as%XML.TextReaderif$$$ISERR(sc)
    {
        write"Failed to parse XData block '" _xdataId,"': ",$SYSTEM.Status.GetErrorText(sc),!
        return sc
    }

    set currentItemName = ""set currentItemClass = ""#dim tRemovedItemCount as%Integer = 0while textreader.Read()
    {
        if (textreader.NodeType '= "element")
        {
            continue
        }

        if (textreader.LocalName = "Item")
        {
            if (textreader.MoveToAttributeName("Name"))
            {
                set currentItemName = textreader.Value
            }

            if (textreader.MoveToAttributeName("ClassName"))
            {
                set currentItemClass = textreader.Value
            }
            #; write "Found Item with Name='" _ currentItemName _ "' of class '" _ currentItemClass _ "':",!continue
        }

        if (textreader.LocalName = "Setting")
        {
            do..HandleXDataSetting(textreader, tProduction, currentItemName, currentItemClass, filter, removeFromProduction, updateSettings, .tRemovedItemCount)
        }
    }

    if tRemovedItemCount > 0
    {
        write"Removed ",tRemovedItemCount," settings; now saving Production '",production,"':"return..SaveProduction(tProduction)
    }

    return$$$OK
}

/// Hanlde setting found in the XData ClassMethod HandleXDataSetting(textreader As%XML.TextReader, tProduction As Ens.Config.Production, currentItemName As%String, currentItemClass As%String, filter As%String, removeFromProduction As%Boolean, updateSettings As%Boolean, ByRef tRemovedItemCount As%Integer)
{
    if (textreader.MoveToAttributeName("Target"))
    {
        set target = textreader.Value
    }
    if (textreader.MoveToAttributeName("Name"))
    {
        set name = textreader.Value
    }

    do textreader.Read() // Read valueset value = textreader.Value

    #; write "Found Setting Target=",target,", name=",name,", Value=",value,!if..InFilter(filter, currentItemName, currentItemClass, target, name, value)
    {
        if updateSettings && $$$ISERR(..HandleSetting(tProduction.Name, currentItemName, currentItemClass, target, name, value))
        {
            return
        }

        if removeFromProduction && ..RemoveSettingFromProduction(tProduction, currentItemName, target, name)
        {
            set tRemovedItemCount = tRemovedItemCount + 1
        }
    }
}

/// SaveProductionClassMethod SaveProduction(tProduction As Ens.Config.Production) As%Status
{
    // Save the changes we made to the productionset sc = tProduction.%Save(1)

    if$$$ISERR(sc)
    {
        write" failed: ",$SYSTEM.Status.GetErrorText(sc),!
        return sc
    }
    write !

    // Regenerate the XData in the corresponding classwrite"Save Production XData: "Set sc = tProduction.SaveToClass()

    if$$$ISERR(sc)
    {
        write" failed: ",$SYSTEM.Status.GetErrorText(sc),!
        return sc
    }
    write !

    // Grab the state of the productionset sc = ##class(Ens.Director).GetProductionStatus(.tRunningProduction, .tState)

    if$$$ISERR(sc)
    {
        write"Failed to get Production status: ",$SYSTEM.Status.GetErrorText(sc),!
        return sc
    }

    // Finally, does the production need updating?if (tRunningProduction = tProduction.Name) && (tState = $$$eProductionStateRunning)
    {
        // Update the running production with the new settingswrite"Update running production: "set sc = ##class(Ens.Director).UpdateProduction(##class(Ens.Director).GetRunningProductionUpdateTimeout())

        if$$$ISERR(sc)
        {
            write" failed: ",$SYSTEM.Status.GetErrorText(sc),!
            return sc
        }
    }

    return$$$OK
}

/// Determine if the setting is in the Filter ClassMethod InFilter(filter As%String, itemName As%String, classAs%String, target As%String, varName As%String, value As%String) As%Boolean
{
    if filter = ""
    {
        return1
    }

    for classIndex = 1:1:$LENGTH(filter, ";")
    {
        set classPart = $PIECE(filter, ";", classIndex)
        set configClass = $PIECE(classPart, ":", 1)

        if (configClass '= "*") && (configClass '= class)
        {
            continue
        }

        set vars = $PIECE(classPart, ":", 2)

        for varIndex = 1:1:$LENGTH(vars, ",")
        {
            if$PIECE(vars, ",", varIndex) = varName
            {
                return1
            }
        }
    }

    return0
}

/// Handle SettingClassMethod HandleSetting(production As%String, item As%String, classAs%String, target As%String, varName As%String, value As%String) As%Status
{
    if##class(Ens.Config.DefaultSettings).IdKeyExists(production, item, class, varName, .id)
    {
        set defaultSetting = ##class(Ens.Config.DefaultSettings).%OpenId(id, , .sc)

        if$$$ISERR(sc)
        {
            write"Failed to get default setting named '",item,":",varName,"': ",$SYSTEM.Status.GetErrorText(sc),!
            return sc
        }

        if defaultSetting.SettingValue = value
        {            
            write"Skipping '",item,":",varName,"' as it already exists with the same value",!
            return$$$OK
        }

        write"Updating '",item,":",varName,"' from '",defaultSetting.SettingValue,"' to '",value,"'",!
    }
    else
    {
        set defaultSetting = ##class(Ens.Config.DefaultSettings).%New()
        set defaultSetting.ProductionName = production
        set defaultSetting.ItemName = item
        set defaultSetting.HostClassName = classset defaultSetting.SettingName = varName
        set defaultSetting.Deployable = 1write"Creating '",item,":",varName,"' from '",defaultSetting.SettingValue,"' with value '",value,"'",!
    }

    set defaultSetting.SettingValue = value

    set sc =  defaultSetting.%Save()

    if$$$ISERR(sc)
    {
        write"Failed setting default setting named '",item,":",varName,"' to '",value,"': ",$SYSTEM.Status.GetErrorText(sc),!
    }

    return sc
}

/// Rmove Setting from productionClassMethod RemoveSettingFromProduction(tProduction As Ens.Config.Production, item As%String, target As%String, varName As%String) As%Boolean
{
    #dim tItemObj as Ens.Config.Item = tProduction.FindItemByConfigName(item, .sc, 1)

    if '$IsObject(tItemObj)
    {
        write"Failed to get item '",item,"': ",$SYSTEM.Status.GetErrorText(sc),!
        return0
    }

    for i = 1:1:tItemObj.Settings.Count()
    {
        #dim tSetting As Ens.Config.Setting = tItemObj.Settings.GetAt(i)

        if (tSetting.Name = varName) && (tSetting.Target = target)
        {
            do tItemObj.Settings.RemoveAt(i, .success)
            return success
        }
    }

    return0
}

}