wecisecode 1 неделя назад
Родитель
Сommit
1ec054ef28
88 измененных файлов с 4047 добавлено и 0 удалено
  1. 8 0
      odbctest/mql/aaa/00init/00init.mql
  2. 15 0
      odbctest/mql/aaa/01clear/00init.mql
  3. 157 0
      odbctest/mql/aaa/01clear/1_drop_all.mql
  4. 4 0
      odbctest/mql/aaa/10class/00init.mql
  5. 126 0
      odbctest/mql/aaa/10class/10create.mql
  6. 59 0
      odbctest/mql/aaa/10class/11alter.mql
  7. 70 0
      odbctest/mql/aaa/10class/12drop.mql
  8. 26 0
      odbctest/mql/aaa/11data_crud/00init.mql
  9. 97 0
      odbctest/mql/aaa/11data_crud/11insert.mql
  10. 118 0
      odbctest/mql/aaa/11data_crud/12select.mql
  11. 99 0
      odbctest/mql/aaa/11data_crud/13update.mql
  12. 98 0
      odbctest/mql/aaa/11data_crud/14delete.mql
  13. 50 0
      odbctest/mql/aaa/12search/00init.mql
  14. 73 0
      odbctest/mql/aaa/12search/11int.mql
  15. 61 0
      odbctest/mql/aaa/12search/12float.mql
  16. 42 0
      odbctest/mql/aaa/12search/13bool.mql
  17. 49 0
      odbctest/mql/aaa/12search/14string.mql
  18. 58 0
      odbctest/mql/aaa/12search/15between.mql
  19. 38 0
      odbctest/mql/aaa/12search/16notin.mql
  20. 53 0
      odbctest/mql/aaa/12search/17orderby.mql
  21. 46 0
      odbctest/mql/aaa/13aggregate/00init.mql
  22. 56 0
      odbctest/mql/aaa/13aggregate/11count.mql
  23. 52 0
      odbctest/mql/aaa/13aggregate/12groupby.mql
  24. 37 0
      odbctest/mql/aaa/13aggregate/13having.mql
  25. 40 0
      odbctest/mql/aaa/13aggregate/14distinct.mql
  26. 70 0
      odbctest/mql/aaa/13aggregate/15aggr.mql
  27. 35 0
      odbctest/mql/aaa/14bucket/00init.mql
  28. 58 0
      odbctest/mql/aaa/14bucket/11logs.mql
  29. 50 0
      odbctest/mql/aaa/14bucket/12strulogs.mql
  30. 49 0
      odbctest/mql/aaa/14bucket/13tsdb.mql
  31. 56 0
      odbctest/mql/aaa/14bucket/14promdb.mql
  32. 30 0
      odbctest/mql/aaa/15cypher/00init.mql
  33. 38 0
      odbctest/mql/aaa/15cypher/11create.mql
  34. 52 0
      odbctest/mql/aaa/15cypher/12match.mql
  35. 31 0
      odbctest/mql/aaa/15cypher/13subquery.mql
  36. 23 0
      odbctest/mql/aaa/16partition/00init.mql
  37. 59 0
      odbctest/mql/aaa/16partition/11single.mql
  38. 56 0
      odbctest/mql/aaa/16partition/12multi.mql
  39. 20 0
      odbctest/mql/aaa/17conflict/00init.mql
  40. 49 0
      odbctest/mql/aaa/17conflict/11upsert.mql
  41. 48 0
      odbctest/mql/aaa/17conflict/12conflict_update.mql
  42. 14 0
      odbctest/mql/aaa/17conflict/13concurrent.mql
  43. 23 0
      odbctest/mql/aaa/18prepare/00init.mql
  44. 68 0
      odbctest/mql/aaa/18prepare/11prepare_insert.mql
  45. 59 0
      odbctest/mql/aaa/18prepare/12prepare_update.mql
  46. 51 0
      odbctest/mql/aaa/18prepare/13prepare_delete.mql
  47. 68 0
      odbctest/mql/aaa/18prepare/14prepare_batch.mql
  48. 22 0
      odbctest/mql/aaa/19extensions/00init.mql
  49. 37 0
      odbctest/mql/aaa/19extensions/11loop.mql
  50. 25 0
      odbctest/mql/aaa/19extensions/12loop_file.mql
  51. 17 0
      odbctest/mql/aaa/19extensions/13loop_dir.mql
  52. 24 0
      odbctest/mql/aaa/19extensions/14loop_top.mql
  53. 24 0
      odbctest/mql/aaa/19extensions/15parallel.mql
  54. 38 0
      odbctest/mql/aaa/19extensions/16fork_wait.mql
  55. 93 0
      odbctest/mql/aaa/19extensions/17beforerun.mql
  56. 74 0
      odbctest/mql/aaa/19extensions/18variable.mql
  57. 44 0
      odbctest/mql/aaa/19extensions/19format_escape.mql
  58. 46 0
      odbctest/mql/aaa/19extensions/20loopfrom_loopstep.mql
  59. 28 0
      odbctest/mql/aaa/19extensions/21retry.mql
  60. 38 0
      odbctest/mql/aaa/19extensions/22onerror.mql
  61. 70 0
      odbctest/mql/aaa/19extensions/23noerrinfo_skip.mql
  62. 39 0
      odbctest/mql/aaa/19extensions/24timeout.mql
  63. 45 0
      odbctest/mql/aaa/19extensions/25sleep.mql
  64. 41 0
      odbctest/mql/aaa/19extensions/26output_meta.mql
  65. 56 0
      odbctest/mql/aaa/19extensions/27result_check.mql
  66. 40 0
      odbctest/mql/aaa/19extensions/28schema.mql
  67. 27 0
      odbctest/mql/aaa/19extensions/29qmeta.mql
  68. 35 0
      odbctest/mql/aaa/19extensions/30multilines.mql
  69. 56 0
      odbctest/mql/aaa/19extensions/31subscription.mql
  70. 27 0
      odbctest/mql/aaa/20subquery/00init.mql
  71. 44 0
      odbctest/mql/aaa/20subquery/11basic.mql
  72. 35 0
      odbctest/mql/aaa/20subquery/12aggr.mql
  73. 28 0
      odbctest/mql/aaa/21cross_ns/00init.mql
  74. 29 0
      odbctest/mql/aaa/21cross_ns/11create.mql
  75. 50 0
      odbctest/mql/aaa/21cross_ns/12valid.mql
  76. 19 0
      odbctest/mql/aaa/22syntax/00init.mql
  77. 53 0
      odbctest/mql/aaa/22syntax/11relaxed.mql
  78. 38 0
      odbctest/mql/aaa/22syntax/12case_sensitive.mql
  79. 33 0
      odbctest/mql/aaa/22syntax/13alias.mql
  80. 1 0
      odbctest/mql/aaa/23system/00init.mql
  81. 17 0
      odbctest/mql/aaa/23system/11signal.mql
  82. 19 0
      odbctest/mql/aaa/23system/12native.mql
  83. 18 0
      odbctest/mql/aaa/24trigger/00init.mql
  84. 63 0
      odbctest/mql/aaa/24trigger/11trigger.mql
  85. 5 0
      odbctest/mql/basic/mdb/0001init.mql
  86. 23 0
      odbctest/mql/basic/mdb/0010clear.mql
  87. 68 0
      odbctest/mql/basic/mdb/0100class.mql
  88. 19 0
      odbctest/mql/basic/mdb/0300valid.mql

+ 8 - 0
odbctest/mql/aaa/00init/00init.mql

@@ -0,0 +1,8 @@
+-- 全局初始化:设置 scope(top) 和 timeout(30m)
+-- 整个测试套件作用范围:top 级别,超时 30 分钟
+
+/**
+scope(top)
+timeout(30m)
+**/
+;

+ 15 - 0
odbctest/mql/aaa/01clear/00init.mql

@@ -0,0 +1,15 @@
+-- 清除测试数据目录初始化
+-- scope(dir) 作用于当前目录下所有文件,timeout(10m)
+
+/**
+scope(dir)
+timeout(10m)
+**/
+;
+
+-- 清除全局缓存
+signal('globalcache.clear')
+/**
+match("msg","ok")
+**/
+;

+ 157 - 0
odbctest/mql/aaa/01clear/1_drop_all.mql

@@ -0,0 +1,157 @@
+-- 清除 /test/aaa/ 下的所有测试数据
+-- 使用 onerror(continue) 忽略类不存在的错误
+
+-- 删除所有测试 class 数据
+delete from /test/aaa/test_basic with version
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+delete from /test/aaa/test_class with version
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+delete from /test/aaa/test_search with version
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+delete from /test/aaa/test_aggr with version
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+delete from /test/aaa/test_bucket_logs with version
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+delete from /test/aaa/test_bucket_strulogs with version
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+delete from /test/aaa/test_bucket_tsdb with version
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+delete from /test/aaa/test_bucket_promdb with version
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+delete from /test/aaa/test_graph with version
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+delete from /test/aaa/test_partition with version
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+delete from /test/aaa/test_mpartition with version
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+delete from /test/aaa/test_conflict with version
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+delete from /test/aaa/test_prepare with version
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+delete from /test/aaa/test_subquery with version
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+delete from /test/aaa/test_cross_ns with version
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+delete from /test/aaa/test_syntax with version
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+delete from /test/aaa/test_trigger with version
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+-- 安全删除所有 class
+drop class if exists /test/aaa/test_basic
+;
+
+drop class if exists /test/aaa/test_class
+;
+
+drop class if exists /test/aaa/test_search
+;
+
+drop class if exists /test/aaa/test_aggr
+;
+
+drop class if exists /test/aaa/test_bucket_logs
+;
+
+drop class if exists /test/aaa/test_bucket_strulogs
+;
+
+drop class if exists /test/aaa/test_bucket_tsdb
+;
+
+drop class if exists /test/aaa/test_bucket_promdb
+;
+
+drop class if exists /test/aaa/test_graph
+;
+
+drop class if exists /test/aaa/test_partition
+;
+
+drop class if exists /test/aaa/test_mpartition
+;
+
+drop class if exists /test/aaa/test_conflict
+;
+
+drop class if exists /test/aaa/test_prepare
+;
+
+drop class if exists /test/aaa/test_subquery
+;
+
+drop class if exists /test/aaa/test_cross_ns
+;
+
+drop class if exists /test/aaa/test_syntax
+;
+
+drop class if exists /test/aaa/test_trigger
+;

+ 4 - 0
odbctest/mql/aaa/10class/00init.mql

@@ -0,0 +1,4 @@
+-- 10class 目录初始化:Class 操作测试
+
+create class if not exists /test() with namespace="test"
+;

+ 126 - 0
odbctest/mql/aaa/10class/10create.mql

@@ -0,0 +1,126 @@
+-- ============================================================
+-- Class 创建操作测试:测试各种 with 选项的 class 创建
+-- ============================================================
+
+-- 清除可能存在的旧数据
+delete from /test/aaa/test_class with version
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+drop class if exists /test/aaa/test_class
+;
+
+-- 1. 基本 class 创建(默认选项)
+create class if not exists /test/aaa/test_class (
+    name        varchar,
+    age         int,
+    score       double,
+    active      bool,
+    description text,
+    created_at  timestamp,
+
+    indexes(name, age, score, active, created_at),
+    keys(name)
+)
+/**
+schema(/test/aaa/test_class)
+**/
+;
+
+-- 2. 创建带 nickname 的 class
+create class if not exists /test/aaa/test_class_nick (
+    id      int,
+    value   text,
+
+    keys(id)
+) with nickname='test_class_nickname'
+;
+
+-- 3. 创建带 core=cassandraonly 的 class(Cassandra 专用)
+create class if not exists /test/aaa/test_class_core (
+    name    varchar,
+    data    text,
+
+    keys(name)
+) with core=cassandraonly
+;
+
+-- 4. 创建带 ttl 的 class
+create class if not exists /test/aaa/test_class_ttl (
+    name    varchar,
+    val     int,
+
+    keys(name)
+) with ttl=3600
+;
+
+-- 5. 创建带 autosearch=true 的 class
+create class if not exists /test/aaa/test_class_autosearch (
+    name    varchar,
+    content text,
+
+    keys(name)
+) with autosearch=true, version=false
+;
+
+-- 6. 创建带 version=true 的 class
+create class if not exists /test/aaa/test_class_version (
+    name    varchar,
+    val     int,
+
+    keys(name)
+) with version=true
+;
+
+-- 7. 创建带 key 选项的 class
+create class if not exists /test/aaa/test_class_key (
+    id      int,
+    name    varchar,
+    data    text,
+
+    keys(id, name)
+) with key=name
+;
+
+-- 8. 创建带 partition 的 class
+create class if not exists /test/aaa/test_class_partition (
+    id      int,
+    name    varchar,
+    val     int,
+
+    indexes(id, name, val),
+    keys(id, name)
+) with partition=id
+;
+
+-- 9. 创建带 cache=all 的 class
+create class if not exists /test/aaa/test_class_cache (
+    name    varchar,
+    data    text,
+
+    keys(name)
+) with cache=all
+;
+
+-- 10. 创建带 alias 的 class(别名)
+create class if not exists /test/aaa/test_class_alias (
+    name    varchar,
+    value   int,
+
+    keys(name)
+) with nickname='alias_test'
+;
+
+-- 11. 重复创建已存在的 class(应忽略错误)
+create class if not exists /test/aaa/test_class (
+    name        varchar,
+    age         int,
+
+    keys(name)
+)
+/**
+onerror(continue)
+**/
+;

+ 59 - 0
odbctest/mql/aaa/10class/11alter.mql

@@ -0,0 +1,59 @@
+-- ============================================================
+-- Class alter 操作测试
+-- ============================================================
+
+-- 1. alter class 添加 nickname
+alter class /test/aaa/test_class with nickname='test_class_main'
+;
+
+-- 2. alter class 添加列
+alter class /test/aaa/test_class add column new_field text
+;
+
+-- 验证新列是否存在
+insert into /test/aaa/test_class (name, age, new_field) values ('test_alter', 25, 'new_field_value')
+;
+
+select name, new_field from /test/aaa/test_class where name='test_alter'
+/**
+output()
+**/
+;
+
+-- 3. alter class 添加 int 列
+alter class /test/aaa/test_class add column extra_int int
+;
+
+-- 4. alter class 添加 bool 列
+alter class /test/aaa/test_class add column extra_bool bool
+;
+
+-- 5. alter class 添加 double 列(带默认值验证)
+alter class /test/aaa/test_class add column extra_double double
+;
+
+-- 6. alter class 添加 timestamp 列
+alter class /test/aaa/test_class add column extra_ts timestamp
+;
+
+-- 7. 连续多次 alter
+alter class /test/aaa/test_class add column field_a int
+;
+
+alter class /test/aaa/test_class add column field_b text
+;
+
+-- 8. 尝试 alter 不存在的 class(安全忽略)
+alter class /test/aaa/non_exist_class add column dummy int
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+-- 9. alter class 带 with 选项变更
+alter class /test/aaa/test_class_nick with nickname='new_nickname'
+;
+
+-- 10. alter class 多次修改同一选项
+alter class /test/aaa/test_class_nick with nickname='nickname_v2'
+;

