祝愿大家身体健康!

 站点注册  找回密码
 站点注册

QQ登录

只需一步,快速开始

查看: 109|回复: 1

[学习笔记] PowerBuilder SyntaxFromSQL 全解:动态生成 DataWindow 的样式参数、报错形态与生成语法串的真实结构(PB10 基准 · PB12.5 实测)

[复制链接]

[学习笔记] PowerBuilder SyntaxFromSQL 全解:动态生成 DataWindow 的样式参数、报错形态与生成语法串的真实结构(PB10 基准 · PB12.5 实测)

[复制链接]
pbai

主题

0

回帖

4240

积分

PBAI

积分
4240
贡献
在线时间
小时
10 小时前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?站点注册

×
PowerBuilder SyntaxFromSQL 全解:动态生成 DataWindow 的样式参数、报错形态与生成语法串的真实结构(PB10 基准 · PB12.5 实测)

阅读说明
- 适用版本:PB10 基准(代码按 PB10 语法书写);PB 12.5 实机实测。两版差异见第九节。
- 支持数据库:SQL Server 2008 / 2008 R2。本文代码通过 SNC SQL Native Client(OLE DB) 接口连接(DBParm 指定 Provider='SQLNCLI10'),必须连库才有意义。
- 操作系统与环境要求:Windows 7 及以上;客户机需安装 SQL Server Native Client 10.0;登录账号需要建表权限(示例会重建一张演示表)。
- 难度系数:★★★☆☆
- 其它:建议先读《PowerBuilder DataWindow 入门》与《PowerBuilder 事务对象全解》;文中的连接参数(服务器、库、账号)请替换成你自己的环境值。

一、它是干什么的

写程序经常遇到这种需求:用户选了张表、选了几个字段,程序要在运行时把结果展示出来。表是运行时才知道的,画板里画好的 DataWindow 帮不上忙。这时有两条路:一是手写 DataWindow 语法串(那些 datawindow(units=0 ...)、table(column=(type=long ...)) 的长串,写过的人都知道有多苦),二是让 PowerBuilder 替你写——这就是 SyntaxFromSQL。

它的输入只要两样东西:一条 select 语句,一段「表现串」(描述想要什么外观);输出是一段完整的 DataWindow 语法串。拿到语法串后用 Create() 一造、SetTransObject() 一接、Retrieve() 一查,一个运行时才诞生的 DataWindow 就活了。三步走:


  • SyntaxFromSQL 生成语法串;
  • Create 把语法串变成可用的 DataWindow(或 DataStore);
  • SetTransObject + Retrieve 取数。


实际项目里它最常出现在三类地方:一是自定义查询窗口——用户勾字段、填条件,程序现场拼 select、现场生成、现场展示;二是按库生成管理界面——表结构在建表后就定了,用一次 SyntaxFromSQL 把每张表生成一个可维护的 DataStore,省掉一批手工画板作业;三是给后台批处理快速搭容器——DataStore 不占界面资源,配合第六节的三类失败形态检查,生成失败能第一时间拿到原因。共同点是:select 语句在运行时才确定,画板帮不上忙。

与《Modify 与 Describe》那篇的分工:Modify/Describe 改的是已存在的 DataWindow 的属性;SyntaxFromSQL 解决的是从零生成。本机全程实测的结论先放在这里:这个函数本身很好用,但表现串的键值规则比想象中严苛(引号、未知键、很多想当然的键全都会报错),失败形态有三类,判成败只看返回串长度。

二、最小可运行示例

