@@ -185,6 +185,284 @@ func TestRuleSQLE00112(t *testing.T) {
185185 session .NewAIMockContext ().WithSQL ("CREATE TABLE orders (c_id VARCHAR(100), order_date DATE);" ).
186186 WithSQL ("CREATE TABLE customers (c_id INT, name VARCHAR(100));" ),
187187 nil , newTestResult ().addResult (ruleName ))
188+
189+ // 新增测试用例:验证修复效果
190+ runAIRuleCase (rule , t , "case 33: UPDATE with BIGINT UNSIGNED and int constant (should pass)" ,
191+ "UPDATE t1 SET name = 'jack' WHERE id = 2838923;" ,
192+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (id BIGINT UNSIGNED NOT NULL, name VARCHAR(100));" ),
193+ nil , newTestResult ())
194+
195+ runAIRuleCase (rule , t , "case 34: UPDATE with BIGINT and int constant (should pass)" ,
196+ "UPDATE t1 SET name = 'jack' WHERE id = 2838923;" ,
197+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (id BIGINT NOT NULL, name VARCHAR(100));" ),
198+ nil , newTestResult ())
199+
200+ runAIRuleCase (rule , t , "case 35: UPDATE with INT and int constant (should pass)" ,
201+ "UPDATE t1 SET name = 'jack' WHERE id = 100;" ,
202+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (id INT NOT NULL, name VARCHAR(100));" ),
203+ nil , newTestResult ())
204+
205+ runAIRuleCase (rule , t , "case 36: UPDATE with BIGINT UNSIGNED and string constant (should fail)" ,
206+ "UPDATE t1 SET name = 'jack' WHERE id = '2838923';" ,
207+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (id BIGINT UNSIGNED NOT NULL, name VARCHAR(100));" ),
208+ nil , newTestResult ().addResult (ruleName ))
209+
210+ runAIRuleCase (rule , t , "case 37: SELECT with BIGINT UNSIGNED and large constant (should pass)" ,
211+ "SELECT * FROM t1 WHERE id = 18446744073709551615;" ,
212+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (id BIGINT UNSIGNED NOT NULL, name VARCHAR(100));" ),
213+ nil , newTestResult ())
214+
215+ // ==== 测试用例分类:数值类型大类匹配 ====
216+ // 测试目标:验证数值类型之间的匹配,确保不会导致隐式转换
217+ // 测试范围:cases 38-43
218+
219+ // 整数类型匹配测试
220+ runAIRuleCase (rule , t , "case 38: TINYINT with INT constant (should pass - 数值在范围内)" ,
221+ "SELECT * FROM t1 WHERE age = 25;" ,
222+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (age TINYINT, name VARCHAR(100));" ),
223+ nil , newTestResult ())
224+
225+ runAIRuleCase (rule , t , "case 39: SMALLINT with INT constant (should pass - 数值在范围内)" ,
226+ "SELECT * FROM t1 WHERE score = 1000;" ,
227+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (score SMALLINT, name VARCHAR(100));" ),
228+ nil , newTestResult ())
229+
230+ runAIRuleCase (rule , t , "case 40: INT with INT constant (should pass)" ,
231+ "SELECT * FROM t1 WHERE id = 2147483647;" ,
232+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (id INT, name VARCHAR(100));" ),
233+ nil , newTestResult ())
234+
235+ // 浮点数与整数匹配测试
236+ runAIRuleCase (rule , t , "case 41: FLOAT with INT constant (should fail - 隐式转换)" ,
237+ "SELECT * FROM t1 WHERE price = 100;" ,
238+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (price FLOAT, name VARCHAR(100));" ),
239+ nil , newTestResult ().addResult (ruleName ))
240+
241+ runAIRuleCase (rule , t , "case 42: DOUBLE with FLOAT constant (should fail - 隐式转换)" ,
242+ "SELECT * FROM t1 WHERE rate = 3.14;" ,
243+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (rate DOUBLE, name VARCHAR(100));" ),
244+ nil , newTestResult ().addResult (ruleName ))
245+
246+ // 精确数值类型匹配测试
247+ runAIRuleCase (rule , t , "case 43: DECIMAL with INT constant (should fail - 隐式转换)" ,
248+ "SELECT * FROM t1 WHERE amount = 100;" ,
249+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (amount DECIMAL(10,2), name VARCHAR(100));" ),
250+ nil , newTestResult ().addResult (ruleName ))
251+
252+ // ==== 测试用例分类:字符串类型大类匹配 ====
253+ // 测试目标:验证字符串类型之间的匹配,确保不会导致隐式转换
254+ // 测试范围:cases 44-47
255+
256+ // 基础字符串类型匹配测试
257+ runAIRuleCase (rule , t , "case 44: CHAR with VARCHAR constant (should pass - 字符串类型兼容)" ,
258+ "SELECT * FROM t1 WHERE code = 'ABC';" ,
259+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (code CHAR(10), name VARCHAR(100));" ),
260+ nil , newTestResult ())
261+
262+ runAIRuleCase (rule , t , "case 45: VARCHAR with CHAR constant (should pass - 字符串类型兼容)" ,
263+ "SELECT * FROM t1 WHERE name = 'John';" ,
264+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (name VARCHAR(100), code CHAR(10));" ),
265+ nil , newTestResult ())
266+
267+ // 二进制字符串类型匹配测试
268+ runAIRuleCase (rule , t , "case 46: BLOB with BLOB constant (should pass)" ,
269+ "SELECT * FROM t1 WHERE data = 0x48656C6C6F;" ,
270+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (data BLOB, name VARCHAR(100));" ),
271+ nil , newTestResult ())
272+
273+ // 枚举类型匹配测试
274+ runAIRuleCase (rule , t , "case 47: ENUM with ENUM constant (should fail - 隐式转换)" ,
275+ "SELECT * FROM t1 WHERE status = 'active';" ,
276+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (status ENUM('active', 'inactive'), name VARCHAR(100));" ),
277+ nil , newTestResult ().addResult (ruleName ))
278+
279+ // ==== 测试用例分类:日期时间类型大类匹配 ====
280+ // 测试目标:验证日期时间类型的匹配,检测隐式转换风险
281+ // 测试范围:cases 48-50B
282+ // 注意:虽然 MySQL 会自动转换字符串为日期,但隐式转换可能导致索引失效
283+ // 正确的做法:应该使用显式转换,如 CAST('1990-01-01' AS DATE) 或 DATE('1990-01-01')
284+
285+ // 日期时间类型与字符串常量不匹配测试(应该报错)
286+ runAIRuleCase (rule , t , "case 48: DATE with string constant (should fail - 隐式转换风险)" ,
287+ "SELECT * FROM t1 WHERE birth_date = '1990-01-01';" ,
288+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (birth_date DATE, name VARCHAR(100));" ),
289+ nil , newTestResult ().addResult (ruleName ))
290+
291+ runAIRuleCase (rule , t , "case 49: DATETIME with string constant (should fail - 隐式转换风险)" ,
292+ "SELECT * FROM t1 WHERE created_at = '2023-01-01 12:00:00';" ,
293+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (created_at DATETIME, name VARCHAR(100));" ),
294+ nil , newTestResult ().addResult (ruleName ))
295+
296+ runAIRuleCase (rule , t , "case 50: TIMESTAMP with string constant (should fail - 隐式转换风险)" ,
297+ "SELECT * FROM t1 WHERE updated_at = '2023-01-01 12:00:00';" ,
298+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (updated_at TIMESTAMP, name VARCHAR(100));" ),
299+ nil , newTestResult ().addResult (ruleName ))
300+
301+ // 日期时间类型与日期时间类型列匹配测试(应该通过)
302+ runAIRuleCase (rule , t , "case 50A: DATE with DATE column (should pass)" ,
303+ "SELECT * FROM t1 WHERE birth_date = created_date;" ,
304+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (birth_date DATE, created_date DATE, name VARCHAR(100));" ),
305+ nil , newTestResult ())
306+
307+ runAIRuleCase (rule , t , "case 50B: DATETIME with DATETIME column (should pass)" ,
308+ "SELECT * FROM t1 WHERE created_at = updated_at;" ,
309+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (created_at DATETIME, updated_at DATETIME, name VARCHAR(100));" ),
310+ nil , newTestResult ())
311+
312+ // ==== 测试用例分类:跨大类不匹配 ====
313+ // 测试目标:验证不同大类类型之间的不匹配,确保检测到隐式转换风险
314+ // 测试范围:cases 51-54
315+
316+ // 数值与字符串类型不匹配测试(应该报错)
317+ runAIRuleCase (rule , t , "case 51: INT with VARCHAR constant (should fail)" ,
318+ "SELECT * FROM t1 WHERE id = '123';" ,
319+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (id INT, name VARCHAR(100));" ),
320+ nil , newTestResult ().addResult (ruleName ))
321+
322+ runAIRuleCase (rule , t , "case 52: VARCHAR with INT constant (should fail)" ,
323+ "SELECT * FROM t1 WHERE name = 123;" ,
324+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (name VARCHAR(100), id INT);" ),
325+ nil , newTestResult ().addResult (ruleName ))
326+
327+ // 日期时间与字符串类型不匹配测试(应该报错)
328+ // 正确的做法:使用 CAST('1990-01-01' AS DATE) 或 DATE('1990-01-01')
329+ runAIRuleCase (rule , t , "case 53: DATE with VARCHAR constant (should fail - 隐式转换风险)" ,
330+ "SELECT * FROM t1 WHERE birth_date = '1990-01-01';" ,
331+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (birth_date DATE, name VARCHAR(100));" ),
332+ nil , newTestResult ().addResult (ruleName ))
333+
334+ // 日期时间与数值类型不匹配测试(应该报错)
335+ // 正确的做法:使用 CAST(19900101 AS DATE) 或 DATE(19900101)
336+ runAIRuleCase (rule , t , "case 54: DATE with INT constant (should fail - 隐式转换风险)" ,
337+ "SELECT * FROM t1 WHERE birth_date = 19900101;" ,
338+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (birth_date DATE, name VARCHAR(100));" ),
339+ nil , newTestResult ().addResult (ruleName ))
340+
341+ // ==== 测试用例分类:边界情况 ====
342+ // 测试目标:验证特殊类型和边界情况的匹配
343+ // 测试范围:cases 55-57
344+
345+ // 位类型匹配测试
346+ runAIRuleCase (rule , t , "case 55: BIT with INT constant (should fail - 隐式转换)" ,
347+ "SELECT * FROM t1 WHERE flag = 1;" ,
348+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (flag BIT(1), name VARCHAR(100));" ),
349+ nil , newTestResult ().addResult (ruleName ))
350+
351+ // 年份类型匹配测试
352+ runAIRuleCase (rule , t , "case 56: YEAR with INT constant (should fail - 隐式转换)" ,
353+ "SELECT * FROM t1 WHERE year_col = 2023;" ,
354+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (year_col YEAR, name VARCHAR(100));" ),
355+ nil , newTestResult ().addResult (ruleName ))
356+
357+ // 集合类型匹配测试
358+ runAIRuleCase (rule , t , "case 57: SET with SET constant (should fail - 隐式转换)" ,
359+ "SELECT * FROM t1 WHERE tags = 'tag1,tag2';" ,
360+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (tags SET('tag1', 'tag2', 'tag3'), name VARCHAR(100));" ),
361+ nil , newTestResult ().addResult (ruleName ))
362+
363+ // ==== 新增测试用例:时间转换函数 ====
364+
365+ // 测试使用时间函数与时间列的比较(应该通过)
366+ runAIRuleCase (rule , t , "case 58: DATE with CURRENT_DATE function (should pass)" ,
367+ "SELECT * FROM t1 WHERE birth_date = CURRENT_DATE();" ,
368+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (birth_date DATE, name VARCHAR(100));" ),
369+ nil , newTestResult ())
370+
371+ runAIRuleCase (rule , t , "case 59: DATETIME with NOW function (should pass)" ,
372+ "SELECT * FROM t1 WHERE created_at = NOW();" ,
373+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (created_at DATETIME, name VARCHAR(100));" ),
374+ nil , newTestResult ())
375+
376+ // ==== 测试用例分类:列与值大类相同但会隐式转换的情况 ====
377+ // 测试目标:验证列与值在大类相同但具体类型不同时的隐式转换检测
378+ // 这些情况虽然大类相同,但会导致隐式转换,影响性能
379+
380+ // 数值类型内部的隐式转换测试(应该报错)
381+ runAIRuleCase (rule , t , "case 60: TINYINT column with BIGINT constant (should fail - 隐式转换)" ,
382+ "SELECT * FROM t1 WHERE age = 9223372036854775807;" ,
383+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (age TINYINT, name VARCHAR(100));" ),
384+ nil , newTestResult ().addResult (ruleName ))
385+
386+ runAIRuleCase (rule , t , "case 61: INT column with BIGINT constant (should fail - 隐式转换)" ,
387+ "SELECT * FROM t1 WHERE id = 9223372036854775807;" ,
388+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (id INT, name VARCHAR(100));" ),
389+ nil , newTestResult ().addResult (ruleName ))
390+
391+ runAIRuleCase (rule , t , "case 62: FLOAT column with DOUBLE constant (should fail - 隐式转换)" ,
392+ "SELECT * FROM t1 WHERE price = 3.141592653589793;" ,
393+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (price FLOAT, name VARCHAR(100));" ),
394+ nil , newTestResult ().addResult (ruleName ))
395+
396+ runAIRuleCase (rule , t , "case 63: DECIMAL(5,2) column with DECIMAL(10,4) constant (should pass - DECIMAL类型兼容)" ,
397+ "SELECT * FROM t1 WHERE amount = 123456.7890;" ,
398+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (amount DECIMAL(5,2), name VARCHAR(100));" ),
399+ nil , newTestResult ())
400+
401+ // 字符串类型内部的兼容性测试
402+ runAIRuleCase (rule , t , "case 64: CHAR(10) column with long VARCHAR constant (should pass - MySQL转换值)" ,
403+ "SELECT * FROM t1 WHERE code = 'This is a very long string that exceeds CHAR(10) limit';" ,
404+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (code CHAR(10), name VARCHAR(100));" ),
405+ nil , newTestResult ())
406+
407+ runAIRuleCase (rule , t , "case 65: VARCHAR(50) column with TEXT constant (should pass - 字符串类型兼容)" ,
408+ "SELECT * FROM t1 WHERE description = 'This is a very long text that would be stored in TEXT type';" ,
409+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (description VARCHAR(50), name VARCHAR(100));" ),
410+ nil , newTestResult ())
411+
412+ runAIRuleCase (rule , t , "case 66: BLOB column with BLOB constant (should pass - BLOB类型兼容)" ,
413+ "SELECT * FROM t1 WHERE data = 0x48656C6C6F576F726C64;" ,
414+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (data BLOB, name VARCHAR(100));" ),
415+ nil , newTestResult ())
416+
417+ // 日期时间类型内部的隐式转换测试(应该报错)
418+ runAIRuleCase (rule , t , "case 67: DATE column with DATETIME constant (should fail - 隐式转换)" ,
419+ "SELECT * FROM t1 WHERE birth_date = '2023-01-01 12:00:00';" ,
420+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (birth_date DATE, name VARCHAR(100));" ),
421+ nil , newTestResult ().addResult (ruleName ))
422+
423+ runAIRuleCase (rule , t , "case 68: DATETIME column with TIMESTAMP constant (should fail - 隐式转换)" ,
424+ "SELECT * FROM t1 WHERE created_at = '2023-01-01 12:00:00';" ,
425+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (created_at DATETIME, name VARCHAR(100));" ),
426+ nil , newTestResult ().addResult (ruleName ))
427+
428+ runAIRuleCase (rule , t , "case 69: TIMESTAMP column with DATE constant (should fail - 隐式转换)" ,
429+ "SELECT * FROM t1 WHERE updated_at = '2023-01-01';" ,
430+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (updated_at TIMESTAMP, name VARCHAR(100));" ),
431+ nil , newTestResult ().addResult (ruleName ))
432+
433+ // 特殊数值类型的隐式转换测试(应该报错)
434+ runAIRuleCase (rule , t , "case 70: TINYINT UNSIGNED column with overflow constant (should fail - 超出范围)" ,
435+ "SELECT * FROM t1 WHERE status = 256;" ,
436+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (status TINYINT UNSIGNED, name VARCHAR(100));" ),
437+ nil , newTestResult ().addResult (ruleName ))
438+
439+ runAIRuleCase (rule , t , "case 71: INT UNSIGNED column with BIGINT constant (should fail - 隐式转换)" ,
440+ "SELECT * FROM t1 WHERE count = 9223372036854775807;" ,
441+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (count INT UNSIGNED, name VARCHAR(100));" ),
442+ nil , newTestResult ().addResult (ruleName ))
443+
444+ // 枚举和集合类型的隐式转换测试(应该报错)
445+ runAIRuleCase (rule , t , "case 72: ENUM column with invalid ENUM constant (should fail - 隐式转换)" ,
446+ "SELECT * FROM t1 WHERE status = 'invalid_status';" ,
447+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (status ENUM('active', 'inactive'), name VARCHAR(100));" ),
448+ nil , newTestResult ().addResult (ruleName ))
449+
450+ runAIRuleCase (rule , t , "case 73: SET column with invalid SET constant (should fail - 隐式转换)" ,
451+ "SELECT * FROM t1 WHERE tags = 'invalid_tag,another_invalid';" ,
452+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (tags SET('tag1', 'tag2', 'tag3'), name VARCHAR(100));" ),
453+ nil , newTestResult ().addResult (ruleName ))
454+
455+ // 边界值隐式转换测试(应该报错)
456+ runAIRuleCase (rule , t , "case 74: SMALLINT column with INT overflow constant (should fail - 隐式转换)" ,
457+ "SELECT * FROM t1 WHERE score = 32768;" ,
458+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (score SMALLINT, name VARCHAR(100));" ),
459+ nil , newTestResult ().addResult (ruleName ))
460+
461+ runAIRuleCase (rule , t , "case 75: MEDIUMINT column with BIGINT constant (should fail - 隐式转换)" ,
462+ "SELECT * FROM t1 WHERE id = 2147483648;" ,
463+ session .NewAIMockContext ().WithSQL ("CREATE TABLE t1 (id MEDIUMINT, name VARCHAR(100));" ),
464+ nil , newTestResult ().addResult (ruleName ))
465+
188466}
189467
190468// ==== Rule test code end ====
0 commit comments