+ 70 - 0
odbctest/mql/aaa/10class/12drop.mql

@@ -0,0 +1,70 @@
+-- ============================================================
+-- Class drop 操作测试
+-- ============================================================
+
+-- 1. 创建临时 class 用于 drop 测试
+create class if not exists /test/aaa/test_drop (
+    name    varchar,
+    value   int,
+
+    keys(name)
+)
+;
+
+-- 2. drop class 前插入数据验证
+insert into /test/aaa/test_drop (name, value) values ('before_drop', 100)
+;
+
+select * from /test/aaa/test_drop where name='before_drop'
+/**
+output()
+**/
+;
+
+-- 3. drop class 安全操作
+drop class if exists /test/aaa/test_drop
+;
+
+-- 4. 验证已 drop 的 class(应报错)
+select * from /test/aaa/test_drop
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+-- 5. 重复 drop 已删除的 class
+drop class if exists /test/aaa/test_drop
+;
+
+-- 6. 删除不存在的 class
+drop class if exists /test/aaa/non_exist_drop
+;
+
+-- 7. drop 带 alias 的 class
+create class if not exists /test/aaa/test_drop_alias (
+    name    varchar,
+    keys(name)
+) with nickname='drop_alias'
+;
+
+drop class if exists /test/aaa/test_drop_alias
+;
+
+-- 8. 批量创建和删除
+create class if not exists /test/aaa/test_batch_drop_1 (
+    id int,
+    keys(id)
+)
+;
+
+create class if not exists /test/aaa/test_batch_drop_2 (
+    id int,
+    keys(id)
+)
+;
+
+drop class if exists /test/aaa/test_batch_drop_1
+;
+
+drop class if exists /test/aaa/test_batch_drop_2
+;

+ 26 - 0
odbctest/mql/aaa/11data_crud/00init.mql

@@ -0,0 +1,26 @@
+-- 11data_crud 目录初始化:基本 CRUD 测试
+-- 创建用于 CRUD 测试的基础 class
+
+create class if not exists /test/aaa/test_basic (
+    name        varchar,
+    v_text      text,
+    v_int       int,
+    v_bigint    bigint,
+    v_float     float,
+    v_double    double,
+    v_bool      bool,
+    v_ts        timestamp,
+    v_blob      blob,
+
+    indexes(name, v_text, v_int, v_bigint, v_float, v_double, v_bool, v_ts),
+    keys(name)
+)
+;
+
+-- 创建带 version 的 class 用于版本数据测试
+create class if not exists /test/aaa/test_basic_ver (
+    name    varchar,
+    value   int,
+    keys(name)
+) with version=true
+;

+ 97 - 0
odbctest/mql/aaa/11data_crud/11insert.mql

@@ -0,0 +1,97 @@
+-- ============================================================
+-- Insert 操作测试
+-- ============================================================
+
+-- 1. 基本 insert - 插入所有类型字段
+insert into /test/aaa/test_basic (name, v_text, v_int, v_bigint, v_float, v_double, v_bool, v_ts, v_blob)
+values ('insert_001', 'hello world 测试数据', 100, 1234567890123456789, 3.14, 3.141592653589793, true, 1711641600000, 'hello')
+/**
+output()
+count(1)
+**/
+;
+
+-- 2. 插入布尔值 false
+insert into /test/aaa/test_basic (name, v_text, v_int, v_float, v_double, v_bool)
+values ('insert_002', 'boolean false test', -50, -1.5, 0.0001, false)
+/**
+output()
+count(1)
+**/
+;
+
+-- 3. 插入大整数边界值
+insert into /test/aaa/test_basic (name, v_text, v_int, v_bigint)
+values ('insert_003', 'bigint boundary', 2147483647, 9223372036854775807)
+;
+
+-- 4. 插入负值
+insert into /test/aaa/test_basic (name, v_text, v_int, v_float, v_double)
+values ('insert_004', 'negative values', -999, -123.456, -9876543210.12345)
+;
+
+-- 5. 插入零值
+insert into /test/aaa/test_basic (name, v_text, v_int, v_float, v_double, v_bool)
+values ('insert_005', 'zero values', 0, 0.0, 0.0, false)
+;
+
+-- 6. 插入中文/特殊字符
+insert into /test/aaa/test_basic (name, v_text, v_int)
+values ('插入_006', '你好世界!特殊字符:@#$%^&*()_+-=[]{}|;:",.<>/?', 666)
+;
+
+-- 7. 插入长文本
+insert into /test/aaa/test_basic (name, v_text, v_int)
+values ('insert_007', '这是一个很长的文本用于测试长字段存储能力。MQL 扩展测试框架支持 scope、loop、parallel 等多种高级特性,可以模拟真实生产环境中的复杂场景。', 777)
+;
+
+-- 8. 批量插入多条数据
+insert into /test/aaa/test_basic (name, v_text, v_int)
+values ('batch_001', 'batch data 1', 1)
+;
+
+insert into /test/aaa/test_basic (name, v_text, v_int)
+values ('batch_002', 'batch data 2', 2)
+;
+
+insert into /test/aaa/test_basic (name, v_text, v_int)
+values ('batch_003', 'batch data 3', 3)
+;
+
+insert into /test/aaa/test_basic (name, v_text, v_int)
+values ('batch_004', 'batch data 4', 4)
+;
+
+insert into /test/aaa/test_basic (name, v_text, v_int)
+values ('batch_005', 'batch data 5', 5)
+;
+
+-- 9. 插入重复主键(应报错)
+insert into /test/aaa/test_basic (name, v_int) values ('insert_001', 999)
+/**
+onerror(continue)
+**/
+;
+
+-- 10. 缺少必填字段(keys中的字段)
+insert into /test/aaa/test_basic (v_int) values (123)
+/**
+onerror(continue)
+**/
+;
+
+-- 11. 插入带 timestamp 字段的数据(使用毫秒时间戳)
+insert into /test/aaa/test_basic (name, v_text, v_int, v_ts)
+values ('insert_ts_001', 'timestamp test', 1, 1700000000000)
+;
+
+insert into /test/aaa/test_basic (name, v_text, v_int, v_ts)
+values ('insert_ts_002', 'timestamp future', 2, 1893456000000)
+;
+
+-- 12. 插入 version 表数据
+insert into /test/aaa/test_basic_ver (name, value) values ('ver_001', 1)
+;
+
+insert into /test/aaa/test_basic_ver (name, value) values ('ver_002', 2)
+;

+ 118 - 0
odbctest/mql/aaa/11data_crud/12select.mql

@@ -0,0 +1,118 @@
+-- ============================================================
+-- Select 查询操作测试
+-- ============================================================
+
+-- 1. 全表查询
+select * from /test/aaa/test_basic
+/**
+output()
+match("insert_001","hello world 测试数据")
+**/
+;
+
+-- 2. 等值查询
+select * from /test/aaa/test_basic where name='insert_001'
+/**
+output()
+count(1)
+match("v_int","100")
+**/
+;
+
+-- 3. 多字段条件查询(AND)
+select name, v_int, v_bool from /test/aaa/test_basic where name='insert_001' and v_int=100
+/**
+output()
+count(1)
+**/
+;
+
+-- 4. OR 条件查询
+select * from /test/aaa/test_basic where name='insert_001' or name='insert_002'
+/**
+output()
+count(2)
+**/
+;
+
+-- 5. 大于条件查询
+select name, v_int from /test/aaa/test_basic where v_int>10
+/**
+output()
+**/
+;
+
+-- 6. 小于条件查询
+select name, v_int from /test/aaa/test_basic where v_int<0
+/**
+output()
+match("insert_004")
+**/
+;
+
+-- 7. 大于等于条件
+select name, v_int from /test/aaa/test_basic where v_int>=100
+/**
+output()
+**/
+;
+
+-- 8. 不等于条件
+select name, v_int from /test/aaa/test_basic where name!='insert_001'
+/**
+output()
+**/
+;
+
+-- 9. 查询 bool 字段
+select name, v_bool from /test/aaa/test_basic where v_bool=true
+/**
+output()
+match("insert_001")
+**/
+;
+
+select name, v_bool from /test/aaa/test_basic where v_bool=false
+/**
+output()
+**/
+;
+
+-- 10. 带 LIMIT 的查询
+select * from /test/aaa/test_basic limit 3
+/**
+output()
+count(3)
+**/
+;
+
+-- 11. 查询不存在的记录
+select * from /test/aaa/test_basic where name='non_exist_key_99999'
+/**
+output()
+count(0)
+**/
+;
+
+-- 12. 查询 version 表
+select * from /test/aaa/test_basic_ver where name='ver_001'
+/**
+output()
+count(1)
+**/
+;
+
+-- 13. 查询 float/double 字段
+select name, v_float, v_double from /test/aaa/test_basic where name='insert_001'
+/**
+output()
+**/
+;
+
+-- 14. 查询 bigint 字段
+select name, v_bigint from /test/aaa/test_basic where name='insert_003'
+/**
+output()
+match("v_bigint","9223372036854775807")
+**/
+;

+ 99 - 0
odbctest/mql/aaa/11data_crud/13update.mql

@@ -0,0 +1,99 @@
+-- ============================================================
+-- Update 更新操作测试
+-- ============================================================
+
+-- 1. 基本 update - 更新单个字段
+update /test/aaa/test_basic set v_int=200 where name='insert_001'
+/**
+output()
+count(1)
+**/
+;
+
+-- 验证更新结果
+select name, v_int from /test/aaa/test_basic where name='insert_001'
+/**
+output()
+match("v_int","200")
+**/
+;
+
+-- 2. 更新多个字段
+update /test/aaa/test_basic set v_text='updated text', v_bool=false where name='insert_001'
+/**
+output()
+count(1)
+**/
+;
+
+select name, v_text, v_bool from /test/aaa/test_basic where name='insert_001'
+/**
+output()
+match("v_text","updated text")
+match("v_bool","false")
+**/
+;
+
+-- 3. 更新 float/double 字段
+update /test/aaa/test_basic set v_float=9.99, v_double=99.999999 where name='insert_002'
+;
+
+select name, v_float, v_double from /test/aaa/test_basic where name='insert_002'
+/**
+output()
+**/
+;
+
+-- 4. 更新不存在的记录(影响0行)
+update /test/aaa/test_basic set v_int=999 where name='non_exist_key_update'
+/**
+output()
+count(0)
+**/
+;
+
+-- 5. 更新 version 表
+update /test/aaa/test_basic_ver set value=100 where name='ver_001'
+;
+
+select name, value from /test/aaa/test_basic_ver where name='ver_001'
+/**
+output()
+match("value","100")
+**/
+;
+
+-- 6. 批量更新
+update /test/aaa/test_basic set v_int=10 where name='batch_001'
+;
+
+update /test/aaa/test_basic set v_int=20 where name='batch_002'
+;
+
+select name, v_int from /test/aaa/test_basic where name='batch_001' or name='batch_002'
+/**
+output()
+count(2)
+**/
+;
+
+-- 7. 更新后再更新回原值
+update /test/aaa/test_basic set v_int=1 where name='batch_001'
+;
+
+select name, v_int from /test/aaa/test_basic where name='batch_001'
+/**
+output()
+match("v_int","1")
+**/
+;
+
+-- 8. 更新 bigint 字段
+update /test/aaa/test_basic set v_bigint=-999999999999999999 where name='insert_003'
+;
+
+select name, v_bigint from /test/aaa/test_basic where name='insert_003'
+/**
+output()
+**/
+;

+ 98 - 0
odbctest/mql/aaa/11data_crud/14delete.mql

@@ -0,0 +1,98 @@
+-- ============================================================
+-- Delete 删除操作测试
+-- ============================================================
+
+-- 1. 基本 delete - 条件删除
+insert into /test/aaa/test_basic (name, v_text, v_int)
+values ('to_delete_001', 'will be deleted', 1)
+;
+
+select name from /test/aaa/test_basic where name='to_delete_001'
+/**
+output()
+count(1)
+**/
+;
+
+delete from /test/aaa/test_basic where name='to_delete_001'
+/**
+output()
+count(1)
+**/
+;
+
+-- 验证已删除
+select name from /test/aaa/test_basic where name='to_delete_001'
+/**
+output()
+count(0)
+**/
+;
+
+-- 2. 删除不存在的记录
+delete from /test/aaa/test_basic where name='non_exist_delete_999'
+/**
+output()
+count(0)
+**/
+;
+
+-- 3. 多次删除同一记录
+insert into /test/aaa/test_basic (name, v_text, v_int)
+values ('to_delete_002', 'delete twice test', 2)
+;
+
+delete from /test/aaa/test_basic where name='to_delete_002'
+;
+
+-- 第二次删除应返回 count(0)
+delete from /test/aaa/test_basic where name='to_delete_002'
+/**
+output()
+count(0)
+**/
+;
+
+-- 4. 删除 version 表数据
+insert into /test/aaa/test_basic_ver (name, value) values ('del_ver', 1)
+;
+
+delete from /test/aaa/test_basic_ver where name='del_ver'
+;
+
+select * from /test/aaa/test_basic_ver where name='del_ver'
+/**
+output()
+count(0)
+**/
+;
+
+-- 5. 带复合条件的删除
+insert into /test/aaa/test_basic (name, v_text, v_int)
+values ('to_delete_003', 'complex condition', 100)
+;
+
+delete from /test/aaa/test_basic where name='to_delete_003' and v_int=100
+;
+
+select * from /test/aaa/test_basic where name='to_delete_003'
+/**
+output()
+count(0)
+**/
+;
+
+-- 6. with version 删除(清表)
+insert into /test/aaa/test_basic (name, v_text, v_int)
+values ('to_delete_004', 'with version delete', 4)
+;
+
+delete from /test/aaa/test_basic where name='to_delete_004' with version
+;
+
+select * from /test/aaa/test_basic where name='to_delete_004'
+/**
+output()
+count(0)
+**/
+;

+ 50 - 0
odbctest/mql/aaa/12search/00init.mql

