@@ -30,6 +30,7 @@ use crate::optimizer::heuristic::optimizer::HepOptimizerPipeline;
3030use crate :: optimizer:: rule:: implementation:: ImplementationRuleImpl ;
3131use crate :: optimizer:: rule:: normalization:: NormalizationRuleImpl ;
3232use crate :: parser:: parse_sql;
33+ use crate :: planner:: operator:: Operator ;
3334use crate :: planner:: LogicalPlan ;
3435use crate :: storage:: memory:: MemoryStorage ;
3536#[ cfg( not( target_arch = "wasm32" ) ) ]
@@ -64,6 +65,7 @@ pub struct DataBaseBuilder {
6465 path : PathBuf ,
6566 scala_functions : ScalaFunctions ,
6667 table_functions : TableFunctions ,
68+ histogram_buckets : Option < usize > ,
6769}
6870
6971impl DataBaseBuilder {
@@ -72,6 +74,7 @@ impl DataBaseBuilder {
7274 path : path. into ( ) ,
7375 scala_functions : Default :: default ( ) ,
7476 table_functions : Default :: default ( ) ,
77+ histogram_buckets : None ,
7578 } ;
7679 builder = builder. register_scala_function ( CharLength :: new ( "char_length" . to_lowercase ( ) ) ) ;
7780 builder =
@@ -85,6 +88,11 @@ impl DataBaseBuilder {
8588 builder
8689 }
8790
91+ pub fn histogram_buckets ( mut self , buckets : usize ) -> Self {
92+ self . histogram_buckets = Some ( buckets) ;
93+ self
94+ }
95+
8896 pub fn register_scala_function ( mut self , function : Arc < dyn ScalarFunctionImpl > ) -> Self {
8997 let summary = function. summary ( ) . clone ( ) ;
9098
@@ -100,41 +108,72 @@ impl DataBaseBuilder {
100108 }
101109
102110 pub fn build_with_storage < T : Storage > ( self , storage : T ) -> Result < Database < T > , DatabaseError > {
103- Self :: _build :: < T > ( storage, self . scala_functions , self . table_functions )
111+ Self :: _build :: < T > (
112+ storage,
113+ self . scala_functions ,
114+ self . table_functions ,
115+ self . histogram_buckets ,
116+ )
104117 }
105118
106119 #[ cfg( target_arch = "wasm32" ) ]
107120 pub fn build ( self ) -> Result < Database < MemoryStorage > , DatabaseError > {
108121 let storage = MemoryStorage :: new ( ) ;
109122
110- Self :: _build :: < MemoryStorage > ( storage, self . scala_functions , self . table_functions )
123+ Self :: _build :: < MemoryStorage > (
124+ storage,
125+ self . scala_functions ,
126+ self . table_functions ,
127+ self . histogram_buckets ,
128+ )
111129 }
112130
113131 #[ cfg( not( target_arch = "wasm32" ) ) ]
114132 pub fn build ( self ) -> Result < Database < RocksStorage > , DatabaseError > {
115133 let storage = RocksStorage :: new ( self . path ) ?;
116134
117- Self :: _build :: < RocksStorage > ( storage, self . scala_functions , self . table_functions )
135+ Self :: _build :: < RocksStorage > (
136+ storage,
137+ self . scala_functions ,
138+ self . table_functions ,
139+ self . histogram_buckets ,
140+ )
118141 }
119142
120143 pub fn build_in_memory ( self ) -> Result < Database < MemoryStorage > , DatabaseError > {
121144 let storage = MemoryStorage :: new ( ) ;
122145
123- Self :: _build :: < MemoryStorage > ( storage, self . scala_functions , self . table_functions )
146+ Self :: _build :: < MemoryStorage > (
147+ storage,
148+ self . scala_functions ,
149+ self . table_functions ,
150+ self . histogram_buckets ,
151+ )
124152 }
125153
126154 #[ cfg( not( target_arch = "wasm32" ) ) ]
127155 pub fn build_optimistic ( self ) -> Result < Database < OptimisticRocksStorage > , DatabaseError > {
128156 let storage = OptimisticRocksStorage :: new ( self . path ) ?;
129157
130- Self :: _build :: < OptimisticRocksStorage > ( storage, self . scala_functions , self . table_functions )
158+ Self :: _build :: < OptimisticRocksStorage > (
159+ storage,
160+ self . scala_functions ,
161+ self . table_functions ,
162+ self . histogram_buckets ,
163+ )
131164 }
132165
133166 fn _build < T : Storage > (
134167 storage : T ,
135168 scala_functions : ScalaFunctions ,
136169 table_functions : TableFunctions ,
170+ histogram_buckets : Option < usize > ,
137171 ) -> Result < Database < T > , DatabaseError > {
172+ if matches ! ( histogram_buckets, Some ( 0 ) ) {
173+ return Err ( DatabaseError :: InvalidValue (
174+ "histogram buckets must be >= 1" . to_string ( ) ,
175+ ) ) ;
176+ }
138177 let meta_cache = SharedLruCache :: new ( 256 , 8 , RandomState :: new ( ) ) ?;
139178 let table_cache = SharedLruCache :: new ( 48 , 4 , RandomState :: new ( ) ) ?;
140179 let view_cache = SharedLruCache :: new ( 12 , 4 , RandomState :: new ( ) ) ?;
@@ -149,6 +188,7 @@ impl DataBaseBuilder {
149188 table_cache,
150189 view_cache,
151190 optimizer_pipeline : default_optimizer_pipeline ( ) ,
191+ histogram_buckets,
152192 _p : Default :: default ( ) ,
153193 } ) ,
154194 } )
@@ -260,6 +300,7 @@ pub(crate) struct State<S> {
260300 table_cache : TableCache ,
261301 view_cache : ViewCache ,
262302 optimizer_pipeline : HepOptimizerPipeline ,
303+ histogram_buckets : Option < usize > ,
263304 _p : PhantomData < S > ,
264305}
265306
@@ -312,11 +353,17 @@ impl<S: Storage> State<S> {
312353 /// Limit(1)
313354 /// Project(a,b)
314355 let source_plan = binder. bind ( stmt) ?;
315- let best_plan = self
356+ let mut best_plan = self
316357 . optimizer_pipeline
317358 . instantiate ( source_plan)
318359 . find_best ( Some ( & transaction. meta_loader ( meta_cache) ) ) ?;
319360
361+ if let Operator :: Analyze ( op) = & mut best_plan. operator {
362+ if op. histogram_buckets . is_none ( ) {
363+ op. histogram_buckets = self . histogram_buckets ;
364+ }
365+ }
366+
320367 Ok ( best_plan)
321368 }
322369
@@ -1036,4 +1083,17 @@ pub(crate) mod test {
10361083
10371084 Ok ( ( ) )
10381085 }
1086+
1087+ #[ test]
1088+ fn test_invalid_histogram_buckets ( ) {
1089+ let temp_dir = TempDir :: new ( ) . expect ( "unable to create temporary working directory" ) ;
1090+ let result = DataBaseBuilder :: path ( temp_dir. path ( ) )
1091+ . histogram_buckets ( 0 )
1092+ . build ( ) ;
1093+
1094+ assert ! ( matches!(
1095+ result,
1096+ Err ( DatabaseError :: InvalidValue ( message) ) if message == "histogram buckets must be >= 1"
1097+ ) ) ;
1098+ }
10391099}
0 commit comments