22
33use crate :: SqlGen ;
44use crate :: ast:: {
5- AlterTableAction , AlterTableActionKind , AlterTableStmt , ColumnDefStmt , ConflictClause ,
5+ AlterTableAction , AlterTableActionKind , AlterTableStmt , BinOp , ColumnDefStmt , ConflictClause ,
66 CreateIndexStmt , CreateTableStmt , CreateTriggerStmt , DeleteStmt , DropIndexStmt , DropTableStmt ,
7- DropTriggerStmt , Expr , InsertStmt , Stmt , TriggerBodyStmtKind , TriggerEvent , TriggerEventKind ,
8- TriggerStmt , TriggerTiming , UpdateStmt ,
7+ DropTriggerStmt , Expr , InsertStmt , Literal , Stmt , TriggerBodyStmtKind , TriggerEvent ,
8+ TriggerEventKind , TriggerStmt , TriggerTiming , UpdateStmt ,
99} ;
1010use crate :: capabilities:: Capabilities ;
1111use crate :: context:: Context ;
@@ -567,6 +567,7 @@ pub fn generate_create_table<C: Capabilities>(
567567 not_null : true ,
568568 unique : false ,
569569 default : None ,
570+ check : None ,
570571 } ) ;
571572
572573 // Generate additional columns
@@ -589,13 +590,20 @@ pub fn generate_create_table<C: Capabilities>(
589590 let name = ctx. gen_unique_name ( "col" , & col_names) ;
590591 col_names. insert ( name. clone ( ) ) ;
591592
593+ let check = if ctx. gen_bool_with_prob ( create_table_config. check_constraint_probability ) {
594+ generate_check_constraint ( generator, ctx, & name, data_type) ?
595+ } else {
596+ None
597+ } ;
598+
592599 columns. push ( ColumnDefStmt {
593600 name,
594601 data_type,
595602 primary_key : false ,
596603 not_null,
597604 unique,
598605 default,
606+ check,
599607 } ) ;
600608 }
601609
@@ -605,9 +613,6 @@ pub fn generate_create_table<C: Capabilities>(
605613 }
606614
607615 // --- Table-level constraints (not yet implemented) ---
608- if ctx. gen_bool_with_prob ( create_table_config. check_constraint_probability ) {
609- let _ = generate_check_constraint ( generator, ctx) ;
610- }
611616 if ctx. gen_bool_with_prob ( create_table_config. foreign_key_probability ) {
612617 let _ = generate_foreign_key ( generator, ctx) ;
613618 }
@@ -730,6 +735,7 @@ fn generate_alter_table_action<C: Capabilities>(
730735 not_null,
731736 unique : false ,
732737 default : None ,
738+ check : None ,
733739 } ) )
734740 }
735741 AlterTableActionKind :: DropColumn => {
@@ -1096,12 +1102,108 @@ fn generate_delete_returning<C: Capabilities>(
10961102
10971103// ---- CREATE TABLE features ----
10981104
1105+ /// Generate a CHECK constraint expression for a column, based on its data type.
1106+ /// Mirrors the approach from sql_gen_prop: simple, deterministic, type-appropriate constraints.
10991107#[ trace_gen( Origin :: CheckConstraint ) ]
11001108fn generate_check_constraint < C : Capabilities > (
11011109 _generator : & SqlGen < C > ,
1102- _ctx : & mut Context ,
1103- ) -> Result < Expr , GenError > {
1104- todo ! ( "CHECK constraint generation" )
1110+ ctx : & mut Context ,
1111+ col_name : & str ,
1112+ data_type : DataType ,
1113+ ) -> Result < Option < Expr > , GenError > {
1114+ match data_type {
1115+ DataType :: Integer => {
1116+ let variant = ctx. gen_range ( 5 ) ;
1117+ let expr = match variant {
1118+ // col >= 0
1119+ 0 => {
1120+ let col = Expr :: column_ref ( ctx, None , col_name. to_string ( ) ) ;
1121+ let rhs = Expr :: literal ( ctx, Literal :: Integer ( 0 ) ) ;
1122+ Expr :: binary_op ( ctx, col, BinOp :: Ge , rhs)
1123+ }
1124+ // col > 0
1125+ 1 => {
1126+ let col = Expr :: column_ref ( ctx, None , col_name. to_string ( ) ) ;
1127+ let rhs = Expr :: literal ( ctx, Literal :: Integer ( 0 ) ) ;
1128+ Expr :: binary_op ( ctx, col, BinOp :: Gt , rhs)
1129+ }
1130+ // col BETWEEN 0 AND 1000
1131+ 2 => {
1132+ let col = Expr :: column_ref ( ctx, None , col_name. to_string ( ) ) ;
1133+ let low = Expr :: literal ( ctx, Literal :: Integer ( 0 ) ) ;
1134+ let high = Expr :: literal ( ctx, Literal :: Integer ( 1000 ) ) ;
1135+ Expr :: between ( ctx, col, low, high, false )
1136+ }
1137+ // col != 0
1138+ 3 => {
1139+ let col = Expr :: column_ref ( ctx, None , col_name. to_string ( ) ) ;
1140+ let rhs = Expr :: literal ( ctx, Literal :: Integer ( 0 ) ) ;
1141+ Expr :: binary_op ( ctx, col, BinOp :: Ne , rhs)
1142+ }
1143+ // col >= N (random N in 1..100)
1144+ _ => {
1145+ let n = ctx. gen_range_inclusive ( 1 , 99 ) as i64 ;
1146+ let col = Expr :: column_ref ( ctx, None , col_name. to_string ( ) ) ;
1147+ let rhs = Expr :: literal ( ctx, Literal :: Integer ( n) ) ;
1148+ Expr :: binary_op ( ctx, col, BinOp :: Ge , rhs)
1149+ }
1150+ } ;
1151+ Ok ( Some ( expr) )
1152+ }
1153+ DataType :: Real => {
1154+ let variant = ctx. gen_range ( 3 ) ;
1155+ let expr = match variant {
1156+ // col >= 0.0
1157+ 0 => {
1158+ let col = Expr :: column_ref ( ctx, None , col_name. to_string ( ) ) ;
1159+ let rhs = Expr :: literal ( ctx, Literal :: Real ( 0.0 ) ) ;
1160+ Expr :: binary_op ( ctx, col, BinOp :: Ge , rhs)
1161+ }
1162+ // col > 0.0
1163+ 1 => {
1164+ let col = Expr :: column_ref ( ctx, None , col_name. to_string ( ) ) ;
1165+ let rhs = Expr :: literal ( ctx, Literal :: Real ( 0.0 ) ) ;
1166+ Expr :: binary_op ( ctx, col, BinOp :: Gt , rhs)
1167+ }
1168+ // col BETWEEN 0.0 AND 1000.0
1169+ _ => {
1170+ let col = Expr :: column_ref ( ctx, None , col_name. to_string ( ) ) ;
1171+ let low = Expr :: literal ( ctx, Literal :: Real ( 0.0 ) ) ;
1172+ let high = Expr :: literal ( ctx, Literal :: Real ( 1000.0 ) ) ;
1173+ Expr :: between ( ctx, col, low, high, false )
1174+ }
1175+ } ;
1176+ Ok ( Some ( expr) )
1177+ }
1178+ DataType :: Text => {
1179+ let variant = ctx. gen_range ( 3 ) ;
1180+ let expr = match variant {
1181+ // length(col) > 0
1182+ 0 => {
1183+ let col = Expr :: column_ref ( ctx, None , col_name. to_string ( ) ) ;
1184+ let len = Expr :: function_call ( ctx, "length" . to_string ( ) , vec ! [ col] ) ;
1185+ let rhs = Expr :: literal ( ctx, Literal :: Integer ( 0 ) ) ;
1186+ Expr :: binary_op ( ctx, len, BinOp :: Gt , rhs)
1187+ }
1188+ // length(col) <= 100
1189+ 1 => {
1190+ let col = Expr :: column_ref ( ctx, None , col_name. to_string ( ) ) ;
1191+ let len = Expr :: function_call ( ctx, "length" . to_string ( ) , vec ! [ col] ) ;
1192+ let rhs = Expr :: literal ( ctx, Literal :: Integer ( 100 ) ) ;
1193+ Expr :: binary_op ( ctx, len, BinOp :: Le , rhs)
1194+ }
1195+ // col != ''
1196+ _ => {
1197+ let col = Expr :: column_ref ( ctx, None , col_name. to_string ( ) ) ;
1198+ let rhs = Expr :: literal ( ctx, Literal :: Text ( String :: new ( ) ) ) ;
1199+ Expr :: binary_op ( ctx, col, BinOp :: Ne , rhs)
1200+ }
1201+ } ;
1202+ Ok ( Some ( expr) )
1203+ }
1204+ // Blob and Null types don't have useful check constraints
1205+ DataType :: Blob | DataType :: Null => Ok ( None ) ,
1206+ }
11051207}
11061208
11071209#[ trace_gen( Origin :: ForeignKey ) ]
0 commit comments