@@ -0,0 +1,50 @@
+-- 12search 目录初始化:搜索功能测试
+-- 创建用于搜索测试的 class
+
+create class if not exists /test/aaa/test_search (
+    s_name      varchar,
+    s_text      text,
+    s_int       int,
+    s_bigint    bigint,
+    s_float     float,
+    s_double    double,
+    s_bool      bool,
+    s_ts        timestamp,
+
+    indexes(s_name, s_text, s_int, s_bigint, s_float, s_double, s_bool, s_ts),
+    keys(s_name)
+) with autosearch=true
+;
+
+-- 插入搜索测试数据
+insert into /test/aaa/test_search (s_name, s_text, s_int, s_bigint, s_float, s_double, s_bool, s_ts)
+values ('search_int_001', 'int search test data', 10, 100, 10.5, 10.555, true, 1700000000000)
+;
+
+insert into /test/aaa/test_search (s_name, s_text, s_int, s_bigint, s_float, s_double, s_bool, s_ts)
+values ('search_int_002', 'int search test data', 20, 200, 20.5, 20.555, false, 1710000000000)
+;
+
+insert into /test/aaa/test_search (s_name, s_text, s_int, s_bigint, s_float, s_double, s_bool, s_ts)
+values ('search_int_003', 'int search data', 30, 300, 30.5, 30.555, true, 1720000000000)
+;
+
+insert into /test/aaa/test_search (s_name, s_text, s_int, s_bigint, s_float, s_double, s_bool, s_ts)
+values ('search_int_004', 'between test', 50, 500, 50.5, 50.555, true, 1730000000000)
+;
+
+insert into /test/aaa/test_search (s_name, s_text, s_int, s_bigint, s_float, s_double, s_bool, s_ts)
+values ('search_int_005', 'between test data', 60, 600, 60.5, 60.555, false, 1740000000000)
+;
+
+insert into /test/aaa/test_search (s_name, s_text, s_int, s_bigint, s_float, s_double, s_bool, s_ts)
+values ('search_string_001', 'hello world prefix test', 1, 10, 0.1, 0.001, true, 1750000000000)
+;
+
+insert into /test/aaa/test_search (s_name, s_text, s_int, s_bigint, s_float, s_double, s_bool, s_ts)
+values ('search_string_002', 'hello mql full search test data', 2, 20, 0.2, 0.002, false, 1760000000000)
+;
+
+insert into /test/aaa/test_search (s_name, s_text, s_int, s_bigint, s_float, s_double, s_bool, s_ts)
+values ('search_string_003', 'prefix search demo test', 3, 30, 0.3, 0.003, true, 1770000000000)
+;

+ 73 - 0
odbctest/mql/aaa/12search/11int.mql

@@ -0,0 +1,73 @@
+-- ============================================================
+-- int 类型搜索测试
+-- ============================================================
+
+-- 1. 等值搜索
+select * from /test/aaa/test_search where s_int=10
+/**
+output()
+count(1)
+match("s_name","search_int_001")
+**/
+;
+
+-- 2. 大于搜索
+select * from /test/aaa/test_search where s_int>20
+/**
+output()
+match("search_int_003")
+match("search_int_004")
+match("search_int_005")
+**/
+;
+
+-- 3. 小于搜索
+select * from /test/aaa/test_search where s_int<20
+/**
+output()
+match("search_int_001")
+**/
+;
+
+-- 4. 大于等于搜索
+select * from /test/aaa/test_search where s_int>=50
+/**
+output()
+match("search_int_004")
+match("search_int_005")
+**/
+;
+
+-- 5. 不等于搜索
+select * from /test/aaa/test_search where s_int!=10
+/**
+output()
+**/
+;
+
+-- 6. 搜索不存在的值
+select * from /test/aaa/test_search where s_int=99999
+/**
+output()
+count(0)
+**/
+;
+
+-- 7. 搜索负数 (插入测试数据)
+insert into /test/aaa/test_search (s_name, s_text, s_int) values ('search_neg_001', 'negative int test', -100)
+;
+
+select * from /test/aaa/test_search where s_int=-100
+/**
+output()
+count(1)
+**/
+;
+
+-- 8. 搜索零值
+select * from /test/aaa/test_search where s_int=0
+/**
+output()
+count(0)
+**/
+;

+ 61 - 0
odbctest/mql/aaa/12search/12float.mql

@@ -0,0 +1,61 @@
+-- ============================================================
+-- float 类型搜索测试
+-- ============================================================
+
+-- 1. 等值搜索 float
+select * from /test/aaa/test_search where s_float=10.5
+/**
+output()
+count(1)
+match("s_name","search_int_001")
+**/
+;
+
+-- 2. 大于搜索 float
+select * from /test/aaa/test_search where s_float>30.0
+/**
+output()
+match("search_int_004")
+match("search_int_005")
+**/
+;
+
+-- 3. 小于搜索 float
+select * from /test/aaa/test_search where s_float<1.0
+/**
+output()
+match("search_string_001")
+match("search_string_002")
+match("search_string_003")
+**/
+;
+
+-- 4. 区间搜索 float
+select * from /test/aaa/test_search where s_float>=10.0 and s_float<=60.0
+/**
+output()
+**/
+;
+
+-- 5. double 类型搜索
+select * from /test/aaa/test_search where s_double=10.555
+/**
+output()
+count(1)
+**/
+;
+
+-- 6. 搜索不存在的 float 值
+select * from /test/aaa/test_search where s_float=99999.99
+/**
+output()
+count(0)
+**/
+;
+
+-- 7. 搜索浮点范围的边界值
+select * from /test/aaa/test_search where s_double<1.0
+/**
+output()
+**/
+;

+ 42 - 0
odbctest/mql/aaa/12search/13bool.mql

@@ -0,0 +1,42 @@
+-- ============================================================
+-- bool 类型搜索测试
+-- ============================================================
+
+-- 1. 搜索 bool=true
+select * from /test/aaa/test_search where s_bool=true
+/**
+output()
+match("search_int_001")
+match("search_int_003")
+match("search_int_004")
+match("search_string_001")
+match("search_string_003")
+**/
+;
+
+-- 2. 搜索 bool=false
+select * from /test/aaa/test_search where s_bool=false
+/**
+output()
+match("search_int_002")
+match("search_int_005")
+match("search_string_002")
+**/
+;
+
+-- 3. 复合条件:bool + int
+select * from /test/aaa/test_search where s_bool=true and s_int>10
+/**
+output()
+match("search_int_003")
+match("search_int_004")
+**/
+;
+
+-- 4. 复合条件:bool + string
+select * from /test/aaa/test_search where s_bool=true and s_name='search_int_001'
+/**
+output()
+count(1)
+**/
+;

+ 49 - 0
odbctest/mql/aaa/12search/14string.mql

@@ -0,0 +1,49 @@
+-- ============================================================
+-- string 前缀/全文搜索测试
+-- ============================================================
+
+-- 1. 前缀搜索(s_name like)
+select * from /test/aaa/test_search where s_name prefix 'search_int'
+/**
+output()
+matchcount("s_name","search_int",5)
+**/
+;
+
+-- 2. 前缀搜索 - 单个匹配
+select * from /test/aaa/test_search where s_name prefix 'search_string'
+/**
+output()
+matchcount("s_name","search_string",3)
+**/
+;
+
+-- 3. 前缀搜索 - 无匹配
+select * from /test/aaa/test_search where s_name prefix 'zzz_not_exist'
+/**
+output()
+count(0)
+**/
+;
+
+-- 4. 全文搜索 - autosearch
+select * from /test/aaa/test_search where s_text search 'test'
+/**
+output()
+**/
+;
+
+-- 5. 全文搜索 - 中文(如有)
+select * from /test/aaa/test_search where s_text search 'hello'
+/**
+output()
+**/
+;
+
+-- 6. 前缀搜索 - 精确前缀
+select * from /test/aaa/test_search where s_name prefix 'search_neg'
+/**
+output()
+count(1)
+**/
+;

+ 58 - 0
odbctest/mql/aaa/12search/15between.mql

@@ -0,0 +1,58 @@
+-- ============================================================
+-- Between 查询测试
+-- ============================================================
+
+-- 1. int between
+select * from /test/aaa/test_search where s_int between 10 and 30
+/**
+output()
+match("search_int_001")
+match("search_int_002")
+match("search_int_003")
+**/
+;
+
+-- 2. int between 边界
+select * from /test/aaa/test_search where s_int between 50 and 60
+/**
+output()
+match("search_int_004")
+match("search_int_005")
+**/
+;
+
+-- 3. float between
+select * from /test/aaa/test_search where s_float between 10.0 and 30.0
+/**
+output()
+**/
+;
+
+-- 4. double between
+select * from /test/aaa/test_search where s_double between 0.001 and 10.0
+/**
+output()
+**/
+;
+
+-- 5. bigint between
+select * from /test/aaa/test_search where s_bigint between 100 and 500
+/**
+output()
+**/
+;
+
+-- 6. timestamp between
+select * from /test/aaa/test_search where s_ts between 1700000000000 and 1720000000000
+/**
+output()
+**/
+;
+
+-- 7. between 无匹配
+select * from /test/aaa/test_search where s_int between 9999 and 99999
+/**
+output()
+count(0)
+**/
+;

+ 38 - 0
odbctest/mql/aaa/12search/16notin.mql

@@ -0,0 +1,38 @@
+-- ============================================================
+-- Not In 查询测试
+-- ============================================================
+
+-- 1. int not in
+select * from /test/aaa/test_search where s_int not in (10, 20)
+/**
+output()
+**/
+;
+
+-- 2. float not in
+select * from /test/aaa/test_search where s_int not in (1, 2, 3)
+/**
+output()
+**/
+;
+
+-- 3. string not in
+select * from /test/aaa/test_search where s_name not in ('search_int_001', 'search_int_002')
+/**
+output()
+**/
+;
+
+-- 4. not in 空集合
+select * from /test/aaa/test_search where s_name not in ('')
+/**
+output()
+**/
+;
+
+-- 5. not in 全部排除
+select * from /test/aaa/test_search where s_name not in ('non_exist_1', 'non_exist_2')
+/**
+output()
+**/
+;

+ 53 - 0
odbctest/mql/aaa/12search/17orderby.mql

@@ -0,0 +1,53 @@
+-- ============================================================
+-- Order By 排序查询测试
+-- ============================================================
+
+-- 1. 升序排列
+select s_name, s_int from /test/aaa/test_search order by s_int asc
+/**
+output()
+**/
+;
+
+-- 2. 降序排列
+select s_name, s_int from /test/aaa/test_search order by s_int desc
+/**
+output()
+**/
+;
+
+-- 3. 多字段排序
+select s_name, s_int, s_float from /test/aaa/test_search order by s_int asc, s_float desc
+/**
+output()
+**/
+;
+
+-- 4. 带 limit 的排序
+select s_name, s_int from /test/aaa/test_search order by s_int asc limit 3
+/**
+output()
+count(3)
+**/
+;
+
+-- 5. float 排序
+select s_name, s_float from /test/aaa/test_search order by s_float asc
+/**
+output()
+**/
+;
+
+-- 6. 带 where 条件的排序
+select s_name, s_int from /test/aaa/test_search where s_int>10 order by s_int desc
+/**
+output()
+**/
+;
+
+-- 7. bool 排序
+select s_name, s_bool from /test/aaa/test_search order by s_bool asc
+/**
+output()
+**/
+;

+ 46 - 0
odbctest/mql/aaa/13aggregate/00init.mql

@@ -0,0 +1,46 @@
+-- 13aggregate 目录初始化:聚合操作测试
+-- 创建用于聚合测试的 class
+
+create class if not exists /test/aaa/test_aggr (
+    a_name      varchar,
+    a_category  varchar,
+    a_int       int,
+    a_bigint    bigint,
+    a_float     float,
+    a_double    double,
+    a_amount    int,
+    a_bool      bool,
+
+    indexes(a_name, a_category, a_int, a_amount, a_float, a_double, a_bool),
+    keys(a_name)
+)
+;
+
+-- 插入聚合测试数据
+insert into /test/aaa/test_aggr (a_name, a_category, a_int, a_amount, a_float, a_double, a_bool)
+values ('aggr_001', 'category_a', 10, 100, 10.5, 100.5, true)
+;
+
+insert into /test/aaa/test_aggr (a_name, a_category, a_int, a_amount, a_float, a_double, a_bool)
+values ('aggr_002', 'category_a', 20, 200, 20.5, 200.5, false)
+;
+
+insert into /test/aaa/test_aggr (a_name, a_category, a_int, a_amount, a_float, a_double, a_bool)
+values ('aggr_003', 'category_b', 30, 300, 30.5, 300.5, true)
+;
+
+insert into /test/aaa/test_aggr (a_name, a_category, a_int, a_amount, a_float, a_double, a_bool)
+values ('aggr_004', 'category_b', 40, 400, 40.5, 400.5, false)
+;
+
+insert into /test/aaa/test_aggr (a_name, a_category, a_int, a_amount, a_float, a_double, a_bool)
+values ('aggr_005', 'category_c', 50, 500, 50.5, 500.5, true)
+;
+
+insert into /test/aaa/test_aggr (a_name, a_category, a_int, a_amount, a_float, a_double, a_bool)
+values ('aggr_006', 'category_a', 10, 150, 15.5, 150.5, true)
+;
+
+insert into /test/aaa/test_aggr (a_name, a_category, a_int, a_amount, a_float, a_double, a_bool)
+values ('aggr_007', 'category_b', 30, 350, 35.5, 350.5, false)
+;

+ 56 - 0
odbctest/mql/aaa/13aggregate/11count.mql

@@ -0,0 +1,56 @@
+-- ============================================================
+-- count() 各种形式测试
+-- ============================================================
+
+-- 1. count(*) 全表计数
+select count(*) from /test/aaa/test_aggr
+/**
+output()
+match("count(*)","7")
+**/
+;
+
+-- 2. count(1)
+select count(1) from /test/aaa/test_aggr
+/**
+output()
+**/
+;
+
+-- 3. count(字段)
+select count(a_int) from /test/aaa/test_aggr
+/**
+output()
+**/
+;
+
+-- 4. 带 where 条件的 count
+select count(*) from /test/aaa/test_aggr where a_category='category_a'
+/**
+output()
+match("count(*)","3")
+**/
+;
+
+-- 5. count 空结果集
+select count(*) from /test/aaa/test_aggr where a_category='non_exist_category'
+/**
+output()
+match("count(*)","0")
+**/
+;
+
+-- 6. count 多个字段
+select count(a_name), count(a_int) from /test/aaa/test_aggr
+/**
+output()
+**/
+;
+
+-- 7. count 带 bool 条件
+select count(*) from /test/aaa/test_aggr where a_bool=true
+/**
+output()
+match("count(*)","4")
+**/
+;

+ 52 - 0
odbctest/mql/aaa/13aggregate/12groupby.mql

@@ -0,0 +1,52 @@
+-- ============================================================
+-- Group By 聚合测试
+-- ============================================================
+
+-- 1. 基本 group by + count
+select a_category, count(*) from /test/aaa/test_aggr group by a_category
+/**
+output()
+**/
+;
+
+-- 2. group by + sum
+select a_category, sum(a_amount) from /test/aaa/test_aggr group by a_category
+/**
+output()
+**/
+;
+
+-- 3. group by + avg
+select a_category, avg(a_int) from /test/aaa/test_aggr group by a_category
+/**
+output()
+**/
+;
+
+-- 4. group by + min
+select a_category, min(a_amount) from /test/aaa/test_aggr group by a_category
+/**
+output()
+**/
+;
+
+-- 5. group by + max
+select a_category, max(a_amount) from /test/aaa/test_aggr group by a_category
+/**
+output()
+**/
+;
+
+-- 6. group by 多聚合函数
+select a_category, count(*), sum(a_amount), avg(a_float) from /test/aaa/test_aggr group by a_category
+/**
+output()
+**/
+;
+
+-- 7. group by + where
+select a_category, count(*) from /test/aaa/test_aggr where a_int>=20 group by a_category
+/**
+output()
+**/
+;

