Skip to content

Scalar

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)

Scalar Construction

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)

Scalar Arithmetic with Native Types

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)

Scalar Type Conversions

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)

Scalar Edge Cases - Integer Types

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)

Scalar Edge Cases - Float Types

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)

Scalar Boolean Operations

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)

Scalar Update Operations

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)

Scalar Utility Functions

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)

Scalar Type Promotion

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)

Scalar Comparison Context

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)

Scalar Edge Cases - Division

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)

Scalar NULL Handling

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);

Scalar Round-Trip Conversions

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)

Scalar Precision and Accuracy

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)

Scalar Memory and Storage

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)

Scalars with Vector Operations

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)

Scalars with Matrix Operations

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)

Scalar Reductions

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)

Scalars as Thresholds

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)

Scalars with eunion Operations

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)

Type Promotion with Scalars

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)

Scalars as Accumulators

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)

Scalars with Descriptors

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)

Scalar Utility Integration

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)

Empty Vector/Matrix with Scalar Operations

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)

Scalar Chains

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)

Scalars with Boolean Operations

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)

Scalar Precision in Integration

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)

Scalar Results from Matrix-Vector Operations

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)

Cross-Type Scalar Integration

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)