vertica_rs/query/
mod.rs

1use crate::error::Result;
2use crate::types::Value;
3
4/// Column information
5#[derive(Debug, Clone, PartialEq)]
6/// 列信息结构体,用于存储数据库列的相关元数据
7pub struct ColumnInfo {
8    /// 列名称
9    pub name: String,
10    /// 数据类型,使用 u32 表示类型标识
11    pub data_type: u32,
12    /// 标识该列是否允许为空
13    pub nullable: bool,
14    /// 可选字段,表示列的精度,某些数据类型可能没有精度信息
15    pub precision: Option<u32>,
16    /// 可选字段,表示列的小数位数,某些数据类型可能没有小数位数信息
17    pub scale: Option<u32>,
18}
19
20/// Query result
21#[derive(Debug, Clone)]
22pub struct QueryResult {
23    rows: Vec<Vec<Value>>,
24    columns: Vec<ColumnInfo>,
25    affected_rows: u64,
26    command_tag: Option<String>,
27}
28
29impl QueryResult {
30    /// Create a new query result from rows and columns
31    pub fn from_rows(rows: Vec<Vec<Value>>, columns: Vec<ColumnInfo>) -> Self {
32        Self {
33            rows,
34            columns,
35            affected_rows: 0,
36            command_tag: None,
37        }
38    }
39
40    /// Create a query result from command execution
41    pub fn from_command(affected_rows: u64, command_tag: Option<String>, _query: String) -> Self {
42        Self {
43            rows: Vec::new(),
44            columns: Vec::new(),
45            affected_rows,
46            command_tag,
47        }
48    }
49
50    /// Get all rows
51    pub fn rows(&self) -> &[Vec<Value>] {
52        &self.rows
53    }
54
55    /// Get columns
56    pub fn columns(&self) -> &[ColumnInfo] {
57        &self.columns
58    }
59
60    /// Get affected rows count
61    pub fn affected_rows(&self) -> u64 {
62        self.affected_rows
63    }
64
65    /// Get command tag
66    pub fn command_tag(&self) -> Option<&str> {
67        self.command_tag.as_deref()
68    }
69
70    /// Get number of rows
71    pub fn len(&self) -> usize {
72        self.rows.len()
73    }
74
75    /// Check if result is empty
76    pub fn is_empty(&self) -> bool {
77        self.rows.is_empty()
78    }
79
80    /// Get a specific row
81    pub fn get(&self, index: usize) -> Option<&[Value]> {
82        self.rows.get(index).map(|row| row.as_slice())
83    }
84
85    /// Convert to iterator over rows
86    pub fn iter(&self) -> std::slice::Iter<'_, Vec<Value>> {
87        self.rows.iter()
88    }
89
90    /// Create an empty query result
91    pub fn empty() -> Self {
92        Self {
93            rows: Vec::new(),
94            columns: Vec::new(),
95            affected_rows: 0,
96            command_tag: None,
97        }
98    }
99}
100
101/// Prepared statement
102#[derive(Debug, Clone)]
103pub struct Statement {
104    client: crate::client::Client,
105    id: String,
106    query: String,
107    parameters: Vec<Value>,
108}
109
110impl Statement {
111    /// Create a new statement
112    pub fn new(client: crate::client::Client, id: String, query: String) -> Self {
113        Self {
114            client,
115            id,
116            query,
117            parameters: Vec::new(),
118        }
119    }
120
121    /// Get statement ID
122    pub fn id(&self) -> &str {
123        &self.id
124    }
125
126    /// Get SQL
127    pub fn sql(&self) -> &str {
128        &self.query
129    }
130
131    /// Get parameters
132    pub fn parameters(&self) -> &[Value] {
133        &self.parameters
134    }
135
136    /// Add parameter
137    pub fn add_param(&mut self, value: Value) {
138        self.parameters.push(value);
139    }
140
141    /// Clear parameters
142    pub fn clear_params(&mut self) {
143        self.parameters.clear();
144    }
145
146    /// Execute the prepared statement with parameters
147    pub async fn execute(&self, params: &[Value]) -> Result<u64> {
148        let client = &self.client;
149        let mut conn = client.connection.lock().await;
150        let result = conn.execute_prepared(&self.id, params).await?;
151        Ok(result.affected_rows())
152    }
153}
154
155/// Transaction
156#[derive(Debug)]
157pub struct Transaction {
158    client: crate::client::Client,
159    committed: bool,
160    rolled_back: bool,
161}
162
163impl Transaction {
164    /// Create a new transaction
165    pub fn new(client: crate::client::Client) -> Self {
166        Self {
167            client,
168            committed: false,
169            rolled_back: false,
170        }
171    }
172
173    /// Commit the transaction
174    pub async fn commit(&mut self) -> Result<()> {
175        if !self.committed && !self.rolled_back {
176            self.client.query("COMMIT").await?;
177            self.committed = true;
178        }
179        Ok(())
180    }
181
182    /// Rollback the transaction
183    pub async fn rollback(&mut self) -> Result<()> {
184        if !self.committed && !self.rolled_back {
185            self.client.query("ROLLBACK").await?;
186            self.rolled_back = true;
187        }
188        Ok(())
189    }
190
191    /// Execute a query within the transaction
192    pub async fn query(&self, query: &str) -> Result<QueryResult> {
193        self.client.query(query).await
194    }
195
196    /// Execute a statement within the transaction
197    pub async fn execute(&self, query: &str, params: &[Value]) -> Result<u64> {
198        let stmt = self.client.prepare(query).await?;
199        stmt.execute(params).await
200    }
201}
202impl Drop for Transaction {
203    fn drop(&mut self) {
204        if !self.committed && !self.rolled_back {
205            // 在异步环境中,我们不能在Drop中执行异步操作
206            // 记录警告并让用户手动处理回滚
207            log::warn!("Transaction dropped without explicit commit or rollback. Consider using explicit rollback.");
208            
209            // 注意:在异步Rust中,Drop不能执行异步操作
210            // 用户应该显式调用rollback()或commit()
211        }
212    }
213}
214
215#[cfg(test)]
216mod tests {
217    use super::*;
218
219    #[test]
220    fn test_query_result_from_rows() {
221        let rows = vec![vec![Value::Int(1), Value::String("test".to_string())]];
222        let columns = vec![
223            ColumnInfo {
224                name: "id".to_string(),
225                data_type: 23,
226                nullable: false,
227                precision: None,
228                scale: None,
229            },
230            ColumnInfo {
231                name: "name".to_string(),
232                data_type: 25,
233                nullable: true,
234                precision: None,
235                scale: None,
236            },
237        ];
238
239        let result = QueryResult::from_rows(rows.clone(), columns.clone());
240        assert_eq!(result.rows().len(), 1);
241        assert_eq!(result.columns().len(), 2);
242        assert_eq!(result.affected_rows(), 0);
243    }
244
245    #[test]
246    fn test_query_result_from_command() {
247        let result = QueryResult::from_command(5, Some("INSERT 5".to_string()), "INSERT INTO users VALUES (1, 'test')".to_string());
248        assert_eq!(result.affected_rows(), 5);
249        assert_eq!(result.command_tag(), Some("INSERT 5"));
250        assert!(result.is_empty());
251    }
252
253    
254}