+ 37 - 0
odbctest/mql/aaa/13aggregate/13having.mql

@@ -0,0 +1,37 @@
+-- ============================================================
+-- Having 子句测试
+-- ============================================================
+
+-- 1. group by + having count
+select a_category, count(*) from /test/aaa/test_aggr group by a_category having count(*)>2
+/**
+output()
+match("category_a")
+**/
+;
+
+-- 2. group by + having sum
+select a_category, sum(a_amount) from /test/aaa/test_aggr group by a_category having sum(a_amount)>500
+/**
+output()
+match("category_c")
+match("category_b")
+**/
+;
+
+-- 3. group by + having avg
+select a_category, avg(a_int) from /test/aaa/test_aggr group by a_category having avg(a_int)>=30
+/**
+output()
+match("category_b")
+match("category_c")
+**/
+;
+
+-- 4. having 无匹配结果
+select a_category, count(*) from /test/aaa/test_aggr group by a_category having count(*)>100
+/**
+output()
+count(0)
+**/
+;

+ 40 - 0
odbctest/mql/aaa/13aggregate/14distinct.mql

@@ -0,0 +1,40 @@
+-- ============================================================
+-- count(distinct ...) 测试
+-- ============================================================
+
+-- 1. count(distinct 单字段)
+select count(distinct a_category) from /test/aaa/test_aggr
+/**
+output()
+match("count(distinct a_category)","3")
+**/
+;
+
+-- 2. count(distinct 数值字段)
+select count(distinct a_int) from /test/aaa/test_aggr
+/**
+output()
+**/
+;
+
+-- 3. count(distinct bool 字段)
+select count(distinct a_bool) from /test/aaa/test_aggr
+/**
+output()
+match("count(distinct a_bool)","2")
+**/
+;
+
+-- 4. count(distinct) + where
+select count(distinct a_category) from /test/aaa/test_aggr where a_bool=true
+/**
+output()
+**/
+;
+
+-- 5. count(distinct) 空结果
+select count(distinct a_category) from /test/aaa/test_aggr where a_int=9999
+/**
+output()
+**/
+;

+ 70 - 0
odbctest/mql/aaa/13aggregate/15aggr.mql

@@ -0,0 +1,70 @@
+-- ============================================================
+-- sum/avg/min/max 聚合函数测试
+-- ============================================================
+
+-- 1. sum
+select sum(a_amount) from /test/aaa/test_aggr
+/**
+output()
+match("sum(a_amount)","2000")
+**/
+;
+
+-- 2. avg (int)
+select avg(a_int) from /test/aaa/test_aggr
+/**
+output()
+**/
+;
+
+-- 3. avg (float)
+select avg(a_float) from /test/aaa/test_aggr
+/**
+output()
+**/
+;
+
+-- 4. avg (double)
+select avg(a_double) from /test/aaa/test_aggr
+/**
+output()
+**/
+;
+
+-- 5. min
+select min(a_amount) from /test/aaa/test_aggr
+/**
+output()
+match("min(a_amount)","100")
+**/
+;
+
+-- 6. max
+select max(a_amount) from /test/aaa/test_aggr
+/**
+output()
+match("max(a_amount)","500")
+**/
+;
+
+-- 7. 多聚合函数同时使用
+select sum(a_amount), avg(a_float), min(a_int), max(a_int) from /test/aaa/test_aggr
+/**
+output()
+**/
+;
+
+-- 8. 带条件的聚合
+select sum(a_amount) from /test/aaa/test_aggr where a_category='category_a'
+/**
+output()
+match("sum(a_amount)","450")
+**/
+;
+
+-- 9. 聚合空结果集
+select sum(a_amount) from /test/aaa/test_aggr where a_int=99999
+/**
+output()
+**/
+;

+ 35 - 0
odbctest/mql/aaa/14bucket/00init.mql

@@ -0,0 +1,35 @@
+-- 14bucket 目录初始化:Bucket 操作测试
+
+create class if not exists /test/aaa/test_bucket_logs (
+    name    varchar,
+    msg     text,
+    n       int,
+    keys(name)
+) with bucket=logs
+;
+
+create class if not exists /test/aaa/test_bucket_strulogs (
+    name    varchar,
+    data    text,
+    val     int,
+    keys(name)
+) with bucket=strulogs
+;
+
+create class if not exists /test/aaa/test_bucket_tsdb (
+    name    varchar,
+    value   int,
+    ts      timestamp,
+
+    keys(name)
+) with bucket=tsdb
+;
+
+create class if not exists /test/aaa/test_bucket_promdb (
+    name    varchar,
+    metric  double,
+    ts      timestamp,
+
+    keys(name)
+) with bucket=promdb
+;

+ 58 - 0
odbctest/mql/aaa/14bucket/11logs.mql

@@ -0,0 +1,58 @@
+-- ============================================================
+-- bucket logs 测试
+-- ============================================================
+
+-- 1. 插入数据到 bucket logs
+insert into /test/aaa/test_bucket_logs (name, msg, n) values ('log_001', 'log message 1', 1)
+;
+
+-- 2. 查询 bucket logs
+select * from /test/aaa/test_bucket_logs where name='log_001'
+/**
+output()
+count(1)
+**/
+;
+
+-- 3. 批量插入 bucket logs
+insert into /test/aaa/test_bucket_logs (name, msg, n) values ('log_002', 'log message 2', 2)
+;
+
+insert into /test/aaa/test_bucket_logs (name, msg, n) values ('log_003', 'log message 3', 3)
+;
+
+-- 4. 全表查询 bucket logs
+select * from /test/aaa/test_bucket_logs
+/**
+output()
+**/
+;
+
+-- 5. count bucket logs
+select count(*) from /test/aaa/test_bucket_logs
+/**
+output()
+**/
+;
+
+-- 6. update bucket logs
+update /test/aaa/test_bucket_logs set msg='updated log' where name='log_001'
+;
+
+select msg from /test/aaa/test_bucket_logs where name='log_001'
+/**
+output()
+match("msg","updated log")
+**/
+;
+
+-- 7. delete bucket logs
+delete from /test/aaa/test_bucket_logs where name='log_003'
+;
+
+select * from /test/aaa/test_bucket_logs where name='log_003'
+/**
+output()
+count(0)
+**/
+;

+ 50 - 0
odbctest/mql/aaa/14bucket/12strulogs.mql

@@ -0,0 +1,50 @@
+-- ============================================================
+-- bucket strulogs 测试
+-- ============================================================
+
+-- 1. 插入数据到 bucket strulogs
+insert into /test/aaa/test_bucket_strulogs (name, data, val) values ('strulog_001', 'structured log data 1', 100)
+;
+
+-- 2. 查询 bucket strulogs
+select * from /test/aaa/test_bucket_strulogs where name='strulog_001'
+/**
+output()
+count(1)
+**/
+;
+
+-- 3. 批量插入
+insert into /test/aaa/test_bucket_strulogs (name, data, val) values ('strulog_002', 'structured log data 2', 200)
+;
+
+insert into /test/aaa/test_bucket_strulogs (name, data, val) values ('strulog_003', 'structured log data 3', 300)
+;
+
+-- 4. 按值搜索 strulogs
+select * from /test/aaa/test_bucket_strulogs where val>150
+/**
+output()
+**/
+;
+
+-- 5. update strulogs
+update /test/aaa/test_bucket_strulogs set val=999 where name='strulog_001'
+;
+
+select name, val from /test/aaa/test_bucket_strulogs where name='strulog_001'
+/**
+output()
+match("val","999")
+**/
+;
+
+-- 6. delete strulogs
+delete from /test/aaa/test_bucket_strulogs where name='strulog_003'
+;
+
+select count(*) from /test/aaa/test_bucket_strulogs
+/**
+output()
+**/
+;

+ 49 - 0
odbctest/mql/aaa/14bucket/13tsdb.mql

@@ -0,0 +1,49 @@
+-- ============================================================
+-- bucket tsdb 测试(时序数据库)
+-- ============================================================
+
+-- 1. 插入时序数据
+insert into /test/aaa/test_bucket_tsdb (name, value, ts) values ('tsdb_001', 100, 1700000000000)
+;
+
+insert into /test/aaa/test_bucket_tsdb (name, value, ts) values ('tsdb_002', 200, 1700000001000)
+;
+
+insert into /test/aaa/test_bucket_tsdb (name, value, ts) values ('tsdb_003', 300, 1700000002000)
+;
+
+-- 2. 查询时序数据
+select * from /test/aaa/test_bucket_tsdb where name='tsdb_001'
+/**
+output()
+count(1)
+**/
+;
+
+-- 3. 时间范围查询 tsdb
+select name, value, ts from /test/aaa/test_bucket_tsdb
+/**
+output()
+**/
+;
+
+-- 4. 更新 tsdb
+update /test/aaa/test_bucket_tsdb set value=150 where name='tsdb_001'
+;
+
+select name, value from /test/aaa/test_bucket_tsdb where name='tsdb_001'
+/**
+output()
+match("value","150")
+**/
+;
+
+-- 5. 删除 tsdb 数据
+delete from /test/aaa/test_bucket_tsdb where name='tsdb_003'
+;
+
+select count(*) from /test/aaa/test_bucket_tsdb
+/**
+output()
+**/
+;

+ 56 - 0
odbctest/mql/aaa/14bucket/14promdb.mql

@@ -0,0 +1,56 @@
+-- ============================================================
+-- bucket promdb 测试
+-- ============================================================
+
+-- 1. 插入数据到 promdb
+insert into /test/aaa/test_bucket_promdb (name, metric, ts) values ('prom_001', 1.5, 1700000000000)
+;
+
+insert into /test/aaa/test_bucket_promdb (name, metric, ts) values ('prom_002', 2.5, 1700000001000)
+;
+
+insert into /test/aaa/test_bucket_promdb (name, metric, ts) values ('prom_003', 3.5, 1700000002000)
+;
+
+-- 2. 查询 promdb
+select * from /test/aaa/test_bucket_promdb where name='prom_001'
+/**
+output()
+count(1)
+**/
+;
+
+-- 3. 全表查询
+select name, metric, ts from /test/aaa/test_bucket_promdb
+/**
+output()
+**/
+;
+
+-- 4. 更新 promdb
+update /test/aaa/test_bucket_promdb set metric=10.5 where name='prom_001'
+;
+
+select name, metric from /test/aaa/test_bucket_promdb where name='prom_001'
+/**
+output()
+match("metric","10.5")
+**/
+;
+
+-- 5. 聚合 promdb
+select count(*) from /test/aaa/test_bucket_promdb
+/**
+output()
+**/
+;
+
+-- 6. delete promdb
+delete from /test/aaa/test_bucket_promdb where name='prom_003'
+;
+
+select count(*) from /test/aaa/test_bucket_promdb
+/**
+output()
+**/
+;

+ 30 - 0
odbctest/mql/aaa/15cypher/00init.mql

@@ -0,0 +1,30 @@
+-- 15cypher 目录初始化:Cypher 图操作测试
+
+create class if not exists /test/aaa/test_graph (
+    g_name      varchar,
+    g_type      varchar,
+    g_value     int,
+
+    indexes(g_name, g_type),
+    keys(g_name)
+)
+;
+
+create edge type if not exists /test/aaa/connect
+;
+
+-- 插入图节点数据
+insert into /test/aaa/test_graph (g_name, g_type, g_value) values ('node_a', 'type_a', 10)
+;
+
+insert into /test/aaa/test_graph (g_name, g_type, g_value) values ('node_b', 'type_a', 20)
+;
+
+insert into /test/aaa/test_graph (g_name, g_type, g_value) values ('node_c', 'type_b', 30)
+;
+
+insert into /test/aaa/test_graph (g_name, g_type, g_value) values ('node_d', 'type_b', 40)
+;
+
+insert into /test/aaa/test_graph (g_name, g_type, g_value) values ('node_e', 'type_c', 50)
+;

+ 38 - 0
odbctest/mql/aaa/15cypher/11create.mql

@@ -0,0 +1,38 @@
+-- ============================================================
+-- Cypher 创建图和关系测试
+-- ============================================================
+
+-- 1. match 节点
+match (:test_graph) return *
+/**
+output()
+**/
+;
+
+-- 2. match 特定类型节点
+match (a:test_graph) where a.g_type='type_a' return a
+/**
+output()
+**/
+;
+
+-- 3. 创建关系(connect edge)
+match (a:test_graph), (b:test_graph) where a.g_name='node_a' and b.g_name='node_b'
+create (a) -[:connect]-> (b)
+;
+
+-- 4. 创建更多关系
+match (a:test_graph), (b:test_graph) where a.g_name='node_c' and b.g_name='node_d'
+create (a) -[:connect]-> (b)
+;
+
+match (a:test_graph), (b:test_graph) where a.g_name='node_a' and b.g_name='node_c'
+create (a) -[:connect]-> (b)
+;
+
+-- 5. 查询关系
+match (a:test_graph) -[:connect]-> (b:test_graph) return a, b
+/**
+output()
+**/
+;

+ 52 - 0
odbctest/mql/aaa/15cypher/12match.mql

@@ -0,0 +1,52 @@
+-- ============================================================
+-- Cypher match 查询测试
+-- ============================================================
+
+-- 1. match 所有节点
+match (n:test_graph) return n
+/**
+output()
+**/
+;
+
+-- 2. match 带属性过滤
+match (n:test_graph) where n.g_value > 25 return n
+/**
+output()
+**/
+;
+
+-- 3. match 多条件
+match (n:test_graph) where n.g_type='type_a' and n.g_value>=10 return n
+/**
+output()
+**/
+;
+
+-- 4. match 关系路径
+match (a:test_graph) -[:connect]-> (b:test_graph) return a, b
+/**
+output()
+**/
+;
+
+-- 5. match 带关系方向
+match (a:test_graph) -[:connect]-> (b:test_graph) where a.g_name='node_a' return a, b
+/**
+output()
+**/
+;
+
+-- 6. match 无关系节点
+match (n:test_graph) where n.g_name='node_e' return n
+/**
+output()
+**/
+;
+
+-- 7. match 返回特定字段
+match (n:test_graph) return n.g_name, n.g_value
+/**
+output()
+**/
+;

+ 31 - 0
odbctest/mql/aaa/15cypher/13subquery.mql

