@@ -68,26 +68,65 @@ pub async fn increment_lsn(client: &mut Client, lsn: Lsn) -> Result<Lsn, SqlServ
68
68
/// - only contains letters, digits, and underscores
69
69
/// - no resserved words
70
70
/// - 32 char max
71
- pub async fn lsn_at_savepoint (
71
+ pub async fn create_savepoint (
72
72
txn : & mut Transaction < ' _ > ,
73
73
savepoint_name : & str ,
74
- ) -> Result < Lsn , SqlServerError > {
75
- let current_lsn_query: & str = "
74
+ ) -> Result < ( ) , SqlServerError > {
75
+ // TODO (maz): make sure savepoint name is safe
76
+ let _result = txn
77
+ . client
78
+ . simple_query ( format ! ( "SAVE TRANSACTION [{savepoint_name}]" ) )
79
+ . await ?;
80
+ Ok ( ( ) )
81
+ }
82
+
83
+ pub async fn get_lsn ( txn : & mut Transaction < ' _ > ) -> Result < Lsn , SqlServerError > {
84
+ static CURRENT_LSN_QUERY : & str = "
76
85
SELECT dt.database_transaction_begin_lsn
77
86
FROM sys.dm_tran_database_transactions AS dt
78
87
JOIN sys.dm_tran_session_transactions AS st
79
88
ON dt.transaction_id = st.transaction_id
80
89
WHERE st.session_id = @@SPID
81
90
" ;
82
- // TODO (maz): make sure savepoint name is safe
83
-
84
- txn. client
85
- . simple_query ( format ! ( "SAVE TRANSACTION [{savepoint_name}]" ) )
86
- . await ?;
87
- let result = txn. client . simple_query ( current_lsn_query) . await ?;
91
+ let result = txn. client . simple_query ( CURRENT_LSN_QUERY ) . await ?;
88
92
parse_numeric_lsn ( & result)
89
93
}
90
94
95
+ pub async fn lock_table (
96
+ txn : & mut Transaction < ' _ > ,
97
+ schema : & str ,
98
+ table : & str ,
99
+ ) -> Result < ( ) , SqlServerError > {
100
+ // This query probably seems odd, but there is no LOCK command in MS SQL. Locks are specified
101
+ // in SELECT using the WITH keyword. This query does not need to return any rows to lock the table,
102
+ // hence the 1=0, which is something short that always evaluates to false in this universe;
103
+ let query = format ! ( "SELECT * FROM {schema}.{table} WITH (TABLOCKX) WHERE 1=0;" ) ;
104
+ let _result = txn. client . query ( query, & [ ] ) . await ?;
105
+ Ok ( ( ) )
106
+ }
107
+
108
+ /// Parse an [`Lsn`] in Decimal(25,0) format of the provided [`tiberius::Row`].
109
+ ///
110
+ /// Returns an error if the provided slice doesn't have exactly one row.
111
+ fn parse_numeric_lsn ( row : & [ tiberius:: Row ] ) -> Result < Lsn , SqlServerError > {
112
+ match row {
113
+ [ r] => {
114
+ let numeric_lsn = r
115
+ . try_get :: < Numeric , _ > ( 0 ) ?
116
+ . ok_or_else ( || SqlServerError :: NullLsn ) ?;
117
+ let lsn = Lsn :: try_from ( numeric_lsn) . map_err ( |msg| SqlServerError :: InvalidData {
118
+ column_name : "lsn" . to_string ( ) ,
119
+ error : msg,
120
+ } ) ?;
121
+ Ok ( lsn)
122
+ }
123
+ other => Err ( SqlServerError :: InvalidData {
124
+ column_name : "lsn" . to_string ( ) ,
125
+ error : format ! ( "expected 1 column, got {other:?}" ) ,
126
+ } ) ,
127
+ }
128
+ }
129
+
91
130
/// Parse an [`Lsn`] from the first column of the provided [`tiberius::Row`].
92
131
///
93
132
/// Returns an error if the provided slice doesn't have exactly one row.
@@ -114,28 +153,6 @@ fn parse_lsn(result: &[tiberius::Row]) -> Result<Lsn, SqlServerError> {
114
153
}
115
154
}
116
155
117
- /// Parse an [`Lsn`] in Decimal(25,0) format of the provided [`tiberius::Row`].
118
- ///
119
- /// Returns an error if the provided slice doesn't have exactly one row.
120
- fn parse_numeric_lsn ( row : & [ tiberius:: Row ] ) -> Result < Lsn , SqlServerError > {
121
- match row {
122
- [ r] => {
123
- let numeric_lsn = r
124
- . try_get :: < Numeric , _ > ( 0 ) ?
125
- . ok_or_else ( || SqlServerError :: NullLsn ) ?;
126
- let lsn = Lsn :: try_from ( numeric_lsn) . map_err ( |msg| SqlServerError :: InvalidData {
127
- column_name : "lsn" . to_string ( ) ,
128
- error : msg,
129
- } ) ?;
130
- Ok ( lsn)
131
- }
132
- other => Err ( SqlServerError :: InvalidData {
133
- column_name : "lsn" . to_string ( ) ,
134
- error : format ! ( "expected 1 column, got {other:?}" ) ,
135
- } ) ,
136
- }
137
- }
138
-
139
156
/// Queries the specified capture instance and returns all changes from
140
157
/// `[start_lsn, end_lsn)`, ordered by `start_lsn` in an ascending fashion.
141
158
///
0 commit comments