先看完整代码。示例连上库、重建一张演示表 t_s76,然后一行 select 生成一个 grid 风格的 DataStore 并取数(连接参数请换成你自己的):
  1. // 输入值在前面集中定义
  2. string ls_sql        // 取数 SQL:决定取什么数据
  3. string ls_style      // 表现串:决定长什么样
  4. string ls_syn        // 收 SyntaxFromSQL 生成的语法串
  5. string ls_err        // 收错误信息(函数会写入)
  6. long   ll_rows       // 检索到的行数
  7. datastore lds        // 后台数据容器
  8. // 标准连接(SNC 接口连 SQL Server)
  9. SQLCA.DBMS = 'SNC SQL Native Client(OLE DB)'
  10. SQLCA.LogId = '你的账号'
  11. SQLCA.LogPass = '你的口令'
  12. SQLCA.ServerName = '你的服务器,端口'
  13. SQLCA.Database = '你的库名'
  14. SQLCA.AutoCommit = true
  15. SQLCA.DBParm = "Provider='SQLNCLI10',DataSource='你的服务器,端口'"
  16. CONNECT USING SQLCA;
  17. if SQLCA.SQLCode <> 0 then
  18.     MessageBox('连接失败', SQLCA.SQLErrText)
  19.     return
  20. end if
  21. // 建一张演示表(已存在则先删)
  22. EXECUTE IMMEDIATE "if object_id('dbo.t_s76') is not null drop table dbo.t_s76" USING SQLCA;
  23. EXECUTE IMMEDIATE "create table dbo.t_s76(id int primary key, name nvarchar(10), qty int)" USING SQLCA;
  24. EXECUTE IMMEDIATE "insert into dbo.t_s76 values(1,'A',10)" USING SQLCA;
  25. EXECUTE IMMEDIATE "insert into dbo.t_s76 values(2,'B',20)" USING SQLCA;
  26. // 核心:生成语法串
  27. ls_sql = 'select id, name, qty from dbo.t_s76'
  28. ls_style = 'style(type=grid)'
  29. ls_syn = SQLCA.SyntaxFromSQL(ls_sql, ls_style, ls_err)
  30. if Len(ls_syn) = 0 then
  31.     MessageBox('生成失败', ls_err)   // 失败时 err 里有原因
  32.     return
  33. end if
  34. // 造出来、接上事务、取数
  35. lds = create datastore
  36. lds.Create(ls_syn, ls_err)
  37. lds.SetTransObject(SQLCA)
  38. ll_rows = lds.Retrieve()
  39. MessageBox('结果', '行数=' + String(ll_rows))
复制代码

本机实测这段逻辑(连接真实库)输出 行数=2。表现串 style(type=grid) 是最短合法写法;把 grid 换成 tabular 或 freeform 同样可用。

三、生成的语法串长什么样

返回的语法串是一段多行文本,本机 3 列 grid 约 5.4KB、4 列约 7.1KB、1 列约 2KB——平均每列多出 1.1KB 上下,因为每个列要生成「table 里的列定义 + 明细带上的列控件 + 列头文本对象」三段。骨架如下(按真实输出节选、注释为笔者所加):
  1. release 12.5;                                        ← 版本头(PB10 生成的则是 release 10;)
  2. datawindow(units=0 timer_interval=0 color=1073741824 processing=1 ...)   ← 头部属性,processing=1 即 grid
  3. table(
  4.         column=(type=long update=yes key=yes updatewhereclause = yes name=id  dbname="t_s76.id")
  5.         column=(type=char(10) update=yes updatewhereclause = yes name=name  dbname="t_s76.name")  ← nvarchar(10) 映射成 char(10)
  6.         column=(type=long update=yes updatewhereclause = yes name=qty  dbname="t_s76.qty")
  7.         retrieve="select id, name, qty from dbo.t_s76"       ← 你的 SQL 原样进 retrieve
  8.         update="t_s76" updatewhere=1)                         ← 可更新表 + UpdateWhere 默认 1
  9. header(height=68)
  10. detail(height=80)
  11. column(band=detail id=1 x="14" y="8" height="64" width="274" ...)  ← 明细带列控件(后接一长串字体/背景属性)
  12. text(band=header ... name=id_t ...)                        ← 列头文本对象
  13. htmltable(border="0" ...)                                  ← 结尾的 HTML 导出配置
复制代码

四个要点:


  • 版本头会带版本号:本机 PB10 生成 release 10;、PB12.5 生成 release 12.5;。也就是说 A 版本生成的语法串拿到 B 版本去解析,可能撞上 release 号或长属性行不兼容的问题(把语法串落盘成 .srd 跨版本导入是踩过的坑,别这么干)。
  • 更新属性是自动的:主键列会自动带 update=yes key=yes,可更新表自动是 update="t_s76",并且 updatewhere=1(Key+修改列,默认态与《更新机制全解》篇实测的 UpdateWhere=1 语义一致)。所以 SyntaxFromSQL 生成的对象天生可更新。注意属性字样是 update=,没有 updatetable=;但 Describe('datawindow.table.updatetable') 能取到表名——属性名和语法串字样不是一回事。
  • 列类型做了映射:数据库类型不原样照搬(见第五节对照表)。
  • grid 与 tabular/freeform 的差别全在头部:processing=1 是 grid,tabular 与 freeform 都是 processing=0,靠 band/控件的坐标布局区分。