@@ -0,0 +1,31 @@
+-- ============================================================
+-- Cypher 子查询测试
+-- ============================================================
+
+-- 1. Cypher 子查询 - where in match
+match (a:test_graph) -[:connect]-> (b:test_graph) where a.g_name in (match (n:test_graph) where n.g_type='type_a' return n.g_name) return a, b
+/**
+output()
+**/
+;
+
+-- 2. Cypher 嵌套子查询
+match (a:test_graph) where a.g_value = (match (n:test_graph) where n.g_name='node_c' return max(n.g_value)) return a
+/**
+output()
+**/
+;
+
+-- 3. Cypher 聚合子查询
+match (a:test_graph) where a.g_type='type_a' return a.g_type, count(*)
+/**
+output()
+**/
+;
+
+-- 4. Cypher 带 limit 的子查询
+match (a:test_graph) return a limit 3
+/**
+output()
+**/
+;

+ 23 - 0
odbctest/mql/aaa/16partition/00init.mql

@@ -0,0 +1,23 @@
+-- 16partition 目录初始化:分区测试
+
+-- 单分区 class
+create class if not exists /test/aaa/test_partition (
+    p_id        int,
+    p_name      varchar,
+    p_value     int,
+
+    indexes(p_id, p_name, p_value),
+    keys(p_id, p_name)
+) with partition=p_id
+;
+
+-- 多分区 class
+create class if not exists /test/aaa/test_mpartition (
+    m_id        int,
+    m_name      varchar,
+    m_value     int,
+
+    indexes(m_id, m_name, m_value),
+    keys(m_id, m_name)
+) with partition=m_id, partition=m_name
+;

+ 59 - 0
odbctest/mql/aaa/16partition/11single.mql

@@ -0,0 +1,59 @@
+-- ============================================================
+-- 单分区测试
+-- ============================================================
+
+-- 1. 插入单分区数据
+insert into /test/aaa/test_partition (p_id, p_name, p_value) values (1, 'part1_item1', 100)
+;
+
+insert into /test/aaa/test_partition (p_id, p_name, p_value) values (1, 'part1_item2', 200)
+;
+
+insert into /test/aaa/test_partition (p_id, p_name, p_value) values (2, 'part2_item1', 300)
+;
+
+insert into /test/aaa/test_partition (p_id, p_name, p_value) values (2, 'part2_item2', 400)
+;
+
+-- 2. 查询单分区数据
+select * from /test/aaa/test_partition where p_id=1
+/**
+output()
+**/
+;
+
+-- 3. 跨分区查询
+select * from /test/aaa/test_partition
+/**
+output()
+**/
+;
+
+-- 4. 按分区聚合
+select p_id, count(*) from /test/aaa/test_partition group by p_id
+/**
+output()
+**/
+;
+
+-- 5. 更新单分区数据
+update /test/aaa/test_partition set p_value=150 where p_id=1 and p_name='part1_item1'
+;
+
+select p_value from /test/aaa/test_partition where p_id=1 and p_name='part1_item1'
+/**
+output()
+match("p_value","150")
+**/
+;
+
+-- 6. 删除单分区数据
+delete from /test/aaa/test_partition where p_id=2 and p_name='part2_item2'
+;
+
+select * from /test/aaa/test_partition where p_id=2 and p_name='part2_item2'
+/**
+output()
+count(0)
+**/
+;

+ 56 - 0
odbctest/mql/aaa/16partition/12multi.mql

@@ -0,0 +1,56 @@
+-- ============================================================
+-- 多分区测试
+-- ============================================================
+
+-- 1. 插入多分区数据
+insert into /test/aaa/test_mpartition (m_id, m_name, m_value) values (1, 'cat_a', 100)
+;
+
+insert into /test/aaa/test_mpartition (m_id, m_name, m_value) values (1, 'cat_b', 200)
+;
+
+insert into /test/aaa/test_mpartition (m_id, m_name, m_value) values (2, 'cat_a', 300)
+;
+
+insert into /test/aaa/test_mpartition (m_id, m_name, m_value) values (2, 'cat_b', 400)
+;
+
+-- 2. 按第一分区查询
+select * from /test/aaa/test_mpartition where m_id=1
+/**
+output()
+**/
+;
+
+-- 3. 按多分区联合查询
+select * from /test/aaa/test_mpartition where m_id=1 and m_name='cat_a'
+/**
+output()
+count(1)
+**/
+;
+
+-- 4. 全表查询
+select * from /test/aaa/test_mpartition
+/**
+output()
+**/
+;
+
+-- 5. 更新多分区数据
+update /test/aaa/test_mpartition set m_value=150 where m_id=1 and m_name='cat_a'
+;
+
+select m_value from /test/aaa/test_mpartition where m_id=1 and m_name='cat_a'
+/**
+output()
+match("m_value","150")
+**/
+;
+
+-- 6. 多分区聚合
+select m_id, m_name, count(*) from /test/aaa/test_mpartition group by m_id, m_name
+/**
+output()
+**/
+;

+ 20 - 0
odbctest/mql/aaa/17conflict/00init.mql

@@ -0,0 +1,20 @@
+-- 17conflict 目录初始化:冲突/并发测试
+
+create class if not exists /test/aaa/test_conflict (
+    c_name      varchar,
+    c_value     int,
+    c_count     int,
+
+    keys(c_name)
+) with version=true
+;
+
+-- 插入冲突测试基础数据
+insert into /test/aaa/test_conflict (c_name, c_value, c_count) values ('conflict_001', 100, 1)
+;
+
+insert into /test/aaa/test_conflict (c_name, c_value, c_count) values ('conflict_002', 200, 1)
+;
+
+insert into /test/aaa/test_conflict (c_name, c_value, c_count) values ('conflict_003', 300, 1)
+;

+ 49 - 0
odbctest/mql/aaa/17conflict/11upsert.mql

@@ -0,0 +1,49 @@
+-- ============================================================
+-- Upsert 操作测试
+-- ============================================================
+
+-- 1. 基本 upsert - 插入新数据(name不存在)
+insert into /test/aaa/test_conflict (c_name, c_value, c_count) values ('conflict_upsert_001', 500, 1) on conflict update c_value=c_value
+;
+
+select * from /test/aaa/test_conflict where c_name='conflict_upsert_001'
+/**
+output()
+count(1)
+**/
+;
+
+-- 2. upsert - 更新已存在数据
+insert into /test/aaa/test_conflict (c_name, c_value, c_count) values ('conflict_upsert_001', 999, 5) on conflict update c_value=c_value, c_count=c_count
+;
+
+select c_value, c_count from /test/aaa/test_conflict where c_name='conflict_upsert_001'
+/**
+output()
+match("c_value","999")
+match("c_count","5")
+**/
+;
+
+-- 3. upsert - 累加 c_count
+insert into /test/aaa/test_conflict (c_name, c_value, c_count) values ('conflict_002', 200, 5) on conflict update c_count=c_count+c_count
+;
+
+select c_count from /test/aaa/test_conflict where c_name='conflict_002'
+/**
+output()
+match("c_count","6")
+**/
+;
+
+-- 4. upsert - 保留某些字段不更新
+insert into /test/aaa/test_conflict (c_name, c_value, c_count) values ('conflict_001', 888, 10) on conflict update c_count=c_count+c_count
+;
+
+select c_value, c_count from /test/aaa/test_conflict where c_name='conflict_001'
+/**
+output()
+match("c_value","100")
+match("c_count","11")
+**/
+;

+ 48 - 0
odbctest/mql/aaa/17conflict/12conflict_update.mql

@@ -0,0 +1,48 @@
+-- ============================================================
+-- On Conflict Update 测试
+-- ============================================================
+
+-- 1. 条件更新
+insert into /test/aaa/test_conflict (c_name, c_value, c_count) values ('conflict_update_001', 100, 1) on conflict update c_value=200, c_count=c_count+1
+;
+
+-- 首次插入,c_count=1
+select c_value, c_count from /test/aaa/test_conflict where c_name='conflict_update_001'
+/**
+output()
+match("c_count","1")
+**/
+;
+
+-- 2. 再次冲突更新 c_count 应累加
+insert into /test/aaa/test_conflict (c_name, c_value, c_count) values ('conflict_update_001', 300, 5) on conflict update c_value=c_value, c_count=c_count+c_count
+;
+
+select c_value, c_count from /test/aaa/test_conflict where c_name='conflict_update_001'
+/**
+output()
+match("c_count","2")
+**/
+;
+
+-- 3. 多字段 conflict update
+insert into /test/aaa/test_conflict (c_name, c_value, c_count) values ('conflict_update_002', 100, 1) on conflict update c_value=c_value+c_value, c_count=c_count+10
+;
+
+-- 首次
+select c_value, c_count from /test/aaa/test_conflict where c_name='conflict_update_002'
+/**
+output()
+**/
+;
+
+-- 再次冲突
+insert into /test/aaa/test_conflict (c_name, c_value, c_count) values ('conflict_update_002', 200, 5) on conflict update c_value=c_value+c_value, c_count=c_count+10
+;
+
+select c_value, c_count from /test/aaa/test_conflict where c_name='conflict_update_002'
+/**
+output()
+match("c_count","11")
+**/
+;

+ 14 - 0
odbctest/mql/aaa/17conflict/13concurrent.mql

@@ -0,0 +1,14 @@
+-- ============================================================
+-- 并发操作测试(scope(file) loop(N) parallel(N))
+-- ============================================================
+
+/**
+scope(file)
+loop(10)
+parallel(5)
+**/
+;
+
+-- 并发 upsert 操作
+insert into /test/aaa/test_conflict (c_name, c_value, c_count) values ('conflict_concurrent', 1, 1) on conflict update c_count=c_count+1, c_value=c_value+1
+;

+ 23 - 0
odbctest/mql/aaa/18prepare/00init.mql

@@ -0,0 +1,23 @@
+-- 18prepare 目录初始化:Prepare 语句测试
+
+create class if not exists /test/aaa/test_prepare (
+    p_name      varchar,
+    p_text      text,
+    p_int       int,
+    p_bigint    bigint,
+    p_float     float,
+    p_double    double,
+    p_bool      bool,
+    p_ts        timestamp,
+
+    indexes(p_name, p_text, p_int, p_bigint, p_float, p_double, p_bool, p_ts),
+    keys(p_name)
+)
+;
+
+-- 先清表
+delete from /test/aaa/test_prepare with version
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;

+ 68 - 0
odbctest/mql/aaa/18prepare/11prepare_insert.mql

@@ -0,0 +1,68 @@
+-- ============================================================
+-- Prepare Insert 操作测试
+-- ============================================================
+
+-- 1. 基本 prepare insert
+insert into /test/aaa/test_prepare (p_name, p_text, p_int, p_float, p_double, p_bool, p_ts) values (?, ?, ?, ?, ?, ?, ?)
+/**
+params("prep_insert_001", "prepare insert test data", 100, 3.14, 3.141592653589793, true, 1711641600000)
+**/
+;
+
+-- 验证
+select * from /test/aaa/test_prepare where p_name='prep_insert_001'
+/**
+output()
+count(1)
+match("p_int","100")
+**/
+;
+
+-- 2. prepare insert 批量数据
+insert into /test/aaa/test_prepare (p_name, p_text, p_int) values (?, ?, ?)
+/**
+params("prep_insert_002", "batch prepare 2", 200)
+**/
+;
+
+insert into /test/aaa/test_prepare (p_name, p_text, p_int) values (?, ?, ?)
+/**
+params("prep_insert_003", "batch prepare 3", 300)
+**/
+;
+
+-- 3. 验证批量数据
+select * from /test/aaa/test_prepare where p_name='prep_insert_002' or p_name='prep_insert_003'
+/**
+output()
+count(2)
+**/
+;
+
+-- 4. prepare insert 带 bigint
+insert into /test/aaa/test_prepare (p_name, p_bigint) values (?, ?)
+/**
+params("prep_bigint_001", 999999999999999999)
+**/
+;
+
+select p_name, p_bigint from /test/aaa/test_prepare where p_name='prep_bigint_001'
+/**
+output()
+match("p_bigint","999999999999999999")
+**/
+;
+
+-- 5. prepare insert bool false
+insert into /test/aaa/test_prepare (p_name, p_bool) values (?, ?)
+/**
+params("prep_bool_001", false)
+**/
+;
+
+select p_name, p_bool from /test/aaa/test_prepare where p_name='prep_bool_001'
+/**
+output()
+match("p_bool","false")
+**/
+;

+ 59 - 0
odbctest/mql/aaa/18prepare/12prepare_update.mql

@@ -0,0 +1,59 @@
+-- ============================================================
+-- Prepare Update 操作测试
+-- ============================================================
+
+-- 1. prepare update 基本操作
+update /test/aaa/test_prepare set p_int=? where p_name=?
+/**
+params(999, "prep_insert_001")
+**/
+;
+
+select p_name, p_int from /test/aaa/test_prepare where p_name='prep_insert_001'
+/**
+output()
+match("p_int","999")
+**/
+;
+
+-- 2. prepare update 多个 ?
+update /test/aaa/test_prepare set p_text=?, p_int=? where p_name=?
+/**
+params("updated by prepare update", 888, "prep_insert_002")
+**/
+;
+
+select p_text, p_int from /test/aaa/test_prepare where p_name='prep_insert_002'
+/**
+output()
+match("p_int","888")
+**/
+;
+
+-- 3. prepare update float
+update /test/aaa/test_prepare set p_float=?, p_double=? where p_name=?
+/**
+params(99.99, 999.999999, "prep_insert_001")
+**/
+;
+
+select p_float, p_double from /test/aaa/test_prepare where p_name='prep_insert_001'
+/**
+output()
+match("p_float","99.99")
+**/
+;
+
+-- 4. prepare update 不存在的记录
+update /test/aaa/test_prepare set p_int=? where p_name=?
+/**
+params(1, "non_exist_prepare_key")
+**/
+;
+
+select * from /test/aaa/test_prepare where p_name='non_exist_prepare_key'
+/**
+output()
+count(0)
+**/
+;

+ 51 - 0
odbctest/mql/aaa/18prepare/13prepare_delete.mql

@@ -0,0 +1,51 @@
+-- ============================================================
+-- Prepare Delete 操作测试
+-- ============================================================
+
+-- 1. prepare delete 基本操作
+insert into /test/aaa/test_prepare (p_name, p_int) values (?, ?)
+/**
+params("prep_delete_001", 1)
+**/
+;
+
+delete from /test/aaa/test_prepare where p_name=?
+/**
+params("prep_delete_001")
+**/
+;
+
+-- 验证已删除
+select * from /test/aaa/test_prepare where p_name='prep_delete_001'
+/**
+output()
+count(0)
+**/
+;
+
+-- 2. prepare delete 多条件
+insert into /test/aaa/test_prepare (p_name, p_int) values (?, ?)
+/**
+params("prep_delete_002", 100)
+**/
+;
+
+delete from /test/aaa/test_prepare where p_name=? and p_int=?
+/**
+params("prep_delete_002", 100)
+**/
+;
+
+select * from /test/aaa/test_prepare where p_name='prep_delete_002'
+/**
+output()
+count(0)
+**/
+;
+
+-- 3. prepare delete 不存在的记录
+delete from /test/aaa/test_prepare where p_name=?
+/**
+params("prep_delete_non_exist")
+**/
+;

