1+ use std:: sync:: Arc ;
12use std:: time:: Duration ;
23
34use super :: ast:: SchemaViewer ;
4- use crate :: db:: relational_db:: { RelationalDB , Tx } ;
5+ use crate :: db:: relational_db:: { MutTx , RelationalDB , Tx } ;
56use crate :: energy:: EnergyQuanta ;
67use crate :: error:: DBError ;
78use crate :: estimation:: estimate_rows_scanned;
@@ -19,13 +20,18 @@ use anyhow::anyhow;
1920use spacetimedb_datastore:: execution_context:: Workload ;
2021use spacetimedb_datastore:: locking_tx_datastore:: state_view:: StateView ;
2122use spacetimedb_datastore:: traits:: IsolationLevel ;
23+ use spacetimedb_expr:: check:: SchemaView ;
24+ use spacetimedb_expr:: errors:: TypingError ;
25+ use spacetimedb_expr:: expr:: CallParams ;
2226use spacetimedb_expr:: statement:: Statement ;
2327use spacetimedb_lib:: identity:: AuthCtx ;
2428use spacetimedb_lib:: metrics:: ExecutionMetrics ;
2529use spacetimedb_lib:: Timestamp ;
2630use spacetimedb_lib:: { AlgebraicType , ProductType , ProductValue } ;
31+ use spacetimedb_primitives:: { ArgId , TableId } ;
2732use spacetimedb_query:: { compile_sql_stmt, execute_dml_stmt, execute_select_stmt} ;
2833use spacetimedb_schema:: relation:: FieldName ;
34+ use spacetimedb_schema:: schema:: TableOrViewSchema ;
2935use spacetimedb_vm:: eval:: run_ast;
3036use spacetimedb_vm:: expr:: { CodeResult , CrudExpr , Expr } ;
3137use spacetimedb_vm:: relation:: MemTable ;
@@ -185,6 +191,19 @@ pub struct SqlResult {
185191 pub metrics : ExecutionMetrics ,
186192}
187193
194+ struct DbParams < ' a > {
195+ db : & ' a RelationalDB ,
196+ tx : & ' a mut MutTx ,
197+ }
198+
199+ impl CallParams for DbParams < ' _ > {
200+ fn create_or_get_param ( & mut self , param : & ProductValue ) -> Result < ArgId , TypingError > {
201+ self . db
202+ . create_or_get_params ( self . tx , & param)
203+ . map_err ( |err| TypingError :: Other ( err. into ( ) ) )
204+ }
205+ }
206+
188207/// Run the `SQL` string using the `auth` credentials
189208pub async fn run (
190209 db : & RelationalDB ,
@@ -196,9 +215,20 @@ pub async fn run(
196215) -> Result < SqlResult , DBError > {
197216 // We parse the sql statement in a mutable transaction.
198217 // If it turns out to be a query, we downgrade the tx.
199- let ( tx, stmt) = db. with_auto_rollback ( db. begin_mut_tx ( IsolationLevel :: Serializable , Workload :: Sql ) , |tx| {
200- compile_sql_stmt ( sql_text, & SchemaViewer :: new ( tx, & auth) , & auth)
201- } ) ?;
218+ let ( tx, stmt) =
219+ db. with_auto_rollback (
220+ db. begin_mut_tx ( IsolationLevel :: Serializable , Workload :: Sql ) ,
221+ |tx| match compile_sql_stmt ( sql_text, & SchemaViewer :: new ( tx, & auth) , & auth) {
222+ Ok ( Statement :: Select ( mut stmt) ) => {
223+ stmt. for_each_fun_call ( & mut |param| {
224+ db. create_or_get_params ( tx, & param)
225+ . map_err ( |err| TypingError :: Other ( err. into ( ) ) )
226+ } ) ?;
227+ Ok ( Statement :: Select ( stmt) )
228+ }
229+ result => result,
230+ } ,
231+ ) ?;
202232
203233 let mut metrics = ExecutionMetrics :: default ( ) ;
204234
@@ -345,7 +375,8 @@ pub(crate) mod tests {
345375 use itertools:: Itertools ;
346376 use pretty_assertions:: assert_eq;
347377 use spacetimedb_datastore:: system_tables:: {
348- StRowLevelSecurityRow , StTableFields , ST_ROW_LEVEL_SECURITY_ID , ST_TABLE_ID , ST_TABLE_NAME ,
378+ StRowLevelSecurityRow , StTableFields , ST_RESERVED_SEQUENCE_RANGE , ST_ROW_LEVEL_SECURITY_ID , ST_TABLE_ID ,
379+ ST_TABLE_NAME ,
349380 } ;
350381 use spacetimedb_lib:: bsatn:: ToBsatn ;
351382 use spacetimedb_lib:: db:: auth:: { StAccess , StTableType } ;
@@ -958,7 +989,7 @@ pub(crate) mod tests {
958989 let db = TestDB :: in_memory ( ) ?;
959990
960991 let schema = [ ( "a" , AlgebraicType :: U8 ) , ( "b" , AlgebraicType :: U8 ) ] ;
961- let ( _, table_id) = tests_utils:: create_view_for_test ( & db, "my_view" , & schema, false ) ?;
992+ let ( _, table_id) = tests_utils:: create_view_for_test ( & db, "my_view" , & schema, ProductType :: unit ( ) , false ) ?;
962993
963994 with_auto_commit ( & db, |tx| -> Result < _ , DBError > {
964995 tests_utils:: insert_into_view ( & db, tx, table_id, Some ( identity_from_u8 ( 1 ) ) , product ! [ 0u8 , 1u8 ] ) ?;
@@ -979,7 +1010,7 @@ pub(crate) mod tests {
9791010 let db = TestDB :: in_memory ( ) ?;
9801011
9811012 let schema = [ ( "a" , AlgebraicType :: U8 ) , ( "b" , AlgebraicType :: U8 ) ] ;
982- let ( _, table_id) = tests_utils:: create_view_for_test ( & db, "my_view" , & schema, true ) ?;
1013+ let ( _, table_id) = tests_utils:: create_view_for_test ( & db, "my_view" , & schema, ProductType :: unit ( ) , true ) ?;
9831014
9841015 with_auto_commit ( & db, |tx| -> Result < _ , DBError > {
9851016 tests_utils:: insert_into_view ( & db, tx, table_id, None , product ! [ 0u8 , 1u8 ] ) ?;
@@ -1000,7 +1031,7 @@ pub(crate) mod tests {
10001031 let db = TestDB :: in_memory ( ) ?;
10011032
10021033 let schema = [ ( "a" , AlgebraicType :: U8 ) , ( "b" , AlgebraicType :: U8 ) ] ;
1003- let ( _, v_id) = tests_utils:: create_view_for_test ( & db, "v" , & schema, false ) ?;
1034+ let ( _, v_id) = tests_utils:: create_view_for_test ( & db, "v" , & schema, ProductType :: unit ( ) , false ) ?;
10041035
10051036 let schema = [ ( "c" , AlgebraicType :: U8 ) , ( "d" , AlgebraicType :: U8 ) ] ;
10061037 let t_id = db. create_table_for_test ( "t" , & schema, & [ 0 . into ( ) ] ) ?;
@@ -1060,10 +1091,10 @@ pub(crate) mod tests {
10601091 let db = TestDB :: in_memory ( ) ?;
10611092
10621093 let schema = [ ( "a" , AlgebraicType :: U8 ) , ( "b" , AlgebraicType :: U8 ) ] ;
1063- let ( _, u_id) = tests_utils:: create_view_for_test ( & db, "u" , & schema, false ) ?;
1094+ let ( _, u_id) = tests_utils:: create_view_for_test ( & db, "u" , & schema, ProductType :: unit ( ) , false ) ?;
10641095
10651096 let schema = [ ( "c" , AlgebraicType :: U8 ) , ( "d" , AlgebraicType :: U8 ) ] ;
1066- let ( _, v_id) = tests_utils:: create_view_for_test ( & db, "v" , & schema, false ) ?;
1097+ let ( _, v_id) = tests_utils:: create_view_for_test ( & db, "v" , & schema, ProductType :: unit ( ) , false ) ?;
10671098
10681099 with_auto_commit ( & db, |tx| -> Result < _ , DBError > {
10691100 tests_utils:: insert_into_view ( & db, tx, u_id, Some ( identity_from_u8 ( 1 ) ) , product ! [ 0u8 , 1u8 ] ) ?;
@@ -1574,4 +1605,37 @@ pub(crate) mod tests {
15741605
15751606 Ok ( ( ) )
15761607 }
1608+
1609+ // Verify calling views with params
1610+ #[ test]
1611+ fn test_view_params ( ) -> ResultTest < ( ) > {
1612+ let db = TestDB :: durable ( ) ?;
1613+ let schema = [ ( "a" , AlgebraicType :: U8 ) , ( "b" , AlgebraicType :: I64 ) ] ;
1614+ let ( _view_id, table_id) = tests_utils:: create_view_for_test (
1615+ & db,
1616+ "my_view" ,
1617+ & schema,
1618+ ProductType :: from ( [ ( "x" , AlgebraicType :: U8 ) ] ) ,
1619+ true ,
1620+ ) ?;
1621+ let arg_id = ST_RESERVED_SEQUENCE_RANGE as u64 ;
1622+
1623+ with_auto_commit ( & db, |tx| -> Result < _ , DBError > {
1624+ tests_utils:: insert_into_view ( & db, tx, table_id, None , product ! [ arg_id + 1 , 0u8 , 1i64 ] ) ?;
1625+ tests_utils:: insert_into_view ( & db, tx, table_id, None , product ! [ arg_id, 1u8 , 2i64 ] ) ?;
1626+ Ok ( ( ) )
1627+ } ) ?;
1628+
1629+ assert_eq ! (
1630+ run_for_testing( & db, "select * from my_view(1)" ) ?,
1631+ vec![ product![ 1u8 , 2i64 ] ]
1632+ ) ;
1633+
1634+ assert_eq ! (
1635+ run_for_testing( & db, "select * from my_view(2)" ) ?,
1636+ vec![ product![ 0u8 , 1i64 ] ]
1637+ ) ;
1638+
1639+ Ok ( ( ) )
1640+ }
15771641}
0 commit comments