搜索​​​​

清除过滤器
公告
Michael Lei · 十月 24, 2023

官宣对 CentOS 的支持终止

终止对 CentOS 的支持 自 InterSystems IRIS 2023.3 发布起,CentOS 将不再是受支持的开发平台。 CentOS 一直是一个受支持的开发平台,为开发人员提供了相当于 Red Hat Enterprise Linux (RHEL) 的免费版本,用于 IRIS 开发。您可能知道,Red Hat 对 CentOS 进行了重大更改,CentOS 已成为 RHEL 的“上游”。这意味着它具有 RHEL 中尚未包含的错误和功能,这可能会给在该平台上构建的开发人员带来问题。 我们鼓励使用 CentOS 的开发人员利用 Red Hat 的免费开发人员计划来获得 RHEL 的免费开发许可证。 CentOS 继续支持 IRIS 2023.2(及更早版本)。
文章
Weiwei Gu · 八月 7, 2023

如何自定义 Web 网关错误消息

InterSystems 常见问题解答标题 您可以为以下 Web Gateway 错误消息/系统响应设置单独的错误页面: 服务器错误 服务器繁忙 服务器无法使用 服务器超时 连接关闭 在 Web Gateway 管理界面上进行设置([Management Portal] > [System Administration] > [Configuration] > [Web Gateway Management] > [Configuration] > [Default Parameters])。 在“默认参数”(Default Parameters )菜单的“错误页面”部分中,设置要显示的 html 页面的文件名或发生错误时要重定向到的 URL。 ※Web网关管理界面也可以从以下URL访问。 http://<web server address>:<port>/csp/bin/Systems/Module.cxw 详细信息请参考以下文档自定义错误页面 [IRIS]
问题
Michael Lei · 二月 14, 2023

有没有办法导出与Production相关的所有内容?

您好,有没有一种简单的方法可以导出与Production相关的所有内容并在另一个实例中导入? 例如导出Production保存的 db、ns、映射、webapp 相关、资源、角色等 您可以使用InterSystems Package Manager(IPM)列出生产的所有成员,并通过IPM注册表或使用zpmhub将其分发到另一台机器(例如您的客户端)。 例如,您可以将多个EnsDemo产品安装为一个包: 用户>zpm“安装irishealth-ensdemo” 或者最近我发布了一个非常简单的CSV数据转换生产示例,您可以将其安装为一行: USER>zpm "install esh-i14y-csv" 下面是如何在module.xml中描述生产的所有模块。
文章
Michael Lei · 五月 17, 2021

iris-fhir-portal 概述