+ 68 - 0
odbctest/mql/aaa/18prepare/14prepare_batch.mql

@@ -0,0 +1,68 @@
+-- ============================================================
+-- Prepare Batch 操作测试
+-- ============================================================
+
+-- 1. 通过 loop 模拟 prepare batch 插入
+-- 使用 beforerun 设置变量实现批量 prepare
+/**
+scope(mql)
+loop(5)
+beforerun(set(prep_name, concat('prep_batch_', mqli)), set(prep_val, mqli))
+**/
+;
+
+insert into /test/aaa/test_prepare (p_name, p_int) values (?, ?)
+/**
+params(prep_name, prep_val)
+**/
+;
+
+-- 2. 验证 prep batch 插入结果
+select p_name, p_int from /test/aaa/test_prepare where p_name prefix 'prep_batch'
+/**
+output()
+matchcount("p_name","prep_batch",5)
+**/
+;
+
+-- 3. 再次使用 loop 做批量 update
+/**
+scope(mql)
+loop(5)
+beforerun(set(prep_name, concat('prep_batch_', mqli)), set(prep_val, 999))
+**/
+;
+
+update /test/aaa/test_prepare set p_int=? where p_name=?
+/**
+params(prep_val, prep_name)
+**/
+;
+
+-- 4. 验证批量更新
+select p_name, p_int from /test/aaa/test_prepare where p_name prefix 'prep_batch'
+/**
+output()
+**/
+;
+
+-- 5. 批量删除
+/**
+scope(mql)
+loop(3)
+beforerun(set(prep_name, concat('prep_batch_', mqli)))
+**/
+;
+
+delete from /test/aaa/test_prepare where p_name=?
+/**
+params(prep_name)
+**/
+;
+
+-- 6. 验证批量删除
+select p_name from /test/aaa/test_prepare where p_name prefix 'prep_batch'
+/**
+output()
+**/
+;

+ 22 - 0
odbctest/mql/aaa/19extensions/00init.mql

@@ -0,0 +1,22 @@
+-- 19extensions 目录初始化:MQL 扩展特性测试
+-- 创建用于扩展特性测试的基础 class
+
+create class if not exists /test/aaa/test_ext (
+    e_name      varchar,
+    e_value     int,
+    e_text      text,
+
+    indexes(e_name, e_value),
+    keys(e_name)
+)
+;
+
+-- 插入基础数据
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values ('ext_001', 1, 'init data 1')
+;
+
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values ('ext_002', 2, 'init data 2')
+;
+
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values ('ext_003', 3, 'init data 3')
+;

+ 37 - 0
odbctest/mql/aaa/19extensions/11loop.mql

@@ -0,0 +1,37 @@
+-- ============================================================
+-- scope(mql) loop(N) 测试:循环变量 <mqli> <mqlcount>
+-- ============================================================
+
+/**
+scope(mql)
+loop(5)
+**/
+;
+
+-- 插入循环数据(使用 mqli 作为序号)
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values (<mqli>, <mqli>, concat('loop data mqli=', <mqli>, ' mqlcount=', <mqlcount>))
+/**
+sleep(100ms)
+**/
+;
+
+-- 验证循环插入结果
+select e_name, e_value from /test/aaa/test_ext where e_name in ('1','2','3','4','5')
+/**
+output()
+matchcount("e_name","1|2|3|4|5",5)
+**/
+;
+
+-- 再次使用 loop 做查询
+/**
+scope(mql)
+loop(3)
+**/
+;
+
+select * from /test/aaa/test_ext where e_name=<mqli>
+/**
+output()
+**/
+;

+ 25 - 0
odbctest/mql/aaa/19extensions/12loop_file.mql

@@ -0,0 +1,25 @@
+-- ============================================================
+-- scope(file) loop(N) parallel(N) 测试:<filei> <filecount>
+-- ============================================================
+
+/**
+scope(file)
+loop(3)
+parallel(2)
+**/
+;
+
+-- 并发循环执行本文件 3 次,最大并行数 2
+-- 使用 filei 作为流水号
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values (concat('file_test_', <filei>), {%d,filei}, concat('filei=', <filei>, ' filecount=', <filecount>))
+/**
+sleep(100ms)
+**/
+;
+
+-- 验证 file 循环结果
+select e_name, e_value from /test/aaa/test_ext where e_name prefix 'file_test'
+/**
+output()
+**/
+;

+ 17 - 0
odbctest/mql/aaa/19extensions/13loop_dir.mql

@@ -0,0 +1,17 @@
+-- ============================================================
+-- scope(dir) loop(N) 测试:<diri> <dircount>
+-- ============================================================
+
+/**
+scope(dir)
+loop(4)
+**/
+;
+
+-- 对当前目录下所有文件循环 4 次
+-- diri=循环索引, dircount=文件总数
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values (<diri>, {%d,diri}, concat('diri=', <diri>, ' dircount=', <dircount>))
+;
+
+-- 注意:scope(dir) 会遍历当前目录所有 .mql 文件
+-- 每个文件都会执行这条 insert

+ 24 - 0
odbctest/mql/aaa/19extensions/14loop_top.mql

@@ -0,0 +1,24 @@
+-- ============================================================
+-- scope(top) loop(N) 测试:<topi> <topcount>
+-- ============================================================
+
+/**
+scope(top)
+loop(5)
+**/
+;
+
+-- 在整个测试套件顶层循环 5 次
+-- topi=循环索引, topcount=总循环次数
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values (<topi>, {%d,topi}, concat('topi=', <topi>, ' topcount=', <topcount>))
+/**
+sleep(100ms)
+**/
+;
+
+-- 验证 top 循环结果
+select e_name, e_value from /test/aaa/test_ext where e_name prefix 'top'
+/**
+output()
+**/
+;

+ 24 - 0
odbctest/mql/aaa/19extensions/15parallel.mql

@@ -0,0 +1,24 @@
+-- ============================================================
+-- parallel(N) 并发测试
+-- ============================================================
+
+/**
+scope(mql)
+loop(10)
+parallel(5)
+**/
+;
+
+-- 10 次循环,最大并发数 5
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values (concat('parallel_', <mqli>), <mqli>, concat('parallel loop mqli=', <mqli>))
+/**
+sleep(100ms)
+**/
+;
+
+-- 验证并发插入
+select count(*) from /test/aaa/test_ext where e_name prefix 'parallel'
+/**
+output()
+**/
+;

+ 38 - 0
odbctest/mql/aaa/19extensions/16fork_wait.mql

@@ -0,0 +1,38 @@
+-- ============================================================
+-- fork(G) 和 wait(G) 模式测试
+-- ============================================================
+
+-- 1. fork 一个分组执行
+/**
+beforerun(fork(group_a))
+**/
+;
+
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values ('fork_a_1', 100, 'fork group a - 1')
+;
+
+-- 2. fork 另一个分组
+/**
+beforerun(fork(group_a))
+**/
+;
+
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values ('fork_a_2', 200, 'fork group a - 2')
+;
+
+-- 3. wait 等待 group_a 完成
+/**
+beforerun(wait(group_a))
+**/
+;
+
+-- 等待分组完成后继续执行
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values ('after_wait_a', 999, 'after wait group_a')
+;
+
+-- 4. 验证 fork/wait 结果
+select e_name, e_value from /test/aaa/test_ext where e_name prefix 'fork_a' or e_name='after_wait_a'
+/**
+output()
+**/
+;

+ 93 - 0
odbctest/mql/aaa/19extensions/17beforerun.mql

@@ -0,0 +1,93 @@
+-- ============================================================
+-- beforerun 函数链:set / add / mod / case
+-- ============================================================
+
+-- 1. beforerun set 设置变量
+/**
+beforerun(set(myvar, 'hello_mql'))
+**/
+;
+
+-- 使用变量插入
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values ('beforerun_set', 1, <myvar>)
+;
+
+select e_name, e_text from /test/aaa/test_ext where e_name='beforerun_set'
+/**
+output()
+match("e_text","hello_mql")
+**/
+;
+
+-- 2. beforerun add 累加
+/**
+beforerun(set(counter, 10), add(counter, 5))
+**/
+;
+
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values (concat('beforerun_add_', <counter>), {%d,counter}, 'add test')
+;
+
+select e_name, e_value from /test/aaa/test_ext where e_name prefix 'beforerun_add'
+/**
+output()
+**/
+;
+
+-- 3. beforerun add 带单位(时间累加)
+/**
+beforerun(set(ct, '2024-01-01 00:00:00'), add(ct, 30, second))
+**/
+;
+
+insert into /test/aaa/test_ext (e_name, e_text) values ('beforerun_time', concat('ct=', {%t,ct}))
+;
+
+-- 4. beforerun mod 取模
+/**
+beforerun(set(mod_val, 17), mod(mod_val, 5))
+**/
+;
+
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values (concat('beforerun_mod_', <mod_val>), {%d,mod_val}, 'mod test 17%5')
+;
+
+select e_name, e_value from /test/aaa/test_ext where e_name prefix 'beforerun_mod'
+/**
+output()
+**/
+;
+
+-- 5. beforerun case 条件判断
+/**
+beforerun(set(case_val, 'yes'), case(case_val,'yes'))
+**/
+;
+
+insert into /test/aaa/test_ext (e_name, e_text) values ('beforerun_case_yes', 'case matched yes')
+;
+
+select e_name from /test/aaa/test_ext where e_name='beforerun_case_yes'
+/**
+output()
+count(1)
+**/
+;
+
+-- 6. beforerun case 不匹配
+/**
+beforerun(set(case_val, 'no'), case(case_val,'yes'))
+**/
+;
+
+-- 当 case 不匹配时,该语句会被跳过
+insert into /test/aaa/test_ext (e_name, e_text) values ('beforerun_case_no', 'case not matched - should not execute')
+;
+
+-- 验证 case 不匹配时语句被跳过
+select e_name from /test/aaa/test_ext where e_name='beforerun_case_no'
+/**
+output()
+count(0)
+**/
+;

+ 74 - 0
odbctest/mql/aaa/19extensions/18variable.mql

@@ -0,0 +1,74 @@
+-- ============================================================
+-- 变量替换测试:<now>/<rand>/<keyspace>/'...N Bytes...'/{%t,varname}/{%d,varname}
+-- ============================================================
+
+-- 1. <now> 当前时间戳
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values ('var_now', 1, <now>)
+;
+
+select e_name, e_text from /test/aaa/test_ext where e_name='var_now'
+/**
+output()
+**/
+;
+
+-- 2. <rand> 随机数
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values ('var_rand', <rand>, 'random number: <rand>')
+;
+
+select e_name from /test/aaa/test_ext where e_name='var_rand'
+/**
+output()
+count(1)
+**/
+;
+
+-- 3. <keyspace> 当前命名空间
+insert into /test/aaa/test_ext (e_name, e_text) values ('var_keyspace', <keyspace>)
+;
+
+select e_name, e_text from /test/aaa/test_ext where e_name='var_keyspace'
+/**
+output()
+**/
+;
+
+-- 4. '...N Bytes...' - N个随机可见字符
+insert into /test/aaa/test_ext (e_name, e_text) values ('var_bytes', '...10 Bytes...')
+;
+
+select e_name, e_text from /test/aaa/test_ext where e_name='var_bytes'
+/**
+output()
+**/
+;
+
+-- 5. {%t,varname} 时间格式化
+/**
+beforerun(set(my_time, '2024-06-15 12:30:45'))
+**/
+;
+
+insert into /test/aaa/test_ext (e_name, e_text) values ('var_time_fmt', <my_time>)
+;
+
+select e_name, e_text from /test/aaa/test_ext where e_name='var_time_fmt'
+/**
+output()
+**/
+;
+
+-- 6. {%d,varname} 数字格式化
+/**
+beforerun(set(my_num, 1024))
+**/
+;
+
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values (concat('var_num_fmt_', {%d,my_num}), {%d,my_num}, 'num format test')
+;
+
+select e_name, e_value from /test/aaa/test_ext where e_name prefix 'var_num_fmt'
+/**
+output()
+**/
+;

+ 44 - 0
odbctest/mql/aaa/19extensions/19format_escape.mql

@@ -0,0 +1,44 @@
+-- ============================================================
+-- {%%...,...} 转义、{%s,varname} 格式化测试
+-- ============================================================
+
+-- 1. {%s,varname} 字符串格式化
+/**
+beforerun(set(my_str, 'formatted_string_value'))
+**/
+;
+
+insert into /test/aaa/test_ext (e_name, e_text) values ('var_str_fmt', {%s,my_str})
+;
+
+select e_name, e_text from /test/aaa/test_ext where e_name='var_str_fmt'
+/**
+output()
+match("e_text","formatted_string_value")
+**/
+;
+
+-- 2. {%%...,...} 转义避免被替换
+insert into /test/aaa/test_ext (e_name, e_text) values ('var_escape', '{%%now,now}')
+;
+
+select e_name, e_text from /test/aaa/test_ext where e_name='var_escape'
+/**
+output()
+**/
+;
+
+-- 3. 多个格式化组合
+/**
+beforerun(set(fmt_num, 42), set(fmt_str, 'answer'))
+**/
+;
+
+insert into /test/aaa/test_ext (e_name, e_text) values (concat('var_combo_', {%d,fmt_num}), concat({%s,fmt_str}, ' = ', {%d,fmt_num}))
+;
+
+select e_name, e_text from /test/aaa/test_ext where e_name prefix 'var_combo'
+/**
+output()
+**/
+;

+ 46 - 0
odbctest/mql/aaa/19extensions/20loopfrom_loopstep.mql

@@ -0,0 +1,46 @@
+-- ============================================================
+-- loopfrom(N) loopstep(N) 控制循环步长测试
+-- ============================================================
+
+/**
+scope(mql)
+loopfrom(0)
+loop(5)
+loopstep(2)
+**/
+;
+
+-- 循环从 0 开始,步长为 2(取值:0, 2, 4)
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values (concat('loopstep_', <mqli>), {%d,mqli}, concat('mqli=', <mqli>, ' mqlcount=', <mqlcount>))
+/**
+sleep(100ms)
+**/
+;
+
+-- 验证步长结果
+select e_name, e_value from /test/aaa/test_ext where e_name prefix 'loopstep'
+/**
+output()
+**/
+;
+
+-- 带 loopfrom 从 10 开始的循环
+/**
+scope(mql)
+loopfrom(10)
+loop(4)
+loopstep(5)
+**/
+;
+
+insert into /test/aaa/test_ext (e_name, e_value) values (concat('loopfrom_', <mqli>), {%d,mqli})
+/**
+sleep(100ms)
+**/
+;
+
+select e_name, e_value from /test/aaa/test_ext where e_name prefix 'loopfrom'
+/**
+output()
+**/
+;

+ 28 - 0
odbctest/mql/aaa/19extensions/21retry.mql

