转到文章 Louis Lu · 八月 6 Include EnsConstants /// Get Settings from Production and Create DefaultSettings Class CONNECTORSPKG.Utility.DefaultSettings { /// List productions ClassMethod ListProductions(print As %Boolean = 1, namespace As %String = {$NAMESPACE}) As %String { new $NAMESPACE set $NAMESPACE = namespace set production = "" if print { 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") } if print { write prdRS.Data("Production")," (",status,")",! } } return production } /// Export to settingsfile ClassMethod Export() As %Status { return ##class(Ens.Config.DefaultSettings).%Export("/home/irisowner/systemdefaults/Ens.Config.DefaultSettings.esd", "MONDRIAAN.FoundationProduction") } /// Export from settingsfile ClassMethod 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 action ClassMethod 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 Production ClassMethod 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.TextReader if $$$ISERR(sc) { write "Failed to parse XData block '" _xdataId,"': ",$SYSTEM.Status.GetErrorText(sc),! return sc } set currentItemName = "" set currentItemClass = "" #dim tRemovedItemCount as %Integer = 0 while 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 value set 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 } } } /// SaveProduction ClassMethod SaveProduction(tProduction As Ens.Config.Production) As %Status { // Save the changes we made to the production set sc = tProduction.%Save(1) if $$$ISERR(sc) { write " failed: ",$SYSTEM.Status.GetErrorText(sc),! return sc } write ! // Regenerate the XData in the corresponding class write "Save Production XData: " Set sc = tProduction.SaveToClass() if $$$ISERR(sc) { write " failed: ",$SYSTEM.Status.GetErrorText(sc),! return sc } write ! // Grab the state of the production set 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 settings write "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, class As %String, target As %String, varName As %String, value As %String) As %Boolean { if filter = "" { return 1 } 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 { return 1 } } } return 0 } /// Handle Setting ClassMethod HandleSetting(production As %String, item As %String, class As %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 = class set defaultSetting.SettingName = varName set defaultSetting.Deployable = 1 write "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 production ClassMethod 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),! return 0 } 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 } } return 0 } }
转到文章 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 · 五月 29, 2023 由以上信息不足以判断安装失败的原因。从我的经验看,最主要安装失败的原因是安装版本和操作系统不匹配造成。 请根据文档 https://docs.intersystems.com/irisforhealth20221/csp/docbook/DocBook.UI.... 确定安装包支持的操作系统。 并同时注意安装IRIS的服务器芯片组,比如是x86-64 或 ARM64等,需要对应不同的安装文件。
转到文章 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 请参考文档:https://docs.intersystems.com/irisforhealth20231/csp/docbook/Doc.View.cl... 提供更多ODBC 日志以供错误排查。 也可以在菜单中选择系统操作 -- 系统日志 -- xDBC错误日志查看。 还可以尝试使用其他三方ODBC工具,同样加载该odbc驱动,看是否报错。
转到文章 Louis Lu · 五月 29, 2023 是的使用了索引,主要过程为:通过IndexBGRQ,将BGRQ对应的ROWId写入 临时文件A 再遍历临时文件A中的RowID,查询DataMaster中的内容。
转到文章 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 这个具体要看代码Fetch2函数的第4行是什么,有可能是在query中使用了Unicode字符,可以尝试使用PrepareW替代Prepare函数,也有可能某些函数仅支持$CHAR(0) 到 $CHAR(255),比如Base64 encoding。 或者在安装的时候需要选择Unicode而不是8-bit的安装参数。 具体原因需要根据源代码分析。
转到文章 Louis Lu · 四月 25, 2023 建议在Unix上使用JDBCGateway,因为目前只有iODBC支持Unicode 下面是示例代码使用JDBCGateway #dim %JDBCGateway As %Net.Remote.Java.JDBCGateway set conn = $system.SQLGateway.GetJDBCConnection("TestConn") if (conn = "") quit 0 set cmd = "select c1,c2,c3 from wrc943403 where c1 = ?" set st = %JDBCGateway.prepareStatement(conn, cmd) do %JDBCGateway.setString(st,1,9) // assign c1 to 9 set 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 · 二月 8, 2023 可以试试在Mirror配置里面选中使用传输的压缩模式,具体文档看这里。 也就是从主机传输到备机、异步镜像成员的内容是压缩后的,这样可以大大较少网络占用。 还有建议将Mirror镜像成员之间传输数据使用的网络和使用数据的外部应用网络区分开,如果使用了ECP配置更加需要注意,如下图区分了1.给用户和其他系统接入使用的网络。2.为ECP通讯使用的私有网以及3.为Mirror通讯的私有网: 更多Mirror架构以及网络配置建议可以参考官方文档,这里。
转到文章 Louis Lu · 一月 4, 2023 如果是运行在IRIS下,可以参考使用JSON Adaptor,详细文档可以参考这里 比如要使用包含下划线_的字段,可以使用%JSONFIELDNAME 定义 更多有关%JSON.Adaptor 类定义可以参考这里
转到文章 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 · 十一月 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}", "SOAP Wizard": "${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 · 九月 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 hisotries while rs.Next() { write rs.Get("Task Name"),":",rs.Get("Result"),! }
转到文章 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 · 三月 27, 2022 在Production中使用函数请参考文档:https://docs.intersystems.com/irisforhealth20212/csp/docbook/DocBook.UI.... 如何自定义函数可以参考:https://docs.intersystems.com/irisforhealth20212/csp/docbook/DocBook.UI....
转到文章 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 · 三月 16, 2022 既然是再研究,何不试试我们最新的InterSystems IRIS。如果以前研究过Caché 会发现,IRIS 还是同样的架构、同样的开发语言、同样的global存储,只是人机交互更流畅、性能更快,增加更多扩展,机器学习、python、丰富的外部BI工具适配、容器化部署、API管理等等等等,都等着你探索。 要想体验就在社区主页左边,选择下载InterSystems IRIS。 WRC可以说是我们对客户的支持中心,所以只面对我们的客户开放注册。