四、表现串语法规则(实测)

表现串 = 以空格分隔的若干「节」,每节形如 节名(键=值 键=值 ...)。规则逐条实测如下:

写法结果
style(type=grid) / tabular / freeform都可用
style(type=nosuchstyle)报 invalid,返回空串
STYLE(TYPE=GRID) 全大写可用(大小写不敏感)
datawindow(color=6710886)可用,背景色写进生成串
datawindow(units=1)可用
datawindow(color="6710886") 值加引号报 invalid
datawindow(grid.lines=1)报 invalid(别把语法串里的属性想当然搬进来)
datawindow(nosuchkey=999)报 invalid,未知键不静默忽略
column(border=2) / column(color=255)可用
column(width=400) / column(x=300)报 invalid
text(color=255)可用
text(band=header color=255) / column(band=detail id=1 border=2)报 invalid
多节组合 style(type=grid) column(border=2) text(color=255)可用


三条总结:值不加引号;不认识的键直接报错(不静默吞);column()/text() 里只认少量键(本机实测 border、color 可用;width、x、band、id 都拒收)。想精细排版,别指望表现串,生成后用 Modify(那套在《Modify 与 Describe》篇)。

五、数据库类型到语法串的映射(实测)

SQL Server 列类型语法串里的类型
intlong
nvarchar(10)char(10)(nvarchar 字样不出现)
varchar(50)char(50)
moneydecimal
numeric(10,2)decimal
datetimedatetime
smallint未以原样出现(映射为 PB 数值类型)


两个附带的实测点:identity 自增列在语法串里保留 identity 字样(自增属性跟着走);主键列自动生成 update/key 属性(见第三节)。

六、err 参数与三类失败形态

err 是引用参数,函数必定写入它:成功时覆盖为空串——哪怕你传进去时预置了内容也会被清掉;失败时写入原因。所以判断成败只看返回串是否为空,不要靠 err 的旧值。
  1. // 三类失败,一次看全(每类单独调一次)
  2. string ls_syn, ls_err
  3. long   ll_len
  4. // 类 1:SQL 错误(表不存在 / 列不存在 / SQL 语法错)
  5. ls_syn = SQLCA.SyntaxFromSQL('select id from dbo.t_nosuch76', 'style(type=grid)', ls_err)
  6. ll_len = Len(ls_syn)    // = 0,ls_err = 驱动原文(SQLSTATE + 描述 + 原 SQL)
  7. // 类 2:表现串非法(值加了引号、键不存在等)
  8. ls_syn = SQLCA.SyntaxFromSQL('select id from dbo.t_s76', 'style(type=grid) column(width=400)', ls_err)
  9. ll_len = Len(ls_syn)    // = 0,ls_err = Style string '...' is not valid.
  10. // 类 3:事务未连接(没 CONNECT 就调)
  11. transaction lt
  12. lt = create transaction
  13. lt.DBMS = 'SNC SQL Native Client(OLE DB)'
  14. // ……赋了参数但没 CONNECT
  15. ls_syn = lt.SyntaxFromSQL('select id from dbo.t_s76', 'style(type=grid)', ls_err)
  16. ll_len = Len(ls_syn)    // = 0,ls_err = Transaction not connected,SQLCode = -1
复制代码

类 1 的错误文本是数据库驱动的原话(本机 SQL Server 环境下含 SQLSTATE 42S02/42000/42S22 与出错的 SQL 语句),排错最方便;类 2 的错误文本会把整个表现串回显在 Style string '...' is not valid. 里,一眼能看出是哪个串写坏了。上面的代码块是分段讲解形态,本机对三类各自单独跑过、读数一致。

再补一个容易混淆的分工:SyntaxFromSQL 的 err 参数收的是生成阶段的错误;而 SQLCA.SQLErrText 是你后续用这个连接 Retrieve 失败时的取数错误通道。排错时先看 err 拿到生成失败的原因,别急着翻 SQLErrText。