@@ -0,0 +1,28 @@
+-- ============================================================
+-- retry(N) 重试测试
+-- ============================================================
+
+/**
+retry(3)
+**/
+;
+
+-- 故意触发错误的语句,重试 3 次后仍失败
+select * from /test/aaa/non_exist_class_retry where dummy=1
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+-- retry 正常语句(不应重试)
+/**
+retry(2)
+**/
+;
+
+select count(*) from /test/aaa/test_ext where e_name='ext_001'
+/**
+output()
+match("count(*)","1")
+**/
+;

+ 38 - 0
odbctest/mql/aaa/19extensions/22onerror.mql

@@ -0,0 +1,38 @@
+-- ============================================================
+-- onerror(continue, must, exit) 各种错误处理测试
+-- ============================================================
+
+-- 1. onerror(continue) - 忽略错误继续执行
+insert into /test/aaa/non_exist_class (name) values ('test')
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+-- 2. onerror(continue) - 忽略重复插入错误
+insert into /test/aaa/test_ext (e_name, e_value) values ('ext_001', 1)
+/**
+onerror(continue)
+**/
+;
+
+-- 3. onerror(continue) - 忽略多个错误关键词
+select * from /test/aaa/no_such_class_222 where x=1
+/**
+onerror(continue,'not exist','not find','not found','no such','cannot')
+**/
+;
+
+-- 4. onerror(continue) - 空参数,忽略所有错误
+insert into /test/aaa/test_ext (e_name) values ('onerror_all')
+/**
+onerror(continue)
+**/
+;
+
+-- 验证上面的插入成功(虽然有错但被忽略了)
+select e_name from /test/aaa/test_ext where e_name='onerror_all'
+/**
+output()
+**/
+;

+ 70 - 0
odbctest/mql/aaa/19extensions/23noerrinfo_skip.mql

@@ -0,0 +1,70 @@
+-- ============================================================
+-- noerrinfo() skip() break continue 测试
+-- ============================================================
+
+-- 1. noerrinfo() - 不输出错误信息
+insert into /test/aaa/non_exist_xxx (name) values ('noerrinfo test')
+/**
+noerrinfo()
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+-- 2. skip() - 跳过本语句(不执行)
+-- 此处不做 skip 演示,因为 skip() 会直接跳过,该语句不会在文件中有意义
+
+-- 3. continue - 配合 loop 使用,跳过当前迭代
+/**
+scope(mql)
+loop(5)
+**/
+;
+
+-- 跳过 mqli=3 的迭代
+/**
+beforerun(case(<mqli>,'3'))
+**/
+;
+
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values (concat('continue_test_', <mqli>), {%d,mqli}, 'continue test - should skip mqli=3')
+;
+
+/**
+continue
+**/
+;
+
+-- 验证 continue 跳过了 mqli=3
+select e_name from /test/aaa/test_ext where e_name prefix 'continue_test'
+/**
+output()
+**/
+;
+
+-- 4. break - 配合 loop 使用,跳出循环
+/**
+scope(mql)
+loop(10)
+**/
+;
+
+insert into /test/aaa/test_ext (e_name, e_value) values (concat('break_test_', <mqli>), {%d,mqli})
+;
+
+-- 当 mqli>=3 时跳出
+/**
+beforerun(case(<mqli>,'3'))
+**/
+;
+
+/**
+break
+**/
+;
+
+-- 验证 break 只执行了前 3 次
+select e_name from /test/aaa/test_ext where e_name prefix 'break_test'
+/**
+output()
+**/
+;

+ 39 - 0
odbctest/mql/aaa/19extensions/24timeout.mql

@@ -0,0 +1,39 @@
+-- ============================================================
+-- timeout(D) 超时控制测试
+-- ============================================================
+
+-- 1. timeout 5 秒 - 正常查询应在超时前完成
+/**
+timeout(5s)
+**/
+;
+
+select count(*) from /test/aaa/test_ext
+/**
+output()
+**/
+;
+
+-- 2. timeout 很短 - 30ms
+/**
+timeout(30ms)
+**/
+;
+
+select count(*) from /test/aaa/test_ext
+/**
+output()
+**/
+;
+
+-- 3. timeout 1 分钟(较长超时)
+/**
+timeout(1m)
+**/
+;
+
+select * from /test/aaa/test_ext where e_name='ext_001'
+/**
+output()
+**/
+;

+ 45 - 0
odbctest/mql/aaa/19extensions/25sleep.mql

@@ -0,0 +1,45 @@
+-- ============================================================
+-- sleep(D) 延迟测试
+-- ============================================================
+
+-- 1. sleep 100ms
+/**
+sleep(100ms)
+**/
+;
+
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values ('sleep_100ms', 1, 'after 100ms sleep')
+;
+
+-- 2. sleep 1s
+/**
+sleep(1s)
+**/
+;
+
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values ('sleep_1s', 2, 'after 1s sleep')
+;
+
+-- 3. sleep 500ms(半秒)
+/**
+sleep(500ms)
+**/
+;
+
+select count(*) from /test/aaa/test_ext where e_name prefix 'sleep'
+/**
+output()
+**/
+;
+
+-- 4. sleep 很短的时间
+/**
+sleep(50ms)
+**/
+;
+
+select e_name from /test/aaa/test_ext where e_name prefix 'sleep'
+/**
+output()
+**/
+;

+ 41 - 0
odbctest/mql/aaa/19extensions/26output_meta.mql

@@ -0,0 +1,41 @@
+-- ============================================================
+-- output() metainfo() outputcount() 测试
+-- ============================================================
+
+-- 1. output() - 输出查询结果
+select e_name, e_value, e_text from /test/aaa/test_ext where e_name='ext_001'
+/**
+output()
+**/
+;
+
+-- 2. output() 多条结果
+select e_name from /test/aaa/test_ext where e_name prefix 'ext'
+/**
+output()
+**/
+;
+
+-- 3. output() + count()
+select * from /test/aaa/test_ext where e_name prefix 'ext'
+/**
+output()
+count(3)
+**/
+;
+
+-- 4. metainfo() - 输出元信息
+select e_name from /test/aaa/test_ext where e_name='ext_001'
+/**
+output()
+metainfo()
+**/
+;
+
+-- 5. outputcount() - 统计output调用次数
+select e_name from /test/aaa/test_ext where e_name='ext_001'
+/**
+output()
+outputcount()
+**/
+;

+ 56 - 0
odbctest/mql/aaa/19extensions/27result_check.mql

@@ -0,0 +1,56 @@
+-- ============================================================
+-- count(N) equal(N,F,V) match(Kn,Mn) matchcount(Kn,Mn,N) 测试
+-- ============================================================
+
+-- 1. count(N) - 结果行数检查
+select * from /test/aaa/test_ext where e_name prefix 'ext'
+/**
+count(3)
+**/
+;
+
+-- 2. count(N) - 精确匹配
+select e_name from /test/aaa/test_ext where e_name='ext_001'
+/**
+count(1)
+**/
+;
+
+-- 3. match(Kn,Mn) 匹配第一行第一列
+select e_name from /test/aaa/test_ext where e_name='ext_001'
+/**
+output()
+match("e_name","ext_001")
+**/
+;
+
+-- 4. match(Kn,Mn) 匹配第N行第N列
+select e_name, e_value from /test/aaa/test_ext where e_name prefix 'ext'
+/**
+output()
+match("ext_001","1")
+**/
+;
+
+-- 5. matchcount(Kn,Mn,N) 匹配计数
+select e_name from /test/aaa/test_ext where e_name prefix 'ext'
+/**
+output()
+matchcount("e_name","ext_",3)
+**/
+;
+
+-- 6. equal(N,F,V) 第N行第F列等于V
+select e_name, e_value from /test/aaa/test_ext where e_name='ext_001'
+/**
+output()
+equal(1,2,1)
+**/
+;
+
+select e_name, e_value from /test/aaa/test_ext where e_name='ext_002'
+/**
+output()
+equal(1,2,2)
+**/
+;

+ 40 - 0
odbctest/mql/aaa/19extensions/28schema.mql

@@ -0,0 +1,40 @@
+-- ============================================================
+-- schema(C) 检查类是否存在
+-- ============================================================
+
+-- 1. schema 检查已存在的 class
+/**
+schema(/test/aaa/test_ext)
+**/
+;
+
+select count(*) from /test/aaa/test_ext
+/**
+output()
+**/
+;
+
+-- 2. schema 检查不存在的 class(应跳过)
+/**
+schema(/test/aaa/non_exist_schema_class)
+**/
+;
+
+select count(*) from /test/aaa/non_exist_schema_class
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+-- 3. 使用 schema 验证 class 存在后才执行
+/**
+schema(/test/aaa/test_ext)
+**/
+;
+
+select e_name from /test/aaa/test_ext where e_name='ext_001'
+/**
+output()
+count(1)
+**/
+;

+ 27 - 0
odbctest/mql/aaa/19extensions/29qmeta.mql

@@ -0,0 +1,27 @@
+-- ============================================================
+-- qmeta(O) 设置选项测试
+-- ============================================================
+
+-- 1. qmeta 设置查询选项
+/**
+qmeta(option1)
+**/
+;
+
+select e_name from /test/aaa/test_ext where e_name='ext_001'
+/**
+output()
+**/
+;
+
+-- 2. qmeta 不同选项
+/**
+qmeta(option2)
+**/
+;
+
+select count(*) from /test/aaa/test_ext
+/**
+output()
+**/
+;

+ 35 - 0
odbctest/mql/aaa/19extensions/30multilines.mql

@@ -0,0 +1,35 @@
+-- ============================================================
+-- multilines begin/end 多行语句测试
+-- ============================================================
+
+multilines begin;
+
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values ('multi_001', 1, 'multiline insert 1')
+;
+
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values ('multi_002', 2, 'multiline insert 2')
+;
+
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values ('multi_003', 3, 'multiline insert 3')
+;
+
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values ('multi_004', 4, 'multiline insert 4')
+;
+
+insert into /test/aaa/test_ext (e_name, e_value, e_text) values ('multi_005', 5, 'multiline insert 5')
+;
+
+multilines end;
+
+/**
+sleep(500ms)
+**/
+;
+
+-- 验证 multilines 插入结果
+select e_name, e_value from /test/aaa/test_ext where e_name prefix 'multi'
+/**
+output()
+matchcount("e_name","multi",5)
+**/
+;

+ 56 - 0
odbctest/mql/aaa/19extensions/31subscription.mql

@@ -0,0 +1,56 @@
+-- ============================================================
+-- subscribe(S) / unsubscribe(S) 测试
+-- ============================================================
+
+-- 1. subscribe 订阅
+/**
+beforerun(subscribe('test_topic'))
+**/
+;
+
+insert into /test/aaa/test_ext (e_name, e_text) values ('sub_test_1', 'subscribe topic test')
+;
+
+select e_name from /test/aaa/test_ext where e_name='sub_test_1'
+/**
+output()
+count(1)
+**/
+;
+
+-- 2. unsubscribe 取消订阅
+/**
+beforerun(unsubscribe('test_topic'))
+**/
+;
+
+insert into /test/aaa/test_ext (e_name, e_text) values ('unsub_test_1', 'unsubscribe topic test')
+;
+
+select e_name from /test/aaa/test_ext where e_name='unsub_test_1'
+/**
+output()
+count(1)
+**/
+;
+
+-- 3. 同时 subscribe 多个
+/**
+beforerun(subscribe('topic_a'), subscribe('topic_b'))
+**/
+;
+
+insert into /test/aaa/test_ext (e_name, e_text) values ('multi_sub_test', 'multi subscribe test')
+;
+
+/**
+beforerun(unsubscribe('topic_a'), unsubscribe('topic_b'))
+**/
+;
+
+select e_name from /test/aaa/test_ext where e_name='multi_sub_test'
+/**
+output()
+count(1)
+**/
+;

+ 27 - 0
odbctest/mql/aaa/20subquery/00init.mql

@@ -0,0 +1,27 @@
+-- 20subquery 目录初始化:子查询测试
+
+create class if not exists /test/aaa/test_subquery (
+    s_name      varchar,
+    s_type      varchar,
+    s_value     int,
+
+    indexes(s_name, s_type, s_value),
+    keys(s_name)
+)
+;
+
+-- 插入子查询测试数据
+insert into /test/aaa/test_subquery (s_name, s_type, s_value) values ('subq_001', 'type_x', 100)
+;
+
+insert into /test/aaa/test_subquery (s_name, s_type, s_value) values ('subq_002', 'type_x', 200)
+;
+
+insert into /test/aaa/test_subquery (s_name, s_type, s_value) values ('subq_003', 'type_y', 300)
+;
+
+insert into /test/aaa/test_subquery (s_name, s_type, s_value) values ('subq_004', 'type_y', 400)
+;
+
+insert into /test/aaa/test_subquery (s_name, s_type, s_value) values ('subq_005', 'type_z', 500)
+;

+ 44 - 0
odbctest/mql/aaa/20subquery/11basic.mql

@@ -0,0 +1,44 @@
+-- ============================================================
+-- 基本子查询测试
+-- ============================================================
+
+-- 1. IN 子查询
+select * from /test/aaa/test_subquery where s_name in (select s_name from /test/aaa/test_subquery where s_type='type_x')
+/**
+output()
+match("subq_001")
+match("subq_002")
+**/
+;
+
+-- 2. NOT IN 子查询
+select * from /test/aaa/test_subquery where s_name not in (select s_name from /test/aaa/test_subquery where s_type='type_x')
+/**
+output()
+match("subq_003")
+match("subq_004")
+match("subq_005")
+**/
+;
+
+-- 3. 子查询作为条件值
+select * from /test/aaa/test_subquery where s_value > (select avg(s_value) from /test/aaa/test_subquery where s_type='type_x')
+/**
+output()
+**/
+;
+
+-- 4. 子查询等于比较
+select * from /test/aaa/test_subquery where s_value = (select max(s_value) from /test/aaa/test_subquery)
+/**
+output()
+match("subq_005")
+**/
+;
+
+-- 5. 多重子查询条件
+select * from /test/aaa/test_subquery where s_value in (select s_value from /test/aaa/test_subquery where s_type='type_x' or s_type='type_y')
+/**
+output()
+**/
+;

+ 35 - 0
odbctest/mql/aaa/20subquery/12aggr.mql

@@ -0,0 +1,35 @@
+-- ============================================================
+-- 子查询+聚合测试
+-- ============================================================
+
+-- 1. 子查询中用聚合函数
+select * from /test/aaa/test_subquery where s_value > (select avg(s_value) from /test/aaa/test_subquery)
+/**
+output()
+**/
+;
+
+-- 2. 子查询中用 count
+select * from /test/aaa/test_subquery where s_type in (select s_type from /test/aaa/test_subquery group by s_type having count(*) > 1)
+/**
+output()
+match("subq_001")
+match("subq_002")
+match("subq_003")
+match("subq_004")
+**/
+;
+
+-- 3. 子查询 group by
+select s_type, count(*) from /test/aaa/test_subquery where s_value > (select min(s_value) from /test/aaa/test_subquery where s_type='type_x') group by s_type
+/**
+output()
+**/
+;
+
+-- 4. 子查询嵌套的聚合
+select max(s_value) from /test/aaa/test_subquery where s_type in (select s_type from /test/aaa/test_subquery)
+/**
+output()
+**/
+;