我创建了 iris-fhir-portal 来参加当前竞赛 **[InterSystems IRIS for Health FHIR](https://community.intersystems.com/post/welcome-intersystems-iris-health-fhir-contest-developers),**本篇快速概述旨在介绍我的应用程序提供的功能。 iris-fhir-portal 的目标是说明使用 IRIS for Health 中的 FHIR 功能创建患者图表并让用户拥有自己的数据有多么简单。 ## 功能 ### 患者列表 在左侧面板上,有一个患者列表,顶部是一个筛选栏。 ![](/sites/default/files/inline/images/images/search.png) ### 患者详细信息 ![](/sites/default/files/inline/images/images/formloaded_badges.png) 表格提供以下信息: * FHIR 患者 ID * SSN(社会保障号码) * 名字 * 姓氏 * 出生日期 * 性别 * 地址 * 城市 * 州/省 * 国家/地区 在患者详细信息表格后面,是一个包含四个信息块的可折叠项。 提供这些信息的 FHIR 资源为: * AllergyIntolerance * Observation * 类别:vital-signs * 类别:laboratory * Immunization 右侧的徽章显示每个项目的结果总数。 附注:我在上一篇文章中写到了如何从 FHIR 资源获取所有这些信息。 https://community.intersystems.com/post/my-experience-working-fhir 例如,以下是实验室数据结果的屏幕截图: ![](/sites/default/files/inline/images/images/accordionresults.png) 为了以透明的方式处理患者数据,在页面末尾有一个模版,其中包含 FHIR 资源提供的所有信息。 ![](/sites/default/files/inline/images/images/fhir_resourcedata.png) ####   #### 您可以在这里试用本应用程序!   如果您喜欢本应用程序,并认为我值得您投票,请为 iris-fhir-portal 投一票!  ![laugh](https://community.intersystems.com/sites/all/libraries/ckeditor/plugins/smiley/images/teeth_smile.png "laugh") ****  
文章
Michael Lei · 三月 21, 2022

消息转换即服务--轻松实现从HL7v2 转换为 FHIR !

# IRIS Healthtoolkit Service 软件即服务 [![Video](https://raw.githubusercontent.com/grongierisc/iris-healthtoolkit-service/main/misc/images/Cover.png)](https://youtu.be/lr2B7zSFkds "Video") 轻松实现HL7v2 转 FHIR, CDA 转 FHIR, FHIR 转 HL7v2 即服务. 这个项目的目标是提供 REST API 可以轻松转化不同的医疗行业格式。 在Rest body 发布需要的格式,在答案中获得新的格式。 * ![emoji](https://community.intersystems.com/sites/all/libraries/ckeditor/plugins/smiley/images/tongue_smile.png) InterSystems 消息转换公有云服务: https://aws.amazon.com/marketplace/pp/prodview-q7ryewpz75cq2 ![emoji](https://community.intersystems.com/sites/all/libraries/ckeditor/plugins/smiley/images/tongue_smile.png) * ![emoji](https://community.intersystems.com/sites/all/libraries/ckeditor/plugins/smiley/images/devil_smile.png) 视频(油管) : https://youtu.be/lr2B7zSFkds ![emoji](https://community.intersystems.com/sites/all/libraries/ckeditor/plugins/smiley/images/devil_smile.png) ## 安装 克隆这个 repository ``` git clone https://github.com/grongierisc/iris-healthtoolkit-service.git ``` Docker ``` docker-compose up --build -d ``` ## 使用 * 访问 : http://localhost:32783/swagger-ui/index.html ## API 细节 * HL7 转 FHIR ``` POST http://localhost:32783/api/hl7/fhir ``` * FHIR 转 HL7 ADT ``` POST http://localhost:32783/api/fhir/hl7/adt ``` * FHIR 转 HL7 ORU ``` POST http://localhost:32783/api/fhir/hl7/oru ``` * FHIR 转 HL7 vxu ``` POST http://localhost:32783/api/fhir/hl7/vxu ``` * CDA 转 FHIR ``` POST http://localhost:32783/api/cda/fhir ``` * FHIR repo ``` GET http://localhost:32783/api/fhir/metadata ``` ## 支持的 HL7 inbound 格式 : * ADT_A01, ADT_A02, ADT_A03, ADT_A04, ADT_A05, ADT_A06, ADT_A07, ADT_A08, ADT_A09, ADT_A10, ADT_A11, ADT_A12, ADT_A13, ADT_A17, ADT_A18, ADT_A23, ADT_A25, ADT_A27, ADT_A28, ADT_A29, ADT_A30, ADT_A31, ADT_A34, ADT_A36, ADT_A39, ADT_A40, ADT_A41, ADT_A45, ADT_A47, ADT_A49, ADT_A50, ADT_A51, ADT_A60 * BAR_P12 * MDM_T02, MDM_T04, MDM_T08, MDM_T11 * OMP_O09 * ORM_O01 * ORU_R01 * PPR_PC1, PPR_PC2, PPR_PC3 * RDE_O11 * SIU_S12, SIU_S13, SIU_S14, SIU_S15, SIU_S16, SIU_S17, SIU_S26 * VXU_V04 ## 如何工作 这个项目基于SDA模型工作. SDA (Summary Document Architecture) 是InterSystems系联公司的临床数据格式。 SDA FHIR 的对应关系在 [这里](https://docs.intersystems.com/irisforhealthlatest/csp/docbook/Doc.View.cls?KEY=HXFHIR_transforms), CDA -> SDA 的对应在[这里](https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI.Page.cls?KEY=HXCDA). ![gif sda pivot](https://raw.githubusercontent.com/grongierisc/iris-healthtoolkit-service/main/misc/images/Gif_SDA_Pivot.gif)
文章
Michael Lei · 四月 17, 2022

在IRIS容器里添加VSCode

# 在IRIS容器里添加VSCode 设置可重复的开发环境的最简单的方法之一是使用容器。我发现在快速迭代时,在我的开发环境容器里托管一个vscode实例是非常方便的。因此,我创建了一个快速的容器脚本,将一个基于浏览器的vscode添加到IRIS容器中。这应该适用于大多数2021.1以上的容器。[我的代码库可以在这里找到](https://github.com/nickmitchko/Hosting-vscode-in-a-container) > 带VSCode 且预连接好的InterSystems IRIS 容器 | Cred | Value | |--------------|:--------:| | User | _SYSTEM | | Password | SYS | ![image](/sites/default/files/inline/images/hostedvscodebanner.gif) ## 概要 这个项目创建了一个IRIS容器,在同一个IRIS容器中提供了vscode的托管(web-based)版本。这提供了: * 同样的容器代码编辑 * 预连接到容器内的IRIS 实例 * 管理门户里的链接 * 自动启动IDE # 快速启动 1. [下载](https://github.com/nickmitchko/Hosting-vscode-in-a-container/archive/refs/heads/master.zip) 或者 `git clone https://github.com/nickmitchko/Hosting-vscode-in-a-container.git` 2. 在项目根目录下, 运行 `docker build . -t vscode-irishealth-ml:latest --no-cache` 3. 执行 `docker-compose up` * 不使用 docker compose? 请看 [这里](#No-Docker-Compose) 4. 浏览 [管理门户](http://localhost:52773/csp/sys/%25CSP.Portal.Home.zen) 5. 用用户名和密码登陆 6. 在Favorites 面板里点击 VSCODE 链接 on the favorites pane 7. 依据提示在VScode里使用相同的用户名/密码 来连接到IRIS 实例 ```bash # New folder for project mkdir vscode-iris cd vscode-iris # Clone repo here git clone https://github.com/nickmitchko/Hosting-vscode-in-a-container.git . # Build image docker build . -t vscode-irishealth-ml:latest --no-cache # Only Run (A) or (B) # # (A) Run compose file docker-compose up # OR (B) if you want a daemon docker-compose up -d ``` ## 添加持久化 如果想要一个持久化IRIS实例, 去掉docker-compose.yml 文件中16-20行里的注释 . 这样就在容器上增加了一个持久化存储的挂载。 ```yml volumes: - "./durable/:/durable/" environment: - ISC_DATA_DIRECTORY=/durable/iconfig ``` ## 改变基础镜像Base Image 这个镜像是建立在 InterSystems 开发者社区 zpm 镜像上 ([看这里](https://hub.docker.com/r/intersystemsdc/iris-community/tags)). 这些镜像包括了让我们从package repo 安装的zpm命令,只是仅有一个90天的社区版 license。 用于这个builds上的镜像标签image tag: ```dockerfile FROM intersystemsdc/irishealth-ml-community:latest ``` 如果你想改变镜像, 把docker 文件里的第一行改成你想要的镜像标签image tag (可以是一个自定义的IRIS instance 或者 [官方支持的](https://docs.intersystems.com/components/csp/docbook/DocBook.UI.Page.cls?KEY=PAGE_containerregistry#PAGE_containerregistry_public)). 例如: ```dockerfile FROM containers.intersystems.com/intersystems/irishealth-community:2021.2.0.651.0 ``` # 无 Docker-Compose 如果你没有用 docker compose, 你仍然可以如下运行容器: ```bash # After building the container # --after command is required docker run --name vscode -d \ --publish 1972:1972 \ --publish 52773:52773 \ --publish 51773:51773 \ --publish 53773:53773 \ --publish 8080:8080 \ --publish 8888:8888 \ vscode-irishealth-ml:latest \ --after "/bin/bash /install/boot.sh" ```
文章
Muhammad Waseem · 八月 11, 2022

FHIR 客户端使用嵌入式 python 连接任何打开的 FHIR 服务器

嗨社区, 这篇文章公开介绍我的 iris-fhir-client 客户端应用。 iris-fhir-client 可以可以借助嵌入式 python 连接到任何开放的 FHIR 服务器 fhirpy 图书馆. 通过终端和使用 CSP Web 应用程序获取资源信息。 查看和激活注册服务器 连接到 IRIS 终端 docker-compose exec iris iris session iris 应用程序将默认注册 InterSystems FHIR Accelerator Service 和 SmartHealthIT Open FHIR Server,两者都可以使用。使用以下命令列出已注册的服务器 do ##class(dc.FhirClient).ServerList() InterSystems FHIR 加速器服务处于激活状态。 为了选择 SmartHealthIT 打开 FHIR 服务器,通过传递服务器 ID 使用 dc.FhirClient 类的 SetFhirServer 函数 do ##class(dc.FhirClient).SetFhirServer(2) 注册的 FHIR 服务器 要注册新服务器,请使用 dc.FhirClient 类的 RegisterServer() 函数class(dc.FhirClient).RegsterServer("Server Name","Endpoint","ApiKey"[optional],"EndpointOAuth"[optional] do ##class(dc.FhirClient).RegisterServer("INTERSYSTEMS FHIR Server","http://localhost:52773/csp/healthshare/samples/fhir/r4/","","") 从 FHIR 服务器获取资源 要检索当前服务器的所有资源,请使用 dc.FhirClient 类的 ListResources() 方法 do ##class(dc.FhirClient).ListResources() 为了显示任何资源的记录数,通过传递 dc.FhirClient 的 Resource 使用 CountResource() 方法下面的命令将从激活的 FHIR 服务器获取患者资源计数器 set count = ##class(dc.FhirClient).CountResource("Patient") write count 要检索所有创建的资源及其计数,只需将 1 传递给 ListResource() 函数 do ##class(dc.FhirClient).ListResources(1) 要获取资源的详细信息,请通过传递 dc.FhirClient 类的 Resource 使用 GetResource()下面的命令将从激活的FHIR 服务器中检索所有患者 do ##class(dc.FhirClient).GetResource("Patient") 下面的命令将从激活的 FHIR 服务器中检索所有观察结果 do ##class(dc.FhirClient).GetResource("Observation") 从 FHIR 服务器获取特定患者的资源 下面的命令将从激活的 FHIR 服务器中检索针对 Patinet ID 1 的观察详细信息 do ##class(dc.FhirClient).GetPatientResources("Observation","1") 从 CSP Web 应用程序查看 FHIR 服务器信息 导航 http://localhost:55037/csp/fhirclient/index.csp索引页面将显示激活的服务器中患者、观察、从业者和就诊次数以及患者和注册服务器的详细信息 索引页面将显示 FHIR 服务器列表,其中选择了激活的服务器。 从列表中选择其他服务器以查看所选服务器的详细信息 将鼠标悬停到患者 ID 并选择以获取患者资源的详细信息 此页面将显示一些患者资源的数量以及患者观察的详细信息 谢谢
文章
Jingwei Wang · 五月 5, 2023

IRIS SQL 编辑器和 IRIS JAVA 连接

WIN SQL是大多数用户使用的普通编辑器。但是我们不能使用winsql下载大量数据。所以我写了一个教程如何连接一个新的基于 Java 的编辑器,叫做 Squirrel SQL,它可以很容易地下载或导出 excel 或任何其他格式的数据。我还包括一个 Java JCBC 连接程序来连接 IRIS 数据库,尤其是镜像/故障转移服务器。 基于 SQL Java 的编辑器导出大量数据和用于 IRIS 连接的 Java JDBC 程序 基于 SQL Java 的编辑器导出大量数据 WinSql 是通常用于从 Iris 数据库中提取数据的编辑器,但是,如果没有许可的 winsql,则无法导出大量数据。 解决方案是使用基于 java 的编辑器,称为 Squirrel SQL。这是一个基于 java 的编辑器,您可以在从 IRIS 数据库执行 fetch 从编辑器中导出大量数据。这是用 Java 构建的开源 SQL 客户端,它使用 JDBC 连接到 IRIS 数据库。 Squirrel SQL 的特点 Java 19 兼容性 多个插入符/光标编辑 全局首选项和新会话属性搜索 Saved Sessions 的多项改进(用于保存和恢复 Session 的所有 SQL 编辑器的特性) 可配置的鼠标右键菜单 重新设计的添加/编辑 JDBC 驱动程序对话框 安装 Squirrel SQL 的步骤 Squirrel SQL 可以从 Squirrel 官网下载https://squirrel-sql.sourceforge.io/ 连接 IRIS 数据库的步骤 向 Squirrel Sql 添加驱动程序 点击“+”图标创建一个新的驱动程序,如下图所示 在“添加驱动程序对话框”中,选择“额外类路径”并单击“添加”,为“Intersystems-jdbc-3.2.0.jar”(jdbc 驱动程序jar 文件)添加一个新条目,如下所示。如果您在本地计算机的 C 盘上安装了 IRIS,这将是基于 IRIS 版本的正常路径 C:\InterSystems\IRISHealth2\dev\java\lib\JDK18\intersystems-jdbc-3.2.0.jar。 如下图所示, 输入驱动程序的名称“Intersystems IRIS”(选择任何有意义的名称) 输入示例 URL 作为 jdbc:IRIS://<host>:<port>/<database> 网站 URL 是可选的。 单击右侧的“List Drivers”按钮并选择“com.intersystems.jdbc.IRISDriver”,如下图所示。 单击“确定”保存驱动程序条目。现在您可以在驱动程序下的左侧菜单栏中看到驱动程序。 添加基于驱动程序的别名(连接) 选择squirrel sql左侧的“别名”选项卡,点击“+”添加新别名,如下图。 在“添加别名”窗口中,为别名输入一个有意义的名称。 从下拉菜单中选择我们新创建的 IRIS 驱动程序。选择驱动程序后,URL 格式将填充为新创建的驱动程序配置。通过添加正确的主机名或 IP 地址、端口号和数据库命名空间来编辑 URL。 例如:jdbc:IRIS://00.00.00.00.00:12345/TEST-TRAK 输入具有 SQL 权限的 IRIS 数据库的用户名和密码 单击测试按钮并验证连接是否成功。 单击“确定”保存新别名 连接到 IRIS 数据库 双击新创建的别名连接到数据库,squirrel 编辑器将打开,您可以尝试使用 sql 查询。 用于编写程序的 IRIS 数据库的 JDBC 连接 import java.sql.*; import com.intersystems.jdbc.*; import java.util.logging.*; import java.io.IOException; import java.util.*; public class Extract { public static Connection TrakCache () throws Exception { IRISDataSource ds = new IRISDataSource(); Connection conn = null ; ds.setURL( "jdbc:IRIS://1.12.333.444:12345/NAMESPACE-TRAK" ); ds.setUser( "username" ); ds.setPassword( "Password" ); try { conn = ds.getConnection(); } catch (Exception e) { System.out.println( "catch" +conn); //You can write another connection here if automatically fail over to another server. } return conn; } }
文章
姚 鑫 · 四月 7, 2023

第二十一章 配置镜像

# 第二十一章 配置镜像 本章提供了镜像和镜像成员的设置、配置和管理的相关信息和步骤。 # 镜像的自动部署方法 本章提供了使用管理门户创建镜像和将现有实例配置为成员的过程。 IRIS Data平台还提供了几种自动部署镜像的方法,这些镜像在部署后完全可运行。 ## 使用云管理器(ICM)部署镜像 ISC建议使用InterSystems Cloud Manager(ICM)部署 IRIS,包括镜像配置。通过将纯文本声明性配置文件、简单的命令行界面和Docker Containers中的 IRIS部署相结合,ICM为提供了一种简单、直观的方式来配置云或虚拟基础架构,并在该基础架构上部署所需的InterSystems IRIS体系结构以及其他服务。ICM可以显著简化部署流程,尤其是对于复杂的水平群集配置。 除了部署独立的镜像实例外,ICM还可以部署具有镜像数据服务器的分布式缓存集群和具有镜像数据节点的分片集群。 ## 使用 Kubernetes运算符(IKO)部署镜像 KUBERNETES一个开源的编排引擎,用于自动部署、扩展和管理容器化的工作负载和服务。可以定义想要部署的容器化服务以及希望它们遵循的策略;Kubernetes以尽可能高效的方式透明地提供所需的资源,在部署偏离规范时修复或恢复部署,并自动或按需扩展。InterSystems Kubernetes运算符(ICO)使用IrisCluster定制资源扩展了Kubernetes API,该资源可以作为InterSystems IRIS分片集群、分布式缓存集群或独立实例部署在任何Kubernetes平台上,所有这些都是可选的镜像。 在Kubernetes下部署 IRIS并不需要ICO,但它极大地简化了过程,并向Kubernetes添加了 IRIS特定的集群管理功能,支持将节点添加到集群等任务,否则您必须通过直接与实例交互来手动完成这些任务。 ## 使用配置合并部署镜像 配置合并功能在Linux和UNIX®系统上可用,它允许通过将所需的声明性配置合并文件应用于部署中的每个实例,来改变从相同映像部署的InterSystems IRIS容器的配置,或从相同工具包安装的本地实例的配置。此合并文件也可在重新启动现有实例时应用,它更新实例的配置参数文件(CPF),其中包含其大部分配置设置;这些设置在每次启动时从CPF中读取,包括部署实例后的第一个设置。当在部署期间应用配置合并时,实际上是用自己的更新版本替换了随实例提供的默认CPF。 使用配置合并,可以部署(或从现有实例配置)一个或多个镜像,包括它们的镜像数据库,方法是将单独的合并文件应用到不同的镜像角色,按顺序部署或配置第一个故障切换成员,然后是第二个故障切换成员,然后是灾难恢复异步成员。(部署或配置镜像后,必须手动将报告异步成员添加到镜像中。)。如果部署主机的名称与特定模式匹配,还可以自动部署多个故障转移对,或为现有主映像部署多个备份。在这种情况下,您可以将单个合并文件同时用于主备份和备份,然后在自动部署故障切换对后,对任何灾难恢复异步成员使用单独的合并文件。 还可以使用配置合并功能来部署具有镜像数据服务器的分布式缓存集群和具有镜像数据节点的分片集群。
文章
姚 鑫 · 五月 18, 2021

第四章 使用Setup和tear Down方法执行测试

# 第四章 使用Setup和tear Down方法执行测试 # 示例:使用Setup和tear Down方法执行测试 以通常的方式执行新的单元测试。 1. 在一直在使用的命名空间中打开终端。 2. 将`^UnitTestRoot`的值设置为包含测试类的目录的父级: ```java USER> Set ^UnitTestRoot="c:\unittests" ``` 3. 使用`%UnitTest.Manager`执行测试: ```jav USER> Do ##class(%UnitTest.Manager).RunTest("mytests") ``` 4. IRIS加载测试类、编译类、执行测试并向终端发送报告。 ```java =============================================================================== Directory: C:\unittests\mytests\cls\MyPackage\ =============================================================================== mytests\cls\MyPackage begins ... Load of directory started on 01/09/2018 14:36:57 '*.xml;*.XML;*.cls;*.mac;*.int;*.inc;*.CLS;*.MAC;*.INT;*.INC' Loading file C:\unittests\mytests\cls\MyPackage\Tests.xml as xml Imported class: MyPackage.Tests Compilation started on 01/09/2018 15:44:01 with qualifiers '' Compiling class MyPackage.Tests Compiling routine MyPackage.Tests.1 Compilation finished successfully in 0.033s. Load finished successfully. MyPackage.Tests begins ... TestAdd() begins ... AssertEquals:Test Add(2,2)=4 (passed) AssertNotEquals:Test Add(2,2)'=5 (passed) LogMessage:Duration of execution: .000073 sec. TestAdd passed TestEditContact() begins ... AssertStatusNotOK:ContactType = Friend (passed) AssertStatusOK:ContactType = Personal (passed) LogMessage:Duration of execution: .001227 sec. TestEditContact passed MyPackage.Tests passed mytests\cls\MyPackage passed Use the following URL to view the result: http://10.0.75.1:52773/csp/sys/%25UnitTest.Portal.Indices.cls?Index=10&$NAMESPACE=USER All PASSED ``` # 执行测试的选项:测试规格和限定符 通常,可以使用以下形式的命令执行`RunTest`: ```java Do ##class(%UnitTest.Manager).RunTest("testspec","qualifiers") ``` `Testspec`参数确定要运行哪些测试以及在哪里可以找到它们。`Testspec`的一般形式是`testSuite:testcase:testmethod`,其中 - `testsuite`(必填)。包含导出的测试类的文件目录。该目录必须是名为`^UnitTestRoot`的目录的子目录。默认情况下,测试管理器执行此目录及其子目录中包含的所有文件中的所有测试。 - `testcase`测试用例(可选)。选择包含要执行的测试方法的单个类。格式为`PackageName.ClassName`。如果存在,则测试管理器仅执行命名类中的测试。 - `testmethod`(可选)。挑选由测试用例指示的测试类的一个方法来执行。 限定符参数指定用于运行测试的各种选项。正如我们已经看到的,当想要从`.cls`文件加载测试时,可以使用`“/loadudl”`限定符。还可以使用限定符来控制测试类在执行后是否从服务器中删除,是否应该从这些外部文件加载测试,或者系统是否应该在测试失败后进入调试模式,等等。限定符参数是一个可选的命令行参数字符串,用于打开或关闭某些测试管理器行为。例如,`“/NoLoad/DEBUG”`告诉管理器不要从目录加载任何测试,也就是说,使用当前在InterSystems IRIS中的测试,并在调试模式下运行测试。这些限定符就是所谓的可否定布尔值。例如,这意味着`“/NoLoad”`等同于`“/Load=0”`。 限定符 | 含义 ---|--- `/load` (default) |从目录加载测试。使用`/NoLoad`不加载测试,并执行InterSystems IRIS中已包含的测试。 `/run` (default) |运行测试。使用`/norun`加载但不运行任何测试。 `/delete` (default) |执行后从InterSystems IRIS中删除测试类。使用`/nodelete`保存类。 `/recursive` (default)| 在指定目录的子目录中查找测试。使用`/norecsive`不执行子目录中包含的测试。 `/debug` (default is /nodebug)| 使用/DEBUG,第一次测试失败后不会执行任何测试。从终端执行时,终端将在第一次故障后进入调试模式。 `/autoload` |使用`/autoload=dir`从`^UnitTestRoot`目录的子目录`“dir”`加载测试。 `/loadudl`|从`.cls`而不是`XML`文件加载测试。 # RunTest 示例 以下是使用`RunTest`执行单元测试的一些示例。 要使用`RunTest`,必须首先为`^UnitTestRoot`分配一个有效的目录名: ```java USER>Set ^UnitTestRoot = "C:\UnitTests" ``` 例1: ```java USER>Do ##class(%UnitTest.Manager).RunTest() ``` 在`^UnitTestRoot`目录的所有子目录中搜索包含测试类的XML文件。加载它找到的任何测试类并执行测试。 执行后从InterSystems IRIS中删除所有加载的测试类。 例2: ```java USER>Do ##class(%UnitTest.Manager).RunTest("mytests") ``` - 加载并执行`^UnitTestRoot`的`mytests`子目录(及其子目录)中的测试。 - 在测试类执行后从InterSystems IRIS中删除它们。 例3: ```java USER>Do ##class(%UnitTest.Manager).RunTest("mytests:MyPackage.Tests") ``` - 从`^UnitTestRoot`目录的`mytest`子目录(及其子目录)加载测试。仅执行`MyPackage.Tests`中的测试。 - 执行测试后从InterSystems IRIS中删除所有测试类。 例4: ```java USER>Do ##class(%UnitTest.Manager).RunTest("mytests:MyPackage.Tests", "/noload/nodelete") ``` - 不将测试加载到IRIS。 - 在`MyPackage.Tests`中执行测试。请注意,`mytest`必须仍然包含带有`MyPackage.Tests`类的XML文件。 - 不从IRIS中删除`MyPackage.Tests`。 # DebugRunTestCase `%UnitTest.Manager`类还包含`DebugRunTestCase`方法。若要使用此方法,仍必须先将`^UnitTestRoot`分配给有效目录: ```java USER>Set ^UnitTestRoot="C:\UnitTests" ``` 例如: ```java USER>Do ##class(%UnitTest.Manager).DebugRunTestCase("mytests","MyPackage.Tests","","") ``` - 该方法不从任何目录加载任何类,也不从InterSystems IRIS删除任何类。 - 该方法执行`MyPackage.Tests`中包含的测试。 - 可选的第三个参数用于限定符。 - 可选的第四个参数用于指定测试类中要执行的单个测试方法。 - 如果测试失败,该方法将继续执行其余的测试方法,但将在测试完成时中断。因此,如果从终端执行,则终端将进入调试模式。 **注意:使用`DebugRunTestCase`时,`mytest`目录实际上不需要包含`MyPackage.Tests`。相比之下,`RunTest`总是要求要执行的测试包含在`^UnitTestRoot`的子目录中,即使在使用`NoLoad”`时也是如此。** # 练习 练习1:`MyPackage.TestMe`包含一个名为`CreateContact`的方法。此方法创建并返回`Contact`实例。它接受`Name`和`ContactType`值作为参数。创建一个测试以下内容的单元测试: - 从`CreateContact`返回的`Contact`实例具有正确的`Name`值。 - 从`CreateContact`返回的`Contact`实例具有正确的`ContactType`值。 - `CreateContact`返回的`Contact`实例保存正确,即`%Save`返回`OK`状态。 练习2:`MyPackage.Contact`包含名为`ByContactType`的类查询。它返回具有`ContactType`指定值的所有`Contact`实例的`ID`值。将单元测试添加到`MyPackages.Tests`,用于测试以下各项: - 该查询返回指定`ContactType`的正确`ID`值数量。为此,必须正确初始化数据库。 - 查询返回的每个`ID`值对应于一个具有指定`ContactType`值的联系人。 请注意,添加此测试不应破坏在完成教程正文中的示例时添加到`MyPackage.Tests`中的测试。因此,必须以正确的方式初始化和恢复数据库。 > 把答案发到评论上!!! 或加群QQ 410039091 分享 # [源码](https://download.csdn.net/download/yaoxin521123/18703118)
文章
Hao Ma · 一月 30, 2021

精华文章--WebGateway系列(1): Web Gateway介绍

本文介绍InterSystems Web Gateway的安装和配置。 在2018以前的ISC产品中, InterSystems Web Gateway被称为CSP Gateway。, CSP是Cache'的页面技术。InterSystems的产品页面,Web服务等大多是CSP写成的。IRIS发布后CSP Gateway改名成Web Gateway, 但内部的配置文件,说明等等还到处可见CSP Gateway的叫法。在本文里不同的地方有这两个说法别奇怪,他们是一个东西。 IRIS通过它和外部Web服务器连接。 本文的内容适用任何ISC产品的部署,包括页面的选项Cache'. IRIS,HealthConnect, Ensemble等等。它的作用和表现是一样的。 无论您使用的是Cache',IRIS , HealthConnect还是HealthShare, 只有在生产环境中使用HTTP请求,基本上都需要使用Web Gateway。 如果需要更详细的内容,请参考在线文档:[InterSystems Web Gateway](https://docs.intersystems.com/healthconnectlatest/csp/docbook/DocBook.UI.Page.cls?KEY=PAGE_web_gateway) ### 什么是Web Gateway CSP是Cache' Server Page的缩写,如同JSP(Java Server Page)是Java的前端技术, CSP是InterSystems的前端技术。要在IRIS或者HealthConnect上提供一个HTTP服务,唯一安全可靠的技术是CSP. 创建HTTP,REST服务直接创建CSP页面, 创建SOAP服务使用%SOAP.WebService或者EnsLib.SOAP.Service, 它们都是%CSP.Page的子类,因此在IRIS的在线文档中有CSP Server的称法,指的就是IRIS中负责CSP处理的那部分功能。 CSP Server并不监听TCP端口得到HTTP消息,它只能通过CSP Gateway从Web服务器接收请求。用户的请求要先发给IIS/Apach/Nginx等Web服务器,转发给IRIS, 而Web Gateway就是Web服务器发请求给IRIS所使用的网关。 或者说, 它是InterSystems提供的给第三方Web服务器的一个组件,或者称为模块。在Windows系统中是若干DLL库文件,在LINUX环境是SO动态链接库。安装CSP Gateway就是诸如”CSPa24.so"等文件拷贝到Web服务器的目录,将这些模块配置到Web服务器,并将以.csp,.cls,.zen结尾的HTTP请求发送给IRIS。如果Web服务器和IRIS独立安装在不同的硬件服务器上(更安全的方式),发送的是TCP消息,到IRIS的superserver端口,默认是51773(Cache'是1972)。 CSP Gateway支持3种Web服务器:IIS, Apache Web Server, Nginx。 后面的链接提供了完整的在各种操作系统中ISC产品支持的Web Server的版本: [IRIS支持的第三方Web Server列表](https://docs.intersystems.com/healthconnectlatest/csp/docbook/platforms/ISP_technologies.html#ISP_webservers) 听上去是不是挺简单?那用户还有什么可糊涂的? ### Private Web Server(PWS)带来的混乱 混乱来自IRIS的安装过程会安装一个私有的Apache Web服务器,被称作PWS。它的作用有两个:支持访问维护页面;给一个测试环境提供测试Web服务的能力。在线文档是这么描述PWS的: >> The PWS is not supported for any other purpose. For deployments of http-based applications, including REST, CSP, Zen, and SOAP over http or https, you should not use the private web server for any application other than the Management Portal; instead, you must install and deploy one of the supported web servers. For information, see the section “Supported Web Servers” in the online InterSystems Supported Platforms document for this release.(**如果要部署http应用, 包括在http或者https上层的REST, CSP, Zen, SOAP,你绝不能让除Management Portal以外的任何应用使用PWS. 你必须安装一个IRIS兼容的Web服务器。了解这部分内容, 请查看InterSystems在线文档的"Supported Web Servers"部分**) 然后很多用户没有意识到这个提醒。当安装IRIS时被问到”你想要安装CSP网关并未CSP网关配置外部Web服务器(IIS和Apache)吗?"时,他们选择了“不要安装CSP网关",然后浏览器接入维护界面,开发了若干Web服务,一直没有意识使用PWS访问IRIS上的Web服务在生产环境是不可接受的。PWS是一个非常轻量级的Apache Web服务器。它的程序包在IRIS安装目录下的httpd子目录里。IRIS启动后, 它开始工作,监听IRIS上配置的Web端口,默认是57772,或者52773.它的工作机制决定了它无法承受大的负载,因此不能用于生产环境的http应用。 它和CSP/IRIS Server的连接用的是与上面讲的CSP Gateway完全相同的方式,也就是说,这里有一个PWS专用的Gateway, 我们可以称它为Private CSP Gateway。为了写的更清楚,总结了下面几点: ***CSP Gateway*** - 安装IRIS实例时用户可以选择是否安装CSP Gateway. 如果这时没选择安装,后面可以用单独的安装包安装。 - 安装的程序可以放在任何位置。比如在Linux默认放在"/opt/webgateway"目录,配置文件在Web Gateway的配置文件目录。 - 访问CSP Gateway的管理页面是 http://WebServer:80/csp/bin/Systems/Module.cxw 。 (这里的WebServer是Web服务器的地址,➕它的端口是默认的80) ***PWS*** - 安装时自动安装 - 程序和配置都在IRIS的安装目录,比如"C:/InterSystems/HealthConnect/CSP/bin/" - 访问管理页面的地址是 http://IRIS:57772/csp/bin/Systems/Module.cxw,这里的IRIS是IRIS服务器的地址,如果是本机登录,也就是localhost. 注意一点:从PWS访问IRIS管理页面, 比如 http://localhost/csp/sys/UtilHome.csp, 选择其中的 “系统管理 > 配置 > Web网关管理"进入的是PWS的配置。如果是从 http://WebServer/csp/sys/UtilHome.csp进入的IRIS管理页面, 那么同样的操作进入的是CSP Gateway的管理页面。 这很容易从页面显示的Web Server的类型和版本发现区别。 ### 其他关于部署CSP Gateway的疑问 - 一个Web服务器可以连接多个CSP Gateway吗? 如果你真正理解了CSP Gateway, 你就明白它是Web服务器工作的一部分,比如在IIS里面它就是配置的一个虚拟路径。技术上你可以多配一个,但完全没有必要。 如果要把HTTP从一个Web服务器发到多个IRIS, 可以在一个Web Gateway里配置多个"Server Access"连接。 - 一个CSP Gateway是怎么连接多个IRIS Server的? CSP Gateway可以配置多个"Server Access”, 只是要区分出收到的请求应该发给那个IRIS Server.如果分发给不同的IRIS的URL是不同的,比如CSP Gateway可以路由"/csp/demo1"到第一个IRIS, "/csp/demo2"到第2个IRIS。 - Web Server要和IRIS部署在一台服务器吗? 生产环境中, 部署单独的Web Server通常是好选择。为了安全起见,很多用户会部署Web Server的高可用。 如果Web Server和Caché/IRIS分别装在两台服务器,IRIS安装时选择“不要安装CSP网关”,在Web Server的服务器上安装单独的Web Gateway软件包,测试和Caché/IRIS的连接。 如果是Web Server和Caché/IRIS装在同一台服务器, 那么应该先安装Web Server, 然后使用Caché/IRIS安装包安装Caché, 选择 “安装CSP网关”, 这样CSP网关会被安装在Web Server的目录下, 相关的模块和Web Server配置也会自动完成。 如果顺序反过来, 那么需要手工配置Web Server, 增加的不必要的复杂步骤。 - 安装外部Web Server能使用私有Web Gateway吗? 对Web服务器有了解的用户更会有这样的疑问。既然Web Gateway只是给Web Gateway工作的程序组件,那么是否从外部服务器就可以直接使用私有的Web Gateway了,何必再多安装一个。 是的,技术上这样是可行的。前提是,1. 外部Web服务器和IRIS在一台硬件服务器上。2. 客户要对外部服务器的配置非常熟悉,可以手工配置外部Web服务器对私有Web Gateway的访问, 包括路径或者虚假路径,文件夹的访问权限,用户或者用户组的权限等等。总的说, 这样既麻烦,又不便于后期的管理,因此我推荐还是重新装一个Web Gateway。只是要分清它和私有的连接PWS的Web Gateway的区别,而永远不要让他们混在一起。 安装CSP Gateway的具体步骤请参考下面的文章: WebGateway系列(2): 配置Apache连接IRIS WebGateway系列(3): 配置IIS连接IRIS
文章
姚 鑫 · 三月 4, 2021

第三章 SQL语言元素(一)

# 第三章 SQL语言元素(一) # 命令和关键字 InterSystems SQL命令(也称为SQL语句)以关键字开头,后跟一个或多个参数。其中一些参数可能是子句或函数,由它们自己的关键字标识。 - **InterSystems SQL命令没有命令终止符,除非在特殊情况下(例如SQL过程代码或触发代码),在这种情况下,SQL命令以单个分号(`;`)终止。否则,InterSystems SQL命令不需要或接受分号命令终止符**。在InterSystems SQL中指定分号命令终止符会导致`SQLCODE -25`错误。 TSQL的InterSystemsIRIS®数据平台实现(Transact-SQL)接受但不需要分号命令终止符。在将SQL代码导入Inter Systems SQL时,会去除分号命令终止符。 - **InterSystems SQL命令没有空格限制。如果命令项之间用空格隔开,则至少需要一个空格。** 如果命令项之间用逗号分隔,则不需要空格。算术运算符之前或之后不需要空格。可以在以空格分隔的项目之间,以逗号分隔的参数列表中的项目之间或在算术运算符之前或之后插入换行符或多个空格。 InterSystems SQL关键字包括命令名称,函数名称,谓词条件名称,数据类型名称,字段约束,优化选项和特殊变量。它们还包括`AND`,`OR`和`NOT`逻辑运算符,`NULL`列值指示符以及ODBC函数构造,例如`{d dateval}`和`{fn CONCAT(str1,str2)}`。 - 关键字不区分大小写。按照惯例,在本文档中,关键字用大写字母表示,但是InterSystems SQL没有大小写限制。 - 有许多关键字是SQL保留字。 InterSystems SQL仅保留那些不能明确解析的关键字。 SQL保留字可用作分隔符。 # 函数:内在的和外在的 - 内在的:InterSystems SQL支持大量内在的(系统提供的)函数。 这些函数包括数字函数、字符串函数以及日期和时间函数。 聚合函数是SQL固有函数,它计算列的所有值并返回单个聚合值。 - InterSystems SQL也可以支持用户提供的ObjectScript函数调用(外部函数),如下所示: 这种写法只能在mac routine里,类文件里编译报错。 ```sql MySQL &sql(SELECT Name,$$MyFunc() INTO :n,:f FROM Sample.Person) WRITE "name is: ",n,! WRITE "function value is: ",f,! QUIT MyFunc() SET x="my text" QUIT x ``` 如果将用户提供的(外部)函数的使用配置为系统范围的选项,则该SQL语句只能调用用户提供的(外部)函数。默认为“否”。默认情况下,尝试调用用户提供的函数会发出`SQLCODE -372`错误。可以使用`%SYSTEM.SQL类的SetAllowExtrinsicFunctions()`方法在系统范围内配置SQL对外部函数的使用。若要确定当前设置,请调用`$SYSTEM.SQL.CurrentSettings()`,该显示显示“允许在SQL语句中使用外部函数”选项。 不能使用用户提供的函数来调用`%routine`(名称以%字符开头的例程)。 尝试这样做会发出`SQLCODE -373`错误。 # 文字 InterSystems SQL文字具有以下语法: ``` literal ::= number | string-literal number ::= {digit}[.]digit{digit}[E[+|-]digit{digit}] digit ::= 0..9 string-literal ::= std-string-literal | ObjectScript-empty-string std-string-literal ::= ' {std-character-representation} ' std-character-representation ::= nonquote-character | quote-symbol quote-symbol ::= '' ObjectScript-empty-string ::= "" ``` 文字是一系列代表实际(文字)值的字符。它可以是数字或字符串。 - 数字不需要任何分隔符。它可以由数字0到9,小数点字符,指数符号以及加号和减号组成。数字中只能使用一个小数点字符。该小数点只能用于数字的基数部分,不能用于指数部分。小数点后不需要数字。允许前导零和尾随零。指数(科学符号)符号为字母E;大写字母E和小写字母E都可以接受,但是大写字母E是首选用法。加号或减号可以加一个底数或一个指数。多个加号和减号可以加上x个基数; SQL将这些符号视为运算符。 x只能有一个正负号。 SQL将此符号视为文字的一部分。请勿在数字中使用逗号或空格。 - 字符串文字包含一对分隔符,其中包含任何类型的字符串。首选的定界符是单引号字符。要将分隔符指定为字符串中的文字,请将该字符加倍;例如: `'Mary's office'`. **空字符串是文字字符串;它由两个单引号字符(`''`)表示。 `NULL`不是文字值;它表示没有任何值。** 注意:在嵌入式SQL中,不允许在字符串文字中使用以`##`开头的一些字符序列,如“使用嵌入式SQL”一章的“文字值”中所述。此限制不适用于其他SQL调用,例如动态SQL。 # 字符串分割符 使用单引号(`'`)字符作为字符串定界符。 SQL兼容性支持双引号字符(`“`)的使用,但由于与定界标识符标准冲突,因此强烈建议不要使用。将一对双引号字符`""`解析为无效的定界标识符。并生成`SQLCODE -1`错误。 要在字符串中指定单引号字符作为字面字符,请指定一对这样的字符作为字面转义序列。 例如,`'a 'normal' string'`。 ## 串联 双竖条(`||`)是首选的SQL连接操作符。 它可以用于连接两个数字、两个字符串或一个数字和一个字符串。 下划线(`_`)作为SQL连接操作符提供,以保证ObjectScript的兼容性。 此连接操作符只能用于连接两个字符串。 如果两个操作数都是字符串,并且两个字符串都具有相同的排序规则类型,则所得的级联字符串具有该排序规则类型。在所有其他情况下,连接的结果是排序类型`EXACT`。 # NULL和空字符串 使用`NULL`关键字表示没有指定值。 在SQL中,`NULL`始终是表示数据值因任何原因未指定或不存在的首选方式。 SQL零长度字符串(空字符串)由两个单引号字符指定。 空字符串(`"`)与空字符串是不同的。 空字符串是一个已定义的值,一个不包含字符的字符串,一个长度为0的字符串。 一个零长度的字符串在内部由非显示字符`$CHAR(0)`表示。 **注意:不建议使用SQL零长度字符串作为字段输入值或字段默认值。 使用`NULL`表示数据值的缺失。** **在SQL编码中应避免使用SQL零长度字符串。 但是,由于许多SQL操作都会删除末尾的空格,所以只包含空格字符(空格和制表符)的数据值可能会导致SQL的零长度字符串。** 注意,不同的SQL length函数返回不同的值:`length`、`CHAR_LENGTH`和`DATALENGTH`返回SQL长度。 `$LENGTH`返回ObjectScript表示长度。 长度不计算尾随空格; 所有其他长度函数都计算末尾的空格。 # null 处理 NOT NULL数据约束要求字段必须接收一个数据值; 不允许指定NULL而不是值。 这个约束不阻止使用空字符串值。 `SELECT`语句的`WHERE`或`HAVING`子句中的`IS NULL`谓词选择空值; 它不选择空字符串值。 `IFNULL`函数计算一个字段值,如果字段值为`NULL`,则返回第二个参数中指定的值。 它不会将空字符串值视为非空值。 `COALESCE`函数从提供的数据中选择第一个非空值。 它将空字符串值视为非空值。 当`CONCAT`函数或`concenate`操作符(`||`)连接一个字符串和一个`NULL`时,结果是`NULL`。 如下面的例子所示: ```sql SELECT {fn CONCAT('fred',NULL)} AS FuncCat, -- returns 'fred'||NULL AS OpCat -- returns ``` `AVG、COUNT、MAX、MIN`和`SUM`聚合函数在执行操作时忽略`NULL`值。 (`COUNT *`统计所有行,因为不可能有一个所有字段都为空值的记录。) `SELECT`语句的`DISTINCT`关键字在其操作中包含`NULL`; 如果指定的字段有空值,`DISTINCT`返回一个空行. `AVG`、`COUNT`和`MIN`、聚合函数受空字符串值的影响。 `MIN`函数将空字符串视为最小值,即使存在值为0的行。 `MAX`和`SUM`聚合函数不受空字符串值的影响。 ## null 表达式 对大多数SQL函数提供`NULL`作为操作数将返回`NULL`。 任何以NULL作为操作数的SQL算术操作都返回`NULL`值。 因此,7 +零=零。 这包括二元运算加法(`+`)、减法(`-`)、乘法(`*`)、除法(`/`)、整数除法(`\`)和取模(`#`),以及一元符号运算符加号(`+`)和减号(`-`)。 算术操作中指定的空字符串将被视为0(零)值。 除法(`/`),整数除法(`\`),或对空字符串(`6/ "`)取模(`#`)会导致``错误。 ## NULL的长度 在SQL中,`NULL`的长度是没有定义的(它返回`< NULL >`)。 然而,空字符串的长度被定义为长度为0。 如下面的例子所示: ```sql SELECT LENGTH(NULL) AS NullLen, -- returns LENGTH('') AS EmpStrLen -- returns 0 ``` 如本例所示,SQL `LENGTH`函数返回SQL长度。 可以使用`ASCII`函数将SQL的零长度字符串转换为`NULL`,示例如下: ```sql SELECT LENGTH(NULL) AS NullLen, -- returns LENGTH({fn ASCII('')}) AS AsciiEmpStrLen, -- returns LENGTH('') AS EmpStrLen -- returns 0 ``` 但是,对标准`SQL`的某些系统间IRIS扩展对`NULL`和空字符串的长度的处理是不同的。 $LENGTH函数返回这些值的InterSystems IRIS内部表示:`NULL`表示为长度为0的已定义值,SQL空字符串表示为长度为0的字符串。 该功能与ObjectScript兼容。 ```sql SELECT $LENGTH(NULL) AS NullLen, -- returns 0 $LENGTH('') AS EmpStrLen, -- returns 0 $LENGTH('a') AS OneCharStrLen, -- returns 1 $LENGTH(CHAR(0)) AS CharZero -- returns 0 ``` 这些值的内部表示方式的另一个重要位置是`%STRING`、`%SQLSTRING`和`%SQLUPPER`函数,它们将空格附加到值中。 因为`NULL`实际上没有值,所以在它后面添加一个空格会创建一个长度为1的字符串。 但是一个空字符串确实有一个字符值,所以在它后面加上一个空格会创建一个长度为2的字符串。 如下面的例子所示: ```sql SELECT CHAR_LENGTH(%STRING(NULL)) AS NullLen, -- returns 1 CHAR_LENGTH(%STRING('')) AS EmpStrLen -- returns 2 ``` 注意,这个例子使用的是`CHAR_LENGTH`,而不是`LENGTH`。 因为`LENGTH`函数删除了末尾的空格,所以`LENGTH(%STRING(NULL))`返回长度为0的字符串; `LENGTH(%STRING("))`返回长度为2的字符串,**因为`%STRING`追加的是前导空格,而不是尾随空格。** ## ObjectScript和SQL 当SQL `NULL`输出到ObjectScript时,它由ObjectScript空字符串(`""`)表示,长度为0的字符串。 当SQL零长度字符串数据输出到ObjectScript时,它由包含`$CHAR(0)`的字符串表示,该字符串长度为1。 ```sql /// d ##class(PHA.TEST.SQL).Null() ClassMethod Null() { &sql(SELECT NULL,'' INTO :a,:b) WRITE !,"NULL length: ",$LENGTH(a) // returns 0 WRITE !,"empty string length: ",$LENGTH(b) // returns 1 } ``` ```sql DHC-APP>d ##class(PHA.TEST.SQL).Null() NULL length: 0 empty string length: 1 ``` 在ObjectScript中,没有值通常用空字符串(`""`)表示。 当这个值被传递到嵌入式SQL中时,它会被视为空值,如下面的例子所示: ```sql /// d ##class(PHA.TEST.SQL).Null1() ClassMethod Null1() { SET x="" SET myquery="SELECT NULL As NoVal,:x As EmpStr" SET tStatement=##class(%SQL.Statement).%New() SET qStatus=tStatement.%Prepare(myquery) IF qStatus'=1 {WRITE "%Prepare failed:" DO $System.Status.DisplayError(qStatus) QUIT} SET rset=tStatement.%Execute() WHILE rset.%Next() { WRITE "NoVal:",rset.%Get("NoVal")," length ",$LENGTH(rset.%Get("NoVal")),! // length 0 WRITE "EmpStr:",rset.%Get("EmpStr")," length ",$LENGTH(rset.%Get("EmpStr")),! // length 0 } WRITE "End of data" } ``` ```sql DHC-APP>d ##class(PHA.TEST.SQL).Null1() NoVal: length 0 EmpStr: length 0 End of data ``` 如果指定了一个未定义的输入主机变量,嵌入式SQL将其值视为`NULL`。 当将NULL或空字符串值从嵌入式SQL传递到ObjectScript时,`NULL`被转换为长度为0的字符串,空字符串被转换为长度为1的字符串。 如下面的例子所示: ```sql /// d ##class(PHA.TEST.SQL).Null2() ClassMethod Null2() { &sql(SELECT NULL, '' INTO :a,:b) WRITE !,"The length of NULL is: ",$LENGTH(a) // length 0 WRITE !,"The length of empty string is: ",$LENGTH(b) // length 1 } ``` ```sql DHC-APP>d ##class(PHA.TEST.SQL).Null2() The length of NULL is: 0 The length of empty string is: 1 ``` 在下面的例子中,SQL的空字符串加上一个空格被传递为长度为2的字符串: ```sql /// d ##class(PHA.TEST.SQL).Null3() ClassMethod Null3() { &sql(SELECT %SQLUPPER('') INTO :y ) WRITE !,"SQL empty string length: ",$LENGTH(y) } ``` ```sql DHC-APP> d ##class(PHA.TEST.SQL).Null3() SQL empty string length: 2 ``` good, mark Thank you! It's very useful for us while using InterSystems SQL. 学习了,谢谢大佬 很实用!感谢总结! 大佬,已被圈粉,长期追踪学习!
文章
Jingwei Wang · 一月 19, 2023

使用嵌入式 Python 创建存储过程

Python 已成为世界上使用最广泛的编程语言(来源:https://www.tiobe.com/tiobe-index/),SQL 作为数据库语言继续引领潮流。 Python 和 SQL 一起工作以提供 SQL 单独无法提供的新功能不是很好吗?毕竟,Python 拥有超过 380,000 个已发布的库(来源:https://pypi.org/),它们具有非常有趣的功能,可以在 Python 中扩展您的 SQL 查询。本文详细介绍了如何使用嵌入式 Python 在 InterSystems IRIS 数据库中创建新的 SQL 存储过程。 用作示例的 Python 库 本文将使用两个非常有用的库:Geopy 和 Chronyk。 Geopy 是一个用于将地理编码(地址和地理坐标的限定)应用于地址数据的库。有了它,就可以从街道名称中获取邮局格式的邮政编码和完整地址。非常有用,因为许多记录都有地址。 Chronyk 用于使用人类语言处理日期和时间。这非常有用,因为在内部,对于 IRIS 和 Python,日期是一个数字,表示自初始日期以来经过的时间量。对于人类来说,日期是 7 月 20 日,或者昨天,或者明天,或者两个小时前。 Chronyk 接受接收这样的日期,然后将其转换为通用日期格式。 InterSystems IRIS 中的 Python 支持 从 2021.1 版开始,可以使用 Python 以双向方式在 Python 和 IRIS (ObjectScript) 之间创建类方法、存储过程、互操作产品和Native调用。我不知道有任何其他数据平台可以如此深入地使用 Python。这个工作的要求是 Python 安装在与 IRIS 相同的物理或虚拟机或容器上。 更多详情请见:https://docs.intersystems.com/iris20221/csp/docbook/DocBook.UI.Page.cls?KEY=AFL_epython。对于安装 python 运行: # install libraries required for python and pip RUN apt-get -y update \ && apt-get -y install apt-utils \ && apt-get install -y build-essential unzip pkg-config wget \ && apt-get install -y python3-pip Python 库支持 InterSystems IRIS 为了使 InterSystems IRIS 能够使用 Python 库,必须将其安装在 <installdir>/mgr/python 中。其中 installdir 是安装 IRIS 的文件夹。要安装新包运行: # use pip3 (the python zpm) to install geopy and chronyk packages RUN pip3 install --upgrade pip setuptools wheel RUN pip3 install --target /usr/irissys/mgr/python geopy chronyk Pip3 是 Python 最受欢迎的包管理器和安装程序 Pip。 Python语言创建存储过程 在 InterSystems IRIS 中使用 Python 的一种可能性是使用 Python 创建存储过程。有两种可能性: Python使用Create Function or Procedure的SQL语句创建存储过程; 使用 sqlProc 和 language=Python 标记在 ObjectScript 类中创建 ClassMethod。 Python使用Create Procedure的SQL语句创建存储过程 根据 InterSystems 文档,您还可以通过在 CREATE 语句中指定 LANGUAGE PYTHON 参数,使用嵌入式 Python 编写 SQL 函数或存储过程,如下所示(来源:https://docs.intersystems.com/iris20221/csp/ docbook/DocBook.UI.Page.cls?KEY=AEPYTHON#AEPYTHON_runpython_sql): CREATE FUNCTION tzconvert(dt TIMESTAMP, tzfrom VARCHAR, tzto VARCHAR) RETURNS TIMESTAMP LANGUAGE PYTHON { from datetime import datetime from dateutil import parser, tz d = parser.parse(dt) if (tzfrom is not None): tzf = tz.gettz(tzfrom) d = d.replace(tzinfo = tzf) return d.astimezone(tz.gettz(tzto)).strftime("%Y-%m-%d %H:%M:%S") } 当您运行这个新的 SQL 函数时: SELECT tzconvert(now(), 'US/Eastern', 'UTC') 该函数返回如下内容: 2022-07-20 15:10:05 使用 sqlProc 和 language=Python 标记在 ObjectScript 类中创建 ClassMethod 我承认我最喜欢这种方法:使用 sqlProc 和 language=Python 标记创建一个 ClassMethod。在我看来,它更容易维护,文档更好,明显并且源代码版本管理更好。对于这种方法,我发布了一个示例应用程序:https://openexchange.intersystems.com/package/Python-IRIS-SQL-Procedures-Sample。我将用它来详细演示第二种方法。 示例应用程序安装 要安装示例应用程序,请按照以下步骤操作: clone/git 将 repo 拉入任何本地目录 $ git clone https://github.com/yurimarx/iris-sql-python-sample.git 在此目录中打开一个 Docker 终端并运行: $ docker-compose build 运行 IRIS 容器: $ docker-compose up -d 另一种安装可能性是使用 ZPM: zpm "install iris-sql-python-sample" 使用 Python 的存储过程示例 第一个示例是处理地址地理编码的存储过程,请参阅源代码: ClassMethod GetFullAddress(Street As %String, City As %String, State As %String) As %String [ Language = python, SqlName = GetFullAddress, SqlProc ] { import geopy.geocoders from geopy.geocoders import Nominatim geopy.geocoders.options.default_timeout = 7 geolocator = Nominatim(user_agent="intersystems_iris") location = geolocator.geocode(Street + ", " + City + ", " + State, country_codes="US") return location.address } 看到使用 [Language = python, SqlProc] 标记声明了一个 ClassMethod(在 dc.pythonsql.Company 类中)。SqlName 标签允许在 SQL 语句中为新的存储过程设置一个名称。 转到管理门户,系统 > SQL 并运行以下代码: SELECT ID, City, Name, State, Street, Zip, dc_pythonsql.GetFullAddress(Street, City, State) As FullAddress FROM dc_pythonsql.Company 现在不完整的地址返回为“完整”地址(完整且合格)。 注意:如果没有返回执行#class(dc.pythonsql.Company).CreateFiveCompanies()。它将创建五家公司用于测试。 该软件包可以与主要的开放和市场地理编码服务一起使用。在此示例中,我们使用开放服务 Nominatim,但也可以使用 Bing、Google、ArcGIS 等。在 https://geopy.readthedocs.io/en/stable/#module-geopy.geocoders 上查看可能性。 第二个例子是人性化格式的日期和时间包,Chronyk。 它允许您发送“明天”、“昨天”、“4 小时后”、“2022 年 7 月 4 日”等句子,并以通用日期格式获取结果。查看存储过程的创建: 类方法 GetHumanDate (语句 作为 %字符串) 作为 %细绳 [ 语言 = 蟒蛇, 数据库名称 = 获取人类日期, SQLProc ] ClassMethod GetHumanDate(Sentence As %String) As %String [ Language = python, SqlName = GetHumanDate, SqlProc ] { from chronyk import Chronyk t = Chronyk(Sentence) return t.ctime() } 在管理门户 > 系统 > SQL 中执行以下调用: SELECT ID, City, Name, State, Street, Zip, dc_pythonsql.GetHumanDate('yesterday') As Datetime FROM dc_pythonsql.Company 如果你只想调用存储过程,你可以使用这个 SQL 语句: select dc_pythonsql.GetHumanDate('yesterday') as Datetime 该库具有多种人性化日期和时间的可能性,请参阅 https://github.com/KoffeinFlummi/Chronyk。 所以,很容易创建 Python 存储过程,尽情享受吧!
文章
Lilian Huang · 七月 13, 2022

用 Python 的 Native API 调用类方法

InterSystems Native SDK for Python是 InterSystems IRIS APIs 的轻量级接口,曾经只能通过 ObjectScript 使用。 准确地说,我对调用 ObjectScript 方法、类方法的能力特别感兴趣。 它可以工作,而且效果很好,但默认情况下,调用只支持标量参数:字符串、布尔值、整数和浮点数。 但如果你想: - 传递或返回结构,例如字典或列表 - 传递或返回流 您需要编写一些粘合代码或使用这个project (使用 pip install edpy 安装)。 edpy 包会给你一个简单的签名: call(iris, class_name, method_name, args) 它允许您调用任何 ObjectScript 方法并返回结果。 像这样导入它: from edpy import iris call accepts 4 required arguments:- iris - a reference to an established IRIS object- class_name - IRIS class to call- method_name - IRIS method to call- args - list of 0 or more arguments 参数 每个参数可以是以下其中之一: string字符串(任意长度,如果大于 $$$MaxStringLength或 3641144 个符号,则会自动转换为流 boolean布尔值 integer整数 float 浮动 dict字典(转换为动态对象) list or tuple列表或元组(转换为动态数组) 字典、列表和元组参数可以递归地包含其他字典、列表和元组(持续性内存)。 返回值 在返回值,我们期望是动态对象/数组或 JSON 字符串/流。 在这种情况下,edpy 会首先将其转换为 Python 字符串,并在可能的情况下将其解释为 Python 字典或列表。 否则,结果将按原样返回给调用者。 就是这样,但让我给你一些 ObjectScript 方法的例子,以及如何使用这个 Python 函数调用它们。 示例1: Pong ClassMethod Test(arg1, arg2, arg3) As %DynamicArray{ return [(arg1), (arg2), (arg3)]} 调为: >>> iris.call(iris_native, "User.Py", "Test", [1, 1.2, "ABC"])[1, 1.2, 'ABC'] 这里没有惊喜。 参数被打包回一个数组并返回给调用者。 示例 2: 属性 ClassMethod Test2(arg As %DynamicObject) As %String{ return arg.Prop} 像这样调用: >>> iris.call(iris_native, "User.Py", "Test2", [{"Prop":123}])123 现在进行更嵌入式的调用: >>> iris.call(iris_native, "User.Py", "Test2", [{"Prop":{"Prop2":123}}]) {'Prop2': 123} 如果属性太长也没关系 - 流将用于将其发送到 IRIS 和/或返回: ret = iris.call(iris_native, "User.Py", "Test2", [{"Prop":"A" * 10000000}]) >>> len(ret) 10000000 如果您需要保证InterSystems IRIS 端的流,您可以使用%Get: set stream = arg.%Get("Prop",,"stream") 如果流是 base64 编码的,您可以使用以下命令自动对其进行解码: set stream = arg.%Get("Prop",,"stream<base64") 示例 3: 字符串或流 ClassMethod Test3(arg As %Stream.Object) As %String { set file = ##class(%Stream.FileCharacter).%New() set file.TranslateTable = "UTF8" set filename = ##class(%File).ManagerDirectory() _ "test.txt" do file.LinkToFile(filename) if $isObject(arg) { set sc = file.CopyFromAndSave(arg) } else { do file.Write(arg) set sc = file.%Save() } if $$$ISERR(sc) { set jsonret = {"status":0, "payload":($system.Status.GetErrorText(sc))} } else { set jsonret = {"status":1} } quit jsonret.%ToJSON() } 这里我们将字符串或流写入 <mgr>test.txt。 >>> iris.call(iris_native, "User.Py", "Test3", ["😊"]) {'status': 1} 注意:在所有代码示例中输入为“&# x1f642;“。 如果我打开文件,我会看到一个 😊 而不是两个 ?? - 所以我们保留编码。 >>> iris.call(iris_native, "User.Py", "Test3", ["🙂" * 10000000]) {'status': 1} 为简便起见,我将省略文件输出,但它就在那里。 最后,通过在内部传递一个动态对象或数组,您可以完全避免字符串/流二分法,即使您不知道该属性是比字符串限制短还是长。 在这种情况下,您始终可以像流一样获取可疑属性。 示例4: 返回流 ClassMethod Test4(arg As %DynamicArray) As %String { return arg.%Get(0) } 看起来是这样: >>> ret = iris.call(iris_native, "User.Py", "Test4", [["😊" * 10000000]]) >>> len(ret) 10000000 >>> ret[:5] '😊😊😊😊😊' 还有一件事 还有一个 get_iris(ip="localhost", port=1972, namespace="USER", username="_SYSTEM", password="SYS") 函数可以让您获得一个工作的 IRIS 对象。 所以这里有一个完整的例子,如果你想自己尝试一下: 首先加载 User.Py class 并安装 edpy python 库: pip install edpy 然后在python调用中: from edpy import iris iris_native = iris.get_iris() iris.call(iris_native, "User.Py", "Test", [1, 1.2, "ABC"]) iris.call(iris_native, "User.Py", "Test2", [{"Prop":123}]) iris.call(iris_native, "User.Py", "Test2", [{"Prop":{"Prop2":123}}]) ret2 = iris.call(iris_native, "User.Py", "Test2", [{"Prop":"A" * 10000000}]) iris.call(iris_native, "User.Py", "Test3", ["😊"]) iris.call(iris_native, "User.Py", "Test3", ["😊" * 10000000]) ret4 = iris.call(iris_native, "User.Py", "Test4", [["😊" * 10000000]]) 结论 适用于 Python 的 Native SDK 是一个强大的工具,为您提供对 InterSystems IRIS 的完整且不受限制的访问。 我希望这个项目可以为您节省一些时间来编组 InterSystems IRIS 调用。 是否有一些它不支持的方法参数组合? 如果是这样,请在评论中分享您是如何调用的。 链接: Native SDK Docs User.Py class Repo 原文请参考链接:https://community.intersystems.com/node/521336
文章
姚 鑫 · 八月 23, 2022

第十章 配置数据库(二)

# 第十章 配置数据库(二) # 本地数据库 “本地数据库”页面显示关于系统上的数据库的以下信息: - `Name`—数据库名称。 - `Mirror`——如果数据库是镜像的,则镜像的名称; - `Directory` - `IRIS.DAT` 文件的位置。 - `Size` 大小 (MB) — 以 `MB` 为单位的数据库大小。 - `Status` 状态 — 指定数据库是挂载、卸载还是卸载;如果已挂载,则指定它是否具有只读或读写权限。 - `Resource Name`资源名称 — 控制对数据库的访问的数据库资源的名称; - `Encrypted` — 指定数据库是否加密; - `Journal` 指定数据库是否被记录; ## 创建本地数据库 要创建本地数据库,请导航到本地数据库页面(系统管理 > 配置 > 系统配置 > 本地数据库)。 1. 单击创建新数据库以打开数据库向导。 2. 在文本框中输入数据库名称。数据库名称必须: - 尚未在 `IRIS` 实例中使用 - 长度在 `1` 到 `30` 个字符之间 - 以字母字符或下划线开头;其余部分可以包括字母数字字符、破折号或下划线 3. 首次使用特定浏览器在 `IRIS` 实例中创建本地数据库时,必须 - 输入数据库目录的名称,在这种情况下,包含 `IRIS.DAT` 文件的目录在确认后将在 `c:\InterSystems\mgr` 中创建 - 单击文件夹图标浏览到现有目录,在这种情况下,将在该目录中创建 `IRIS.DAT` 文件 此后,默认情况下,将在与先前数据库目录相同的位置创建一个与提供的数据库名称相同的目录,其中包含 `IRIS.DAT` 文件。例如,如果首先在 `c:\InterSystems\mgr` 下的任何目录中创建数据库 `db22`,当再次单击 `Create New Database` 并在 `Enter the name of your database` 框中输入 `db33` 时,`c:\InterSystems\mgr\db33` 会自动填写到数据库目录文本框中。如果将其更改为 `c:\InterSystems\db33` 并创建 `db33`,则下次将填充基本目录 `c:\InterSystems`。 注意:不支持在配置数据库目录时使用符号链接。 4. 单击下一步继续配置数据库。如果指定的目录中已经存在 `IRIS.DAT` 文件,会收到警告,并且可以 - 单击完成以使用现有文件,在这种情况下,所有数据库特征都由 `IRIS.DAT` 文件确定。您通常会在从另一个实例复制或移动数据库时执行此操作,或者在同一系统上临时挂载在另一个实例中创建的数据库时执行此操作。 - 单击 `Back` 指定另一个目录,然后再次单击 `Next` 以在下一步中继续指定新数据库的特征。 5. 在 `Initial Size` 文本框中,键入数据库大小的兆字节数(默认值为 `1 MB`)。 **注意:不能创建或编辑数据库,使其大小大于可用的总磁盘空间。如果指定的大小在磁盘可用空间的 `90%` 以内,会收到警告并且必须确认操作。** 6. 从 `Block size for this database will be` 下拉列表中选择所需的块大小。默认情况下,所有新数据库都使用 `8 KB` 的块大小创建。 注意:请勿从下拉列表中选择 `8 KB` 以外的块大小,除非已阅读并理解大块大小注意事项`/` 7. 从 `Journal globals` 中选择是否要在此数据库中记录全局变量`?`下拉列表。 注意:如果将数据库配置为存储临时全局变量,将 `Journal globals` 属性设置为 `No` 与将临时全局变量存储在 IRSTEMP 中是不同的。 8. 如果激活了加密,可以通过选择是加密数据库来加密这个数据库?。 9. 如果实例是镜像的一部分,可以通过为 `Mirrored Database?` 选择 `Yes` 来将此数据库添加到镜像中。 10. 从此面板开始,可以单击下一步。继续配置数据库或完成以接受剩余的默认值。 11. 选择资源来控制对该数据库的访问: - 默认值 — `%DB_%DEFAULT` - 现有 - 从现有数据库资源列表中选择 - 新建 — 创建新的数据库资源(新名称默认为 `%DB_%` 数据库名称) 12. 单击下一步查看数据库属性列表。 13. 单击完成以添加数据库。 现在已准备好配置和管理新数据库。 **注意:为防止意外损坏数据库,不能打开或写入名为 `IRIS.DAT` 的操作系统文件,即使它不是已安装的数据库。**