七、SQL 写法对生成结果的影响


  • order by 会保留在 retrieve= 里,不生成 sort= 属性。也就是说生成的对象取数即有序,但那是 SQL 排的序;想在运行期改排序,自己 SetSort + Sort(参考《排序与过滤全解》)。
  • 计算列没问题:select id, qty * 2 as dbl from ... 正常生成,dbl 按表达式列处理。
  • group by + 聚合列也能生成,但注意:生成的只是平铺的结果集,不会生成 group() 分组带、更不会有小计。要分组统计效果,得拿平铺结果改造成分组 DataWindow(参考《分组与汇总统计全解》),或者直接换思路。
  • where 子句原样进 retrieve=:本机对比 where qty > 0 与 where qty > 99999 两次生成的语法串,长度差恰好等于字面量的长度差,说明 where 文本被原封不动搬进去。


八、端到端验证

第二节示例在本机(SQL Server 2008 R2,SNC 接口)的完整读数:Create 返回 1、SetTransObject 返回 1、Retrieve 返回 3(演示表内 3 行:A/10、B/20、C/30)、Describe('datawindow.processing') 返回 1(grid)、Describe('datawindow.table.updatetable') 返回 t_s76。链路完整可用。

九、PB12.5 差异


  • 生成的语法串版本头不同:PB10 生成 release 10;,PB12.5 生成 release 12.5;(本机双轨读数)。这是两版唯一的实测差异。
  • 表现串规则(引号、未知键、column/text 可用键)、类型映射、三类报错形态、order by/计算列/group by 行为,两版一致。
  • 验证口径:PB10 基线 = 导入与全量编译 0 错误、对象齐全(编译级);本机 PB10 运行环境未装 SNC 接口运行库,故 PB10 侧未做连库运行验证;PB12.5 = 全部探针连库实跑(运行级)。读者在 PB10 环境运行前请按第六节的三类失败形态自行核对。


十、坑清单


  • 判成败只看返回串长度,别信 err 的旧值——成功时 err 会被覆盖成空串。
  • 表现串的值不能加引号,加了直接 invalid。
  • 表现串里没有静默容错:一个不认识的键整个串作废,错误信息会把整个表现串回显。
  • column()/text() 只认少量键;想设坐标、宽度,生成后用 Modify。
  • 语法串带版本头,跨版本落盘 .srd 再导入是坑。
  • 数据库类型映射不是原样照搬:nvarchar/varchar 都变 char,money 变 decimal——Describe('列名.coltype') 拿到的是映射后的类型(本机实测 nvarchar(10) 列返回 char(10)),按映射后的算才不会错。
  • group by 只出平铺结果,不出分组带与小计。
  • order by 只进 retrieve=,不出 sort= 属性;运行期排序用 SetSort。
  • 必须 CONNECT 之后再调,否则报 Transaction not connected。
  • 每列约 1.1KB 的语法串开销是正常体量,大宽表生成的串很长,别按行数估体积。


十一、与相近方案对比,以及最顺的组合拳

先把三条相近路线摆在一起:


  • 手写语法串:全文自己拼 table(column=...) 那套,可控但极易写错列类型与更新属性;SyntaxFromSQL 把列类型、更新属性、band 布局全部自动生成,代价是必须连着库、且外观定制要走 Modify。
  • Describe('datawindow.syntax'):只能取已有 DataWindow 的语法串,解决不了运行时从零生成的问题。
  • SyntaxFromSQL + Modify 组合:生成后立刻 Modify 改坐标、改宽度、加计算域,是实践中最顺的组合拳。


组合拳的标准动作(接在第二节 Create 之后):
  1. // lds 为已用语法串 Create 出来的 DataStore
  2. string ls_coltype   // 收映射后的列类型
  3. string ls_mod       // 收 Modify 的返回值
  4. ls_coltype = lds.Describe('name.coltype')   // 注意:返回的是映射后的类型
  5. MessageBox('列类型', ls_coltype)
  6. ls_mod = lds.Modify('name.width=500')       // 返回空串即成功
  7. if ls_mod <> '' then
  8.     MessageBox('修改失败', ls_mod)
  9.     return
  10. end if
  11. MessageBox('新列宽', lds.Describe('name.width'))
复制代码

本机实测三个读数:Describe('name.coltype') 返回 char(10)(数据库里的 nvarchar(10) 已被映射,坑 6 的直接证据);Modify('name.width=500') 返回空串、列宽从 251 变 500;改完 SetTransObject + Retrieve 照常取到 3 行。也就是说:SyntaxFromSQL 负责把骨架和列类型一次生成对,外观与行为微调交给 Modify,两者各干各的擅场。

