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