This documentation is also tests for the code, the examples below show the literal output of these statements from Postgres.
Some setup to make sure warnings are shown, and that the extension is installed.
set client_min_messages = 'WARNING';
create extension if not exists onesparse;
Describe the scalar type
List of data types
┌───────────┬────────┬───────────────┬──────┬──────────┬──────────┬───────────────────┬─────────────────────────────────────────┐
│ Schema │ Name │ Internal name │ Size │ Elements │ Owner │ Access privileges │ Description │
├───────────┼────────┼───────────────┼──────┼──────────┼──────────┼───────────────────┼─────────────────────────────────────────┤
│ onesparse │ scalar │ scalar │ var │ │ postgres │ │ Scalars hold individual element values. │
└───────────┴────────┴───────────────┴──────┴──────────┴──────────┴───────────────────┴─────────────────────────────────────────┘
(1 row)
print a scalar, this renders the value with no prefix
select print('int32:42'::scalar);
┌───────┐
│ print │
├───────┤
│ 42 │
└───────┘
(1 row)
Duplicate a scalar
select dup('int32:42'::scalar);
┌──────────┐
│ dup │
├──────────┤
│ int32:42 │
└──────────┘
(1 row)
Wait for a scalar to complete in non-blocking mode
select wait('int32:42'::scalar);
┌──────────┐
│ wait │
├──────────┤
│ int32:42 │
└──────────┘
(1 row)
Clear a scalar, deleting its stored element.
select clear('int32:42'::scalar);
┌───────┐
│ clear │
├───────┤
│ int32 │
└───────┘
(1 row)
Various ways to construct scalars from native Postgres values. Construct from literals using cast
select 42::int::scalar;
┌──────────┐
│ scalar │
├──────────┤
│ int32:42 │
└──────────┘
(1 row)
select 3.14::float8::scalar;
┌───────────────┐
│ scalar │
├───────────────┤
│ fp64:3.140000 │
└───────────────┘
(1 row)
select true::bool::scalar;
┌────────┐
│ scalar │
├────────┤
│ bool:t │
└────────┘
(1 row)
Construct using explicit type
select 'int32:42'::scalar;
┌──────────┐
│ scalar │
├──────────┤
│ int32:42 │
└──────────┘
(1 row)
select 'fp64:3.14'::scalar;
┌───────────────┐
│ scalar │
├───────────────┤
│ fp64:3.140000 │
└───────────────┘
(1 row)
select 'bool:true'::scalar;
┌────────┐
│ scalar │
├────────┤
│ bool:t │
└────────┘
(1 row)
Construct from different integer sizes
select 127::int2::scalar as int16_scalar;
┌──────────────┐
│ int16_scalar │
├──────────────┤
│ int16:127 │
└──────────────┘
(1 row)
select 32767::int4::scalar as int32_scalar;
┌──────────────┐
│ int32_scalar │
├──────────────┤
│ int32:32767 │
└──────────────┘
(1 row)
select 2147483647::int8::scalar as int64_scalar;
┌──────────────────┐
│ int64_scalar │
├──────────────────┤
│ int64:2147483647 │
└──────────────────┘
(1 row)
Construct from different float sizes
select 3.14::float4::scalar as fp32_scalar;
┌───────────────┐
│ fp32_scalar │
├───────────────┤
│ fp32:3.140000 │
└───────────────┘
(1 row)
select 3.14159265::float8::scalar as fp64_scalar;
┌───────────────┐
│ fp64_scalar │
├───────────────┤
│ fp64:3.141593 │
└───────────────┘
(1 row)
Empty scalar (no value set)
select 'int32'::scalar;
┌────────┐
│ scalar │
├────────┤
│ int32 │
└────────┘
(1 row)
select nvals('int32'::scalar);
┌───────┐
│ nvals │
├───────┤
│ 0 │
└───────┘
(1 row)
Scalar with value
select 'int32:42'::scalar;
┌──────────┐
│ scalar │
├──────────┤
│ int32:42 │
└──────────┘
(1 row)
select nvals('int32:42'::scalar);
┌───────┐
│ nvals │
├───────┤
│ 1 │
└───────┘
(1 row)
Scalars can be combined with native Postgres types using standard operators. Addition: scalar + native
select 'int32:10'::scalar + 5;
┌──────────┐
│ ?column? │
├──────────┤
│ int32:15 │
└──────────┘
(1 row)
select 'fp64:3.14'::scalar + 2.0;
┌───────────────┐
│ ?column? │
├───────────────┤
│ fp64:5.140000 │
└───────────────┘
(1 row)
Addition: native + scalar
select 5 + 'int32:10'::scalar;
┌──────────┐
│ ?column? │
├──────────┤
│ 15 │
└──────────┘
(1 row)
select 2.0 + 'fp64:3.14'::scalar;
┌───────────────────┐
│ ?column? │
├───────────────────┤
│ 5.140000000000001 │
└───────────────────┘
(1 row)
Subtraction: scalar - native
select 'int32:20'::scalar - 5;
┌──────────┐
│ ?column? │
├──────────┤
│ int32:15 │
└──────────┘
(1 row)
select 'fp64:10.5'::scalar - 2.5;
┌───────────────┐
│ ?column? │
├───────────────┤
│ fp64:8.000000 │
└───────────────┘
(1 row)
Subtraction: native - scalar
select 30 - 'int32:10'::scalar;
┌──────────┐
│ ?column? │
├──────────┤
│ 20 │
└──────────┘
(1 row)
select 15.5 - 'fp64:5.5'::scalar;
┌──────────┐
│ ?column? │
├──────────┤
│ 10 │
└──────────┘
(1 row)
Multiplication: scalar * native
select 'int32:7'::scalar * 6;
┌──────────┐
│ ?column? │
├──────────┤
│ int32:42 │
└──────────┘
(1 row)
select 'fp64:2.5'::scalar * 3.0;
┌───────────────┐
│ ?column? │
├───────────────┤
│ fp64:7.500000 │
└───────────────┘
(1 row)
Multiplication: native * scalar
select 6 * 'int32:7'::scalar;
┌──────────┐
│ ?column? │
├──────────┤
│ 42 │
└──────────┘
(1 row)
select 3.0 * 'fp64:2.5'::scalar;
┌──────────┐
│ ?column? │
├──────────┤
│ 7.5 │
└──────────┘
(1 row)
Division: scalar / native
select 'int32:20'::scalar / 4;
┌──────────┐
│ ?column? │
├──────────┤
│ int32:5 │
└──────────┘
(1 row)
select 'fp64:10.0'::scalar / 2.5;
┌───────────────┐
│ ?column? │
├───────────────┤
│ fp64:4.000000 │
└───────────────┘
(1 row)
Division: native / scalar
select 100 / 'int32:5'::scalar;
┌──────────┐
│ ?column? │
├──────────┤
│ 20 │
└──────────┘
(1 row)
select 15.0 / 'fp64:3.0'::scalar;
┌──────────┐
│ ?column? │
├──────────┤
│ 5 │
└──────────┘
(1 row)
Convert between different scalar types and native Postgres types. Cast scalar to native type
select 'int32:42'::scalar::int4;
┌──────┐
│ int4 │
├──────┤
│ 42 │
└──────┘
(1 row)
select 'fp64:3.14'::scalar::float8;
┌────────┐
│ float8 │
├────────┤
│ 3.14 │
└────────┘
(1 row)
select 'bool:true'::scalar::bool;
┌──────┐
│ bool │
├──────┤
│ t │
└──────┘
(1 row)
Cast between scalar types (int to float)
select cast('int32:42'::scalar as scalar); -- stays int32
┌──────────┐
│ scalar │
├──────────┤
│ int32:42 │
└──────────┘
(1 row)
select 'int32:42'::scalar::int4::float8::scalar; -- through native
┌────────────────┐
│ scalar │
├────────────────┤
│ fp64:42.000000 │
└────────────────┘
(1 row)
Cast float to int (truncates)
select 'fp64:3.9'::scalar::int4;
┌──────┐
│ int4 │
├──────┤
│ 3 │
└──────┘
(1 row)
select 'fp64:-3.9'::scalar::int4;
┌──────┐
│ int4 │
├──────┤
│ -3 │
└──────┘
(1 row)
Cast bool to int
select 'bool:true'::scalar::int4;
┌──────┐
│ int4 │
├──────┤
│ 1 │
└──────┘
(1 row)
select 'bool:false'::scalar::int4;
┌──────┐
│ int4 │
├──────┤
│ 0 │
└──────┘
(1 row)
Cast int to bool (0=false, non-zero=true)
select 0::int::scalar::bool;
┌──────┐
│ bool │
├──────┤
│ f │
└──────┘
(1 row)
select 1::int::scalar::bool;
┌──────┐
│ bool │
├──────┤
│ t │
└──────┘
(1 row)
select 5::int::scalar::bool;
┌──────┐
│ bool │
├──────┤
│ t │
└──────┘
(1 row)
select (-1)::int::scalar::bool;
┌──────┐
│ bool │
├──────┤
│ t │
└──────┘
(1 row)
Cast between integer sizes
select 127::int2::scalar::int4; -- int16 to int32
┌──────┐
│ int4 │
├──────┤
│ 127 │
└──────┘
(1 row)
select 32767::int4::scalar::int8; -- int32 to int64
┌───────┐
│ int8 │
├───────┤
│ 32767 │
└───────┘
(1 row)
Test boundary values for integer types. INT16 (int2) boundaries
select (-32768)::int2::scalar as int16_min;
┌──────────────┐
│ int16_min │
├──────────────┤
│ int16:-32768 │
└──────────────┘
(1 row)
select 32767::int2::scalar as int16_max;
┌─────────────┐
│ int16_max │
├─────────────┤
│ int16:32767 │
└─────────────┘
(1 row)
select 0::int2::scalar as int16_zero;
┌────────────┐
│ int16_zero │
├────────────┤
│ int16:0 │
└────────────┘
(1 row)
INT32 (int4) boundaries
select (-2147483648)::int4::scalar as int32_min;
┌───────────────────┐
│ int32_min │
├───────────────────┤
│ int32:-2147483648 │
└───────────────────┘
(1 row)
select 2147483647::int4::scalar as int32_max;
┌──────────────────┐
│ int32_max │
├──────────────────┤
│ int32:2147483647 │
└──────────────────┘
(1 row)
select 0::int4::scalar as int32_zero;
┌────────────┐
│ int32_zero │
├────────────┤
│ int32:0 │
└────────────┘
(1 row)
INT64 (int8) boundaries
select (-9223372036854775808)::int8::scalar as int64_min;
┌────────────────────────────┐
│ int64_min │
├────────────────────────────┤
│ int64:-9223372036854775808 │
└────────────────────────────┘
(1 row)
select 9223372036854775807::int8::scalar as int64_max;
┌───────────────────────────┐
│ int64_max │
├───────────────────────────┤
│ int64:9223372036854775807 │
└───────────────────────────┘
(1 row)
select 0::int8::scalar as int64_zero;
┌────────────┐
│ int64_zero │
├────────────┤
│ int64:0 │
└────────────┘
(1 row)
Arithmetic near boundaries
select 'int32:2147483647'::scalar + 0 as at_max;
┌──────────────────┐
│ at_max │
├──────────────────┤
│ int32:2147483647 │
└──────────────────┘
(1 row)
select 'int32:-2147483648'::scalar + 0 as at_min;
┌───────────────────┐
│ at_min │
├───────────────────┤
│ int32:-2147483648 │
└───────────────────┘
(1 row)
Multiplication preserving range
select 'int32:1000'::scalar * 1000;
┌───────────────┐
│ ?column? │
├───────────────┤
│ int32:1000000 │
└───────────────┘
(1 row)
select 'int32:-1000'::scalar * 1000;
┌────────────────┐
│ ?column? │
├────────────────┤
│ int32:-1000000 │
└────────────────┘
(1 row)
Division by small values
select 'int32:1000'::scalar / 1;
┌────────────┐
│ ?column? │
├────────────┤
│ int32:1000 │
└────────────┘
(1 row)
select 'int32:1000'::scalar / 2;
┌───────────┐
│ ?column? │
├───────────┤
│ int32:500 │
└───────────┘
(1 row)
select 'int32:1000'::scalar / 3;
┌───────────┐
│ ?column? │
├───────────┤
│ int32:333 │
└───────────┘
(1 row)
Test special floating-point values. FP32 (float4) boundaries
select 'fp32:3.40282347e+38'::scalar as fp32_max;
┌─────────────────────────────────────────────────────┐
│ fp32_max │
├─────────────────────────────────────────────────────┤
│ fp32:340282346638528859811704183484516925440.000000 │
└─────────────────────────────────────────────────────┘
(1 row)
select 'fp32:-3.40282347e+38'::scalar as fp32_min;
┌──────────────────────────────────────────────────────┐
│ fp32_min │
├──────────────────────────────────────────────────────┤
│ fp32:-340282346638528859811704183484516925440.000000 │
└──────────────────────────────────────────────────────┘
(1 row)
select 'fp32:1.17549435e-38'::scalar as fp32_smallest_positive;
┌────────────────────────┐
│ fp32_smallest_positive │
├────────────────────────┤
│ fp32:0.000000 │
└────────────────────────┘
(1 row)
FP64 (float8) boundaries
select 'fp64:1.7976931348623157e+308'::scalar as fp64_max;
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ fp64_max │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ fp64:17976931348623157081452742373170435679807056752584499659891747680315726078002853876058955863276687817154045895351438246423 │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
(1 row)
select 'fp64:-1.7976931348623157e+308'::scalar as fp64_min;
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ fp64_min │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ fp64:-1797693134862315708145274237317043567980705675258449965989174768031572607800285387605895586327668781715404589535143824642 │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
(1 row)
select 'fp64:2.2250738585072014e-308'::scalar as fp64_smallest_positive;
┌────────────────────────┐
│ fp64_smallest_positive │
├────────────────────────┤
│ fp64:0.000000 │
└────────────────────────┘
(1 row)
Zero values
select 0.0::float4::scalar as fp32_zero;
┌───────────────┐
│ fp32_zero │
├───────────────┤
│ fp32:0.000000 │
└───────────────┘
(1 row)
select 0.0::float8::scalar as fp64_zero;
┌───────────────┐
│ fp64_zero │
├───────────────┤
│ fp64:0.000000 │
└───────────────┘
(1 row)
select (-0.0)::float8::scalar as fp64_negative_zero;
┌────────────────────┐
│ fp64_negative_zero │
├────────────────────┤
│ fp64:0.000000 │
└────────────────────┘
(1 row)
Infinity
select 'Infinity'::float8::scalar as positive_infinity;
┌───────────────────┐
│ positive_infinity │
├───────────────────┤
│ fp64:Infinity │
└───────────────────┘
(1 row)
select '-Infinity'::float8::scalar as negative_infinity;
┌───────────────────┐
│ negative_infinity │
├───────────────────┤
│ fp64:-Infinity │
└───────────────────┘
(1 row)
NaN (Not a Number)
select 'NaN'::float8::scalar as not_a_number;
┌──────────────┐
│ not_a_number │
├──────────────┤
│ fp64:NaN │
└──────────────┘
(1 row)
Arithmetic with special values
select 'fp64:1.0'::scalar + 'Infinity'::float8;
┌───────────────┐
│ ?column? │
├───────────────┤
│ fp64:Infinity │
└───────────────┘
(1 row)
select 'fp64:1.0'::scalar * 'Infinity'::float8;
┌───────────────┐
│ ?column? │
├───────────────┤
│ fp64:Infinity │
└───────────────┘
(1 row)
select 'fp64:1.0'::scalar / 'Infinity'::float8;
┌───────────────┐
│ ?column? │
├───────────────┤
│ fp64:0.000000 │
└───────────────┘
(1 row)
select 'Infinity'::float8 / 'fp64:2.0'::scalar;
┌──────────┐
│ ?column? │
├──────────┤
│ Infinity │
└──────────┘
(1 row)
Operations producing NaN
select 'fp64:0.0'::scalar / 0.0; -- 0/0 = NaN
┌──────────┐
│ ?column? │
├──────────┤
│ fp64:NaN │
└──────────┘
(1 row)
select 'Infinity'::float8 - 'Infinity'::float8::scalar; -- Inf - Inf = NaN
┌──────────┐
│ ?column? │
├──────────┤
│ NaN │
└──────────┘
(1 row)
Very small numbers
select 'fp64:1e-100'::scalar * 1e-100;
┌───────────────┐
│ ?column? │
├───────────────┤
│ fp64:0.000000 │
└───────────────┘
(1 row)
select 'fp64:1e-200'::scalar + 1e-200;
┌───────────────┐
│ ?column? │
├───────────────┤
│ fp64:0.000000 │
└───────────────┘
(1 row)
Very large numbers
select 'fp64:1e100'::scalar * 1.0;
┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ?column? │
├───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ fp64:10000000000000000159028911097599180468360808563945281389781327557747838772170381060813469985856815104.000000 │
└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
(1 row)
select 'fp64:1e200'::scalar + 0.0;
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ?column? │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ fp64:99999999999999996973312221251036165947450327545502362648241750950346848435554075534196338404706251868027512415973882408182 │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
(1 row)
Test boolean scalar operations. Boolean construction
select true::bool::scalar;
┌────────┐
│ scalar │
├────────┤
│ bool:t │
└────────┘
(1 row)
select false::bool::scalar;
┌────────┐
│ scalar │
├────────┤
│ bool:f │
└────────┘
(1 row)
Boolean with different representations
select 't'::bool::scalar;
┌────────┐
│ scalar │
├────────┤
│ bool:t │
└────────┘
(1 row)
select 'f'::bool::scalar;
┌────────┐
│ scalar │
├────────┤
│ bool:f │
└────────┘
(1 row)
select 'yes'::bool::scalar;
┌────────┐
│ scalar │
├────────┤
│ bool:t │
└────────┘
(1 row)
select 'no'::bool::scalar;
┌────────┐
│ scalar │
├────────┤
│ bool:f │
└────────┘
(1 row)
Boolean casting
select true::bool::scalar::bool;
┌──────┐
│ bool │
├──────┤
│ t │
└──────┘
(1 row)
select false::bool::scalar::bool;
┌──────┐
│ bool │
├──────┤
│ f │
└──────┘
(1 row)
Boolean to int conversion
select true::bool::scalar::int4 as true_as_int;
┌─────────────┐
│ true_as_int │
├─────────────┤
│ 1 │
└─────────────┘
(1 row)
select false::bool::scalar::int4 as false_as_int;
┌──────────────┐
│ false_as_int │
├──────────────┤
│ 0 │
└──────────────┘
(1 row)
Int to boolean conversion
select 0::int4::scalar::bool as zero_as_bool;
┌──────────────┐
│ zero_as_bool │
├──────────────┤
│ f │
└──────────────┘
(1 row)
select 1::int4::scalar::bool as one_as_bool;
┌─────────────┐
│ one_as_bool │
├─────────────┤
│ t │
└─────────────┘
(1 row)
select 42::int4::scalar::bool as nonzero_as_bool;
┌─────────────────┐
│ nonzero_as_bool │
├─────────────────┤
│ t │
└─────────────────┘
(1 row)
select (-1)::int4::scalar::bool as negative_as_bool;
┌──────────────────┐
│ negative_as_bool │
├──────────────────┤
│ t │
└──────────────────┘
(1 row)
Test the set() function to update scalar values. Basic set operation
select set('int32:42'::scalar, 100);
┌───────────┐
│ set │
├───────────┤
│ int32:100 │
└───────────┘
(1 row)
Set with different types
select set('fp64:3.14'::scalar, 2.71);
┌───────────────┐
│ set │
├───────────────┤
│ fp64:2.710000 │
└───────────────┘
(1 row)
select set('bool:true'::scalar, false);
┌────────┐
│ set │
├────────┤
│ bool:f │
└────────┘
(1 row)
Set on empty scalar
select set('int32'::scalar, 42);
┌──────────┐
│ set │
├──────────┤
│ int32:42 │
└──────────┘
(1 row)
Set to zero
select set('int32:42'::scalar, 0);
┌─────────┐
│ set │
├─────────┤
│ int32:0 │
└─────────┘
(1 row)
Set to negative
select set('int32:42'::scalar, -100);
┌────────────┐
│ set │
├────────────┤
│ int32:-100 │
└────────────┘
(1 row)
Set boundary values
select set('int32:0'::scalar, 2147483647);
┌──────────────────┐
│ set │
├──────────────────┤
│ int32:2147483647 │
└──────────────────┘
(1 row)
select set('int32:0'::scalar, -2147483648);
┌───────────────────┐
│ set │
├───────────────────┤
│ int32:-2147483648 │
└───────────────────┘
(1 row)
Set float values
select set('fp64:0.0'::scalar, 'Infinity'::float8);
┌───────────────┐
│ set │
├───────────────┤
│ fp64:Infinity │
└───────────────┘
(1 row)
select set('fp64:0.0'::scalar, 'NaN'::float8);
┌──────────┐
│ set │
├──────────┤
│ fp64:NaN │
└──────────┘
(1 row)
select set('fp64:0.0'::scalar, -0.0);
┌───────────────┐
│ set │
├───────────────┤
│ fp64:0.000000 │
└───────────────┘
(1 row)
Test other scalar utility functions. Print scalar value
select print('int32:42'::scalar);
┌───────┐
│ print │
├───────┤
│ 42 │
└───────┘
(1 row)
select print('fp64:3.14'::scalar);
┌──────────┐
│ print │
├──────────┤
│ 3.140000 │
└──────────┘
(1 row)
select print('bool:true'::scalar);
┌───────┐
│ print │
├───────┤
│ t │
└───────┘
(1 row)
Print empty scalar
select print('int32'::scalar);
┌───────┐
│ print │
├───────┤
│ │
└───────┘
(1 row)
Get scalar type
select type('int32:42'::scalar);
┌───────┐
│ type │
├───────┤
│ int32 │
└───────┘
(1 row)
select type('fp64:3.14'::scalar);
┌──────┐
│ type │
├──────┤
│ fp64 │
└──────┘
(1 row)
select type('bool:true'::scalar);
┌──────┐
│ type │
├──────┤
│ bool │
└──────┘
(1 row)
select type('int16:1'::scalar);
┌───────┐
│ type │
├───────┤
│ int16 │
└───────┘
(1 row)
Count values (always 0 or 1 for scalars)
select nvals('int32:42'::scalar) as has_value;
┌───────────┐
│ has_value │
├───────────┤
│ 1 │
└───────────┘
(1 row)
select nvals('int32'::scalar) as empty;
┌───────┐
│ empty │
├───────┤
│ 0 │
└───────┘
(1 row)
Duplicate scalar
select dup('int32:42'::scalar);
┌──────────┐
│ dup │
├──────────┤
│ int32:42 │
└──────────┘
(1 row)
select dup('fp64:3.14'::scalar);
┌───────────────┐
│ dup │
├───────────────┤
│ fp64:3.140000 │
└───────────────┘
(1 row)
Wait for scalar (synchronization in async mode)
select wait('int32:42'::scalar);
┌──────────┐
│ wait │
├──────────┤
│ int32:42 │
└──────────┘
(1 row)
Clear scalar (removes value)
select nvals(clear('int32:42'::scalar));
┌───────┐
│ nvals │
├───────┤
│ 0 │
└───────┘
(1 row)
select clear('int32:42'::scalar);
┌───────┐
│ clear │
├───────┤
│ int32 │
└───────┘
(1 row)
Clear already empty scalar
select clear('int32'::scalar);
┌───────┐
│ clear │
├───────┤
│ int32 │
└───────┘
(1 row)
Test how scalars interact with different native types. Int32 scalar with different int sizes
select 'int32:100'::scalar + 1::int2; -- scalar + int16
┌───────────┐
│ ?column? │
├───────────┤
│ int16:101 │
└───────────┘
(1 row)
select 'int32:100'::scalar + 1::int4; -- scalar + int32
┌───────────┐
│ ?column? │
├───────────┤
│ int32:101 │
└───────────┘
(1 row)
select 'int32:100'::scalar + 1::int8; -- scalar + int64
┌───────────┐
│ ?column? │
├───────────┤
│ int64:101 │
└───────────┘
(1 row)
Float scalar with different float sizes
select 'fp64:3.14'::scalar + 1.0::float4; -- scalar + float32
┌───────────────┐
│ ?column? │
├───────────────┤
│ fp32:4.140000 │
└───────────────┘
(1 row)
select 'fp64:3.14'::scalar + 1.0::float8; -- scalar + float64
┌───────────────┐
│ ?column? │
├───────────────┤
│ fp64:4.140000 │
└───────────────┘
(1 row)
Int scalar with float (promotes to float)
select 'int32:10'::scalar + 3.14::float8;
┌────────────────┐
│ ?column? │
├────────────────┤
│ fp64:13.140000 │
└────────────────┘
(1 row)
Small int with large int
select 1::int2 + 'int32:100'::scalar; -- int16 + scalar
┌──────────┐
│ ?column? │
├──────────┤
│ 101 │
└──────────┘
(1 row)
select 1::int8 + 'int32:100'::scalar; -- int64 + scalar
┌──────────┐
│ ?column? │
├──────────┤
│ 101 │
└──────────┘
(1 row)
While scalars don't have direct comparison operators, they can be extracted and compared as native types. Extract and compare
select ('int32:10'::scalar::int4) = 10;
┌──────────┐
│ ?column? │
├──────────┤
│ t │
└──────────┘
(1 row)
select ('int32:10'::scalar::int4) > 5;
┌──────────┐
│ ?column? │
├──────────┤
│ t │
└──────────┘
(1 row)
select ('int32:10'::scalar::int4) < 20;
┌──────────┐
│ ?column? │
├──────────┤
│ t │
└──────────┘
(1 row)
Compare two scalar values via extraction
select ('int32:10'::scalar::int4) = ('int32:10'::scalar::int4);
┌──────────┐
│ ?column? │
├──────────┤
│ t │
└──────────┘
(1 row)
select ('int32:10'::scalar::int4) < ('int32:20'::scalar::int4);
┌──────────┐
│ ?column? │
├──────────┤
│ t │
└──────────┘
(1 row)
Compare floats
select ('fp64:3.14'::scalar::float8) = 3.14;
┌──────────┐
│ ?column? │
├──────────┤
│ t │
└──────────┘
(1 row)
select ('fp64:3.14'::scalar::float8) > 3.0;
┌──────────┐
│ ?column? │
├──────────┤
│ t │
└──────────┘
(1 row)
Compare booleans
select ('bool:true'::scalar::bool) = true;
┌──────────┐
│ ?column? │
├──────────┤
│ t │
└──────────┘
(1 row)
select ('bool:false'::scalar::bool) = false;
┌──────────┐
│ ?column? │
├──────────┤
│ t │
└──────────┘
(1 row)
Test division edge cases and error conditions. Integer division truncates
select 'int32:7'::scalar / 2;
┌──────────┐
│ ?column? │
├──────────┤
│ int32:3 │
└──────────┘
(1 row)
select 'int32:7'::scalar / 3;
┌──────────┐
│ ?column? │
├──────────┤
│ int32:2 │
└──────────┘
(1 row)
select 'int32:-7'::scalar / 2;
┌──────────┐
│ ?column? │
├──────────┤
│ int32:-3 │
└──────────┘
(1 row)
Division by 1 and -1
select 'int32:42'::scalar / 1;
┌──────────┐
│ ?column? │
├──────────┤
│ int32:42 │
└──────────┘
(1 row)
select 'int32:42'::scalar / -1;
┌───────────┐
│ ?column? │
├───────────┤
│ int32:-42 │
└───────────┘
(1 row)
Float division
select 'fp64:7.0'::scalar / 2.0;
┌───────────────┐
│ ?column? │
├───────────────┤
│ fp64:3.500000 │
└───────────────┘
(1 row)
select 'fp64:1.0'::scalar / 3.0;
┌───────────────┐
│ ?column? │
├───────────────┤
│ fp64:0.333333 │
└───────────────┘
(1 row)
Division producing very small results
select 'fp64:1.0'::scalar / 1e100;
┌───────────────┐
│ ?column? │
├───────────────┤
│ fp64:0.000000 │
└───────────────┘
(1 row)
Division producing very large results
select 'fp64:1e100'::scalar / 0.001;
┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ?column? │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ fp64:10000000000000000019156750857346687362159551272651920111528035145993793242039887559612361451081803235328.000000 │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
(1 row)
Test how scalars interact with SQL NULLs. NULL cast to scalar produces NULL
select NULL::int::scalar;
┌────────┐
│ scalar │
├────────┤
│ int32 │
└────────┘
(1 row)
Scalar operations with NULL
select 'int32:42'::scalar + NULL::int;
ERROR: Cannot pass NULL to scalar_plus_int32
select NULL::int + 'int32:42'::scalar;
ERROR: Cannot pass NULL to plus_scalar_int32
Set with NULL (should fail or create empty scalar) Note: This may error depending on implementation select set('int32:42'::scalar, NULL::int);
Test that values survive round-trip conversions. Int round-trips
select 42::int4::scalar::int4;
┌──────┐
│ int4 │
├──────┤
│ 42 │
└──────┘
(1 row)
select (-42)::int4::scalar::int4;
┌──────┐
│ int4 │
├──────┤
│ -42 │
└──────┘
(1 row)
select 0::int4::scalar::int4;
┌──────┐
│ int4 │
├──────┤
│ 0 │
└──────┘
(1 row)
Float round-trips (may have precision differences)
select 3.14::float8::scalar::float8;
┌────────┐
│ float8 │
├────────┤
│ 3.14 │
└────────┘
(1 row)
select (-3.14)::float8::scalar::float8;
┌────────┐
│ float8 │
├────────┤
│ -3.14 │
└────────┘
(1 row)
select 0.0::float8::scalar::float8;
┌────────┐
│ float8 │
├────────┤
│ 0 │
└────────┘
(1 row)
Bool round-trips
select true::bool::scalar::bool;
┌──────┐
│ bool │
├──────┤
│ t │
└──────┘
(1 row)
select false::bool::scalar::bool;
┌──────┐
│ bool │
├──────┤
│ f │
└──────┘
(1 row)
Large int round-trips
select 2147483647::int4::scalar::int4;
┌────────────┐
│ int4 │
├────────────┤
│ 2147483647 │
└────────────┘
(1 row)
select (-2147483648)::int4::scalar::int4;
┌─────────────┐
│ int4 │
├─────────────┤
│ -2147483648 │
└─────────────┘
(1 row)
Special float round-trips
select 'Infinity'::float8::scalar::float8;
┌──────────┐
│ float8 │
├──────────┤
│ Infinity │
└──────────┘
(1 row)
select '-Infinity'::float8::scalar::float8;
┌───────────┐
│ float8 │
├───────────┤
│ -Infinity │
└───────────┘
(1 row)
select 'NaN'::float8::scalar::float8;
┌────────┐
│ float8 │
├────────┤
│ NaN │
└────────┘
(1 row)
Test precision maintenance across operations. Float precision
select 'fp64:0.1'::scalar + 0.2; -- famous 0.3 problem
┌───────────────┐
│ ?column? │
├───────────────┤
│ fp64:0.300000 │
└───────────────┘
(1 row)
select 'fp64:1.0'::scalar / 3.0 * 3.0; -- should be close to 1.0
┌───────────────┐
│ ?column? │
├───────────────┤
│ fp64:1.000000 │
└───────────────┘
(1 row)
Very precise values
select 'fp64:3.141592653589793'::scalar::float8;
┌───────────────────┐
│ float8 │
├───────────────────┤
│ 3.141592653589793 │
└───────────────────┘
(1 row)
Addition of very different magnitudes
select 'fp64:1e20'::scalar + 1.0;
┌───────────────────────────────────┐
│ ?column? │
├───────────────────────────────────┤
│ fp64:100000000000000000000.000000 │
└───────────────────────────────────┘
(1 row)
select 'fp64:1.0'::scalar + 1e-20;
┌───────────────┐
│ ?column? │
├───────────────┤
│ fp64:1.000000 │
└───────────────┘
(1 row)
Subtraction producing small differences
select 'fp64:1.000000001'::scalar - 1.0;
┌───────────────┐
│ ?column? │
├───────────────┤
│ fp64:0.000000 │
└───────────────┘
(1 row)
Test internal representation details. Empty scalars should be lightweight
select nvals('int32'::scalar);
┌───────┐
│ nvals │
├───────┤
│ 0 │
└───────┘
(1 row)
select nvals('fp64'::scalar);
┌───────┐
│ nvals │
├───────┤
│ 0 │
└───────┘
(1 row)
select nvals('bool'::scalar);
┌───────┐
│ nvals │
├───────┤
│ 0 │
└───────┘
(1 row)
Scalars with values
select nvals('int32:0'::scalar); -- zero is still a value
┌───────┐
│ nvals │
├───────┤
│ 1 │
└───────┘
(1 row)
select nvals('fp64:0.0'::scalar);
┌───────┐
│ nvals │
├───────┤
│ 1 │
└───────┘
(1 row)
select nvals('bool:false'::scalar);
┌───────┐
│ nvals │
├───────┤
│ 1 │
└───────┘
(1 row)
Type information preserved
select type('int32'::scalar);
┌───────┐
│ type │
├───────┤
│ int32 │
└───────┘
(1 row)
select type('int32:42'::scalar);
┌───────┐
│ type │
├───────┤
│ int32 │
└───────┘
(1 row)
Value preserved after dup
select 'int32:42'::scalar::int4;
┌──────┐
│ int4 │
├──────┤
│ 42 │
└──────┘
(1 row)
select dup('int32:42'::scalar)::int4;
┌─────┐
│ dup │
├─────┤
│ 42 │
└─────┘
(1 row)
Test scalar parameters and results in vector operations. Vector apply with scalar (apply_first: scalar op vector)
select apply(5::int, 'int32(5)[0:10 1:20 2:30]'::vector, 'plus_int32'::binaryop);
┌──────────────────────────┐
│ apply │
├──────────────────────────┤
│ int32(5)[0:15 1:25 2:35] │
└──────────────────────────┘
(1 row)
select apply(10::int, 'int32(5)[0:1 1:2 2:3 3:4 4:5]'::vector, 'times_int32'::binaryop);
┌────────────────────────────────────┐
│ apply │
├────────────────────────────────────┤
│ int32(5)[0:10 1:20 2:30 3:40 4:50] │
└────────────────────────────────────┘
(1 row)
select apply(100::int, 'int32(5)[0:10 1:20 2:30]'::vector, 'minus_int32'::binaryop);
┌──────────────────────────┐
│ apply │
├──────────────────────────┤
│ int32(5)[0:90 1:80 2:70] │
└──────────────────────────┘
(1 row)
Vector apply with scalar (apply_second: vector op scalar)
select apply('int32(5)[0:10 1:20 2:30]'::vector, 5::int, 'plus_int32'::binaryop);
┌──────────────────────────┐
│ apply │
├──────────────────────────┤
│ int32(5)[0:15 1:25 2:35] │
└──────────────────────────┘
(1 row)
select apply('int32(5)[0:1 1:2 2:3 3:4 4:5]'::vector, 10::int, 'times_int32'::binaryop);
┌────────────────────────────────────┐
│ apply │
├────────────────────────────────────┤
│ int32(5)[0:10 1:20 2:30 3:40 4:50] │
└────────────────────────────────────┘
(1 row)
select apply('int32(5)[0:100 1:200 2:300]'::vector, 50::int, 'minus_int32'::binaryop);
┌────────────────────────────┐
│ apply │
├────────────────────────────┤
│ int32(5)[0:50 1:150 2:250] │
└────────────────────────────┘
(1 row)
Vector apply with float scalar
select apply(2.5::double precision, 'fp64(5)[0:1.0 1:2.0 2:3.0]'::vector, 'times_fp64'::binaryop);
┌───────────────────────────────────────────┐
│ apply │
├───────────────────────────────────────────┤
│ fp64(5)[0:2.500000 1:5.000000 2:7.500000] │
└───────────────────────────────────────────┘
(1 row)
select apply('fp64(5)[0:10.0 1:20.0 2:30.0]'::vector, 5.0::double precision, 'div_fp64'::binaryop);
┌───────────────────────────────────────────┐
│ apply │
├───────────────────────────────────────────┤
│ fp64(5)[0:2.000000 1:4.000000 2:6.000000] │
└───────────────────────────────────────────┘
(1 row)
Vector set_element with scalar value
select set_element('int32(10)[0:1 2:3 4:5]'::vector, 1, 100::int);
┌──────────────────────────────┐
│ set_element │
├──────────────────────────────┤
│ int32(10)[0:1 1:100 2:3 4:5] │
└──────────────────────────────┘
(1 row)
select set_element('int32(10)[0:1 2:3 4:5]'::vector, 5, 42::int);
┌─────────────────────────────┐
│ set_element │
├─────────────────────────────┤
│ int32(10)[0:1 2:3 4:5 5:42] │
└─────────────────────────────┘
(1 row)
select set_element('fp64(5)[0:1.5 2:3.5]'::vector, 3, 2.71::double precision);
┌───────────────────────────────────────────┐
│ set_element │
├───────────────────────────────────────────┤
│ fp64(5)[0:1.500000 2:3.500000 3:2.710000] │
└───────────────────────────────────────────┘
(1 row)
Vector get_element returns scalar (conceptually)
select get_element('int32[0:10 1:20 2:30]'::vector, 1);
┌─────────────┐
│ get_element │
├─────────────┤
│ int32:20 │
└─────────────┘
(1 row)
select get_element('fp64[0:1.5 1:2.5 2:3.5]'::vector, 2);
┌───────────────┐
│ get_element │
├───────────────┤
│ fp64:3.500000 │
└───────────────┘
(1 row)
select get_element('bool[0:true 1:false 2:true]'::vector, 0);
┌─────────────┐
│ get_element │
├─────────────┤
│ bool:t │
└─────────────┘
(1 row)
Test scalar parameters in matrix operations. Matrix set_element with scalar value
select set_element('int32(3,3)[0:0:10 1:1:20 2:2:30]'::matrix, 0, 1, 15::int);
┌────────────────────────────────────────┐
│ set_element │
├────────────────────────────────────────┤
│ int32(3:)[0:0:10 0:1:15 1:1:20 2:2:30] │
└────────────────────────────────────────┘
(1 row)
select set_element('fp64(3,3)[0:0:1.5 1:1:2.5]'::matrix, 2, 2, 3.14::double precision);
┌──────────────────────────────────────────────────┐
│ set_element │
├──────────────────────────────────────────────────┤
│ fp64(3:)[0:0:1.500000 1:1:2.500000 2:2:3.140000] │
└──────────────────────────────────────────────────┘
(1 row)
Matrix get_element returns scalar (conceptually)
select get_element('int32[0:0:10 0:1:15 1:0:20 1:1:25]'::matrix, 0, 1);
┌─────────────┐
│ get_element │
├─────────────┤
│ int32:15 │
└─────────────┘
(1 row)
select get_element('fp64[0:0:1.5 1:1:2.5 2:2:3.5]'::matrix, 1, 1);
┌───────────────┐
│ get_element │
├───────────────┤
│ fp64:2.500000 │
└───────────────┘
(1 row)
Matrix apply with scalar (apply_first: scalar op matrix)
select apply(10::int, 'int32(3,3)[0:0:1 1:1:2 2:2:3]'::matrix, 'times_int32'::binaryop);
┌─────────────────────────────────┐
│ apply │
├─────────────────────────────────┤
│ int32(3:)[0:0:10 1:1:20 2:2:30] │
└─────────────────────────────────┘
(1 row)
select apply(100::int, 'int32(3,3)[0:0:10 0:1:20 1:0:30]'::matrix, 'minus_int32'::binaryop);
┌─────────────────────────────────┐
│ apply │
├─────────────────────────────────┤
│ int32(3:)[0:0:90 0:1:80 1:0:70] │
└─────────────────────────────────┘
(1 row)
Matrix apply with scalar (apply_second: matrix op scalar)
select apply('int32(3,3)[0:0:10 1:1:20 2:2:30]'::matrix, 5::int, 'plus_int32'::binaryop);
┌─────────────────────────────────┐
│ apply │
├─────────────────────────────────┤
│ int32(3:)[0:0:15 1:1:25 2:2:35] │
└─────────────────────────────────┘
(1 row)
select apply('fp64(3,3)[0:0:2.0 1:1:4.0 2:2:6.0]'::matrix, 2.0::double precision, 'div_fp64'::binaryop);
┌──────────────────────────────────────────────────┐
│ apply │
├──────────────────────────────────────────────────┤
│ fp64(3:)[0:0:1.000000 1:1:2.000000 2:2:3.000000] │
└──────────────────────────────────────────────────┘
(1 row)
Operations that reduce vectors or matrices to scalars. Vector reduce to scalar
select reduce_scalar('int32[0:10 1:20 2:30]'::vector, 'plus_monoid_int32'::monoid);
┌───────────────┐
│ reduce_scalar │
├───────────────┤
│ int32:60 │
└───────────────┘
(1 row)
select reduce_scalar('int32[0:5 1:10 2:15 3:20]'::vector, 'times_monoid_int32'::monoid);
┌───────────────┐
│ reduce_scalar │
├───────────────┤
│ int32:15000 │
└───────────────┘
(1 row)
select reduce_scalar('fp64[0:1.5 1:2.5 2:3.5]'::vector, 'plus_monoid_fp64'::monoid);
┌───────────────┐
│ reduce_scalar │
├───────────────┤
│ fp64:7.500000 │
└───────────────┘
(1 row)
Vector reduce with different monoids
select reduce_scalar('int32[0:10 1:5 2:20 3:15]'::vector, 'max_monoid_int32'::monoid);
┌───────────────┐
│ reduce_scalar │
├───────────────┤
│ int32:20 │
└───────────────┘
(1 row)
select reduce_scalar('int32[0:10 1:5 2:20 3:15]'::vector, 'min_monoid_int32'::monoid);
┌───────────────┐
│ reduce_scalar │
├───────────────┤
│ int32:5 │
└───────────────┘
(1 row)
Matrix reduce to scalar
select reduce_scalar('int32[0:0:1 0:1:2 1:0:3 1:1:4]'::matrix, 'plus_monoid_int32'::monoid);
┌───────────────┐
│ reduce_scalar │
├───────────────┤
│ int32:10 │
└───────────────┘
(1 row)
select reduce_scalar('fp64[0:0:1.5 0:1:2.5 1:0:3.5 1:1:4.5]'::matrix, 'times_monoid_fp64'::monoid);
┌────────────────┐
│ reduce_scalar │
├────────────────┤
│ fp64:59.062500 │
└────────────────┘
(1 row)
Reduce with identity returns identity for empty
select reduce_scalar('int32(10)[]'::vector, 'plus_monoid_int32'::monoid);
┌───────────────┐
│ reduce_scalar │
├───────────────┤
│ int32 │
└───────────────┘
(1 row)
select reduce_scalar('int32(5,5)[]'::matrix, 'times_monoid_int32'::monoid);
┌───────────────┐
│ reduce_scalar │
├───────────────┤
│ int32 │
└───────────────┘
(1 row)
Use scalars as comparison thresholds in select operations. Vector select with scalar threshold
select choose('int32(10)[0:5 1:15 2:10 3:20 4:8]'::vector, 'valuelt_int32'::indexunaryop, 10::int);
┌────────────────────┐
│ choose │
├────────────────────┤
│ int32(10)[0:5 4:8] │
└────────────────────┘
(1 row)
select choose('int32(10)[0:5 1:15 2:10 3:20 4:8]'::vector, 'valuegt_int32'::indexunaryop, 10::int);
┌──────────────────────┐
│ choose │
├──────────────────────┤
│ int32(10)[1:15 3:20] │
└──────────────────────┘
(1 row)
select choose('int32(10)[0:5 1:15 2:10 3:20 4:8]'::vector, 'valuege_int32'::indexunaryop, 10::int);
┌───────────────────────────┐
│ choose │
├───────────────────────────┤
│ int32(10)[1:15 2:10 3:20] │
└───────────────────────────┘
(1 row)
select choose('int32(10)[0:5 1:15 2:10 3:20 4:8]'::vector, 'valuele_int32'::indexunaryop, 10::int);
┌─────────────────────────┐
│ choose │
├─────────────────────────┤
│ int32(10)[0:5 2:10 4:8] │
└─────────────────────────┘
(1 row)
select choose('int32(10)[0:5 1:15 2:10 3:20 4:8]'::vector, 'valueeq_int32'::indexunaryop, 10::int);
┌─────────────────┐
│ choose │
├─────────────────┤
│ int32(10)[2:10] │
└─────────────────┘
(1 row)
select choose('int32(10)[0:5 1:15 2:10 3:20 4:8]'::vector, 'valuene_int32'::indexunaryop, 10::int);
┌──────────────────────────────┐
│ choose │
├──────────────────────────────┤
│ int32(10)[0:5 1:15 3:20 4:8] │
└──────────────────────────────┘
(1 row)
Float vector select with float threshold
select choose('fp64(5)[0:1.5 1:2.5 2:1.0 3:3.5 4:2.0]'::vector, 'valuegt_fp64'::indexunaryop, 2.0::double precision);
┌────────────────────────────────┐
│ choose │
├────────────────────────────────┤
│ fp64(5)[1:2.500000 3:3.500000] │
└────────────────────────────────┘
(1 row)
select choose('fp64(5)[0:1.5 1:2.5 2:1.0 3:3.5 4:2.0]'::vector, 'valuele_fp64'::indexunaryop, 2.0::double precision);
┌───────────────────────────────────────────┐
│ choose │
├───────────────────────────────────────────┤
│ fp64(5)[0:1.500000 2:1.000000 4:2.000000] │
└───────────────────────────────────────────┘
(1 row)
Matrix select with scalar threshold
select choose('int32(4,4)[0:0:5 0:1:15 1:0:10 1:1:20 2:2:8]'::matrix, 'valuegt_int32'::indexunaryop, 10::int);
┌──────────────────────────┐
│ choose │
├──────────────────────────┤
│ int32(4:)[0:1:15 1:1:20] │
└──────────────────────────┘
(1 row)
select choose('fp64(3,3)[0:0:1.5 1:1:2.5 2:2:3.5]'::matrix, 'valuele_fp64'::indexunaryop, 2.0::double precision);
┌────────────────────────┐
│ choose │
├────────────────────────┤
│ fp64(3:)[0:0:1.500000] │
└────────────────────────┘
(1 row)
eunion uses scalar defaults for missing values. Vector eunion with scalar defaults
select eunion('int32(5)[0:10 2:30]'::vector,
5::int,
'int32(5)[1:20 3:40]'::vector,
7::int,
'plus_int32'::binaryop);
┌───────────────────────────────┐
│ eunion │
├───────────────────────────────┤
│ int32(5)[0:17 1:25 2:37 3:45] │
└───────────────────────────────┘
(1 row)
select eunion('fp64(5)[0:1.5 2:3.5]'::vector,
2.0::double precision,
'fp64(5)[1:2.5 3:4.5]'::vector,
3.0::double precision,
'times_fp64'::binaryop);
┌───────────────────────────────────────────────────────┐
│ eunion │
├───────────────────────────────────────────────────────┤
│ fp64(5)[0:4.500000 1:5.000000 2:10.500000 3:9.000000] │
└───────────────────────────────────────────────────────┘
(1 row)
Matrix eunion with scalar defaults
select eunion('int32(3,3)[0:0:10 1:1:20]'::matrix,
0::int,
'int32(3,3)[0:1:15 2:2:30]'::matrix,
0::int,
'plus_int32'::binaryop);
┌────────────────────────────────────────┐
│ eunion │
├────────────────────────────────────────┤
│ int32(3:)[0:0:10 0:1:15 1:1:20 2:2:30] │
└────────────────────────────────────────┘
(1 row)
eunion with different default values
select eunion('int32(5)[0:10 2:30]'::vector,
0::int,
'int32(5)[1:20 3:40]'::vector,
100::int,
'plus_int32'::binaryop);
┌─────────────────────────────────┐
│ eunion │
├─────────────────────────────────┤
│ int32(5)[0:110 1:20 2:130 3:40] │
└─────────────────────────────────┘
(1 row)
Test how scalars interact across different types. int32 scalar with int64 vector
select apply(5::int4, 'int64(5)[0:100 1:200 2:300]'::vector, 'plus_int64'::binaryop);
┌─────────────────────────────┐
│ apply │
├─────────────────────────────┤
│ int64(5)[0:105 1:205 2:305] │
└─────────────────────────────┘
(1 row)
int64 scalar with int32 vector
select apply(1000::int8, 'int32(5)[0:10 1:20 2:30]'::vector, 'times_int32'::binaryop);
┌───────────────────────────────────┐
│ apply │
├───────────────────────────────────┤
│ int32(5)[0:10000 1:20000 2:30000] │
└───────────────────────────────────┘
(1 row)
float scalar with int vector (via native operations)
select 'int32(5)[0:10 1:20 2:30]'::vector + 5::int;
┌──────────────────────────┐
│ ?column? │
├──────────────────────────┤
│ int32(5)[0:15 1:25 2:35] │
└──────────────────────────┘
(1 row)
select 'fp64(5)[0:1.5 1:2.5 2:3.5]'::vector * 2.0::double precision;
┌───────────────────────────────────────────┐
│ ?column? │
├───────────────────────────────────────────┤
│ fp64(5)[0:3.000000 1:5.000000 2:7.000000] │
└───────────────────────────────────────────┘
(1 row)
While scalars aren't directly used as accumulators, test accumulator functionality with scalar results. Reduction with different accumulators would accumulate intermediate scalars (though GraphBLAS handles this internally) Test that accumulation works correctly
select reduce_scalar(apply('int32[0:1 1:2 2:3]'::vector, 'minv_int32'::unaryop), 'plus_monoid_int32'::monoid);
┌───────────────┐
│ reduce_scalar │
├───────────────┤
│ int32:1 │
└───────────────┘
(1 row)
Test scalar operations with descriptors (limited applicability). Matrix/vector operations with scalars typically don't use descriptors, but verify they work when provided
select apply(10::int, 'int32(5)[0:1 1:2 2:3]'::vector, 'plus_int32'::binaryop);
┌──────────────────────────┐
│ apply │
├──────────────────────────┤
│ int32(5)[0:11 1:12 2:13] │
└──────────────────────────┘
(1 row)
Test utility functions in integration contexts. Print scalars from reductions
select print(reduce_scalar('int32[0:10 1:20 2:30]'::vector, 'plus_monoid_int32'::monoid)::scalar);
┌───────┐
│ print │
├───────┤
│ 60 │
└───────┘
(1 row)
Check type of reduced scalar
select type(reduce_scalar('fp64[0:1.5 1:2.5 2:3.5]'::vector, 'plus_monoid_fp64'::monoid)::scalar);
┌──────┐
│ type │
├──────┤
│ fp64 │
└──────┘
(1 row)
Test scalar operations on empty structures. Empty vector with scalar
select apply(10::int, 'int32(5)[]'::vector, 'plus_int32'::binaryop);
┌──────────┐
│ apply │
├──────────┤
│ int32(5) │
└──────────┘
(1 row)
select apply('int32(5)[]'::vector, 5::int, 'times_int32'::binaryop);
┌──────────┐
│ apply │
├──────────┤
│ int32(5) │
└──────────┘
(1 row)
Reduce empty vector to scalar
select reduce_scalar('int32(10)[]'::vector, 'plus_monoid_int32'::monoid);
┌───────────────┐
│ reduce_scalar │
├───────────────┤
│ int32 │
└───────────────┘
(1 row)
Empty matrix with scalar
select apply(5::int, 'int32(3,3)[]'::matrix, 'plus_int32'::binaryop);
┌───────────┐
│ apply │
├───────────┤
│ int32(3:) │
└───────────┘
(1 row)
Reduce empty matrix to scalar
select reduce_scalar('int32(5,5)[]'::matrix, 'times_monoid_int32'::monoid);
┌───────────────┐
│ reduce_scalar │
├───────────────┤
│ int32 │
└───────────────┘
(1 row)
Operations that chain multiple scalar transformations. Extract element, modify via scalar ops, set back
select set_element('int32[0:10 1:20 2:30]'::vector,
1,
(get_element('int32[0:10 1:20 2:30]'::vector, 1)::int + 5)::int);
┌───────────────────────┐
│ set_element │
├───────────────────────┤
│ int32[0:10 1:25 2:30] │
└───────────────────────┘
(1 row)
Reduce to scalar, use in apply
select apply('int32[0:1 1:2 2:3]'::vector,
reduce_scalar('int32[0:10 1:20 2:30]'::vector, 'plus_monoid_int32'::monoid)::int,
'plus_int32'::binaryop);
┌───────────────────────┐
│ apply │
├───────────────────────┤
│ int32[0:61 1:62 2:63] │
└───────────────────────┘
(1 row)
Test boolean scalars in integration contexts. Boolean scalar with vector apply
select apply(true::bool, 'bool(5)[0:false 1:true 2:false]'::vector, 'lor'::binaryop);
┌──────────────────────┐
│ apply │
├──────────────────────┤
│ bool(5)[0:t 1:t 2:t] │
└──────────────────────┘
(1 row)
select apply('bool(5)[0:false 1:true 2:false]'::vector, false::bool, 'land'::binaryop);
┌──────────────────────┐
│ apply │
├──────────────────────┤
│ bool(5)[0:f 1:f 2:f] │
└──────────────────────┘
(1 row)
Boolean reduction
select reduce_scalar('bool[0:true 1:false 2:true]'::vector, 'lor_monoid_bool'::monoid);
┌───────────────┐
│ reduce_scalar │
├───────────────┤
│ bool:t │
└───────────────┘
(1 row)
select reduce_scalar('bool[0:true 1:true 2:true]'::vector, 'land_monoid_bool'::monoid);
┌───────────────┐
│ reduce_scalar │
├───────────────┤
│ bool:t │
└───────────────┘
(1 row)
Test that precision is maintained through operations. High-precision float through operations
select reduce_scalar('fp64[0:3.141592653589793 1:2.718281828459045 2:1.414213562373095]'::vector,
'plus_monoid_fp64'::monoid);
┌───────────────┐
│ reduce_scalar │
├───────────────┤
│ fp64:7.274088 │
└───────────────┘
(1 row)
Very small values
select reduce_scalar('fp64[0:1e-100 1:1e-100 2:1e-100]'::vector, 'plus_monoid_fp64'::monoid);
┌───────────────┐
│ reduce_scalar │
├───────────────┤
│ fp64:0.000000 │
└───────────────┘
(1 row)
Very large values
select reduce_scalar('fp64[0:1e100 1:1e100 2:1e100]'::vector, 'plus_monoid_fp64'::monoid);
┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ reduce_scalar │
├───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ fp64:30000000000000002419755625518526612324544332515354750811750821725383037568323552921344695162778943488.000000 │
└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
(1 row)
Test operations that produce scalars from matrix-vector products. This would test vxm and mxv but returning the result value (GraphBLAS typically returns vectors, but single-element results are scalar-like) Matrix-vector multiply resulting in single value
select get_element(
mxv('int32[0:0:2 0:1:3]'::matrix, 'int32[0:10 1:20]'::vector),
0
);
┌─────────────┐
│ get_element │
├─────────────┤
│ int32:80 │
└─────────────┘
(1 row)
Vector-matrix multiply resulting in single value
select get_element(
vxm('int32[0:5 1:10]'::vector, 'int32[0:0:2 1:0:3]'::matrix),
0
);
┌─────────────┐
│ get_element │
├─────────────┤
│ int32:40 │
└─────────────┘
(1 row)
Test scalars of one type with structures of another. int scalar with float vector
select apply('fp64(5)[0:1.5 1:2.5 2:3.5]'::vector,
((5::int)::scalar::int)::double precision,
'plus_fp64'::binaryop);
┌───────────────────────────────────────────┐
│ apply │
├───────────────────────────────────────────┤
│ fp64(5)[0:6.500000 1:7.500000 2:8.500000] │
└───────────────────────────────────────────┘
(1 row)
float scalar with int vector (requires conversion)
select apply('int32(5)[0:10 1:20 2:30]'::vector,
((2.5::double precision)::scalar::double precision)::int,
'times_int32'::binaryop);
┌──────────────────────────┐
│ apply │
├──────────────────────────┤
│ int32(5)[0:20 1:40 2:60] │
└──────────────────────────┘
(1 row)