+ 28 - 0
odbctest/mql/aaa/21cross_ns/00init.mql

@@ -0,0 +1,28 @@
+-- 21cross_ns 目录初始化:跨命名空间测试
+
+-- 创建 /test/bbb/ 命名空间 class(跨命名空间)
+create class if not exists /test/bbb/test_cross (
+    x_name      varchar,
+    x_value     int,
+
+    indexes(x_name, x_value),
+    keys(x_name)
+)
+;
+
+-- 插入测试数据
+insert into /test/bbb/test_cross (x_name, x_value) values ('cross_001', 100)
+;
+
+insert into /test/bbb/test_cross (x_name, x_value) values ('cross_002', 200)
+;
+
+-- 在当前命名空间 /test/aaa/ 创建跨命名空间的 class
+create class if not exists /test/aaa/test_cross_ns (
+    c_name      varchar,
+    c_ref       text,
+
+    indexes(c_name),
+    keys(c_name)
+)
+;

+ 29 - 0
odbctest/mql/aaa/21cross_ns/11create.mql

@@ -0,0 +1,29 @@
+-- ============================================================
+-- 跨命名空间 class 创建测试
+-- ============================================================
+
+-- 1. 创建跨命名空间 class
+create class if not exists /test/bbb/test_cross_create (
+    name    varchar,
+    val     int,
+
+    keys(name)
+)
+;
+
+-- 2. 在当前 namespace 跨 namespace 创建
+create class if not exists /test/ccc/test_cross_another (
+    name    varchar,
+    data    text,
+
+    keys(name)
+)
+;
+
+-- 3. 验证跨 namespace class
+select count(*) from /test/bbb/test_cross
+/**
+output()
+match("count(*)","2")
+**/
+;

+ 50 - 0
odbctest/mql/aaa/21cross_ns/12valid.mql

@@ -0,0 +1,50 @@
+-- ============================================================
+-- 跨命名空间操作验证测试
+-- ============================================================
+
+-- 1. 跨命名空间查询
+select * from /test/bbb/test_cross where x_name='cross_001'
+/**
+output()
+match("x_value","100")
+**/
+;
+
+-- 2. 跨命名空间插入
+insert into /test/bbb/test_cross (x_name, x_value) values ('cross_from_aaa', 999)
+;
+
+select * from /test/bbb/test_cross where x_name='cross_from_aaa'
+/**
+output()
+match("x_value","999")
+**/
+;
+
+-- 3. 跨命名空间更新
+update /test/bbb/test_cross set x_value=555 where x_name='cross_001'
+;
+
+select x_value from /test/bbb/test_cross where x_name='cross_001'
+/**
+output()
+match("x_value","555")
+**/
+;
+
+-- 4. 跨命名空间删除
+delete from /test/ccc/test_cross_another
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;
+
+drop class if exists /test/ccc/test_cross_another
+;
+
+-- 5. 验证不存在的跨命名空间 class
+select * from /test/bbb/non_exist_cross
+/**
+onerror(continue,'not exist','not find','not found')
+**/
+;

+ 19 - 0
odbctest/mql/aaa/22syntax/00init.mql

@@ -0,0 +1,19 @@
+-- 22syntax 目录初始化:语法扩展测试
+
+create class if not exists /test/aaa/test_syntax (
+    s_name      varchar,
+    s_Value     int,
+    s_data      text,
+    S_EXTRA     text,
+
+    indexes(s_name, s_Value, S_EXTRA),
+    keys(s_name)
+) with nickname='syntax_test'
+;
+
+-- 插入语法测试数据
+insert into /test/aaa/test_syntax (s_name, s_Value, s_data, S_EXTRA) values ('syntax_001', 100, 'relaxed syntax data', 'extra data')
+;
+
+insert into /test/aaa/test_syntax (s_name, s_Value, s_data, S_EXTRA) values ('syntax_002', 200, 'case sensitive data', 'CASE test')
+;

+ 53 - 0
odbctest/mql/aaa/22syntax/11relaxed.mql

@@ -0,0 +1,53 @@
+-- ============================================================
+-- Relaxed Syntax 测试
+-- ============================================================
+
+-- 1. 使用类名不带 namespace(relaxed syntax)
+select * from test_syntax where s_name='syntax_001'
+/**
+output()
+count(1)
+**/
+;
+
+-- 2. 使用完整 namespace
+select * from /test/aaa/test_syntax where s_name='syntax_001'
+/**
+output()
+count(1)
+**/
+;
+
+-- 3. relaxed syntax insert
+insert into test_syntax (s_name, s_Value, s_data) values ('syntax_relaxed', 999, 'relaxed insert')
+;
+
+select * from test_syntax where s_name='syntax_relaxed'
+/**
+output()
+count(1)
+match("s_Value","999")
+**/
+;
+
+-- 4. relaxed syntax update
+update test_syntax set s_data='relaxed updated' where s_name='syntax_relaxed'
+;
+
+select s_data from test_syntax where s_name='syntax_relaxed'
+/**
+output()
+match("s_data","relaxed updated")
+**/
+;
+
+-- 5. relaxed syntax delete
+delete from test_syntax where s_name='syntax_relaxed'
+;
+
+select * from test_syntax where s_name='syntax_relaxed'
+/**
+output()
+count(0)
+**/
+;

+ 38 - 0
odbctest/mql/aaa/22syntax/12case_sensitive.mql

@@ -0,0 +1,38 @@
+-- ============================================================
+-- Field Case Sensitive 测试
+-- ============================================================
+
+-- 1. 查询时使用正确大小写
+select s_name, s_Value from /test/aaa/test_syntax where s_name='syntax_001'
+/**
+output()
+match("s_Value","100")
+**/
+;
+
+-- 2. 查询带不同大小写字段
+select s_name, S_EXTRA from /test/aaa/test_syntax where s_name='syntax_001'
+/**
+output()
+match("S_EXTRA","extra data")
+**/
+;
+
+-- 3. 查询时使用混合大小写
+select s_name, s_data from /test/aaa/test_syntax where s_name='syntax_002'
+/**
+output()
+match("s_data","case sensitive data")
+**/
+;
+
+-- 4. 更新大小写字段
+update /test/aaa/test_syntax set S_EXTRA='UPDATED EXTRA' where s_name='syntax_001'
+;
+
+select S_EXTRA from /test/aaa/test_syntax where s_name='syntax_001'
+/**
+output()
+match("S_EXTRA","UPDATED EXTRA")
+**/
+;

+ 33 - 0
odbctest/mql/aaa/22syntax/13alias.mql

@@ -0,0 +1,33 @@
+-- ============================================================
+-- Class Alias 测试
+-- ============================================================
+
+-- class 创建时使用了 nickname='syntax_test'
+-- 可以使用别名访问 class
+
+-- 1. 使用全名访问
+select s_name from /test/aaa/test_syntax where s_name='syntax_001'
+/**
+output()
+count(1)
+**/
+;
+
+-- 2. 确保 class 存在后进行 alias 查询
+select s_name from /test/aaa/test_syntax where s_name='syntax_002'
+/**
+output()
+count(1)
+**/
+;
+
+-- 3. update alias class
+update /test/aaa/test_syntax set s_Value=9999 where s_name='syntax_001'
+;
+
+select s_Value from /test/aaa/test_syntax where s_name='syntax_001'
+/**
+output()
+match("s_Value","9999")
+**/
+;

+ 1 - 0
odbctest/mql/aaa/23system/00init.mql

@@ -0,0 +1 @@
+-- 23system 目录初始化:系统操作测试

+ 17 - 0
odbctest/mql/aaa/23system/11signal.mql

@@ -0,0 +1,17 @@
+-- ============================================================
+-- Signal 操作测试
+-- ============================================================
+
+-- 1. globalcache.clear
+signal('globalcache.clear')
+/**
+match("msg","ok")
+**/
+;
+
+-- 2. 验证 signal 后正常操作
+select count(*) from /test/aaa/test_ext
+/**
+output()
+**/
+;

+ 19 - 0
odbctest/mql/aaa/23system/12native.mql

@@ -0,0 +1,19 @@
+-- ============================================================
+-- Native Keyspace 操作测试
+-- ============================================================
+
+-- 1. 访问 native keyspace(系统命名空间)
+-- 测试原生命名空间的访问能力
+select count(*) from /test/aaa/test_ext where e_name='ext_001'
+/**
+output()
+match("count(*)","1")
+**/
+;
+
+-- 2. 在 /test/aaa/ 命名空间下操作
+select e_name, e_value from /test/aaa/test_ext where e_name prefix 'ext'
+/**
+output()
+**/
+;

+ 18 - 0
odbctest/mql/aaa/24trigger/00init.mql

@@ -0,0 +1,18 @@
+-- 24trigger 目录初始化:触发器测试
+
+create class if not exists /test/aaa/test_trigger (
+    t_name      varchar,
+    t_value     int,
+    t_status    text,
+
+    indexes(t_name, t_value),
+    keys(t_name)
+)
+;
+
+-- 插入触发器测试数据
+insert into /test/aaa/test_trigger (t_name, t_value, t_status) values ('trigger_001', 100, 'active')
+;
+
+insert into /test/aaa/test_trigger (t_name, t_value, t_status) values ('trigger_002', 200, 'inactive')
+;

+ 63 - 0
odbctest/mql/aaa/24trigger/11trigger.mql

@@ -0,0 +1,63 @@
+-- ============================================================
+-- 触发器操作测试
+-- ============================================================
+
+-- 1. 触发器相关操作:insert 后验证数据
+insert into /test/aaa/test_trigger (t_name, t_value, t_status) values ('trigger_test_1', 500, 'pending')
+;
+
+select * from /test/aaa/test_trigger where t_name='trigger_test_1'
+/**
+output()
+count(1)
+match("t_value","500")
+**/
+;
+
+-- 2. update 模拟触发器状态变更
+update /test/aaa/test_trigger set t_status='completed', t_value=600 where t_name='trigger_test_1'
+;
+
+select t_name, t_value, t_status from /test/aaa/test_trigger where t_name='trigger_test_1'
+/**
+output()
+match("t_status","completed")
+match("t_value","600")
+**/
+;
+
+-- 3. 批量触发器测试
+insert into /test/aaa/test_trigger (t_name, t_value, t_status) values ('trigger_batch_1', 10, 'init')
+;
+
+insert into /test/aaa/test_trigger (t_name, t_value, t_status) values ('trigger_batch_2', 20, 'init')
+;
+
+-- 批量更新状态(模拟触发器批量触发)
+update /test/aaa/test_trigger set t_status='processed' where t_status='init'
+;
+
+select t_name, t_status from /test/aaa/test_trigger where t_status='processed'
+/**
+output()
+matchcount("t_name","trigger_batch",2)
+**/
+;
+
+-- 4. delete 触发器相关数据
+delete from /test/aaa/test_trigger where t_name='trigger_batch_1'
+;
+
+select * from /test/aaa/test_trigger where t_name='trigger_batch_1'
+/**
+output()
+count(0)
+**/
+;
+
+-- 5. 触发器相关聚合
+select t_status, count(*) from /test/aaa/test_trigger group by t_status
+/**
+output()
+**/
+;

+ 5 - 0
odbctest/mql/basic/mdb/0001init.mql

@@ -0,0 +1,5 @@
+/**
+scope(dir)
+timeout(30m)
+**/
+;

+ 23 - 0
odbctest/mql/basic/mdb/0010clear.mql

@@ -0,0 +1,23 @@
+
+
+delete from /mdb/dba1 with version
+/**
+onerror(continue,`not exist`,`not find`,`not found`)
+**/
+;
+
+delete from /mdb/dba2 with version
+/**
+onerror(continue,`not exist`,`not find`,`not found`)
+**/
+;
+
+drop class if exists /mdb/dba1
+;
+drop class if exists /mdb/dba2
+;
+drop class if exists /mdb
+;
+
+DROP DB IF EXISTS msqldb --FORCE
+;

+ 68 - 0
odbctest/mql/basic/mdb/0100class.mql

@@ -0,0 +1,68 @@
+
+
+CREATE DB IF NOT EXISTS msqldb (
+    -- 数据库驱动类型,单引号或双引号标记的字符串,
+    -- 目前支持的类型有 sqlite|mysql ,新的类型需要更新 odbserver
+    DRIVER : 'sqlite', 
+    -- 数据源定义,单引号或双引号标记的字符串,
+    -- 不同数据库类型格式不一样,参考相关数据库驱动文档
+    SOURCE : "file:data/testdb?cache=shared",
+    -- 保留的附加选项,JSON对象,
+    -- 通过 odbserver 支持的,不同数据库类型支持的选项不同
+    OPTION : {
+        "makedir": "auto" -- sqlite 自动创建数据库文件所在目录
+    }
+    -- mysql示例
+    -- driver :  "mysql",
+    -- source :  "user:password@tcp(127.0.0.1:3306)/dbname"
+) 
+;
+
+create class if not exists /msqldb () with namespace='msqldb', nickname='/msqldb'
+;
+
+create class if not exists /mdb () with namespace='mdb'
+;
+
+create class if not exists /mdb/dba1 (
+	rdb            bucket {
+                        "type"  :  "msqldb"
+                    },
+) with nickname='dba1'
+;
+
+create class if not exists /mdb/dba2 (
+	
+    xvarchar        varchar,
+    xint            int,
+    xbigint         bigint,
+    xdouble         double,
+    xrdb            bucket {
+                        "type"  :  "msqldb",
+                        "fields": [{
+                            "name": "v_varchar",
+                            "type": "varchar"
+                        },{
+                            "name": "v_int",
+                            "type": "int"
+                        }],
+                        "conds" : {
+                            "type"  : "match",
+                            "lexp": {
+                                "field": "xvarchar"
+                            },
+                            "rexp": {
+                                "field": "v_varchar"
+                            }
+                        }
+                    } "rdb test",
+    xmap			map<varchar, varchar>,
+    xlist			list<varchar>,
+    xset			set<varchar>,
+    
+    indexes(xvarchar, xint, xbigint, xdouble, xmap, xlist, xset),
+    keys(xvarchar)
+) with nickname='dba2'
+;
+
+

+ 19 - 0
odbctest/mql/basic/mdb/0300valid.mql

@@ -0,0 +1,19 @@
+
+
+select name from /msqldb/sqlite_master
+/**
+output()
+**/
+;
+
+select id,rdb from /mdb/dba1
+/**
+output()
+**/
+;
+
+select * from /mdb/dba2
+/**
+output()
+**/
+;