Skip to content

Commit 6780fd9

Browse files
authored
feat!: Add TinyInt / i8 type (#190)
# Rationale for this change We already have `SmallInt / i16`, `Int / i32`, and `BigInt / i64` data types supported. Adding an additional `TinyInt / i8` data type would be helpful to some users and would additionally have (minor) performance benefits with those columns. # What changes are included in this PR? Added a TinyInt variant to the various *Column* enum types. Added a branch for handling TinyInt everywhere that SmallInt, Int, and BigInt are handled. # Are these changes tested? Added unit tests covering the additional code.
1 parent 96e0d95 commit 6780fd9

29 files changed

Lines changed: 1388 additions & 15 deletions

crates/proof-of-sql/benches/bench_append_rows.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use proof_of_sql::{
1414
database::{
1515
owned_table_utility::{
1616
bigint, boolean, decimal75, int, int128, owned_table, scalar, smallint,
17-
timestamptz, varchar,
17+
timestamptz, tinyint, varchar,
1818
},
1919
OwnedTable,
2020
},
@@ -86,6 +86,7 @@ pub fn generate_random_owned_table<S: Scalar>(
8686
"scalar",
8787
"varchar",
8888
"decimal75",
89+
"tinyint",
8990
"smallint",
9091
"int",
9192
"timestamptz",
@@ -118,6 +119,7 @@ pub fn generate_random_owned_table<S: Scalar>(
118119
2,
119120
vec![generate_random_u64_array(); num_rows],
120121
)),
122+
"tinyint" => columns.push(tinyint(identifier.deref(), vec![rng.gen::<i8>(); num_rows])),
121123
"smallint" => columns.push(smallint(
122124
identifier.deref(),
123125
vec![rng.gen::<i16>(); num_rows],

crates/proof-of-sql/src/base/commitment/column_bounds.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ pub struct ColumnBoundsMismatch {
203203
pub enum ColumnBounds {
204204
/// Column does not have order.
205205
NoOrder,
206+
/// The bounds of a `TinyInt` column.
207+
TinyInt(Bounds<i8>),
206208
/// The bounds of a `SmallInt` column.
207209
SmallInt(Bounds<i16>),
208210
/// The bounds of an Int column.
@@ -222,6 +224,7 @@ impl ColumnBounds {
222224
#[must_use]
223225
pub fn from_column(column: &CommittableColumn) -> ColumnBounds {
224226
match column {
227+
CommittableColumn::TinyInt(ints) => ColumnBounds::TinyInt(Bounds::from_iter(*ints)),
225228
CommittableColumn::SmallInt(ints) => ColumnBounds::SmallInt(Bounds::from_iter(*ints)),
226229
CommittableColumn::Int(ints) => ColumnBounds::Int(Bounds::from_iter(*ints)),
227230
CommittableColumn::BigInt(ints) => ColumnBounds::BigInt(Bounds::from_iter(*ints)),
@@ -243,6 +246,9 @@ impl ColumnBounds {
243246
pub fn try_union(self, other: Self) -> Result<Self, ColumnBoundsMismatch> {
244247
match (self, other) {
245248
(ColumnBounds::NoOrder, ColumnBounds::NoOrder) => Ok(ColumnBounds::NoOrder),
249+
(ColumnBounds::TinyInt(bounds_a), ColumnBounds::TinyInt(bounds_b)) => {
250+
Ok(ColumnBounds::TinyInt(bounds_a.union(bounds_b)))
251+
}
246252
(ColumnBounds::SmallInt(bounds_a), ColumnBounds::SmallInt(bounds_b)) => {
247253
Ok(ColumnBounds::SmallInt(bounds_a.union(bounds_b)))
248254
}
@@ -272,6 +278,9 @@ impl ColumnBounds {
272278
pub fn try_difference(self, other: Self) -> Result<Self, ColumnBoundsMismatch> {
273279
match (self, other) {
274280
(ColumnBounds::NoOrder, ColumnBounds::NoOrder) => Ok(self),
281+
(ColumnBounds::TinyInt(bounds_a), ColumnBounds::TinyInt(bounds_b)) => {
282+
Ok(ColumnBounds::TinyInt(bounds_a.difference(bounds_b)))
283+
}
275284
(ColumnBounds::SmallInt(bounds_a), ColumnBounds::SmallInt(bounds_b)) => {
276285
Ok(ColumnBounds::SmallInt(bounds_a.difference(bounds_b)))
277286
}
@@ -497,6 +506,14 @@ mod tests {
497506
let varchar_column_bounds = ColumnBounds::from_column(&committable_varchar_column);
498507
assert_eq!(varchar_column_bounds, ColumnBounds::NoOrder);
499508

509+
let tinyint_column = OwnedColumn::<Curve25519Scalar>::TinyInt([1, 2, 3, 1, 0].to_vec());
510+
let committable_tinyint_column = CommittableColumn::from(&tinyint_column);
511+
let tinyint_column_bounds = ColumnBounds::from_column(&committable_tinyint_column);
512+
assert_eq!(
513+
tinyint_column_bounds,
514+
ColumnBounds::TinyInt(Bounds::Sharp(BoundsInner { min: 0, max: 3 }))
515+
);
516+
500517
let smallint_column = OwnedColumn::<Curve25519Scalar>::SmallInt([1, 2, 3, 1, 0].to_vec());
501518
let committable_smallint_column = CommittableColumn::from(&smallint_column);
502519
let smallint_column_bounds = ColumnBounds::from_column(&committable_smallint_column);
@@ -560,6 +577,13 @@ mod tests {
560577
let no_order = ColumnBounds::NoOrder;
561578
assert_eq!(no_order.try_union(no_order).unwrap(), no_order);
562579

580+
let tinyint_a = ColumnBounds::TinyInt(Bounds::Sharp(BoundsInner { min: 1, max: 3 }));
581+
let tinyint_b = ColumnBounds::TinyInt(Bounds::Sharp(BoundsInner { min: 4, max: 6 }));
582+
assert_eq!(
583+
tinyint_a.try_union(tinyint_b).unwrap(),
584+
ColumnBounds::TinyInt(Bounds::Sharp(BoundsInner { min: 1, max: 6 }))
585+
);
586+
563587
let smallint_a = ColumnBounds::SmallInt(Bounds::Sharp(BoundsInner { min: 1, max: 3 }));
564588
let smallint_b = ColumnBounds::SmallInt(Bounds::Sharp(BoundsInner { min: 4, max: 6 }));
565589
assert_eq!(
@@ -607,6 +631,7 @@ mod tests {
607631
#[test]
608632
fn we_cannot_union_mismatched_column_bounds() {
609633
let no_order = ColumnBounds::NoOrder;
634+
let tinyint = ColumnBounds::TinyInt(Bounds::Sharp(BoundsInner { min: -3, max: 3 }));
610635
let smallint = ColumnBounds::SmallInt(Bounds::Sharp(BoundsInner { min: -5, max: 5 }));
611636
let int = ColumnBounds::Int(Bounds::Sharp(BoundsInner { min: -10, max: 10 }));
612637
let bigint = ColumnBounds::BigInt(Bounds::Sharp(BoundsInner { min: 1, max: 3 }));
@@ -615,6 +640,7 @@ mod tests {
615640

616641
let bounds = [
617642
(no_order, "NoOrder"),
643+
(tinyint, "TinyInt"),
618644
(smallint, "SmallInt"),
619645
(int, "Int"),
620646
(bigint, "BigInt"),
@@ -639,6 +665,10 @@ mod tests {
639665
let no_order = ColumnBounds::NoOrder;
640666
assert_eq!(no_order.try_difference(no_order).unwrap(), no_order);
641667

668+
let tinyint_a = ColumnBounds::TinyInt(Bounds::Sharp(BoundsInner { min: 1, max: 3 }));
669+
let tinyint_b = ColumnBounds::TinyInt(Bounds::Empty);
670+
assert_eq!(tinyint_a.try_difference(tinyint_b).unwrap(), tinyint_a);
671+
642672
let smallint_a = ColumnBounds::SmallInt(Bounds::Sharp(BoundsInner { min: 1, max: 3 }));
643673
let smallint_b = ColumnBounds::SmallInt(Bounds::Empty);
644674
assert_eq!(smallint_a.try_difference(smallint_b).unwrap(), smallint_a);
@@ -672,6 +702,7 @@ mod tests {
672702
let bigint = ColumnBounds::BigInt(Bounds::Sharp(BoundsInner { min: 1, max: 3 }));
673703
let int128 = ColumnBounds::Int128(Bounds::Sharp(BoundsInner { min: 4, max: 6 }));
674704
let timestamp = ColumnBounds::TimestampTZ(Bounds::Sharp(BoundsInner { min: 4, max: 6 }));
705+
let tinyint = ColumnBounds::TinyInt(Bounds::Sharp(BoundsInner { min: 1, max: 3 }));
675706
let smallint = ColumnBounds::SmallInt(Bounds::Sharp(BoundsInner { min: 1, max: 3 }));
676707

677708
assert!(no_order.try_difference(bigint).is_err());
@@ -683,6 +714,9 @@ mod tests {
683714
assert!(bigint.try_difference(int128).is_err());
684715
assert!(int128.try_difference(bigint).is_err());
685716

717+
assert!(tinyint.try_difference(timestamp).is_err());
718+
assert!(timestamp.try_difference(tinyint).is_err());
719+
686720
assert!(smallint.try_difference(timestamp).is_err());
687721
assert!(timestamp.try_difference(smallint).is_err());
688722
}

crates/proof-of-sql/src/base/commitment/column_commitment_metadata.rs

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ impl ColumnCommitmentMetadata {
4444
bounds: ColumnBounds,
4545
) -> Result<ColumnCommitmentMetadata, InvalidColumnCommitmentMetadata> {
4646
match (column_type, bounds) {
47-
(ColumnType::SmallInt, ColumnBounds::SmallInt(_))
47+
(ColumnType::TinyInt, ColumnBounds::TinyInt(_))
48+
| (ColumnType::SmallInt, ColumnBounds::SmallInt(_))
4849
| (ColumnType::Int, ColumnBounds::Int(_))
4950
| (ColumnType::BigInt, ColumnBounds::BigInt(_))
5051
| (ColumnType::Int128, ColumnBounds::Int128(_))
@@ -189,6 +190,18 @@ mod tests {
189190

190191
#[test]
191192
fn we_can_construct_metadata() {
193+
assert_eq!(
194+
ColumnCommitmentMetadata::try_new(
195+
ColumnType::TinyInt,
196+
ColumnBounds::TinyInt(Bounds::Empty)
197+
)
198+
.unwrap(),
199+
ColumnCommitmentMetadata {
200+
column_type: ColumnType::TinyInt,
201+
bounds: ColumnBounds::TinyInt(Bounds::Empty)
202+
}
203+
);
204+
192205
assert_eq!(
193206
ColumnCommitmentMetadata::try_new(
194207
ColumnType::SmallInt,
@@ -436,6 +449,17 @@ mod tests {
436449
panic!("Bounds constructed from nonempty BigInt column should be ColumnBounds::Int(Bounds::Sharp(_))");
437450
}
438451

452+
let tinyint_column = OwnedColumn::<Curve25519Scalar>::TinyInt([1, 2, 3, 1, 0].to_vec());
453+
let committable_tinyint_column = CommittableColumn::from(&tinyint_column);
454+
let tinyint_metadata = ColumnCommitmentMetadata::from_column(&committable_tinyint_column);
455+
assert_eq!(tinyint_metadata.column_type(), &ColumnType::TinyInt);
456+
if let ColumnBounds::TinyInt(Bounds::Sharp(bounds)) = tinyint_metadata.bounds() {
457+
assert_eq!(bounds.min(), &0);
458+
assert_eq!(bounds.max(), &3);
459+
} else {
460+
panic!("Bounds constructed from nonempty BigInt column should be ColumnBounds::TinyInt(Bounds::Sharp(_))");
461+
}
462+
439463
let smallint_column = OwnedColumn::<Curve25519Scalar>::SmallInt([1, 2, 3, 1, 0].to_vec());
440464
let committable_smallint_column = CommittableColumn::from(&smallint_column);
441465
let smallint_metadata = ColumnCommitmentMetadata::from_column(&committable_smallint_column);
@@ -504,6 +528,18 @@ mod tests {
504528
);
505529

506530
// Ordered case
531+
let ints = [1, 2, 3, 1, 0];
532+
let tinyint_column_a = CommittableColumn::TinyInt(&ints[..2]);
533+
let tinyint_metadata_a = ColumnCommitmentMetadata::from_column(&tinyint_column_a);
534+
let tinyint_column_b = CommittableColumn::TinyInt(&ints[2..]);
535+
let tinyint_metadata_b = ColumnCommitmentMetadata::from_column(&tinyint_column_b);
536+
let tinyint_column_c = CommittableColumn::TinyInt(&ints);
537+
let tinyint_metadata_c = ColumnCommitmentMetadata::from_column(&tinyint_column_c);
538+
assert_eq!(
539+
tinyint_metadata_a.try_union(tinyint_metadata_b).unwrap(),
540+
tinyint_metadata_c
541+
);
542+
507543
let ints = [1, 2, 3, 1, 0];
508544
let smallint_column_a = CommittableColumn::SmallInt(&ints[..2]);
509545
let smallint_metadata_a = ColumnCommitmentMetadata::from_column(&smallint_column_a);
@@ -650,6 +686,43 @@ mod tests {
650686
);
651687
}
652688

689+
#[test]
690+
fn we_can_difference_tinyint_matching_metadata() {
691+
// Ordered case
692+
let tinyints = [1, 2, 3, 1, 0];
693+
let tinyint_column_a = CommittableColumn::TinyInt(&tinyints[..2]);
694+
let tinyint_metadata_a = ColumnCommitmentMetadata::from_column(&tinyint_column_a);
695+
let tinyint_column_b = CommittableColumn::TinyInt(&tinyints);
696+
let tinyint_metadata_b = ColumnCommitmentMetadata::from_column(&tinyint_column_b);
697+
698+
let b_difference_a = tinyint_metadata_b
699+
.try_difference(tinyint_metadata_a)
700+
.unwrap();
701+
assert_eq!(b_difference_a.column_type, ColumnType::TinyInt);
702+
if let ColumnBounds::TinyInt(Bounds::Bounded(bounds)) = b_difference_a.bounds() {
703+
assert_eq!(bounds.min(), &0);
704+
assert_eq!(bounds.max(), &3);
705+
} else {
706+
panic!("difference of overlapping bounds should be Bounded");
707+
}
708+
709+
let tinyint_column_empty = CommittableColumn::TinyInt(&[]);
710+
let tinyint_metadata_empty = ColumnCommitmentMetadata::from_column(&tinyint_column_empty);
711+
712+
assert_eq!(
713+
tinyint_metadata_b
714+
.try_difference(tinyint_metadata_empty)
715+
.unwrap(),
716+
tinyint_metadata_b
717+
);
718+
assert_eq!(
719+
tinyint_metadata_empty
720+
.try_difference(tinyint_metadata_b)
721+
.unwrap(),
722+
tinyint_metadata_empty
723+
);
724+
}
725+
653726
#[test]
654727
fn we_can_difference_smallint_matching_metadata() {
655728
// Ordered case
@@ -732,6 +805,10 @@ mod tests {
732805
column_type: ColumnType::Scalar,
733806
bounds: ColumnBounds::NoOrder,
734807
};
808+
let tinyint_metadata = ColumnCommitmentMetadata {
809+
column_type: ColumnType::TinyInt,
810+
bounds: ColumnBounds::TinyInt(Bounds::Empty),
811+
};
735812
let smallint_metadata = ColumnCommitmentMetadata {
736813
column_type: ColumnType::SmallInt,
737814
bounds: ColumnBounds::SmallInt(Bounds::Empty),
@@ -753,6 +830,18 @@ mod tests {
753830
bounds: ColumnBounds::Int128(Bounds::Empty),
754831
};
755832

833+
assert!(tinyint_metadata.try_union(scalar_metadata).is_err());
834+
assert!(scalar_metadata.try_union(tinyint_metadata).is_err());
835+
836+
assert!(tinyint_metadata.try_union(decimal75_metadata).is_err());
837+
assert!(decimal75_metadata.try_union(tinyint_metadata).is_err());
838+
839+
assert!(tinyint_metadata.try_union(varchar_metadata).is_err());
840+
assert!(varchar_metadata.try_union(tinyint_metadata).is_err());
841+
842+
assert!(tinyint_metadata.try_union(boolean_metadata).is_err());
843+
assert!(boolean_metadata.try_union(tinyint_metadata).is_err());
844+
756845
assert!(smallint_metadata.try_union(scalar_metadata).is_err());
757846
assert!(scalar_metadata.try_union(smallint_metadata).is_err());
758847

0 commit comments

Comments
 (0)