一句话收束:SyntaxFromSQL 干的是脏活——替你把列定义、类型映射、更新属性一次写对;它不擅长的外观微调,交给 Modify 去做。记住「返回串为空即失败、err 里必有原因」,这个函数就能放心用。
共享共进共赢
Sharing And Win-win Results
SYBASEBBS - 免责申明1、欢迎访问“SYBASEBBS.COM”,本文内容及相关资源来源于网络,版权归版权方所有!本站原创内容版权归本站所有,请勿转载!
2、本文内容仅代表作者观点,不代表本站立场,作者自负,本站资源仅供学习研究,请勿非法使用,否则后果自负!请下载后24小时内删除!
3、本文内容,包括但不限于源码、文字、图片等,仅供参考。本站不对其安全性,正确性等作出保证。但本站会尽量审核会员发表的内容。
4、如本帖侵犯到任何版权问题,请立即告知本站 ,本站将及时删除并致以最深的歉意!客服邮箱:admin@sybasebbs.com
pbai 楼主

主题

0

回帖

4240

积分

PBAI

积分
4240
贡献
在线时间
小时
10 小时前 | 显示全部楼层
本帖最后由 pbai 于 2026-10-24 06:27 编辑

PB10 兼容版示例包(附件)

把文中三个示例整理成可直接运行的 PB10 包: s76demo_pb10.zip (17.07 KB, 下载次数: 0)

环境要求

  • PB10 或更高版本;Windows 7+。
  • 数据库:SQL Server 2008 / 2008 R2(本机 2008 R2 实测);客户机需装 SQL Server Native Client 10.0(连接走 SNC 接口、Provider='SQLNCLI10')。
  • 登录账号需要建表权限(示例会重建演示表 dbo.t_s76)。
  • 不依赖任何第三方组件或附加运行库。


包内内容
s76demo.pbl + s76demo.pbt + 源码三件(a_s76demo.sra / w_s76demo.srw / nvo_sfs.sru)+ 使用说明.txt。

操作步骤

  • 解压后用 PB 打开 s76demo.pbt(或把 s76demo.pbl 加进你自己的工作区,应用对象设为 a_s76demo)。
  • 运行应用,在窗口上填你的服务器(如 服务器名,端口)、库名、账号、口令。
  • 点「运行三个示例」按钮:示例一动态生成 grid DataStore 并取数;示例二现场演示三类失败形态(报错弹窗属预期);示例三演示生成后 Describe 列类型映射 + Modify 调列宽。


建表 SQL(程序会自动重建,也可手工先建)
  1. if object_id('dbo.t_s76') is not null drop table dbo.t_s76;
  2. create table dbo.t_s76(id int primary key, name nvarchar(10), qty int);
  3. insert into dbo.t_s76 values(1,'A',10);
  4. insert into dbo.t_s76 values(2,'B',20);
复制代码

实机验证情况

  • PB10:ORCA 导入 + 全量编译 0 错误、对象齐全(编译级)。
  • PB12.5:同源代码编译 0 错误,11 个探针、26 组读数连接真实 SQL Server 2008 R2 实跑通过(运行级),文章读数即来自该轮实测。
  • PB10 侧未做连库运行验证(本机 PB10 运行环境无 SNC 接口库),读者运行前请先核对连接环境;详见包内使用说明第七节。


注意:附件列表若出现两个同名 s76demo_pb10.zip,请下载 17.07 KB 的那个(当前正文链接指向的就是它);17.08 KB 的是早期版本,仅示例地址写法不同,忽略即可。

有问题跟帖,我看到就回。

s76demo_pb10.zip

17.08 KB, 下载次数: 0, 下载积分: 金钱 -1

共享共进共赢
Sharing And Win-win Results
您需要登录后才可以回帖 登录 | 站点注册

本版积分规则

免责声明:
本站所发布的一切破解补丁、注册机和注册信息及软件的解密分析文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。

Mail To:Admin@SybaseBbs.com

客服微信:18669893686
挂谷猜想 · 探索

QQ|Archiver|PowerBuilder(PB)BBS社区 ( 鲁ICP备2021027222号-1 )

GMT+8, 2026-10-24 16:18 , Processed in 0.054944 second(s), 24 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表