From 0e2d408d686397a6924b0e2a48d16cb762a3a5bf Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 1 Sep 2024 22:42:43 -0300 Subject: [PATCH 01/58] query struct + WIP procesar query --- src/main.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index e7a11a9..be04baf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,70 @@ +use std::{collections::HashMap, io::Empty, iter::Enumerate}; + fn main() { - println!("Hello, world!"); + let args: Vec = std::env::args().collect(); + if args.len() < 3 { + println!("Uso: cargo run -- ruta/a/tablas \"query\""); + } else { + let path: &String = &args[1]; + let text_query: &String = &args[2]; + let query_result = build_query(text_query, path); + } +} + +fn build_query(text_query: &String, path: &String) -> Result{ + let args = text_to_vec(text_query); + match full_check_query(&args) { + Ok(x) => Ok(0), + Err(x) => Err(x) + } + +} + +fn text_to_vec(text_query: &String) -> Vec { + let mut resultado: Vec = Vec::new(); + let mut split = text_query.split(' '); + + let mut element_opt = split.next(); + while element_opt.is_some() { + match element_opt { + Some(x) => resultado.push(x.to_string()), // TODO: Check si esto esta bien + None => continue + } + element_opt = split.next(); + } + + resultado +} + +fn full_check_query(args: &Vec) -> Result { + let mut result :u32 = 0; + match check_operation(&args[0]) { + Ok(x) => result += x, + Err(x) => result += x + } + match +} + +fn check_operation(operation: &String) -> Result { + if operation.eq("DELETE") || operation.eq("INSERT") || operation.eq("SELECT") || operation.eq("UPDATE") { + Ok(0) + } else { + Err(1) + } +} + +enum queryType { + DELETE, + INSERT, + SELECT, + UPDATE +} + +struct query { + operation: queryType, + tabla: String, // DELETE, INSERT, SELECT, UPDATE + selectores: Option>, // INSERT, SELECT, UPDATE + where_condition: Option, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) + order_by: Option, // SELECT (a veces) + values: Option // INSERT y UPDATE (en update es set) } From c13aecafcfb61f8974712a54608cc42c5bd37541 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Wed, 4 Sep 2024 20:12:27 -0300 Subject: [PATCH 02/58] WIP: validacion formato y exec --- src/main.rs | 97 +++++++++++++++++++++++++++++++++++++--------------- src/query.rs | 31 +++++++++++++++++ 2 files changed, 101 insertions(+), 27 deletions(-) create mode 100644 src/query.rs diff --git a/src/main.rs b/src/main.rs index be04baf..f82b570 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ -use std::{collections::HashMap, io::Empty, iter::Enumerate}; +use core::fmt; +use std::{collections::HashMap, error, io::Empty, iter::Enumerate, path::Display}; fn main() { let args: Vec = std::env::args().collect(); @@ -7,15 +8,23 @@ fn main() { } else { let path: &String = &args[1]; let text_query: &String = &args[2]; - let query_result = build_query(text_query, path); + match build_query(text_query, path) { + Ok(x) => exec_query(&path, x), + Err(x) => print_err(x) + } } } +fn exec_query(path: &String, query: query) { + let mut file = std::fs::File::open(format!("{}/{}",path,query.operation)); + +} + fn build_query(text_query: &String, path: &String) -> Result{ + // Crea query valida o devuelve codigo de error. let args = text_to_vec(text_query); - match full_check_query(&args) { - Ok(x) => Ok(0), - Err(x) => Err(x) + match full_check_query(&arg, &path) { + Ok(x) => } } @@ -35,36 +44,70 @@ fn text_to_vec(text_query: &String) -> Vec { resultado } +fn full_check_query(args: &Vec, path: &String) -> Result { + let mut error_code :u32 = 0; + let mut codigo_query: queryType; + match check_operation(&args) { + Ok(x) => codigo_query = x, + Err(x) => return Err(x) + } + match check_table_exist(path, &args, codigo_query){ + Ok(x) => error_code = x, + Err(x) => return Err(x) + } + match +} -fn full_check_query(args: &Vec) -> Result { - let mut result :u32 = 0; - match check_operation(&args[0]) { - Ok(x) => result += x, - Err(x) => result += x +fn check_operation(args: &Vec) -> Result { + let operation = &args[0]; + if operation.eq("DELETE") { + check_format_delete(args) + } else if operation.eq("INSERT" ) { + check_format_insert(args) + } else if operation.eq("SELECT") { + check_format_select(args) + } else if operation.eq("UPDATE") { + Ok(queryType::UPDATE) + } else { + Err(1) // Codigo: OPERACION INVALIDA } - match } -fn check_operation(operation: &String) -> Result { - if operation.eq("DELETE") || operation.eq("INSERT") || operation.eq("SELECT") || operation.eq("UPDATE") { - Ok(0) +fn check_format_delete(args: &Vec) -> Result { + if args[1].eq("FROM") && args[3].eq("WHERE"){ + Ok(queryType::DELETE) } else { - Err(1) + Err(3) // Codigo: DELETE MAL FORMATEADO + } +} + +fn check_format_insert(args: &Vec) -> Result { + if args[1].eq("INTO") { + if (args.len() - 3) % 2 != 0 || args.len() - 3 < 0 { + Err(2) + } else{ + let mut counter = 0; + let correct_value_len = (args.len() - 3)/2; // INSERT INTO a b c VALUES x y z. Len = 9. Correct len = 3. + while counter < correct_value_len && ! args[counter].eq("VALUES"){ + counter += 1; + } + + if counter == correct_value_len && args[counter].eq("VALUES") { + Ok(queryType::INSERT) + } else{ + Err(2) // Codigo: INSERT MAL FORMATEADO + } + } + } + else { + Err(2) // Codigo: INSERT MAL FORMATEADO } } -enum queryType { - DELETE, - INSERT, - SELECT, - UPDATE +fn check_format_select(args: &Vec) -> Result { + Ok(0) } -struct query { - operation: queryType, - tabla: String, // DELETE, INSERT, SELECT, UPDATE - selectores: Option>, // INSERT, SELECT, UPDATE - where_condition: Option, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) - order_by: Option, // SELECT (a veces) - values: Option // INSERT y UPDATE (en update es set) +fn check_table_exist(path: &String, args: &Vec, query: queryType) -> Result{ +// std::fs::File } diff --git a/src/query.rs b/src/query.rs new file mode 100644 index 0000000..7b15b2d --- /dev/null +++ b/src/query.rs @@ -0,0 +1,31 @@ +#[derive(Debug)] + +enum queryType { + DELETE, + INSERT, + SELECT, + UPDATE +} + +struct query { + operation: queryType, + tabla: String, // DELETE, INSERT, SELECT, UPDATE + selectores: Option>, // INSERT, SELECT, UPDATE + where_condition: Option, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) + order_by: Option, // SELECT (a veces) + values: Option // INSERT y UPDATE (en update es set) +} + +impl std::fmt::Display for query { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.operation == queryType::DELETE { + write!(f,"{}","DELETE") + } else if self.operation == queryType::INSERT { + write!(f,"{}","INSERT") + } else if self.operation == queryType::SELECT { + write!(f,"{}","SELECT") + } else if self.operation == queryType::UPDATE { + write!(f,"{}","UPDATE") + } + } +} \ No newline at end of file From cd942d655df2cc418528dc4e43c26cc1d48b8a6c Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Fri, 6 Sep 2024 21:05:53 -0300 Subject: [PATCH 03/58] WIP: Por iniciar exec --- src/query/query_type.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/query/query_type.rs diff --git a/src/query/query_type.rs b/src/query/query_type.rs new file mode 100644 index 0000000..9e2eb41 --- /dev/null +++ b/src/query/query_type.rs @@ -0,0 +1,19 @@ +use core::fmt; + +pub enum QueryType { + DELETE, + INSERT, + SELECT, + UPDATE +} + +impl std::fmt::Display for QueryType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + QueryType::DELETE => write!(f,"{}","DELETE"), + QueryType::INSERT => write!(f,"{}","INSERT"), + QueryType::SELECT => write!(f,"{}","SELECT"), + QueryType::UPDATE => write!(f,"{}","UPDATE"), + } + } +} \ No newline at end of file From fb8477539ca8b929becb687c7466afa4a5712fd8 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Fri, 6 Sep 2024 21:06:27 -0300 Subject: [PATCH 04/58] WIP: Por iniciar exec --- src/main.rs | 284 +++++++++++++++++++++++++++++++++++++++++++++------ src/query.rs | 43 +++----- 2 files changed, 271 insertions(+), 56 deletions(-) diff --git a/src/main.rs b/src/main.rs index f82b570..e76463e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,34 +1,204 @@ -use core::fmt; +use std::io::BufReader; +use std::fs::File; +use std::vec; use std::{collections::HashMap, error, io::Empty, iter::Enumerate, path::Display}; +pub mod query; +use query::build_empty_query; + +use crate::query::Query; +use crate::query::query_type::QueryType; + fn main() { let args: Vec = std::env::args().collect(); if args.len() < 3 { println!("Uso: cargo run -- ruta/a/tablas \"query\""); } else { let path: &String = &args[1]; - let text_query: &String = &args[2]; - match build_query(text_query, path) { - Ok(x) => exec_query(&path, x), - Err(x) => print_err(x) + let args = text_to_vec(&args[2]); // Tokenization + match build_query(args, path) { + Ok(x) => exec_query(x), +// Err(x) => print_err(x) + Err(_) => println!("TODO print_err") } } } -fn exec_query(path: &String, query: query) { - let mut file = std::fs::File::open(format!("{}/{}",path,query.operation)); +fn exec_query(query: query::Query) { + match query.table { + Some(f) => { + let mut file = std::fs::File::open(f); + + }, + None => println!("Esto no debería pasar :(") + } } -fn build_query(text_query: &String, path: &String) -> Result{ +/* +fn build_query(text_query: &String, path: &String) -> Result{ // Crea query valida o devuelve codigo de error. let args = text_to_vec(text_query); - match full_check_query(&arg, &path) { - Ok(x) => + let mut resultado = build_empty_query(); + + match full_check_query(&args, &path, &mut resultado) { + Ok(_) => return Ok(resultado), + Err(x) => return Err(x) + } + +} +*/ + +fn build_query(args: Vec, path: &String) -> Result { + // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build + match vec_to_query(&args, path) { + Ok(x) => return validate_query(x), // Sintaxis analysis + Err(x) => return Err(x) + } +} + +fn validate_query(query: Query) -> Result { + // Sintatic analysis + +} + +fn text_to_vec(text_query: &String) -> Vec { + // Text to vector. Tokenization by space, new line & coma + let mut result: Vec = Vec::new(); + let mut split = text_query.split(&[' ', '\n']); + + let mut element_opt = split.next(); + while element_opt.is_some() { + match element_opt { + Some(x) => { + if x.contains(',') { + let mut tmp = String::from(x); + tmp.pop(); + result.push(tmp); + } + else { + result.push(x.to_string()); + } + }, + None => continue + } + + element_opt = split.next(); + } + result +} + +fn vec_to_query(args: &Vec, path: &String) -> Result{ + // Vec to non validated query + let mut result = build_empty_query(); + match check_operation(&args) { + Ok(x) => { + match &x { + QueryType::DELETE => separate_args_delete(args, path, &mut result), + QueryType::INSERT => separate_args_insert(args, path, &mut result), + QueryType::SELECT => separate_args_select(args, path, &mut result), + QueryType::UPDATE => separate_args_update(args, path, &mut result) + } + result.operation = Some(x); + }, + Err(x) => return Err(x) + } + + Ok(result) +} + +fn merge_table_and_path(path: &String, table: &String) -> String { + let mut table_full: String = path.to_string(); + table_full.push('/'); + table_full.push_str(table); + + table_full +} + +fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) { + result.table = Some(merge_table_and_path(path, &args[2])); + + let mut where_condition = args[4].to_string(); + let mut counter = 5; + while counter < args.len() { + where_condition.push_str(&args[counter].to_string()); + counter += 1; } + result.where_condition = Some(where_condition); } +fn separate_args_insert(args: &Vec, path: &String, result: &mut Query) { + result.table = Some(merge_table_and_path(path, &args[2])); + + let mut columns: Vec = Vec::new(); + let mut counter = 3; + while counter < args.len()/2 && ! args[counter].eq("VALUES") { + columns.push(args[counter].to_string()); + counter += 1; + } + + counter += 1; + let mut values: Vec = Vec::new(); + while counter < args.len() { + values.push(args[counter].to_string()); + counter += 1; + } + + result.columns = Some(columns); + result.values = Some(values); +} + +fn separate_args_update(args: &Vec, path: &String, result: &mut Query) { + result.table = Some(merge_table_and_path(path, &args[1])); + + let mut counter = 3; + let mut columns: Vec = Vec::new(); + let mut values: Vec = Vec::new(); + + while counter < args.len() && !args[counter].eq("WHERE") { + if counter % 3 == 0 { + columns.push(args[counter].to_string()); + } else if ( counter % 3 ) == 2 { + values.push(args[counter].to_string()); + } + counter += 1; + } + counter += 1; + + let mut where_condition = String::new(); + while counter < args.len() { + where_condition.push_str(&args[counter].to_string()); + counter += 1; + } + + result.columns = Some(columns); + result.where_condition = Some(where_condition); + result.values = Some(values); +} + +fn separate_args_select(args: &Vec, path: &String, result: &mut Query) { + let mut columns: Vec = Vec::new(); + let mut counter = 1; + while counter < args.len() && !args[counter].eq("FROM") { + columns.push(args[counter].to_string()); + counter += 1; + } + counter += 1; + result.table = Some(merge_table_and_path(path, &args[counter])); + + let mut where_condition = String::new(); + while counter < args.len() && !args[counter].eq("ORDER") { + where_condition.push_str(&args[counter].to_string()); + counter += 1; + } + result.where_condition = Some(where_condition); + + // Last condition returns false on desc, true on asc + result.order_by = Some((args[counter + 2].to_string(),counter + 3 != args.len())); +} + +/* fn text_to_vec(text_query: &String) -> Vec { let mut resultado: Vec = Vec::new(); let mut split = text_query.split(' '); @@ -36,7 +206,20 @@ fn text_to_vec(text_query: &String) -> Vec { let mut element_opt = split.next(); while element_opt.is_some() { match element_opt { - Some(x) => resultado.push(x.to_string()), // TODO: Check si esto esta bien + Some(x) => { + + if x.contains('\n') { + let mut split2 = x.split('\n'); + let mut element_split2 = split2.next(); + resultado.push(element_split2.unwrap().to_string()); + element_split2 = split2.next(); + resultado.push(element_split2.unwrap().to_string()); + } else if x.contains(',') { + + } else { + resultado.push(x.to_string()) + } + }, // TODO: Check si esto esta bien None => continue } element_opt = split.next(); @@ -44,21 +227,26 @@ fn text_to_vec(text_query: &String) -> Vec { resultado } -fn full_check_query(args: &Vec, path: &String) -> Result { + +fn full_check_query(args: &Vec, path: &String) -> Result { let mut error_code :u32 = 0; - let mut codigo_query: queryType; + let mut result = build_empty_query(); match check_operation(&args) { - Ok(x) => codigo_query = x, + Ok(x) => result.operation = Some(x), Err(x) => return Err(x) } - match check_table_exist(path, &args, codigo_query){ - Ok(x) => error_code = x, + match check_table_exist(path, args, &result.operation.unwrap()){ + Ok(x) => result.table = Some(x), Err(x) => return Err(x) } - match + match check_columns_exist(args,&result.table.unwrap()) { + + } } +*/ -fn check_operation(args: &Vec) -> Result { +fn check_operation(args: &Vec) -> Result { + // Check correct operation sintaxis let operation = &args[0]; if operation.eq("DELETE") { check_format_delete(args) @@ -67,21 +255,21 @@ fn check_operation(args: &Vec) -> Result { } else if operation.eq("SELECT") { check_format_select(args) } else if operation.eq("UPDATE") { - Ok(queryType::UPDATE) + Ok(QueryType::UPDATE) } else { - Err(1) // Codigo: OPERACION INVALIDA + Err(1) // Code: OPERACION INVALIDA } } -fn check_format_delete(args: &Vec) -> Result { +fn check_format_delete(args: &Vec) -> Result { if args[1].eq("FROM") && args[3].eq("WHERE"){ - Ok(queryType::DELETE) + Ok(QueryType::DELETE) } else { - Err(3) // Codigo: DELETE MAL FORMATEADO + Err(3) // Code: DELETE MAL FORMATEADO } } -fn check_format_insert(args: &Vec) -> Result { +fn check_format_insert(args: &Vec) -> Result { if args[1].eq("INTO") { if (args.len() - 3) % 2 != 0 || args.len() - 3 < 0 { Err(2) @@ -93,21 +281,57 @@ fn check_format_insert(args: &Vec) -> Result { } if counter == correct_value_len && args[counter].eq("VALUES") { - Ok(queryType::INSERT) + Ok(QueryType::INSERT) } else{ Err(2) // Codigo: INSERT MAL FORMATEADO } } } else { - Err(2) // Codigo: INSERT MAL FORMATEADO + Err(2) // Codigo: INSERT MAL FORMATEADO } } -fn check_format_select(args: &Vec) -> Result { - Ok(0) +fn check_format_select(args: &Vec) -> Result { + Ok(QueryType::SELECT) } -fn check_table_exist(path: &String, args: &Vec, query: queryType) -> Result{ -// std::fs::File +fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) -> Result{ + // Asume query bien formateado + let mut table= String::from(path); + table.push('/'); + match &operation { + QueryType::DELETE => table.push_str(&args[2]), + QueryType::INSERT => table.push_str(&args[2]), + QueryType::SELECT => { + // Debo encontrar cual es la tabla (asumiendo query bien formateado) + let mut counter = 2; + while ! args[counter].eq("FROM"){ + counter += 1; + } + table.push_str(&args[counter + 1]) + }, + QueryType::UPDATE => table.push_str(&args[1]), + } + + match File::open(&table) { // TODO: Path::exist()? + Ok(_) => return Ok(table), + Err(_) => return Err(4) // Código: NO SE PUDO ABRIR ARCHIVO + } } + +fn check_columns_exist(args: &Vec, result: &mut Query) -> Result,u32> { + let file = File::open(&result.table.unwrap() ); + match file { + Ok(_) => { + let mut reader = BufReader::new(file); + + let mut line = String::new(); + match reader.read_line(&mut line) { + + } + } + Err(_) => return Err(5) + } + +} \ No newline at end of file diff --git a/src/query.rs b/src/query.rs index 7b15b2d..913fb22 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,31 +1,22 @@ -#[derive(Debug)] +pub mod query_type; -enum queryType { - DELETE, - INSERT, - SELECT, - UPDATE +use query_type::QueryType; +pub struct Query { + pub operation: Option, + pub table: Option, // DELETE, INSERT, SELECT, UPDATE + pub columns: Option>, // INSERT, SELECT, UPDATE + pub where_condition: Option, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) + pub order_by: Option<(String,bool)>, // SELECT (a veces) + pub values: Option> // INSERT y UPDATE (en update es set) } -struct query { - operation: queryType, - tabla: String, // DELETE, INSERT, SELECT, UPDATE - selectores: Option>, // INSERT, SELECT, UPDATE - where_condition: Option, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) - order_by: Option, // SELECT (a veces) - values: Option // INSERT y UPDATE (en update es set) -} - -impl std::fmt::Display for query { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.operation == queryType::DELETE { - write!(f,"{}","DELETE") - } else if self.operation == queryType::INSERT { - write!(f,"{}","INSERT") - } else if self.operation == queryType::SELECT { - write!(f,"{}","SELECT") - } else if self.operation == queryType::UPDATE { - write!(f,"{}","UPDATE") - } +pub fn build_empty_query() -> Query { + return Query { + operation: None, + table: None, + columns: None, + where_condition: None, + order_by: None, + values: None, } } \ No newline at end of file From fce4e38a818383ccacd40d496788a1470735005f Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sat, 7 Sep 2024 15:11:58 -0300 Subject: [PATCH 05/58] SEPARACION EN LIBS --- src/libs/error.rs | 0 src/libs/exec.rs | 17 +++ src/libs/parsing.rs | 300 ++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 23 ++-- 4 files changed, 333 insertions(+), 7 deletions(-) create mode 100644 src/libs/error.rs create mode 100644 src/libs/exec.rs create mode 100644 src/libs/parsing.rs diff --git a/src/libs/error.rs b/src/libs/error.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/libs/exec.rs b/src/libs/exec.rs new file mode 100644 index 0000000..dbd6ea5 --- /dev/null +++ b/src/libs/exec.rs @@ -0,0 +1,17 @@ +fn exec_query(query: query::Query) -> Result { + match query.table { + Some(f) => match std::fs::File::open(f) { + Ok(x) => { + match query.operation.unwrap() { + QueryType::DELETE => exec_query_delete(x, query), + QueryType::INSERT => exec_query_insert(x, query), + QueryType::SELECT => exec_query_select(x, query), + QueryType::UPDATE => exec_query_update(x, query), + } + }, + Err(_) => return Err(6) + } , + None => return Err(6) + } + +} \ No newline at end of file diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs new file mode 100644 index 0000000..ddadfcb --- /dev/null +++ b/src/libs/parsing.rs @@ -0,0 +1,300 @@ +fn build_query(args: Vec, path: &String) -> Result { + // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build + match vec_to_query(&args, path) { + Ok(x) => return validate_query(x), // Sintaxis analysis + Err(x) => return Err(x) + } +} + +/* +fn build_query(text_query: &String, path: &String) -> Result{ + // Crea query valida o devuelve codigo de error. + let args = text_to_vec(text_query); + let mut resultado = build_empty_query(); + + match full_check_query(&args, &path, &mut resultado) { + Ok(_) => return Ok(resultado), + Err(x) => return Err(x) + } + +} +*/ + +fn validate_query(query: Query) -> Result { + // Sintatic analysis + +} + +fn text_to_vec(text_query: &String) -> Vec { + // Text to vector. Tokenization by space, new line & coma + let mut result: Vec = Vec::new(); + let mut split = text_query.split(&[' ', '\n']); + + let mut element_opt = split.next(); + while element_opt.is_some() { + match element_opt { + Some(x) => { + if x.contains(',') { + let mut tmp = String::from(x); + tmp.pop(); + result.push(tmp); + } + else { + result.push(x.to_string()); + } + }, + None => continue + } + + element_opt = split.next(); + } + result +} + +fn vec_to_query(args: &Vec, path: &String) -> Result{ + // Vec to non validated query + let mut result = build_empty_query(); + match check_operation(&args) { + Ok(x) => { + match &x { + QueryType::DELETE => separate_args_delete(args, path, &mut result), + QueryType::INSERT => separate_args_insert(args, path, &mut result), + QueryType::SELECT => separate_args_select(args, path, &mut result), + QueryType::UPDATE => separate_args_update(args, path, &mut result) + } + result.operation = Some(x); + }, + Err(x) => return Err(x) + } + + Ok(result) +} + +fn merge_table_and_path(path: &String, table: &String) -> String { + let mut table_full: String = path.to_string(); + table_full.push('/'); + table_full.push_str(table); + + table_full +} + +fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) { + result.table = Some(merge_table_and_path(path, &args[2])); + + let mut where_condition = args[4].to_string(); + let mut counter = 5; + while counter < args.len() { + where_condition.push_str(&args[counter].to_string()); + counter += 1; + } + + result.where_condition = Some(where_condition); +} + +fn separate_args_insert(args: &Vec, path: &String, result: &mut Query) { + result.table = Some(merge_table_and_path(path, &args[2])); + + let mut columns: Vec = Vec::new(); + let mut counter = 3; + while counter < args.len()/2 && ! args[counter].eq("VALUES") { + columns.push(args[counter].to_string()); + counter += 1; + } + + counter += 1; + let mut values: Vec = Vec::new(); + while counter < args.len() { + values.push(args[counter].to_string()); + counter += 1; + } + + result.columns = Some(columns); + result.values = Some(values); +} + +fn separate_args_update(args: &Vec, path: &String, result: &mut Query) { + result.table = Some(merge_table_and_path(path, &args[1])); + + let mut counter = 3; + let mut columns: Vec = Vec::new(); + let mut values: Vec = Vec::new(); + + while counter < args.len() && !args[counter].eq("WHERE") { + if counter % 3 == 0 { + columns.push(args[counter].to_string()); + } else if ( counter % 3 ) == 2 { + values.push(args[counter].to_string()); + } + counter += 1; + } + counter += 1; + + let mut where_condition = String::new(); + while counter < args.len() { + where_condition.push_str(&args[counter].to_string()); + counter += 1; + } + + result.columns = Some(columns); + result.where_condition = Some(where_condition); + result.values = Some(values); +} + +fn separate_args_select(args: &Vec, path: &String, result: &mut Query) { + let mut columns: Vec = Vec::new(); + let mut counter = 1; + while counter < args.len() && !args[counter].eq("FROM") { + columns.push(args[counter].to_string()); + counter += 1; + } + counter += 1; + result.table = Some(merge_table_and_path(path, &args[counter])); + + let mut where_condition = String::new(); + while counter < args.len() && !args[counter].eq("ORDER") { + where_condition.push_str(&args[counter].to_string()); + counter += 1; + } + result.where_condition = Some(where_condition); + + // Last condition returns false on desc, true on asc + result.order_by = Some((args[counter + 2].to_string(),counter + 3 != args.len())); +} + +/* +fn text_to_vec(text_query: &String) -> Vec { + let mut resultado: Vec = Vec::new(); + let mut split = text_query.split(' '); + + let mut element_opt = split.next(); + while element_opt.is_some() { + match element_opt { + Some(x) => { + + if x.contains('\n') { + let mut split2 = x.split('\n'); + let mut element_split2 = split2.next(); + resultado.push(element_split2.unwrap().to_string()); + element_split2 = split2.next(); + resultado.push(element_split2.unwrap().to_string()); + } else if x.contains(',') { + + } else { + resultado.push(x.to_string()) + } + }, // TODO: Check si esto esta bien + None => continue + } + element_opt = split.next(); + } + + resultado +} + +fn full_check_query(args: &Vec, path: &String) -> Result { + let mut error_code :u32 = 0; + let mut result = build_empty_query(); + match check_operation(&args) { + Ok(x) => result.operation = Some(x), + Err(x) => return Err(x) + } + match check_table_exist(path, args, &result.operation.unwrap()){ + Ok(x) => result.table = Some(x), + Err(x) => return Err(x) + } + match check_columns_exist(args,&result.table.unwrap()) { + + } +} +*/ + +fn check_operation(args: &Vec) -> Result { + // Check correct operation sintaxis + let operation = &args[0]; + if operation.eq("DELETE") { + check_format_delete(args) + } else if operation.eq("INSERT" ) { + check_format_insert(args) + } else if operation.eq("SELECT") { + check_format_select(args) + } else if operation.eq("UPDATE") { + Ok(QueryType::UPDATE) + } else { + Err(1) // Code: OPERACION INVALIDA + } +} + +fn check_format_delete(args: &Vec) -> Result { + if args[1].eq("FROM") && args[3].eq("WHERE"){ + Ok(QueryType::DELETE) + } else { + Err(3) // Code: DELETE MAL FORMATEADO + } +} + +fn check_format_insert(args: &Vec) -> Result { + if args[1].eq("INTO") { + if (args.len() - 3) % 2 != 0 || args.len() - 3 < 0 { + Err(2) + } else{ + let mut counter = 0; + let correct_value_len = (args.len() - 3)/2; // INSERT INTO a b c VALUES x y z. Len = 9. Correct len = 3. + while counter < correct_value_len && ! args[counter].eq("VALUES"){ + counter += 1; + } + + if counter == correct_value_len && args[counter].eq("VALUES") { + Ok(QueryType::INSERT) + } else{ + Err(2) // Codigo: INSERT MAL FORMATEADO + } + } + } + else { + Err(2) // Codigo: INSERT MAL FORMATEADO + } +} + +fn check_format_select(args: &Vec) -> Result { + Ok(QueryType::SELECT) +} + +fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) -> Result{ + // Asume query bien formateado + let mut table= String::from(path); + table.push('/'); + match &operation { + QueryType::DELETE => table.push_str(&args[2]), + QueryType::INSERT => table.push_str(&args[2]), + QueryType::SELECT => { + // Debo encontrar cual es la tabla (asumiendo query bien formateado) + let mut counter = 2; + while ! args[counter].eq("FROM"){ + counter += 1; + } + table.push_str(&args[counter + 1]) + }, + QueryType::UPDATE => table.push_str(&args[1]), + } + + match File::open(&table) { // TODO: Path::exist()? + Ok(_) => return Ok(table), + Err(_) => return Err(4) // Código: NO SE PUDO ABRIR ARCHIVO + } +} + +fn check_columns_exist(args: &Vec, result: &mut Query) -> Result,u32> { + let file = File::open(&result.table.unwrap() ); + match file { + Ok(_) => { + let mut reader = BufReader::new(file); + + let mut line = String::new(); + match reader.read_line(&mut line) { + + } + } + Err(_) => return Err(5) + } + +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index e76463e..7782e58 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,8 +4,10 @@ use std::vec; use std::{collections::HashMap, error, io::Empty, iter::Enumerate, path::Display}; pub mod query; -use query::build_empty_query; +pub mod libs; +use crate::libs:: +use query::build_empty_query; use crate::query::Query; use crate::query::query_type::QueryType; @@ -24,13 +26,20 @@ fn main() { } } -fn exec_query(query: query::Query) { +fn exec_query(query: query::Query) -> Result { match query.table { - Some(f) => { - let mut file = std::fs::File::open(f); - - }, - None => println!("Esto no debería pasar :(") + Some(f) => match std::fs::File::open(f) { + Ok(x) => { + match query.operation.unwrap() { + QueryType::DELETE => exec_query_delete(x, query), + QueryType::INSERT => exec_query_insert(x, query), + QueryType::SELECT => exec_query_select(x, query), + QueryType::UPDATE => exec_query_update(x, query), + } + }, + Err(_) => return Err(6) + } , + None => return Err(6) } } From 68098288e5d9311e6e3a79399787d37436b13f03 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sat, 7 Sep 2024 17:40:11 -0300 Subject: [PATCH 06/58] WIP: Parse y exec. OK: separacion en libs --- src/libs.rs | 4 + src/libs/error.rs | 11 ++ src/libs/exec.rs | 46 ++++-- src/libs/parsing.rs | 356 +++++++++++++++++++++++++--------------- src/main.rs | 340 +------------------------------------- src/query.rs | 2 +- src/query/query_type.rs | 1 - 7 files changed, 282 insertions(+), 478 deletions(-) create mode 100644 src/libs.rs diff --git a/src/libs.rs b/src/libs.rs new file mode 100644 index 0000000..1bd6d7c --- /dev/null +++ b/src/libs.rs @@ -0,0 +1,4 @@ +// Dumb file for organize everything into libs +pub mod error; +pub mod exec; +pub mod parsing; diff --git a/src/libs/error.rs b/src/libs/error.rs index e69de29..5ffae73 100644 --- a/src/libs/error.rs +++ b/src/libs/error.rs @@ -0,0 +1,11 @@ +pub static OPERACION_INVALIDA: u32 = 1; +pub static DELETE_MAL_FORMATEADO: u32 = 2; +pub static INSERT_MAL_FORMATEADO: u32 = 3; +pub static SELECT_MAL_FORMATEADO: u32 = 4; +pub static UPDATE_MAL_FORMATEADO: u32 = 5; +pub static ARCHIVO_NO_PUDO_SER_ABIERTO: u32 = 6; +pub static ARCHIVO_SIN_COLUMNAS: u32 = 7; + +pub fn print_err(error_code: u32) { + // TODO print error +} \ No newline at end of file diff --git a/src/libs/exec.rs b/src/libs/exec.rs index dbd6ea5..7a751eb 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -1,17 +1,41 @@ -fn exec_query(query: query::Query) -> Result { - match query.table { +use std::fs::File; + +use crate::query::query_type::QueryType; +use crate::query::Query; + +pub fn exec_query(query: Query) { + let table = &query.table; + match table { Some(f) => match std::fs::File::open(f) { - Ok(x) => { - match query.operation.unwrap() { - QueryType::DELETE => exec_query_delete(x, query), - QueryType::INSERT => exec_query_insert(x, query), - QueryType::SELECT => exec_query_select(x, query), - QueryType::UPDATE => exec_query_update(x, query), + Ok(file) => { + match &query.operation { + Some(op) => match op { + QueryType::DELETE => exec_query_delete(file, query), + QueryType::INSERT => exec_query_insert(file, query), + QueryType::SELECT => exec_query_select(file, query), + QueryType::UPDATE => exec_query_update(file, query), + }, + None => println!("Error en el programa") } }, - Err(_) => return Err(6) + Err(_) => println!("Error en el programa") } , - None => return Err(6) + None => println!("Error en el programa") } +} + +fn exec_query_delete(file: File, query: Query) { + // TODO +} + +fn exec_query_insert(file: File, query: Query) { + // TODO +} + +fn exec_query_select(file: File, query: Query) { + // TODO +} -} \ No newline at end of file +fn exec_query_update(file: File, query: Query) { + // TODO +} diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index ddadfcb..b08efe6 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -1,79 +1,25 @@ -fn build_query(args: Vec, path: &String) -> Result { - // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build - match vec_to_query(&args, path) { - Ok(x) => return validate_query(x), // Sintaxis analysis - Err(x) => return Err(x) - } -} +use std::io::{BufRead, BufReader}; +use std::fs::File; -/* -fn build_query(text_query: &String, path: &String) -> Result{ - // Crea query valida o devuelve codigo de error. - let args = text_to_vec(text_query); - let mut resultado = build_empty_query(); +use crate::libs::error; +use crate::query::Query; +use crate::query::query_type::QueryType; +use crate::query::build_empty_query; - match full_check_query(&args, &path, &mut resultado) { - Ok(_) => return Ok(resultado), +pub fn build_query(text_query: &String, path: &String) -> Result { + // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build + let args = text_to_vec(&text_query); + match vec_to_query(&args, path) { // sintactic analysis + Ok(x) => return validate_query(x), // Semantic analysis Err(x) => return Err(x) } - -} -*/ - -fn validate_query(query: Query) -> Result { - // Sintatic analysis - -} - -fn text_to_vec(text_query: &String) -> Vec { - // Text to vector. Tokenization by space, new line & coma - let mut result: Vec = Vec::new(); - let mut split = text_query.split(&[' ', '\n']); - - let mut element_opt = split.next(); - while element_opt.is_some() { - match element_opt { - Some(x) => { - if x.contains(',') { - let mut tmp = String::from(x); - tmp.pop(); - result.push(tmp); - } - else { - result.push(x.to_string()); - } - }, - None => continue - } - - element_opt = split.next(); - } - result -} - -fn vec_to_query(args: &Vec, path: &String) -> Result{ - // Vec to non validated query - let mut result = build_empty_query(); - match check_operation(&args) { - Ok(x) => { - match &x { - QueryType::DELETE => separate_args_delete(args, path, &mut result), - QueryType::INSERT => separate_args_insert(args, path, &mut result), - QueryType::SELECT => separate_args_select(args, path, &mut result), - QueryType::UPDATE => separate_args_update(args, path, &mut result) - } - result.operation = Some(x); - }, - Err(x) => return Err(x) - } - - Ok(result) } fn merge_table_and_path(path: &String, table: &String) -> String { let mut table_full: String = path.to_string(); table_full.push('/'); table_full.push_str(table); + table_full.push_str(".csv"); table_full } @@ -81,10 +27,12 @@ fn merge_table_and_path(path: &String, table: &String) -> String { fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) { result.table = Some(merge_table_and_path(path, &args[2])); - let mut where_condition = args[4].to_string(); + let mut where_condition: Vec = Vec::new(); + where_condition.push(args[4].to_string()); + let mut counter = 5; while counter < args.len() { - where_condition.push_str(&args[counter].to_string()); + where_condition.push(args[counter].to_string()); counter += 1; } @@ -129,9 +77,9 @@ fn separate_args_update(args: &Vec, path: &String, result: &mut Query) { } counter += 1; - let mut where_condition = String::new(); + let mut where_condition = Vec::new(); while counter < args.len() { - where_condition.push_str(&args[counter].to_string()); + where_condition.push(args[counter].to_string()); counter += 1; } @@ -150,9 +98,9 @@ fn separate_args_select(args: &Vec, path: &String, result: &mut Query) { counter += 1; result.table = Some(merge_table_and_path(path, &args[counter])); - let mut where_condition = String::new(); + let mut where_condition = Vec::new(); while counter < args.len() && !args[counter].eq("ORDER") { - where_condition.push_str(&args[counter].to_string()); + where_condition.push(args[counter].to_string()); counter += 1; } result.where_condition = Some(where_condition); @@ -161,78 +109,31 @@ fn separate_args_select(args: &Vec, path: &String, result: &mut Query) { result.order_by = Some((args[counter + 2].to_string(),counter + 3 != args.len())); } -/* -fn text_to_vec(text_query: &String) -> Vec { - let mut resultado: Vec = Vec::new(); - let mut split = text_query.split(' '); - - let mut element_opt = split.next(); - while element_opt.is_some() { - match element_opt { - Some(x) => { - - if x.contains('\n') { - let mut split2 = x.split('\n'); - let mut element_split2 = split2.next(); - resultado.push(element_split2.unwrap().to_string()); - element_split2 = split2.next(); - resultado.push(element_split2.unwrap().to_string()); - } else if x.contains(',') { - - } else { - resultado.push(x.to_string()) - } - }, // TODO: Check si esto esta bien - None => continue - } - element_opt = split.next(); - } - - resultado -} - -fn full_check_query(args: &Vec, path: &String) -> Result { - let mut error_code :u32 = 0; - let mut result = build_empty_query(); - match check_operation(&args) { - Ok(x) => result.operation = Some(x), - Err(x) => return Err(x) - } - match check_table_exist(path, args, &result.operation.unwrap()){ - Ok(x) => result.table = Some(x), - Err(x) => return Err(x) - } - match check_columns_exist(args,&result.table.unwrap()) { - - } -} -*/ - -fn check_operation(args: &Vec) -> Result { +fn check_operation_format(args: &Vec) -> Result { // Check correct operation sintaxis let operation = &args[0]; if operation.eq("DELETE") { - check_format_delete(args) + check_delete_format(args) } else if operation.eq("INSERT" ) { - check_format_insert(args) + check_insert_format(args) } else if operation.eq("SELECT") { - check_format_select(args) + check_select_format(args) } else if operation.eq("UPDATE") { - Ok(QueryType::UPDATE) + check_update_format(args) } else { - Err(1) // Code: OPERACION INVALIDA + Err(error::OPERACION_INVALIDA) } } -fn check_format_delete(args: &Vec) -> Result { +fn check_delete_format(args: &Vec) -> Result { if args[1].eq("FROM") && args[3].eq("WHERE"){ Ok(QueryType::DELETE) } else { - Err(3) // Code: DELETE MAL FORMATEADO + Err(error::DELETE_MAL_FORMATEADO) } } -fn check_format_insert(args: &Vec) -> Result { +fn check_insert_format(args: &Vec) -> Result { if args[1].eq("INTO") { if (args.len() - 3) % 2 != 0 || args.len() - 3 < 0 { Err(2) @@ -246,19 +147,25 @@ fn check_format_insert(args: &Vec) -> Result { if counter == correct_value_len && args[counter].eq("VALUES") { Ok(QueryType::INSERT) } else{ - Err(2) // Codigo: INSERT MAL FORMATEADO + Err(error::INSERT_MAL_FORMATEADO) } } } else { - Err(2) // Codigo: INSERT MAL FORMATEADO + Err(error::INSERT_MAL_FORMATEADO) } } -fn check_format_select(args: &Vec) -> Result { +fn check_select_format(args: &Vec) -> Result { + // TODO format select Ok(QueryType::SELECT) } +fn check_update_format(args: &Vec) -> Result { + // TODO format select + Ok(QueryType::UPDATE) +} + fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) -> Result{ // Asume query bien formateado let mut table= String::from(path); @@ -279,11 +186,137 @@ fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) - match File::open(&table) { // TODO: Path::exist()? Ok(_) => return Ok(table), - Err(_) => return Err(4) // Código: NO SE PUDO ABRIR ARCHIVO + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) } } + +fn validate_query(query: Query) -> Result { + // Pre: Sintactical query OK + // Post: Valid query for execution + match File::open(&query.table.unwrap()) { + Ok(_) => {}, + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + } + + match &query.operation.unwrap() { + QueryType::DELETE => validate_delete_query(&query), + QueryType::INSERT => validate_insert_query(query), + QueryType::SELECT => validate_select_query(query), + QueryType::UPDATE => validate_update_query(query), + } +} + +fn validate_delete_query(query: &Query) -> Result { + if query.columns.is_none() && query.values.is_none() && query.columns.is_none() { + match query.table { + Some(table) => { + + }, + Err(_) => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + } + + match File::open(query.table.unwrap()) { + Ok(x) => { + match get_columns(x) { + Some(x) => check_columns_contains(x, &query), + None => return Err(error::ARCHIVO_SIN_COLUMNAS) + } + }, + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + } + } else { + Err(error::DELETE_MAL_FORMATEADO) + } +} + +fn get_columns(file: File) -> Option> { + let mut result: Vec = Vec::new(); + let mut reader: BufReader = BufReader::new(file); + let mut line = String::new(); + match reader.read_line(&mut line) { + Ok(_) => { + let mut split = line.split(','); + let mut element_opt = split.next(); + while element_opt.is_some() { + match element_opt { + Some(x) => result.push(x.to_string()), + None => continue + } + element_opt = split.next(); + } + + Some(result) + }, + Err(_) => None + } +} + +fn check_columns_contains(columns: Vec, query: &Query) -> Result { + +} + + +fn text_to_vec(text_query: &String) -> Vec { + // Text to vector. Tokenization by space, new line & coma + let mut result: Vec = Vec::new(); + let mut split = text_query.split(&[' ', '\n']); + + let mut element_opt = split.next(); + while element_opt.is_some() { + match element_opt { + Some(x) => { + if x.contains(',') { + let mut tmp = String::from(x); + tmp.pop(); + result.push(tmp); + } + else { + result.push(x.to_string()); + } + }, + None => continue + } + + element_opt = split.next(); + } + result +} + +fn vec_to_query(args: &Vec, path: &String) -> Result{ + // Vec to non validated query + let mut result: Query = build_empty_query(); + match check_operation_format(&args) { + Ok(x) => { + match &x { + QueryType::DELETE => separate_args_delete(args, path, &mut result), + QueryType::INSERT => separate_args_insert(args, path, &mut result), + QueryType::SELECT => separate_args_select(args, path, &mut result), + QueryType::UPDATE => separate_args_update(args, path, &mut result) + } + result.operation = Some(x); + }, + Err(x) => return Err(x) + } + + Ok(result) +} + +/* +fn build_query(text_query: &String, path: &String) -> Result{ + // Crea query valida o devuelve codigo de error. + let args = text_to_vec(text_query); + let mut resultado = build_empty_query(); + + match full_check_query(&args, &path, &mut resultado) { + Ok(_) => return Ok(resultado), + Err(x) => return Err(x) + } + +} + fn check_columns_exist(args: &Vec, result: &mut Query) -> Result,u32> { + // TODO columns exist let file = File::open(&result.table.unwrap() ); match file { Ok(_) => { @@ -297,4 +330,63 @@ fn check_columns_exist(args: &Vec, result: &mut Query) -> Result return Err(5) } +} + +fn text_to_vec(text_query: &String) -> Vec { + let mut resultado: Vec = Vec::new(); + let mut split = text_query.split(' '); + + let mut element_opt = split.next(); + while element_opt.is_some() { + match element_opt { + Some(x) => { + + if x.contains('\n') { + let mut split2 = x.split('\n'); + let mut element_split2 = split2.next(); + resultado.push(element_split2.unwrap().to_string()); + element_split2 = split2.next(); + resultado.push(element_split2.unwrap().to_string()); + } else if x.contains(',') { + + } else { + resultado.push(x.to_string()) + } + }, // TODO: Check si esto esta bien + None => continue + } + element_opt = split.next(); + } + + resultado +} + +fn full_check_query(args: &Vec, path: &String) -> Result { + let mut error_code :u32 = 0; + let mut result = build_empty_query(); + match check_operation(&args) { + Ok(x) => result.operation = Some(x), + Err(x) => return Err(x) + } + match check_table_exist(path, args, &result.operation.unwrap()){ + Ok(x) => result.table = Some(x), + Err(x) => return Err(x) + } + match check_columns_exist(args,&result.table.unwrap()) { + + } +} +*/ + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_text_to_vec(){ + let rt1 = text_to_vec(&String::from("SELECT * FROM table")); + assert_eq!(rt1, vec!["SELECT","*","FROM","table"]); + let rt2 = text_to_vec(&String::from("SELECT id, producto, id_cliente\nFROM ordenes\nWHERE cantidad > 1")); + assert_eq!(rt2, vec!["SELECT","id","producto","id_cliente","FROM","ordenes","WHERE","cantidad>1"]); + } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 7782e58..842dfb2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,9 @@ -use std::io::BufReader; -use std::fs::File; -use std::vec; -use std::{collections::HashMap, error, io::Empty, iter::Enumerate, path::Display}; - pub mod query; pub mod libs; -use crate::libs:: -use query::build_empty_query; -use crate::query::Query; -use crate::query::query_type::QueryType; +use libs::error::print_err; +use libs::exec::exec_query; +use libs::parsing::build_query; fn main() { let args: Vec = std::env::args().collect(); @@ -17,330 +11,10 @@ fn main() { println!("Uso: cargo run -- ruta/a/tablas \"query\""); } else { let path: &String = &args[1]; - let args = text_to_vec(&args[2]); // Tokenization - match build_query(args, path) { - Ok(x) => exec_query(x), -// Err(x) => print_err(x) - Err(_) => println!("TODO print_err") + let text_query: &String = &args[2]; + match build_query(text_query, path) { + Ok(x) => exec_query(x), + Err(x) => print_err(x) } } } - -fn exec_query(query: query::Query) -> Result { - match query.table { - Some(f) => match std::fs::File::open(f) { - Ok(x) => { - match query.operation.unwrap() { - QueryType::DELETE => exec_query_delete(x, query), - QueryType::INSERT => exec_query_insert(x, query), - QueryType::SELECT => exec_query_select(x, query), - QueryType::UPDATE => exec_query_update(x, query), - } - }, - Err(_) => return Err(6) - } , - None => return Err(6) - } - -} - -/* -fn build_query(text_query: &String, path: &String) -> Result{ - // Crea query valida o devuelve codigo de error. - let args = text_to_vec(text_query); - let mut resultado = build_empty_query(); - - match full_check_query(&args, &path, &mut resultado) { - Ok(_) => return Ok(resultado), - Err(x) => return Err(x) - } - -} -*/ - -fn build_query(args: Vec, path: &String) -> Result { - // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build - match vec_to_query(&args, path) { - Ok(x) => return validate_query(x), // Sintaxis analysis - Err(x) => return Err(x) - } -} - -fn validate_query(query: Query) -> Result { - // Sintatic analysis - -} - -fn text_to_vec(text_query: &String) -> Vec { - // Text to vector. Tokenization by space, new line & coma - let mut result: Vec = Vec::new(); - let mut split = text_query.split(&[' ', '\n']); - - let mut element_opt = split.next(); - while element_opt.is_some() { - match element_opt { - Some(x) => { - if x.contains(',') { - let mut tmp = String::from(x); - tmp.pop(); - result.push(tmp); - } - else { - result.push(x.to_string()); - } - }, - None => continue - } - - element_opt = split.next(); - } - result -} - -fn vec_to_query(args: &Vec, path: &String) -> Result{ - // Vec to non validated query - let mut result = build_empty_query(); - match check_operation(&args) { - Ok(x) => { - match &x { - QueryType::DELETE => separate_args_delete(args, path, &mut result), - QueryType::INSERT => separate_args_insert(args, path, &mut result), - QueryType::SELECT => separate_args_select(args, path, &mut result), - QueryType::UPDATE => separate_args_update(args, path, &mut result) - } - result.operation = Some(x); - }, - Err(x) => return Err(x) - } - - Ok(result) -} - -fn merge_table_and_path(path: &String, table: &String) -> String { - let mut table_full: String = path.to_string(); - table_full.push('/'); - table_full.push_str(table); - - table_full -} - -fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) { - result.table = Some(merge_table_and_path(path, &args[2])); - - let mut where_condition = args[4].to_string(); - let mut counter = 5; - while counter < args.len() { - where_condition.push_str(&args[counter].to_string()); - counter += 1; - } - - result.where_condition = Some(where_condition); -} - -fn separate_args_insert(args: &Vec, path: &String, result: &mut Query) { - result.table = Some(merge_table_and_path(path, &args[2])); - - let mut columns: Vec = Vec::new(); - let mut counter = 3; - while counter < args.len()/2 && ! args[counter].eq("VALUES") { - columns.push(args[counter].to_string()); - counter += 1; - } - - counter += 1; - let mut values: Vec = Vec::new(); - while counter < args.len() { - values.push(args[counter].to_string()); - counter += 1; - } - - result.columns = Some(columns); - result.values = Some(values); -} - -fn separate_args_update(args: &Vec, path: &String, result: &mut Query) { - result.table = Some(merge_table_and_path(path, &args[1])); - - let mut counter = 3; - let mut columns: Vec = Vec::new(); - let mut values: Vec = Vec::new(); - - while counter < args.len() && !args[counter].eq("WHERE") { - if counter % 3 == 0 { - columns.push(args[counter].to_string()); - } else if ( counter % 3 ) == 2 { - values.push(args[counter].to_string()); - } - counter += 1; - } - counter += 1; - - let mut where_condition = String::new(); - while counter < args.len() { - where_condition.push_str(&args[counter].to_string()); - counter += 1; - } - - result.columns = Some(columns); - result.where_condition = Some(where_condition); - result.values = Some(values); -} - -fn separate_args_select(args: &Vec, path: &String, result: &mut Query) { - let mut columns: Vec = Vec::new(); - let mut counter = 1; - while counter < args.len() && !args[counter].eq("FROM") { - columns.push(args[counter].to_string()); - counter += 1; - } - counter += 1; - result.table = Some(merge_table_and_path(path, &args[counter])); - - let mut where_condition = String::new(); - while counter < args.len() && !args[counter].eq("ORDER") { - where_condition.push_str(&args[counter].to_string()); - counter += 1; - } - result.where_condition = Some(where_condition); - - // Last condition returns false on desc, true on asc - result.order_by = Some((args[counter + 2].to_string(),counter + 3 != args.len())); -} - -/* -fn text_to_vec(text_query: &String) -> Vec { - let mut resultado: Vec = Vec::new(); - let mut split = text_query.split(' '); - - let mut element_opt = split.next(); - while element_opt.is_some() { - match element_opt { - Some(x) => { - - if x.contains('\n') { - let mut split2 = x.split('\n'); - let mut element_split2 = split2.next(); - resultado.push(element_split2.unwrap().to_string()); - element_split2 = split2.next(); - resultado.push(element_split2.unwrap().to_string()); - } else if x.contains(',') { - - } else { - resultado.push(x.to_string()) - } - }, // TODO: Check si esto esta bien - None => continue - } - element_opt = split.next(); - } - - resultado -} - -fn full_check_query(args: &Vec, path: &String) -> Result { - let mut error_code :u32 = 0; - let mut result = build_empty_query(); - match check_operation(&args) { - Ok(x) => result.operation = Some(x), - Err(x) => return Err(x) - } - match check_table_exist(path, args, &result.operation.unwrap()){ - Ok(x) => result.table = Some(x), - Err(x) => return Err(x) - } - match check_columns_exist(args,&result.table.unwrap()) { - - } -} -*/ - -fn check_operation(args: &Vec) -> Result { - // Check correct operation sintaxis - let operation = &args[0]; - if operation.eq("DELETE") { - check_format_delete(args) - } else if operation.eq("INSERT" ) { - check_format_insert(args) - } else if operation.eq("SELECT") { - check_format_select(args) - } else if operation.eq("UPDATE") { - Ok(QueryType::UPDATE) - } else { - Err(1) // Code: OPERACION INVALIDA - } -} - -fn check_format_delete(args: &Vec) -> Result { - if args[1].eq("FROM") && args[3].eq("WHERE"){ - Ok(QueryType::DELETE) - } else { - Err(3) // Code: DELETE MAL FORMATEADO - } -} - -fn check_format_insert(args: &Vec) -> Result { - if args[1].eq("INTO") { - if (args.len() - 3) % 2 != 0 || args.len() - 3 < 0 { - Err(2) - } else{ - let mut counter = 0; - let correct_value_len = (args.len() - 3)/2; // INSERT INTO a b c VALUES x y z. Len = 9. Correct len = 3. - while counter < correct_value_len && ! args[counter].eq("VALUES"){ - counter += 1; - } - - if counter == correct_value_len && args[counter].eq("VALUES") { - Ok(QueryType::INSERT) - } else{ - Err(2) // Codigo: INSERT MAL FORMATEADO - } - } - } - else { - Err(2) // Codigo: INSERT MAL FORMATEADO - } -} - -fn check_format_select(args: &Vec) -> Result { - Ok(QueryType::SELECT) -} - -fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) -> Result{ - // Asume query bien formateado - let mut table= String::from(path); - table.push('/'); - match &operation { - QueryType::DELETE => table.push_str(&args[2]), - QueryType::INSERT => table.push_str(&args[2]), - QueryType::SELECT => { - // Debo encontrar cual es la tabla (asumiendo query bien formateado) - let mut counter = 2; - while ! args[counter].eq("FROM"){ - counter += 1; - } - table.push_str(&args[counter + 1]) - }, - QueryType::UPDATE => table.push_str(&args[1]), - } - - match File::open(&table) { // TODO: Path::exist()? - Ok(_) => return Ok(table), - Err(_) => return Err(4) // Código: NO SE PUDO ABRIR ARCHIVO - } -} - -fn check_columns_exist(args: &Vec, result: &mut Query) -> Result,u32> { - let file = File::open(&result.table.unwrap() ); - match file { - Ok(_) => { - let mut reader = BufReader::new(file); - - let mut line = String::new(); - match reader.read_line(&mut line) { - - } - } - Err(_) => return Err(5) - } - -} \ No newline at end of file diff --git a/src/query.rs b/src/query.rs index 913fb22..0acc4f4 100644 --- a/src/query.rs +++ b/src/query.rs @@ -5,7 +5,7 @@ pub struct Query { pub operation: Option, pub table: Option, // DELETE, INSERT, SELECT, UPDATE pub columns: Option>, // INSERT, SELECT, UPDATE - pub where_condition: Option, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) + pub where_condition: Option>, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) pub order_by: Option<(String,bool)>, // SELECT (a veces) pub values: Option> // INSERT y UPDATE (en update es set) } diff --git a/src/query/query_type.rs b/src/query/query_type.rs index 9e2eb41..d1ddba5 100644 --- a/src/query/query_type.rs +++ b/src/query/query_type.rs @@ -1,5 +1,4 @@ use core::fmt; - pub enum QueryType { DELETE, INSERT, From f5e05ea22667fa0cffbdeb5ecc5799ec304fa813 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sat, 7 Sep 2024 21:42:55 -0300 Subject: [PATCH 07/58] WIP: Dios que complejo --- src/condition.rs | 31 ++++++++ src/condition/condition_type.rs | 13 ++++ src/libs/error.rs | 4 +- src/libs/parsing.rs | 127 ++++++++++++++++++++++++-------- src/main.rs | 1 + src/query.rs | 17 +++-- 6 files changed, 154 insertions(+), 39 deletions(-) create mode 100644 src/condition.rs create mode 100644 src/condition/condition_type.rs diff --git a/src/condition.rs b/src/condition.rs new file mode 100644 index 0000000..3a721ed --- /dev/null +++ b/src/condition.rs @@ -0,0 +1,31 @@ +pub mod condition_type; +use condition_type::BooleanOperator; +use condition_type::ConditionOperator; + +pub struct Condition { + pub condition: ConditionOperator, + pub v1: Option, + pub v2: Option, +} + +pub struct ComplexCondition { + pub operator: BooleanOperator, + pub cond1: Condition, + pub nest_cond: Box // Linked list of complex conditions +} + +pub fn build_condition(v1: String, v2: String, condition: ConditionOperator) -> Condition { + return Condition { + condition: condition, + v1: Some(v1), + v2: Some(v2), + } +} + +pub fn build_complex_condition(op: BooleanOperator,condition: Condition, comp: Box) -> ComplexCondition { + return Condition { + operator: op, + cond1: condition, + nest_cond: comp // Linked list of complex conditions + } +} \ No newline at end of file diff --git a/src/condition/condition_type.rs b/src/condition/condition_type.rs new file mode 100644 index 0000000..68e318b --- /dev/null +++ b/src/condition/condition_type.rs @@ -0,0 +1,13 @@ +pub enum ConditionOperator { + Minor, // Int + MinorEqual, // Int + Equal, // Int and String + Higher, // Int + HigherEqual, // Int +} + +pub enum BooleanOperator { + AND, + OR, + NOT +} \ No newline at end of file diff --git a/src/libs/error.rs b/src/libs/error.rs index 5ffae73..85979bc 100644 --- a/src/libs/error.rs +++ b/src/libs/error.rs @@ -4,7 +4,9 @@ pub static INSERT_MAL_FORMATEADO: u32 = 3; pub static SELECT_MAL_FORMATEADO: u32 = 4; pub static UPDATE_MAL_FORMATEADO: u32 = 5; pub static ARCHIVO_NO_PUDO_SER_ABIERTO: u32 = 6; -pub static ARCHIVO_SIN_COLUMNAS: u32 = 7; +pub static ARCHIVO_VACIO: u32 = 7; +pub static ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS: u32 = 8; +pub static WHERE_EN_DELETE_MAL_FORMATEADO: u32 = 9; pub fn print_err(error_code: u32) { // TODO print error diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index b08efe6..c568328 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -1,16 +1,18 @@ use std::io::{BufRead, BufReader}; use std::fs::File; +use crate::condition::{build_condition, ComplexCondition, Condition}; use crate::libs::error; use crate::query::Query; use crate::query::query_type::QueryType; use crate::query::build_empty_query; + pub fn build_query(text_query: &String, path: &String) -> Result { // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build let args = text_to_vec(&text_query); - match vec_to_query(&args, path) { // sintactic analysis - Ok(x) => return validate_query(x), // Semantic analysis + match vec_to_query(&args, path) { + Ok(x) => return validate_query(x), Err(x) => return Err(x) } } @@ -27,13 +29,18 @@ fn merge_table_and_path(path: &String, table: &String) -> String { fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) { result.table = Some(merge_table_and_path(path, &args[2])); - let mut where_condition: Vec = Vec::new(); - where_condition.push(args[4].to_string()); - + let mut where_condition: ComplexCondition; + let mut simple_condition_tmp: Condition; + let mut complex_condition_tmp: Condition; let mut counter = 5; + while counter < args.len() { - where_condition.push(args[counter].to_string()); - counter += 1; + if args[counter].eq("AND") || args[counter].eq["OR"] || args[counter].eq("NOT") { + complex_condition_tmp = build_condition(v1, v2, condition) + } + simple_condition = build_condition(args[counter].to_string(), args[counter + 1].to_string(), condition); + + counter += 3; } result.where_condition = Some(where_condition); @@ -126,13 +133,30 @@ fn check_operation_format(args: &Vec) -> Result { } fn check_delete_format(args: &Vec) -> Result { - if args[1].eq("FROM") && args[3].eq("WHERE"){ - Ok(QueryType::DELETE) + if args[1].eq("FROM") && args[3].eq("WHERE") { + non_valid_keywords = vec!["INSERT","INTO",""] + Ok(QueryType::DELETE) } else { Err(error::DELETE_MAL_FORMATEADO) } } +fn check_non_valid_keywords(args: &Vec, non_valid_keywords: Vec<&str>) -> bool { + // Checks if args contains any non valid keyword + let mut result = true; + let mut counter = 0; + + while counter < args.len() && result { + if non_valid_keywords.contains(&&args[counter].as_str()) { + result = false; + } else { + counter += 1; + } + } + + result +} + fn check_insert_format(args: &Vec) -> Result { if args[1].eq("INTO") { if (args.len() - 3) % 2 != 0 || args.len() - 3 < 0 { @@ -166,6 +190,41 @@ fn check_update_format(args: &Vec) -> Result { Ok(QueryType::UPDATE) } +fn check_where_format(args: &Vec, start_position: usize) -> bool { + let mut result = true; + + let mut counter: usize = start_position; + + let mut not_detected: bool = false; + let mut op_detected: bool = false; + + while counter < args.len() && result { + if args[counter].eq("NOT") { + if not_detected || op_detected { + result = false; // NOT NOT. Que estas haciendo ? + } else { + not_detected = true; + counter += 1; + } + } else if args[counter].eq("AND") || args[counter].eq("OR") { + if op_detected { + result = false; // AND OR , OR AND, OR OR, AND AND. Que estas haciendo ? + } else { + op_detected = true; + counter += 1; + } + } else { + if counter + 3 > args.len() { + result = false; + } else { + + } + } + } + + result +} + fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) -> Result{ // Asume query bien formateado let mut table= String::from(path); @@ -199,31 +258,34 @@ fn validate_query(query: Query) -> Result { Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) } - match &query.operation.unwrap() { - QueryType::DELETE => validate_delete_query(&query), - QueryType::INSERT => validate_insert_query(query), - QueryType::SELECT => validate_select_query(query), - QueryType::UPDATE => validate_update_query(query), + match &query.operation { + Some(op) => { + match &query.operation.unwrap() { + QueryType::DELETE => validate_delete_query(query), + QueryType::INSERT => validate_insert_query(query), + QueryType::SELECT => validate_select_query(query), + QueryType::UPDATE => validate_update_query(query), + } + }, + None => return Err(error::OPERACION_INVALIDA) } } -fn validate_delete_query(query: &Query) -> Result { +fn validate_delete_query(query: Query) -> Result { if query.columns.is_none() && query.values.is_none() && query.columns.is_none() { - match query.table { + match &query.table { Some(table) => { - + match File::open(table) { + Ok(file) => { + match get_columns(file) { + Some(columns) => check_columns_contains_condition(columns,query), + None => return Err(error::ARCHIVO_VACIO) + } + }, + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + } }, - Err(_) => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) - } - - match File::open(query.table.unwrap()) { - Ok(x) => { - match get_columns(x) { - Some(x) => check_columns_contains(x, &query), - None => return Err(error::ARCHIVO_SIN_COLUMNAS) - } - }, - Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + None => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) } } else { Err(error::DELETE_MAL_FORMATEADO) @@ -252,10 +314,13 @@ fn get_columns(file: File) -> Option> { } } -fn check_columns_contains(columns: Vec, query: &Query) -> Result { +fn get_where_columns(query: &Query) -> Option> { -} +} +fn check_columns_contains_condition(columns: Vec, query: Query) -> Result { + +} fn text_to_vec(text_query: &String) -> Vec { // Text to vector. Tokenization by space, new line & coma @@ -266,7 +331,7 @@ fn text_to_vec(text_query: &String) -> Vec { while element_opt.is_some() { match element_opt { Some(x) => { - if x.contains(',') { + if x.contains(',') || x.contains(";"){ let mut tmp = String::from(x); tmp.pop(); result.push(tmp); diff --git a/src/main.rs b/src/main.rs index 842dfb2..6b8e678 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +pub mod condition; pub mod query; pub mod libs; diff --git a/src/query.rs b/src/query.rs index 0acc4f4..2d2d272 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,13 +1,16 @@ pub mod query_type; use query_type::QueryType; + +use crate::condition::ComplexCondition; + pub struct Query { - pub operation: Option, - pub table: Option, // DELETE, INSERT, SELECT, UPDATE - pub columns: Option>, // INSERT, SELECT, UPDATE - pub where_condition: Option>, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) - pub order_by: Option<(String,bool)>, // SELECT (a veces) - pub values: Option> // INSERT y UPDATE (en update es set) + pub operation: Option, // DELETE, INSERT, SELECT, UPDATE + pub table: Option, // DELETE, INSERT, SELECT, UPDATE + pub columns: Option>, // INSERT, SELECT, UPDATE + pub where_condition: Option, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) + pub order_by: Option<(String,bool)>, // SELECT (a veces) + pub values: Option> // INSERT y UPDATE (en update es set) } pub fn build_empty_query() -> Query { @@ -19,4 +22,4 @@ pub fn build_empty_query() -> Query { order_by: None, values: None, } -} \ No newline at end of file +} From f81db0ff0f186fff16ef0a8ae9746f3911bceaad Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 01:24:35 -0300 Subject: [PATCH 08/58] WIP: Arbol de expresiones binarias --- src/condition.rs | 63 +++++++++++++++++--- src/libs/error.rs | 1 + src/libs/parsing.rs | 138 ++++++++++++++++++++++++++++---------------- src/query.rs | 6 +- 4 files changed, 147 insertions(+), 61 deletions(-) diff --git a/src/condition.rs b/src/condition.rs index 3a721ed..9264314 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -1,4 +1,7 @@ pub mod condition_type; +use std::ops::RemAssign; +use std::ptr::null; + use condition_type::BooleanOperator; use condition_type::ConditionOperator; @@ -9,9 +12,12 @@ pub struct Condition { } pub struct ComplexCondition { - pub operator: BooleanOperator, - pub cond1: Condition, - pub nest_cond: Box // Linked list of complex conditions + // Tree of complex conditions + pub operator: Option, + pub condition: Option, + pub left_cond: Option>, // Oldest condition ( first to be found ) + pub parent: Option>, // Newest condition ( last to be found ) + pub right_cond: Option> // Newest condition ( last to be found ) } pub fn build_condition(v1: String, v2: String, condition: ConditionOperator) -> Condition { @@ -22,10 +28,49 @@ pub fn build_condition(v1: String, v2: String, condition: ConditionOperator) -> } } -pub fn build_complex_condition(op: BooleanOperator,condition: Condition, comp: Box) -> ComplexCondition { - return Condition { - operator: op, - cond1: condition, - nest_cond: comp // Linked list of complex conditions +pub fn build_empty_complex_condition() -> ComplexCondition { + return ComplexCondition { + operator: None, + condition: None, + left_cond: None, + right_cond: None, + parent: None, + } +} + +pub fn tree_check(root: ComplexCondition) -> bool { + match &root.operator { + Some(op) => { + match op { + BooleanOperator::OR => tree_check_or_and(root), + BooleanOperator::AND => tree_check_or_and(root), + BooleanOperator::NOT => tree_check_not(root) + } + }, + None => return true + } +} + +fn tree_check_or_and(root: ComplexCondition) -> bool { + match root.left_cond { + Some(left) => { + match root.right_cond { + Some(right) => return tree_check(*left) && tree_check(*right), + None => return false + } + }, + None => return false + } +} + +fn tree_check_not(root: ComplexCondition) -> bool { + match root.left_cond { + Some(left) => { + match root.right_cond { + Some(_) => return false, + None => return tree_check(*left) + } + }, + None => return false } -} \ No newline at end of file +} diff --git a/src/libs/error.rs b/src/libs/error.rs index 85979bc..da794e6 100644 --- a/src/libs/error.rs +++ b/src/libs/error.rs @@ -7,6 +7,7 @@ pub static ARCHIVO_NO_PUDO_SER_ABIERTO: u32 = 6; pub static ARCHIVO_VACIO: u32 = 7; pub static ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS: u32 = 8; pub static WHERE_EN_DELETE_MAL_FORMATEADO: u32 = 9; +pub static WHERE_MAL_FORMATEADO: u32 = 10; pub fn print_err(error_code: u32) { // TODO print error diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index c568328..e4c8761 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -1,13 +1,12 @@ use std::io::{BufRead, BufReader}; use std::fs::File; -use crate::condition::{build_condition, ComplexCondition, Condition}; +use crate::condition::{build_condition, build_empty_complex_condition, tree_check, ComplexCondition, Condition}; use crate::libs::error; use crate::query::Query; use crate::query::query_type::QueryType; use crate::query::build_empty_query; - pub fn build_query(text_query: &String, path: &String) -> Result { // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build let args = text_to_vec(&text_query); @@ -26,24 +25,55 @@ fn merge_table_and_path(path: &String, table: &String) -> String { table_full } -fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) { +fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) -> Result { result.table = Some(merge_table_and_path(path, &args[2])); + match get_where_condition(args, 4, build_empty_complex_condition()) { + Ok(cond) => result.where_condition = Some(cond), + Err(x) => return Err(x) + } + Ok(0) +} - let mut where_condition: ComplexCondition; - let mut simple_condition_tmp: Condition; - let mut complex_condition_tmp: Condition; - let mut counter = 5; - - while counter < args.len() { - if args[counter].eq("AND") || args[counter].eq["OR"] || args[counter].eq("NOT") { - complex_condition_tmp = build_condition(v1, v2, condition) +fn get_where_condition(args: &Vec, start_position: usize, root: ComplexCondition) -> Result { + if start_position == args.len() || args[start_position].eq("ORDER") { + if tree_check(root) { + Ok(root) + } else { + Err(error::WHERE_MAL_FORMATEADO) } - simple_condition = build_condition(args[counter].to_string(), args[counter + 1].to_string(), condition); + } else if args[start_position].eq("OR") { + + } else if args[start_position].eq("AND") { - counter += 3; + } else if args[start_position].eq("NOT") { + + } else if check_valid_args_for_basic_condition(args, start_position) { + + } else { + Err(error::WHERE_MAL_FORMATEADO) } +} - result.where_condition = Some(where_condition); +fn check_valid_args_for_basic_condition(args: &Vec, start_position: usize) -> bool { + if start_position + 3 > args.len() { + false + } else { + let first = &args[start_position]; + let second = &args[start_position + 1]; + let third = &args[start_position + 2]; + + if first.eq("AND") || first.eq("OR") || first.eq("NOT") { + false + } else if second.eq("AND") || second.eq("OR") || second.eq("NOT") { + false + } else if ! ( second.eq(">") || second.eq(">=") || second.eq("=") || second.eq("<") || second.eq("<=") ) { + false + } else if third.eq("AND") || third.eq("OR") || third.eq("NOT") { + false + } else { + true + } + } } fn separate_args_insert(args: &Vec, path: &String, result: &mut Query) { @@ -121,7 +151,7 @@ fn check_operation_format(args: &Vec) -> Result { let operation = &args[0]; if operation.eq("DELETE") { check_delete_format(args) - } else if operation.eq("INSERT" ) { + } else if operation.eq("INSERT") { check_insert_format(args) } else if operation.eq("SELECT") { check_select_format(args) @@ -133,32 +163,17 @@ fn check_operation_format(args: &Vec) -> Result { } fn check_delete_format(args: &Vec) -> Result { - if args[1].eq("FROM") && args[3].eq("WHERE") { - non_valid_keywords = vec!["INSERT","INTO",""] - Ok(QueryType::DELETE) + let non_valid_keywords = vec!["INSERT","INTO","VALUES","SELECT","ORDER","BY","UPDATE","SET"]; + if args[1].eq("FROM") && args[3].eq("WHERE") && check_non_valid_keywords(args, non_valid_keywords) { + Ok(QueryType::DELETE) } else { Err(error::DELETE_MAL_FORMATEADO) } } -fn check_non_valid_keywords(args: &Vec, non_valid_keywords: Vec<&str>) -> bool { - // Checks if args contains any non valid keyword - let mut result = true; - let mut counter = 0; - - while counter < args.len() && result { - if non_valid_keywords.contains(&&args[counter].as_str()) { - result = false; - } else { - counter += 1; - } - } - - result -} - fn check_insert_format(args: &Vec) -> Result { - if args[1].eq("INTO") { + let non_valid_keywords = vec!["DELETE","FROM","SELECT","ORDER","BY","UPDATE","SET","WHERE","AND","OR","NOT"]; + if args[1].eq("INTO") && check_non_valid_keywords(args, non_valid_keywords){ if (args.len() - 3) % 2 != 0 || args.len() - 3 < 0 { Err(2) } else{ @@ -181,13 +196,38 @@ fn check_insert_format(args: &Vec) -> Result { } fn check_select_format(args: &Vec) -> Result { - // TODO format select - Ok(QueryType::SELECT) + let non_valid_keywords = vec!["DELETE","INSERT","INTO","VALUES","UPDATE","SET"]; + if check_non_valid_keywords(args, non_valid_keywords) { + // TODO format select + Ok(QueryType::SELECT) + } else { + Err(error::SELECT_MAL_FORMATEADO) + } } fn check_update_format(args: &Vec) -> Result { - // TODO format select - Ok(QueryType::UPDATE) + let non_valid_keywords = vec!["DELETE","FROM","INSERT","INTO","SELECT","VALUES","ORDER","BY"]; + if args[2].eq("SET") && args.contains(&"WHERE".to_string()) && check_non_valid_keywords(args, non_valid_keywords) { + Ok(QueryType::UPDATE) + } else{ + Err(error::UPDATE_MAL_FORMATEADO) + } +} + +fn check_non_valid_keywords(args: &Vec, non_valid_keywords: Vec<&str>) -> bool { + // Checks if args contains any non valid keyword + let mut result = true; + let mut counter = 0; + + while counter < args.len() && result { + if non_valid_keywords.contains(&&args[counter].as_str()) { + result = false; + } else { + counter += 1; + } + } + + result } fn check_where_format(args: &Vec, start_position: usize) -> bool { @@ -324,21 +364,18 @@ fn check_columns_contains_condition(columns: Vec, query: Query) -> Resul fn text_to_vec(text_query: &String) -> Vec { // Text to vector. Tokenization by space, new line & coma + let tmp_text_query = text_query; + tmp_text_query.replace('\n', " "); + tmp_text_query.replace(',', " "); + tmp_text_query.replace(';', ""); let mut result: Vec = Vec::new(); - let mut split = text_query.split(&[' ', '\n']); + let mut split = tmp_text_query.split(' '); let mut element_opt = split.next(); while element_opt.is_some() { match element_opt { Some(x) => { - if x.contains(',') || x.contains(";"){ - let mut tmp = String::from(x); - tmp.pop(); - result.push(tmp); - } - else { - result.push(x.to_string()); - } + result.push(x.to_string()); }, None => continue } @@ -354,7 +391,10 @@ fn vec_to_query(args: &Vec, path: &String) -> Result{ match check_operation_format(&args) { Ok(x) => { match &x { - QueryType::DELETE => separate_args_delete(args, path, &mut result), + QueryType::DELETE => match separate_args_delete(args, path, &mut result){ + Ok(_) => , + Err(x) => return Err(x) + }, QueryType::INSERT => separate_args_insert(args, path, &mut result), QueryType::SELECT => separate_args_select(args, path, &mut result), QueryType::UPDATE => separate_args_update(args, path, &mut result) diff --git a/src/query.rs b/src/query.rs index 2d2d272..452e235 100644 --- a/src/query.rs +++ b/src/query.rs @@ -8,9 +8,9 @@ pub struct Query { pub operation: Option, // DELETE, INSERT, SELECT, UPDATE pub table: Option, // DELETE, INSERT, SELECT, UPDATE pub columns: Option>, // INSERT, SELECT, UPDATE - pub where_condition: Option, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) - pub order_by: Option<(String,bool)>, // SELECT (a veces) - pub values: Option> // INSERT y UPDATE (en update es set) + pub where_condition: Option, // DELETE (always), SELECT (sometimes), UPDATE (always) . Tree of conditions + pub order_by: Option<(String,bool)>, // SELECT (sometimes) + pub values: Option> // INSERT, UPDATE (in update is set) } pub fn build_empty_query() -> Query { From d7540f7334b7aa1a6ba0d918f65f3dae8fbaf22c Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 13:21:01 -0300 Subject: [PATCH 09/58] WIP: Nuevo branch para simplificar --- README.md | 8 ++ src/condition.rs | 119 +++++++++++++++++++-- src/libs/error.rs | 1 + src/libs/parsing.rs | 247 +++++++++++++++++++++++--------------------- src/query.rs | 6 ++ 5 files changed, 255 insertions(+), 126 deletions(-) diff --git a/README.md b/README.md index e69de29..76dbff9 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,8 @@ +# Ejercicio individual | (75.42) Taller de programación I + +## Alumno: Testa Santiago Tomas ( 108301 ) + +### Detalles de implementación + +Para la lógica compuesta del WHERE el objetivo era crear un arbol de condiciones formado por las relaciones de precedencia. + diff --git a/src/condition.rs b/src/condition.rs index 9264314..dbbc9cc 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -1,14 +1,14 @@ pub mod condition_type; -use std::ops::RemAssign; -use std::ptr::null; +use crate::query::Query; +use crate::libs::error; use condition_type::BooleanOperator; use condition_type::ConditionOperator; pub struct Condition { pub condition: ConditionOperator, - pub v1: Option, - pub v2: Option, + pub column: Option, + pub value: Option, } pub struct ComplexCondition { @@ -16,15 +16,14 @@ pub struct ComplexCondition { pub operator: Option, pub condition: Option, pub left_cond: Option>, // Oldest condition ( first to be found ) - pub parent: Option>, // Newest condition ( last to be found ) pub right_cond: Option> // Newest condition ( last to be found ) } -pub fn build_condition(v1: String, v2: String, condition: ConditionOperator) -> Condition { +pub fn build_condition(column: String, value: String, condition: ConditionOperator) -> Condition { return Condition { condition: condition, - v1: Some(v1), - v2: Some(v2), + column: Some(column), + value: Some(value), } } @@ -33,12 +32,21 @@ pub fn build_empty_complex_condition() -> ComplexCondition { operator: None, condition: None, left_cond: None, - right_cond: None, - parent: None, + right_cond: None } } +pub fn build_complex_condition(operator: BooleanOperator, left: Option>, right: Option>) -> ComplexCondition { + return ComplexCondition { + operator: Some(operator), + condition: None, + left_cond: left, + right_cond: right + } +} + pub fn tree_check(root: ComplexCondition) -> bool { + // In Order valid check ( no None leafs ) match &root.operator { Some(op) => { match op { @@ -74,3 +82,94 @@ fn tree_check_not(root: ComplexCondition) -> bool { None => return false } } + +pub fn add_node_to_tree(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { + if *start_position == args.len() || args[*start_position].eq("ORDER") { + if tree_check(root) { + Ok(root) + } else { + Err(error::WHERE_MAL_FORMATEADO) + } + } else if args[*start_position].eq("OR") { + add_node_to_tree_or(args, &mut start_position, root) + } else if args[*start_position].eq("AND") { + add_node_to_tree_and(args, &mut start_position, root) + } else if args[*start_position].eq("NOT") { + add_node_to_tree_not(args, &mut start_position, root) + } else if check_valid_args_for_basic_condition(args, *start_position) { + match root.operator { + Some(op) => {}, + None => {} + } + } else { + Err(error::WHERE_MAL_FORMATEADO) + } +} + +fn add_node_to_tree_or(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { + let new_root = build_complex_condition(BooleanOperator::OR, Some(Box(root)), None ); + *start_position += 1; + add_node_to_tree(args, start_position, new_root) +} + +fn add_node_to_tree_and(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { + match root.operator { + Some(op) => { + match op { + BooleanOperator::OR => {}, + BooleanOperator::AND => { + let new_root = build_complex_condition(BooleanOperator::AND, Some(Box(root)), None ); + *start_position += 1; + add_node_to_tree(args, start_position , new_root) + }, + BooleanOperator::NOT => { + let new_root = build_complex_condition(BooleanOperator::AND, Some(Box(root)), None ); + *start_position += 1; + add_node_to_tree(args, start_position, new_root) + }, + } + }, + None => { + let new_root = build_complex_condition(BooleanOperator::AND, Some(Box(root)), None ); + add_node_to_tree(args, start_position + 1, new_root) + } + } +} + +fn add_node_to_tree_not(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { + +} + +fn check_valid_args_for_basic_condition(args: &Vec, start_position: usize) -> bool { + if start_position + 3 > args.len() { + false + } else { + let first = &args[start_position]; + let second = &args[start_position + 1]; + let third = &args[start_position + 2]; + + if first.eq("AND") || first.eq("OR") || first.eq("NOT") { + false + } else if second.eq("AND") || second.eq("OR") || second.eq("NOT") { + false + } else if ! ( second.eq(">") || second.eq(">=") || second.eq("=") || second.eq("<") || second.eq("<=") ) { + false + } else if third.eq("AND") || third.eq("OR") || third.eq("NOT") { + false + } else { + true + } + } +} + +fn get_where_columns(query: &Query, vec: Vec, node: &ComplexCondition) -> Vec { + match node.operator { + Some(_) => {}, + None => { + match node.condition { + Some(_) => {}, + None => return vec + } + } + } +} \ No newline at end of file diff --git a/src/libs/error.rs b/src/libs/error.rs index da794e6..bbe0641 100644 --- a/src/libs/error.rs +++ b/src/libs/error.rs @@ -8,6 +8,7 @@ pub static ARCHIVO_VACIO: u32 = 7; pub static ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS: u32 = 8; pub static WHERE_EN_DELETE_MAL_FORMATEADO: u32 = 9; pub static WHERE_MAL_FORMATEADO: u32 = 10; +pub static ORDER_BY_MAL_FORMATEADO: u32 = 11; pub fn print_err(error_code: u32) { // TODO print error diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index e4c8761..26b6b1c 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -1,12 +1,15 @@ use std::io::{BufRead, BufReader}; use std::fs::File; -use crate::condition::{build_condition, build_empty_complex_condition, tree_check, ComplexCondition, Condition}; +use crate::condition::condition_type::BooleanOperator; +use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, tree_check, ComplexCondition, Condition}; use crate::libs::error; -use crate::query::Query; +use crate::query::{Query, DELETE_MIN_LEN, INSERT_MIN_LEN, SELECT_MIN_LEN, UPDATE_MIN_LEN}; use crate::query::query_type::QueryType; use crate::query::build_empty_query; +use super::error::DELETE_MAL_FORMATEADO; + pub fn build_query(text_query: &String, path: &String) -> Result { // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build let args = text_to_vec(&text_query); @@ -26,124 +29,117 @@ fn merge_table_and_path(path: &String, table: &String) -> String { } fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) -> Result { - result.table = Some(merge_table_and_path(path, &args[2])); - match get_where_condition(args, 4, build_empty_complex_condition()) { - Ok(cond) => result.where_condition = Some(cond), - Err(x) => return Err(x) - } - Ok(0) -} - -fn get_where_condition(args: &Vec, start_position: usize, root: ComplexCondition) -> Result { - if start_position == args.len() || args[start_position].eq("ORDER") { - if tree_check(root) { - Ok(root) - } else { - Err(error::WHERE_MAL_FORMATEADO) - } - } else if args[start_position].eq("OR") { - - } else if args[start_position].eq("AND") { - - } else if args[start_position].eq("NOT") { - - } else if check_valid_args_for_basic_condition(args, start_position) { - + if args.len() < DELETE_MIN_LEN { + return Err(error::DELETE_MAL_FORMATEADO); } else { - Err(error::WHERE_MAL_FORMATEADO) + result.table = Some(merge_table_and_path(path, &args[2])); + match add_node_to_tree(args, &mut 4, build_empty_complex_condition()) { + Ok(cond) => result.where_condition = Some(cond), + Err(x) => return Err(x) + } + Ok(0) } } -fn check_valid_args_for_basic_condition(args: &Vec, start_position: usize) -> bool { - if start_position + 3 > args.len() { - false +fn separate_args_insert(args: &Vec, path: &String, result: &mut Query) -> Result { + if args.len() < INSERT_MIN_LEN { + return Err(error::INSERT_MAL_FORMATEADO) } else { - let first = &args[start_position]; - let second = &args[start_position + 1]; - let third = &args[start_position + 2]; - - if first.eq("AND") || first.eq("OR") || first.eq("NOT") { - false - } else if second.eq("AND") || second.eq("OR") || second.eq("NOT") { - false - } else if ! ( second.eq(">") || second.eq(">=") || second.eq("=") || second.eq("<") || second.eq("<=") ) { - false - } else if third.eq("AND") || third.eq("OR") || third.eq("NOT") { - false - } else { - true - } - } -} - -fn separate_args_insert(args: &Vec, path: &String, result: &mut Query) { - result.table = Some(merge_table_and_path(path, &args[2])); - - let mut columns: Vec = Vec::new(); - let mut counter = 3; - while counter < args.len()/2 && ! args[counter].eq("VALUES") { - columns.push(args[counter].to_string()); - counter += 1; - } + result.table = Some(merge_table_and_path(path, &args[2])); - counter += 1; - let mut values: Vec = Vec::new(); - while counter < args.len() { - values.push(args[counter].to_string()); + let mut columns: Vec = Vec::new(); + let mut counter = 3; + while counter < args.len()/2 && ! args[counter].eq("VALUES") { + columns.push(args[counter].to_string()); + counter += 1; + } + counter += 1; + let mut values: Vec = Vec::new(); + while counter < args.len() { + values.push(args[counter].to_string()); + counter += 1; + } + + result.columns = Some(columns); + result.values = Some(values); + Ok(0) } - - result.columns = Some(columns); - result.values = Some(values); } -fn separate_args_update(args: &Vec, path: &String, result: &mut Query) { - result.table = Some(merge_table_and_path(path, &args[1])); - - let mut counter = 3; - let mut columns: Vec = Vec::new(); - let mut values: Vec = Vec::new(); +fn separate_args_update(args: &Vec, path: &String, result: &mut Query) -> Result { + if args.len() < UPDATE_MIN_LEN { + result.table = Some(merge_table_and_path(path, &args[1])); - while counter < args.len() && !args[counter].eq("WHERE") { - if counter % 3 == 0 { - columns.push(args[counter].to_string()); - } else if ( counter % 3 ) == 2 { - values.push(args[counter].to_string()); - } - counter += 1; - } - counter += 1; - - let mut where_condition = Vec::new(); - while counter < args.len() { - where_condition.push(args[counter].to_string()); + let mut counter = 3; + let mut columns: Vec = Vec::new(); + let mut values: Vec = Vec::new(); + + while counter < args.len() && !args[counter].eq("WHERE") { + if counter % 3 == 0 { + columns.push(args[counter].to_string()); + } else if ( counter % 3 ) == 2 { + values.push(args[counter].to_string()); + } + counter += 1; + } counter += 1; + + result.columns = Some(columns); + result.values = Some(values); + + match add_node_to_tree(args, &mut counter, build_empty_complex_condition()) { + Ok(cond) => result.where_condition = Some(cond), + Err(x) => return Err(x) + } + Ok(0) + } else { + return Err(error::UPDATE_MAL_FORMATEADO) } - - result.columns = Some(columns); - result.where_condition = Some(where_condition); - result.values = Some(values); } -fn separate_args_select(args: &Vec, path: &String, result: &mut Query) { - let mut columns: Vec = Vec::new(); - let mut counter = 1; - while counter < args.len() && !args[counter].eq("FROM") { - columns.push(args[counter].to_string()); +fn separate_args_select(args: &Vec, path: &String, result: &mut Query) -> Result { + if args.len() < SELECT_MIN_LEN { + return Err(error::SELECT_MAL_FORMATEADO) + } else { + let mut columns: Vec = Vec::new(); + let mut counter = 1; + while counter < args.len() && !args[counter].eq("FROM") { + columns.push(args[counter].to_string()); + counter += 1; + } counter += 1; - } - counter += 1; - result.table = Some(merge_table_and_path(path, &args[counter])); - - let mut where_condition = Vec::new(); - while counter < args.len() && !args[counter].eq("ORDER") { - where_condition.push(args[counter].to_string()); + result.table = Some(merge_table_and_path(path, &args[counter])); counter += 1; + + if counter == args.len() { + Ok(0) + } else { + match add_node_to_tree(args, &mut counter, build_empty_complex_condition()) { + Ok(cond) => result.where_condition = Some(cond), + Err(x) => return Err(x) + } + + if counter < args.len() { + if args[counter + 1].eq("BY") { + if counter + 3 == args.len() { // ORDER BY column + result.order_by = Some((args[counter + 2].to_string(), true)); + } else if counter + 4 == args.len() { // ORDER BY column ASC/DESC + if args[counter + 3].eq("ASC") || args[counter + 3].eq("DESC") { + result.order_by = Some((args[counter + 2].to_string(), args[counter + 2].eq("ASC"))); + } else { + return Err(error::ORDER_BY_MAL_FORMATEADO) + } + } else { + return Err(error::ORDER_BY_MAL_FORMATEADO) + } + } else { + return Err(error::ORDER_BY_MAL_FORMATEADO) + } + } + Ok(0) + } } - result.where_condition = Some(where_condition); - - // Last condition returns false on desc, true on asc - result.order_by = Some((args[counter + 2].to_string(),counter + 3 != args.len())); } fn check_operation_format(args: &Vec) -> Result { @@ -300,7 +296,7 @@ fn validate_query(query: Query) -> Result { match &query.operation { Some(op) => { - match &query.operation.unwrap() { + match op { QueryType::DELETE => validate_delete_query(query), QueryType::INSERT => validate_insert_query(query), QueryType::SELECT => validate_select_query(query), @@ -312,7 +308,7 @@ fn validate_query(query: Query) -> Result { } fn validate_delete_query(query: Query) -> Result { - if query.columns.is_none() && query.values.is_none() && query.columns.is_none() { + if query.columns.is_none() && query.values.is_none() && query.where_condition.is_some() { match &query.table { Some(table) => { match File::open(table) { @@ -332,6 +328,21 @@ fn validate_delete_query(query: Query) -> Result { } } +fn validate_insert_query(query: Query) -> Result { + // TODO + Ok(query) +} + +fn validate_select_query(query: Query) -> Result { + // TODO + Ok(query) +} + +fn validate_update_query(query: Query) -> Result { + // TODO + Ok(query) +} + fn get_columns(file: File) -> Option> { let mut result: Vec = Vec::new(); let mut reader: BufReader = BufReader::new(file); @@ -354,23 +365,19 @@ fn get_columns(file: File) -> Option> { } } -fn get_where_columns(query: &Query) -> Option> { - -} - fn check_columns_contains_condition(columns: Vec, query: Query) -> Result { - + // TODO } fn text_to_vec(text_query: &String) -> Vec { // Text to vector. Tokenization by space, new line & coma let tmp_text_query = text_query; tmp_text_query.replace('\n', " "); - tmp_text_query.replace(',', " "); + tmp_text_query.replace(',', ""); tmp_text_query.replace(';', ""); - let mut result: Vec = Vec::new(); let mut split = tmp_text_query.split(' '); + let mut result: Vec = Vec::new(); let mut element_opt = split.next(); while element_opt.is_some() { match element_opt { @@ -392,14 +399,22 @@ fn vec_to_query(args: &Vec, path: &String) -> Result{ Ok(x) => { match &x { QueryType::DELETE => match separate_args_delete(args, path, &mut result){ - Ok(_) => , + Ok(_) => result.operation = Some(x), Err(x) => return Err(x) }, - QueryType::INSERT => separate_args_insert(args, path, &mut result), - QueryType::SELECT => separate_args_select(args, path, &mut result), - QueryType::UPDATE => separate_args_update(args, path, &mut result) + QueryType::INSERT => match separate_args_insert(args, path, &mut result) { + Ok(_) => result.operation = Some(x), + Err(x) => return Err(x) + }, + QueryType::SELECT => match separate_args_select(args, path, &mut result) { + Ok(_) => result.operation = Some(x), + Err(x) => return Err(x) + }, + QueryType::UPDATE => match separate_args_update(args, path, &mut result) { + Ok(_) => result.operation = Some(x), + Err(x) => return Err(x) + } } - result.operation = Some(x); }, Err(x) => return Err(x) } diff --git a/src/query.rs b/src/query.rs index 452e235..45c2a3e 100644 --- a/src/query.rs +++ b/src/query.rs @@ -4,6 +4,12 @@ use query_type::QueryType; use crate::condition::ComplexCondition; +pub static DELETE_MIN_LEN :usize = 7; // DELETE FROM tabla WHERE a < b +pub static INSERT_MIN_LEN :usize = 6; // INSERT INTO tabla col VALUES val +pub static SELECT_MIN_LEN :usize = 4; // SELECT * FROM tabla +pub static UPDATE_MIN_LEN :usize = 10; // UPDATE tabla SET col = valor WHERE a < b + + pub struct Query { pub operation: Option, // DELETE, INSERT, SELECT, UPDATE pub table: Option, // DELETE, INSERT, SELECT, UPDATE From ef08de54693002bb19d391f8fe2cefe7d37ba4c3 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 13:38:09 -0300 Subject: [PATCH 10/58] WIP: corrigiendo el arbol --- src/condition.rs | 2 +- src/libs/error.rs | 1 + src/libs/parsing.rs | 27 +++++++++++++++++++++++---- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/condition.rs b/src/condition.rs index dbbc9cc..f005c7e 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -162,7 +162,7 @@ fn check_valid_args_for_basic_condition(args: &Vec, start_position: usiz } } -fn get_where_columns(query: &Query, vec: Vec, node: &ComplexCondition) -> Vec { +pub fn get_where_columns(query: &Query, vec: Vec, node: &ComplexCondition) -> Vec { match node.operator { Some(_) => {}, None => { diff --git a/src/libs/error.rs b/src/libs/error.rs index bbe0641..2e05cd5 100644 --- a/src/libs/error.rs +++ b/src/libs/error.rs @@ -9,6 +9,7 @@ pub static ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS: u32 = 8; pub static WHERE_EN_DELETE_MAL_FORMATEADO: u32 = 9; pub static WHERE_MAL_FORMATEADO: u32 = 10; pub static ORDER_BY_MAL_FORMATEADO: u32 = 11; +pub static NO_WHERE: u32 = 12; pub fn print_err(error_code: u32) { // TODO print error diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 26b6b1c..552e358 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -2,7 +2,7 @@ use std::io::{BufRead, BufReader}; use std::fs::File; use crate::condition::condition_type::BooleanOperator; -use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, tree_check, ComplexCondition, Condition}; +use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, get_where_columns, tree_check, ComplexCondition, Condition}; use crate::libs::error; use crate::query::{Query, DELETE_MIN_LEN, INSERT_MIN_LEN, SELECT_MIN_LEN, UPDATE_MIN_LEN}; use crate::query::query_type::QueryType; @@ -289,9 +289,12 @@ fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) - fn validate_query(query: Query) -> Result { // Pre: Sintactical query OK // Post: Valid query for execution - match File::open(&query.table.unwrap()) { - Ok(_) => {}, - Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + match &query.table { + Some(table) => match File::open(table) { + Ok(_) => {}, + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + }, + None => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) } match &query.operation { @@ -367,6 +370,22 @@ fn get_columns(file: File) -> Option> { fn check_columns_contains_condition(columns: Vec, query: Query) -> Result { // TODO + match &query.where_condition { + Some(node) => { + let where_columnns = get_where_columns(&query, Vec::new(), node ); + let mut counter = 0; + while counter < columns.len() && where_columnns.contains(&columns[counter]) { + counter += 1; + } + + if counter == columns.len() { + Ok(query) + } else { + Err(error::NO_WHERE) + } + }, + None => return Err(error::NO_WHERE) + } } fn text_to_vec(text_query: &String) -> Vec { From b359e61f74195068e8f7e8c22a60495d44788e7b Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 15:35:47 -0300 Subject: [PATCH 11/58] MOD: where simple sin relaciones complejas. TODO complejas --- README.md | 1 + src/condition.rs | 159 +-------------------------- src/condition/complex_condition.rs | 166 +++++++++++++++++++++++++++++ src/libs/parsing.rs | 47 ++++---- src/query.rs | 6 +- 5 files changed, 204 insertions(+), 175 deletions(-) create mode 100644 src/condition/complex_condition.rs diff --git a/README.md b/README.md index 76dbff9..eadd1c2 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,4 @@ Para la lógica compuesta del WHERE el objetivo era crear un arbol de condiciones formado por las relaciones de precedencia. +Dicho objetivo no pudo ser implementado. Se implementó lógica de condiciones simples ( no compuestas ) diff --git a/src/condition.rs b/src/condition.rs index f005c7e..1ec5875 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -1,8 +1,12 @@ pub mod condition_type; +/* +pub mod complex_condition; use crate::query::Query; use crate::libs::error; use condition_type::BooleanOperator; +*/ + use condition_type::ConditionOperator; pub struct Condition { @@ -11,14 +15,6 @@ pub struct Condition { pub value: Option, } -pub struct ComplexCondition { - // Tree of complex conditions - pub operator: Option, - pub condition: Option, - pub left_cond: Option>, // Oldest condition ( first to be found ) - pub right_cond: Option> // Newest condition ( last to be found ) -} - pub fn build_condition(column: String, value: String, condition: ConditionOperator) -> Condition { return Condition { condition: condition, @@ -26,150 +22,3 @@ pub fn build_condition(column: String, value: String, condition: ConditionOperat value: Some(value), } } - -pub fn build_empty_complex_condition() -> ComplexCondition { - return ComplexCondition { - operator: None, - condition: None, - left_cond: None, - right_cond: None - } -} - -pub fn build_complex_condition(operator: BooleanOperator, left: Option>, right: Option>) -> ComplexCondition { - return ComplexCondition { - operator: Some(operator), - condition: None, - left_cond: left, - right_cond: right - } -} - -pub fn tree_check(root: ComplexCondition) -> bool { - // In Order valid check ( no None leafs ) - match &root.operator { - Some(op) => { - match op { - BooleanOperator::OR => tree_check_or_and(root), - BooleanOperator::AND => tree_check_or_and(root), - BooleanOperator::NOT => tree_check_not(root) - } - }, - None => return true - } -} - -fn tree_check_or_and(root: ComplexCondition) -> bool { - match root.left_cond { - Some(left) => { - match root.right_cond { - Some(right) => return tree_check(*left) && tree_check(*right), - None => return false - } - }, - None => return false - } -} - -fn tree_check_not(root: ComplexCondition) -> bool { - match root.left_cond { - Some(left) => { - match root.right_cond { - Some(_) => return false, - None => return tree_check(*left) - } - }, - None => return false - } -} - -pub fn add_node_to_tree(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { - if *start_position == args.len() || args[*start_position].eq("ORDER") { - if tree_check(root) { - Ok(root) - } else { - Err(error::WHERE_MAL_FORMATEADO) - } - } else if args[*start_position].eq("OR") { - add_node_to_tree_or(args, &mut start_position, root) - } else if args[*start_position].eq("AND") { - add_node_to_tree_and(args, &mut start_position, root) - } else if args[*start_position].eq("NOT") { - add_node_to_tree_not(args, &mut start_position, root) - } else if check_valid_args_for_basic_condition(args, *start_position) { - match root.operator { - Some(op) => {}, - None => {} - } - } else { - Err(error::WHERE_MAL_FORMATEADO) - } -} - -fn add_node_to_tree_or(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { - let new_root = build_complex_condition(BooleanOperator::OR, Some(Box(root)), None ); - *start_position += 1; - add_node_to_tree(args, start_position, new_root) -} - -fn add_node_to_tree_and(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { - match root.operator { - Some(op) => { - match op { - BooleanOperator::OR => {}, - BooleanOperator::AND => { - let new_root = build_complex_condition(BooleanOperator::AND, Some(Box(root)), None ); - *start_position += 1; - add_node_to_tree(args, start_position , new_root) - }, - BooleanOperator::NOT => { - let new_root = build_complex_condition(BooleanOperator::AND, Some(Box(root)), None ); - *start_position += 1; - add_node_to_tree(args, start_position, new_root) - }, - } - }, - None => { - let new_root = build_complex_condition(BooleanOperator::AND, Some(Box(root)), None ); - add_node_to_tree(args, start_position + 1, new_root) - } - } -} - -fn add_node_to_tree_not(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { - -} - -fn check_valid_args_for_basic_condition(args: &Vec, start_position: usize) -> bool { - if start_position + 3 > args.len() { - false - } else { - let first = &args[start_position]; - let second = &args[start_position + 1]; - let third = &args[start_position + 2]; - - if first.eq("AND") || first.eq("OR") || first.eq("NOT") { - false - } else if second.eq("AND") || second.eq("OR") || second.eq("NOT") { - false - } else if ! ( second.eq(">") || second.eq(">=") || second.eq("=") || second.eq("<") || second.eq("<=") ) { - false - } else if third.eq("AND") || third.eq("OR") || third.eq("NOT") { - false - } else { - true - } - } -} - -pub fn get_where_columns(query: &Query, vec: Vec, node: &ComplexCondition) -> Vec { - match node.operator { - Some(_) => {}, - None => { - match node.condition { - Some(_) => {}, - None => return vec - } - } - } -} \ No newline at end of file diff --git a/src/condition/complex_condition.rs b/src/condition/complex_condition.rs new file mode 100644 index 0000000..0f41a05 --- /dev/null +++ b/src/condition/complex_condition.rs @@ -0,0 +1,166 @@ +use crate::query::Query; +use crate::libs::error; +use super::BooleanOperator; + +pub struct ComplexCondition { + // Tree of complex conditions + pub operator: Option, + pub condition: Option, + pub left_cond: Option>, // Oldest condition ( first to be found ) + pub right_cond: Option> // Newest condition ( last to be found ) +} + +pub fn build_empty_complex_condition() -> ComplexCondition { + return ComplexCondition { + operator: None, + condition: None, + left_cond: None, + right_cond: None + } +} + +pub fn build_complex_condition(operator: BooleanOperator, left: Option>, right: Option>) -> ComplexCondition { + return ComplexCondition { + operator: Some(operator), + condition: None, + left_cond: left, + right_cond: right + } +} + +pub fn tree_check(root: ComplexCondition) -> bool { + // In Order valid check ( no None leafs ) + match &root.operator { + Some(op) => { + match op { + BooleanOperator::OR => tree_check_or_and(root), + BooleanOperator::AND => tree_check_or_and(root), + BooleanOperator::NOT => tree_check_not(root) + } + }, + None => return true + } +} + +fn tree_check_or_and(root: ComplexCondition) -> bool { + match root.left_cond { + Some(left) => { + match root.right_cond { + Some(right) => return tree_check(*left) && tree_check(*right), + None => return false + } + }, + None => return false + } +} + +fn tree_check_not(root: ComplexCondition) -> bool { + match root.left_cond { + Some(left) => { + match root.right_cond { + Some(_) => return false, + None => return tree_check(*left) + } + }, + None => return false + } +} + +pub fn add_node_to_tree(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { + if *start_position == args.len() || args[*start_position].eq("ORDER") { + if tree_check(root) { + Ok(root) + } else { + Err(error::WHERE_MAL_FORMATEADO) + } + } else if args[*start_position].eq("OR") { + add_node_to_tree_or(args, &mut start_position, root) + } else if args[*start_position].eq("AND") { + add_node_to_tree_and(args, &mut start_position, root) + } else if args[*start_position].eq("NOT") { + add_node_to_tree_not(args, &mut start_position, root) + } else if check_valid_args_for_basic_condition(args, *start_position) { + match root.operator { + Some(op) => { + + }, + None => return Err(error::WHERE_MAL_FORMATEADO) // C1 C2 + } + } else { + Err(error::WHERE_MAL_FORMATEADO) + } +} + +fn add_node_to_tree_or(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { + let new_root = build_complex_condition(BooleanOperator::OR, Some(Box::new(root)), None ); + *start_position += 1; + add_node_to_tree(args, start_position, new_root) +} + +fn add_node_to_tree_and(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { + match root.operator { + Some(op) => { + match op { + BooleanOperator::OR => { + match root.left_cond { + Some(x) => {}, + None => return Err(error::WHERE_MAL_FORMATEADO) + } + }, + BooleanOperator::AND => { + let new_root = build_complex_condition(BooleanOperator::AND, Some(Box::new(root)), None ); + *start_position += 1; + add_node_to_tree(args, start_position , new_root) + }, + BooleanOperator::NOT => { + let new_root = build_complex_condition(BooleanOperator::AND, Some(Box::new(root)), None ); + *start_position += 1; + add_node_to_tree(args, start_position, new_root) + }, + } + }, + None => { + let new_root = build_complex_condition(BooleanOperator::AND, Some(Box::new(root)), None ); + *start_position += 1; + add_node_to_tree(args, start_position, new_root) + } + } +} + +fn add_node_to_tree_not(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { + +} + +fn check_valid_args_for_basic_condition(args: &Vec, start_position: usize) -> bool { + if start_position + 3 > args.len() { + false + } else { + let first = &args[start_position]; + let second = &args[start_position + 1]; + let third = &args[start_position + 2]; + + if first.eq("AND") || first.eq("OR") || first.eq("NOT") { + false + } else if second.eq("AND") || second.eq("OR") || second.eq("NOT") { + false + } else if ! ( second.eq(">") || second.eq(">=") || second.eq("=") || second.eq("<") || second.eq("<=") ) { + false + } else if third.eq("AND") || third.eq("OR") || third.eq("NOT") { + false + } else { + true + } + } +} + +pub fn get_where_columns(query: &Query, vec: Vec, node: &ComplexCondition) -> Vec { + match node.operator { + Some(_) => {}, + None => { + match node.condition { + Some(_) => {}, + None => return vec + } + } + } +} \ No newline at end of file diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 552e358..f8b9012 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -1,15 +1,13 @@ use std::io::{BufRead, BufReader}; use std::fs::File; -use crate::condition::condition_type::BooleanOperator; -use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, get_where_columns, tree_check, ComplexCondition, Condition}; +//use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, get_where_columns, tree_check, ComplexCondition, Condition}; +// use crate::condition::Condition; use crate::libs::error; use crate::query::{Query, DELETE_MIN_LEN, INSERT_MIN_LEN, SELECT_MIN_LEN, UPDATE_MIN_LEN}; use crate::query::query_type::QueryType; use crate::query::build_empty_query; -use super::error::DELETE_MAL_FORMATEADO; - pub fn build_query(text_query: &String, path: &String) -> Result { // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build let args = text_to_vec(&text_query); @@ -32,11 +30,14 @@ fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) - if args.len() < DELETE_MIN_LEN { return Err(error::DELETE_MAL_FORMATEADO); } else { - result.table = Some(merge_table_and_path(path, &args[2])); + result.table = Some(merge_table_and_path(path, &args[2])); + + /* TODO: Code for complex conditions match add_node_to_tree(args, &mut 4, build_empty_complex_condition()) { Ok(cond) => result.where_condition = Some(cond), Err(x) => return Err(x) } + */ Ok(0) } } @@ -87,11 +88,13 @@ fn separate_args_update(args: &Vec, path: &String, result: &mut Query) - result.columns = Some(columns); result.values = Some(values); - + + /* TODO: Code for complex conditions match add_node_to_tree(args, &mut counter, build_empty_complex_condition()) { Ok(cond) => result.where_condition = Some(cond), Err(x) => return Err(x) } + */ Ok(0) } else { return Err(error::UPDATE_MAL_FORMATEADO) @@ -115,11 +118,13 @@ fn separate_args_select(args: &Vec, path: &String, result: &mut Query) - if counter == args.len() { Ok(0) } else { + /* TODO: Code for complex conditions match add_node_to_tree(args, &mut counter, build_empty_complex_condition()) { Ok(cond) => result.where_condition = Some(cond), Err(x) => return Err(x) } - + */ + if counter < args.len() { if args[counter + 1].eq("BY") { if counter + 3 == args.len() { // ORDER BY column @@ -370,24 +375,30 @@ fn get_columns(file: File) -> Option> { fn check_columns_contains_condition(columns: Vec, query: Query) -> Result { // TODO - match &query.where_condition { - Some(node) => { - let where_columnns = get_where_columns(&query, Vec::new(), node ); - let mut counter = 0; - while counter < columns.len() && where_columnns.contains(&columns[counter]) { - counter += 1; - } - - if counter == columns.len() { - Ok(query) + match get_where_columns(&query) { + Some(column) => { + if columns.contains(&column) { + Ok(query) } else { - Err(error::NO_WHERE) + Err(error::ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS) } }, None => return Err(error::NO_WHERE) } } +fn get_where_columns(query: &Query) -> Option { + match &query.where_condition { + Some(cond) => { + match &cond.column { + Some(col) => return Some(col.to_string()), + None => return None + } + }, + None => return None + } +} + fn text_to_vec(text_query: &String) -> Vec { // Text to vector. Tokenization by space, new line & coma let tmp_text_query = text_query; diff --git a/src/query.rs b/src/query.rs index 45c2a3e..6fba4ad 100644 --- a/src/query.rs +++ b/src/query.rs @@ -2,7 +2,9 @@ pub mod query_type; use query_type::QueryType; -use crate::condition::ComplexCondition; +use crate::condition::Condition; + +// use crate::condition::ComplexCondition; pub static DELETE_MIN_LEN :usize = 7; // DELETE FROM tabla WHERE a < b pub static INSERT_MIN_LEN :usize = 6; // INSERT INTO tabla col VALUES val @@ -14,7 +16,7 @@ pub struct Query { pub operation: Option, // DELETE, INSERT, SELECT, UPDATE pub table: Option, // DELETE, INSERT, SELECT, UPDATE pub columns: Option>, // INSERT, SELECT, UPDATE - pub where_condition: Option, // DELETE (always), SELECT (sometimes), UPDATE (always) . Tree of conditions + pub where_condition: Option, // DELETE (always), SELECT (sometimes), UPDATE (always) . Tree of conditions pub order_by: Option<(String,bool)>, // SELECT (sometimes) pub values: Option> // INSERT, UPDATE (in update is set) } From 831f56637c2b39e8e4eb7c20c80cf27ba23ba123 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 20:20:47 -0300 Subject: [PATCH 12/58] WIP gdb: SELECT * FROM clientes --- README.md | 10 ++- src/condition.rs | 15 +++- src/libs/error.rs | 1 + src/libs/exec.rs | 204 +++++++++++++++++++++++++++++++++++++++----- src/libs/parsing.rs | 153 +++++++++++++++------------------ src/query.rs | 2 +- 6 files changed, 279 insertions(+), 106 deletions(-) diff --git a/README.md b/README.md index eadd1c2..1081626 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,16 @@ ## Alumno: Testa Santiago Tomas ( 108301 ) +### Detalles de entrega + +El trabajo no se encuentra completo. Las siguientes funcionalidades se encuentran pendientes: + +1. Logica booleana + +2. + ### Detalles de implementación -Para la lógica compuesta del WHERE el objetivo era crear un arbol de condiciones formado por las relaciones de precedencia. +Para la lógica booleana el objetivo era crear un arbol de condiciones formado por las relaciones de precedencia. Dicho objetivo no pudo ser implementado. Se implementó lógica de condiciones simples ( no compuestas ) diff --git a/src/condition.rs b/src/condition.rs index 1ec5875..79cfc34 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -1,8 +1,8 @@ pub mod condition_type; +use crate::query::Query; /* pub mod complex_condition; -use crate::query::Query; use crate::libs::error; use condition_type::BooleanOperator; */ @@ -22,3 +22,16 @@ pub fn build_condition(column: String, value: String, condition: ConditionOperat value: Some(value), } } + +/* +pub fn operate_condition(filter: (&u32,&ConditionOperator,&String), elements: &Vec) -> bool { + let (column, operator, value) = filter; + match operator { + ConditionOperator::Minor => {}, + ConditionOperator::MinorEqual => {}, + ConditionOperator::Equal => {}, + ConditionOperator::Higher => {}, + ConditionOperator::HigherEqual => {}, + } +} +*/ \ No newline at end of file diff --git a/src/libs/error.rs b/src/libs/error.rs index 2e05cd5..60bc4d5 100644 --- a/src/libs/error.rs +++ b/src/libs/error.rs @@ -13,4 +13,5 @@ pub static NO_WHERE: u32 = 12; pub fn print_err(error_code: u32) { // TODO print error + println!("ERROR. Codigo: {}",error_code) } \ No newline at end of file diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 7a751eb..17d1554 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -1,41 +1,203 @@ +use std::io::{BufRead, BufReader}; use std::fs::File; +//use crate::condition::operate_condition; use crate::query::query_type::QueryType; use crate::query::Query; +use super::parsing::get_file_first_line; + pub fn exec_query(query: Query) { - let table = &query.table; - match table { - Some(f) => match std::fs::File::open(f) { - Ok(file) => { - match &query.operation { - Some(op) => match op { - QueryType::DELETE => exec_query_delete(file, query), - QueryType::INSERT => exec_query_insert(file, query), - QueryType::SELECT => exec_query_select(file, query), - QueryType::UPDATE => exec_query_update(file, query), - }, - None => println!("Error en el programa") - } - }, - Err(_) => println!("Error en el programa") - } , + match &query.operation { + Some(op) => match op { + QueryType::DELETE => exec_query_delete(query), + QueryType::INSERT => exec_query_insert(query), + QueryType::SELECT => exec_query_select(query), + QueryType::UPDATE => exec_query_update(query), + }, None => println!("Error en el programa") } } -fn exec_query_delete(file: File, query: Query) { +fn exec_query_delete(query: Query) { // TODO } -fn exec_query_insert(file: File, query: Query) { +fn exec_query_insert(query: Query) { // TODO } -fn exec_query_select(file: File, query: Query) { - // TODO +fn exec_query_select(query: Query) { + match &query.order_by { + Some(_) => exec_query_select_order_by(query), + None => { + let col_index = find_filter_column(&query); + let print_columns: Vec = find_print_columns(&query); + read_and_print_file(&query, col_index, &print_columns ); + } + } +} + +fn find_print_columns(query: &Query) -> Vec { + let mut result: Vec = Vec::new(); + match &query.columns { + Some(cols) => match get_file_first_line(query) { + Some(line) => { + let table_columns: Vec = line_to_vec(&line); + for element in cols { + let mut counter = 0; + while ! table_columns[counter].eq(element) && counter < table_columns.len() { + counter += 1; + } + if counter < table_columns.len() { + result.push(counter); + } + } + + result + }, + None => result + }, + None => result + } +} + +fn find_filter_column(query: &Query) -> i32 { + let mut col_index_filter = -1; + match &query.where_condition { + Some(x) => { + match &x.column { + Some(column) => { + match &query.table { + Some(table) => match File::open(table){ + Ok(file) => { + let mut reader: BufReader = BufReader::new(file); + let mut line = String::new(); + match reader.read_line(&mut line) { + Ok(_) => { + let mut split = line.split(','); + let mut element_opt = split.next(); + let mut counter = 0; + + while element_opt.is_some() && col_index_filter < 0 { + match element_opt { + Some(x) => { + if x.eq(column) { + col_index_filter = counter; + } + } + None => {} + } + counter += 1; + element_opt = split.next(); + } + }, + Err(_) => col_index_filter = -1, + } + }, + Err(_) => return -1 + }, + None => return -1 + } + }, + None => { col_index_filter = -1; } + } + }, + None => col_index_filter = -1 + } + col_index_filter +} + +fn read_and_print_file(query: &Query, col_filter: i32, columns: &Vec ) { + match &query.table { + Some(table) => match File::open(table) { + Ok(f) => { + let mut reader: BufReader = BufReader::new(f); + let mut line = String::new(); + + // Print header + reader.read_line(&mut line); + println!("{}",line); + + // Print other lines + let mut read = true; + while read { + match reader.read_line(&mut line) { + Ok(x) => { + read = x != 0; + if read { + let elements = line_to_vec(&line); + match &query.where_condition { + Some(condition) => {}, + None => print_file_unconditional(&columns, &elements) + } + } + }, + Err(_) => println!("Error en el programa") + } + } + }, + Err(_) => println!("Error en el programa") + }, + None => println!("Error en el programa ") + } +} + +fn print_file_unconditional(columns: &Vec, elements: &Vec ) { + // Pre: Columns vector sorted incremental && Elements of line content vector + // Post: print to stdout the correct columns + + if columns.is_empty(){ + let mut counter = 0; + for element in elements { + print!("{}",element); + if counter < elements.len() - 1 { + print!(","); + } + + counter += 1; + } + } else { + let mut counter = 0; + let mut found_count = 0; + while counter < elements.len() { + if columns.contains(&counter) { + if found_count == 0 { + print!("{}",elements[counter]); + } else { + print!(",{}",elements[counter]); + } + found_count += 1; + } + + counter += 1; + } + } + println!(); +} + +fn line_to_vec(line: &String) -> Vec { + let mut result: Vec = Vec::new(); + let mut split = line.split(','); + + let mut element_opt = split.next(); + while element_opt.is_some() { + match element_opt { + Some(x) => { + result.push(x.to_string()); + }, + None => continue + } + + element_opt = split.next(); + } + result +} + +fn exec_query_select_order_by(query: Query) { + } -fn exec_query_update(file: File, query: Query) { +fn exec_query_update(query: Query) { // TODO } diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index f8b9012..28de3ba 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -1,6 +1,8 @@ use std::io::{BufRead, BufReader}; use std::fs::File; +use crate::condition::condition_type::ConditionOperator; +use crate::condition::{build_condition, Condition}; //use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, get_where_columns, tree_check, ComplexCondition, Condition}; // use crate::condition::Condition; use crate::libs::error; @@ -8,6 +10,8 @@ use crate::query::{Query, DELETE_MIN_LEN, INSERT_MIN_LEN, SELECT_MIN_LEN, UPDATE use crate::query::query_type::QueryType; use crate::query::build_empty_query; +use super::error::SELECT_MAL_FORMATEADO; + pub fn build_query(text_query: &String, path: &String) -> Result { // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build let args = text_to_vec(&text_query); @@ -32,12 +36,30 @@ fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) - } else { result.table = Some(merge_table_and_path(path, &args[2])); - /* TODO: Code for complex conditions - match add_node_to_tree(args, &mut 4, build_empty_complex_condition()) { - Ok(cond) => result.where_condition = Some(cond), - Err(x) => return Err(x) + if args.len() != DELETE_MIN_LEN { + return Err(error::DELETE_MAL_FORMATEADO) + } else { + /* TODO: Code for complex conditions + match add_node_to_tree(args, &mut 4, build_empty_complex_condition()) { + Ok(cond) => result.where_condition = Some(cond), + Err(x) => return Err(x) + } + */ + + if args[5].eq("<") { + result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::Minor)) + } else if args[5].eq("<=") { + result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::MinorEqual)) + } else if args[5].eq("=") { + result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::Equal)) + } else if args[5].eq(">=") { + result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::HigherEqual)) + } else if args[5].eq(">") { + result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::Higher)) + } else { + return Err(error::WHERE_MAL_FORMATEADO) + } } - */ Ok(0) } } @@ -124,9 +146,27 @@ fn separate_args_select(args: &Vec, path: &String, result: &mut Query) - Err(x) => return Err(x) } */ + if counter + 3 > args.len(){ + return Err(SELECT_MAL_FORMATEADO); + } else if args[counter].eq("WHERE") { + counter += 1; + if args[counter + 1].eq("<") { + result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::Minor)) + } else if args[counter + 1].eq("<=") { + result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::MinorEqual)) + } else if args[counter + 1].eq("=") { + result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::Equal)) + } else if args[counter + 1].eq(">=") { + result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::HigherEqual)) + } else if args[counter + 1].eq(">") { + result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::Higher)) + } else { + return Err(error::WHERE_MAL_FORMATEADO) + } + } if counter < args.len() { - if args[counter + 1].eq("BY") { + if args[counter].eq("ORDER") && args[counter + 1].eq("BY") { if counter + 3 == args.len() { // ORDER BY column result.order_by = Some((args[counter + 2].to_string(), true)); } else if counter + 4 == args.len() { // ORDER BY column ASC/DESC @@ -401,10 +441,10 @@ fn get_where_columns(query: &Query) -> Option { fn text_to_vec(text_query: &String) -> Vec { // Text to vector. Tokenization by space, new line & coma - let tmp_text_query = text_query; - tmp_text_query.replace('\n', " "); - tmp_text_query.replace(',', ""); - tmp_text_query.replace(';', ""); + let mut tmp_text_query = text_query.to_string(); + tmp_text_query = tmp_text_query.replace("\n", " "); + tmp_text_query = tmp_text_query.replace(",", ""); + tmp_text_query = tmp_text_query.replace(";", ""); let mut split = tmp_text_query.split(' '); let mut result: Vec = Vec::new(); @@ -452,91 +492,40 @@ fn vec_to_query(args: &Vec, path: &String) -> Result{ Ok(result) } -/* -fn build_query(text_query: &String, path: &String) -> Result{ - // Crea query valida o devuelve codigo de error. - let args = text_to_vec(text_query); - let mut resultado = build_empty_query(); - - match full_check_query(&args, &path, &mut resultado) { - Ok(_) => return Ok(resultado), - Err(x) => return Err(x) - } - -} - -fn check_columns_exist(args: &Vec, result: &mut Query) -> Result,u32> { - // TODO columns exist - let file = File::open(&result.table.unwrap() ); - match file { - Ok(_) => { - let mut reader = BufReader::new(file); - - let mut line = String::new(); - match reader.read_line(&mut line) { - - } - } - Err(_) => return Err(5) - } - -} - -fn text_to_vec(text_query: &String) -> Vec { - let mut resultado: Vec = Vec::new(); - let mut split = text_query.split(' '); - - let mut element_opt = split.next(); - while element_opt.is_some() { - match element_opt { - Some(x) => { - - if x.contains('\n') { - let mut split2 = x.split('\n'); - let mut element_split2 = split2.next(); - resultado.push(element_split2.unwrap().to_string()); - element_split2 = split2.next(); - resultado.push(element_split2.unwrap().to_string()); - } else if x.contains(',') { +pub fn get_file_first_line(query: &Query) -> Option { + match &query.table { + Some(table) => match File::open(table) { + Ok(f) => { + let mut reader: BufReader = BufReader::new(f); + let mut line = String::new(); - } else { - resultado.push(x.to_string()) + match reader.read_line(&mut line) { + Ok(_) => Some(line), + Err(_) => None } - }, // TODO: Check si esto esta bien - None => continue - } - element_opt = split.next(); + }, + Err(_) => None + }, + None => None } - - resultado } -fn full_check_query(args: &Vec, path: &String) -> Result { - let mut error_code :u32 = 0; - let mut result = build_empty_query(); - match check_operation(&args) { - Ok(x) => result.operation = Some(x), - Err(x) => return Err(x) - } - match check_table_exist(path, args, &result.operation.unwrap()){ - Ok(x) => result.table = Some(x), - Err(x) => return Err(x) - } - match check_columns_exist(args,&result.table.unwrap()) { - - } -} -*/ #[cfg(test)] mod tests { use super::*; #[test] - fn test_text_to_vec(){ + fn test_text_to_vec1(){ let rt1 = text_to_vec(&String::from("SELECT * FROM table")); assert_eq!(rt1, vec!["SELECT","*","FROM","table"]); + } + + #[test] + fn test_text_to_vec2(){ let rt2 = text_to_vec(&String::from("SELECT id, producto, id_cliente\nFROM ordenes\nWHERE cantidad > 1")); - assert_eq!(rt2, vec!["SELECT","id","producto","id_cliente","FROM","ordenes","WHERE","cantidad>1"]); + assert_eq!(rt2, vec!["SELECT","id","producto","id_cliente","FROM","ordenes","WHERE","cantidad",">","1"]); } + + } \ No newline at end of file diff --git a/src/query.rs b/src/query.rs index 6fba4ad..c3ef6aa 100644 --- a/src/query.rs +++ b/src/query.rs @@ -16,7 +16,7 @@ pub struct Query { pub operation: Option, // DELETE, INSERT, SELECT, UPDATE pub table: Option, // DELETE, INSERT, SELECT, UPDATE pub columns: Option>, // INSERT, SELECT, UPDATE - pub where_condition: Option, // DELETE (always), SELECT (sometimes), UPDATE (always) . Tree of conditions + pub where_condition: Option, // DELETE (always), SELECT (sometimes), UPDATE (always) . pub order_by: Option<(String,bool)>, // SELECT (sometimes) pub values: Option> // INSERT, UPDATE (in update is set) } From 2ce7a7917d64f3738d7cdd0c3191c583aaf659d1 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 20:29:57 -0300 Subject: [PATCH 13/58] OK: SELECT * FROM --- src/libs/exec.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 17d1554..bb4530b 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -116,8 +116,13 @@ fn read_and_print_file(query: &Query, col_filter: i32, columns: &Vec ) { let mut line = String::new(); // Print header - reader.read_line(&mut line); - println!("{}",line); + match reader.read_line(&mut line) { + Ok(_) => { + print!("{}",line); + line.clear(); + }, + Err(_) => println!("Error en el programa") // TODO + } // Print other lines let mut read = true; @@ -131,6 +136,7 @@ fn read_and_print_file(query: &Query, col_filter: i32, columns: &Vec ) { Some(condition) => {}, None => print_file_unconditional(&columns, &elements) } + line.clear(); } }, Err(_) => println!("Error en el programa") @@ -173,7 +179,6 @@ fn print_file_unconditional(columns: &Vec, elements: &Vec ) { counter += 1; } } - println!(); } fn line_to_vec(line: &String) -> Vec { From 509a0cf7b5b877224c268bcac33185769a44947c Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 21:13:55 -0300 Subject: [PATCH 14/58] OK: Select columns FROM tabla --- src/libs/exec.rs | 6 +++++- src/libs/parsing.rs | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index bb4530b..dd65e73 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -75,6 +75,7 @@ fn find_filter_column(query: &Query) -> i32 { let mut line = String::new(); match reader.read_line(&mut line) { Ok(_) => { + line = line.replace("\n", ""); let mut split = line.split(','); let mut element_opt = split.next(); let mut counter = 0; @@ -118,7 +119,8 @@ fn read_and_print_file(query: &Query, col_filter: i32, columns: &Vec ) { // Print header match reader.read_line(&mut line) { Ok(_) => { - print!("{}",line); + line = line.replace("\n", ""); + println!("{}",line); line.clear(); }, Err(_) => println!("Error en el programa") // TODO @@ -129,6 +131,7 @@ fn read_and_print_file(query: &Query, col_filter: i32, columns: &Vec ) { while read { match reader.read_line(&mut line) { Ok(x) => { + line = line.replace("\n", ""); read = x != 0; if read { let elements = line_to_vec(&line); @@ -179,6 +182,7 @@ fn print_file_unconditional(columns: &Vec, elements: &Vec ) { counter += 1; } } + println!(""); } fn line_to_vec(line: &String) -> Vec { diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 28de3ba..021341f 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -134,6 +134,7 @@ fn separate_args_select(args: &Vec, path: &String, result: &mut Query) - counter += 1; } counter += 1; + result.columns = Some(columns); result.table = Some(merge_table_and_path(path, &args[counter])); counter += 1; From d0929442776fdb7db460547e4452f7a839ac71df Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 21:37:57 -0300 Subject: [PATCH 15/58] Corregido SELECT * --- src/libs/parsing.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 021341f..83e1267 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -134,7 +134,12 @@ fn separate_args_select(args: &Vec, path: &String, result: &mut Query) - counter += 1; } counter += 1; - result.columns = Some(columns); + + + if ! &columns[0].eq("*") { + result.columns = Some(columns); + } + result.table = Some(merge_table_and_path(path, &args[counter])); counter += 1; From 166c9cce8d8e5052a66e6c0939ac992891194e48 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 21:42:47 -0300 Subject: [PATCH 16/58] limpiando clippy --- src/condition.rs | 7 +-- src/libs/parsing.rs | 127 ++++++++++++++++++++-------------------- src/query/query_type.rs | 8 +-- 3 files changed, 70 insertions(+), 72 deletions(-) diff --git a/src/condition.rs b/src/condition.rs index 79cfc34..5377d4f 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -1,5 +1,4 @@ pub mod condition_type; -use crate::query::Query; /* pub mod complex_condition; @@ -15,9 +14,9 @@ pub struct Condition { pub value: Option, } -pub fn build_condition(column: String, value: String, condition: ConditionOperator) -> Condition { - return Condition { - condition: condition, +pub fn build_condition(column: String, value: String, cond: ConditionOperator) -> Condition { + Condition { + condition: cond, column: Some(column), value: Some(value), } diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 83e1267..7ebe6e7 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -2,7 +2,7 @@ use std::io::{BufRead, BufReader}; use std::fs::File; use crate::condition::condition_type::ConditionOperator; -use crate::condition::{build_condition, Condition}; +use crate::condition::build_condition ; //use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, get_where_columns, tree_check, ComplexCondition, Condition}; // use crate::condition::Condition; use crate::libs::error; @@ -106,12 +106,12 @@ fn separate_args_update(args: &Vec, path: &String, result: &mut Query) - } counter += 1; } - counter += 1; result.columns = Some(columns); result.values = Some(values); - /* TODO: Code for complex conditions + /* TODO: Code for complex conditions + counter += 1; match add_node_to_tree(args, &mut counter, build_empty_complex_condition()) { Ok(cond) => result.where_condition = Some(cond), Err(x) => return Err(x) @@ -277,66 +277,6 @@ fn check_non_valid_keywords(args: &Vec, non_valid_keywords: Vec<&str>) result } -fn check_where_format(args: &Vec, start_position: usize) -> bool { - let mut result = true; - - let mut counter: usize = start_position; - - let mut not_detected: bool = false; - let mut op_detected: bool = false; - - while counter < args.len() && result { - if args[counter].eq("NOT") { - if not_detected || op_detected { - result = false; // NOT NOT. Que estas haciendo ? - } else { - not_detected = true; - counter += 1; - } - } else if args[counter].eq("AND") || args[counter].eq("OR") { - if op_detected { - result = false; // AND OR , OR AND, OR OR, AND AND. Que estas haciendo ? - } else { - op_detected = true; - counter += 1; - } - } else { - if counter + 3 > args.len() { - result = false; - } else { - - } - } - } - - result -} - -fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) -> Result{ - // Asume query bien formateado - let mut table= String::from(path); - table.push('/'); - match &operation { - QueryType::DELETE => table.push_str(&args[2]), - QueryType::INSERT => table.push_str(&args[2]), - QueryType::SELECT => { - // Debo encontrar cual es la tabla (asumiendo query bien formateado) - let mut counter = 2; - while ! args[counter].eq("FROM"){ - counter += 1; - } - table.push_str(&args[counter + 1]) - }, - QueryType::UPDATE => table.push_str(&args[1]), - } - - match File::open(&table) { // TODO: Path::exist()? - Ok(_) => return Ok(table), - Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) - } -} - - fn validate_query(query: Query) -> Result { // Pre: Sintactical query OK // Post: Valid query for execution @@ -534,4 +474,63 @@ mod tests { } -} \ No newline at end of file +} + +/* +fn check_where_format(args: &Vec, start_position: usize) -> bool { + let mut result = true; + + let mut counter: usize = start_position; + + let mut not_detected: bool = false; + let mut op_detected: bool = false; + + while counter < args.len() && result { + if args[counter].eq("NOT") { + if not_detected || op_detected { + result = false; // NOT NOT. Que estas haciendo ? + } else { + not_detected = true; + counter += 1; + } + } else if args[counter].eq("AND") || args[counter].eq("OR") { + if op_detected { + result = false; // AND OR , OR AND, OR OR, AND AND. Que estas haciendo ? + } else { + op_detected = true; + counter += 1; + } + } else if counter + 3 > args.len() { + result = false; + } else { + + } + } + + result +} + +fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) -> Result{ + // Asume query bien formateado + let mut table= String::from(path); + table.push('/'); + match &operation { + QueryType::DELETE => table.push_str(&args[2]), + QueryType::INSERT => table.push_str(&args[2]), + QueryType::SELECT => { + // Debo encontrar cual es la tabla (asumiendo query bien formateado) + let mut counter = 2; + while ! args[counter].eq("FROM"){ + counter += 1; + } + table.push_str(&args[counter + 1]) + }, + QueryType::UPDATE => table.push_str(&args[1]), + } + + match File::open(&table) { // TODO: Path::exist()? + Ok(_) => return Ok(table), + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + } +} +*/ \ No newline at end of file diff --git a/src/query/query_type.rs b/src/query/query_type.rs index d1ddba5..ffd21e2 100644 --- a/src/query/query_type.rs +++ b/src/query/query_type.rs @@ -9,10 +9,10 @@ pub enum QueryType { impl std::fmt::Display for QueryType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - QueryType::DELETE => write!(f,"{}","DELETE"), - QueryType::INSERT => write!(f,"{}","INSERT"), - QueryType::SELECT => write!(f,"{}","SELECT"), - QueryType::UPDATE => write!(f,"{}","UPDATE"), + QueryType::DELETE => write!(f,"DELETE"), + QueryType::INSERT => write!(f,"INSERT"), + QueryType::SELECT => write!(f,"SELECT"), + QueryType::UPDATE => write!(f,"UPDATE"), } } } \ No newline at end of file From 31183a8a5b4fccf974c68e8ce4ab6346d4b55a63 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 22:10:19 -0300 Subject: [PATCH 17/58] SELECT last_column OK --- src/libs/exec.rs | 36 ++++++++++-------------- src/libs/parsing.rs | 67 +++++++++++++++++++++++---------------------- src/query.rs | 2 +- 3 files changed, 51 insertions(+), 54 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index dd65e73..44d7bbb 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -75,19 +75,16 @@ fn find_filter_column(query: &Query) -> i32 { let mut line = String::new(); match reader.read_line(&mut line) { Ok(_) => { - line = line.replace("\n", ""); + line = line.replace('\n', ""); let mut split = line.split(','); let mut element_opt = split.next(); let mut counter = 0; while element_opt.is_some() && col_index_filter < 0 { - match element_opt { - Some(x) => { - if x.eq(column) { - col_index_filter = counter; - } + if let Some(x) = element_opt { + if x.eq(column) { + col_index_filter = counter; } - None => {} } counter += 1; element_opt = split.next(); @@ -109,7 +106,7 @@ fn find_filter_column(query: &Query) -> i32 { col_index_filter } -fn read_and_print_file(query: &Query, col_filter: i32, columns: &Vec ) { +fn read_and_print_file(query: &Query, col_filter: i32, columns: &[usize] ) { match &query.table { Some(table) => match File::open(table) { Ok(f) => { @@ -117,27 +114,27 @@ fn read_and_print_file(query: &Query, col_filter: i32, columns: &Vec ) { let mut line = String::new(); // Print header - match reader.read_line(&mut line) { +/* match reader.read_line(&mut line) { Ok(_) => { - line = line.replace("\n", ""); + line = line.replace('\n', ""); println!("{}",line); line.clear(); }, Err(_) => println!("Error en el programa") // TODO } - +*/ // Print other lines let mut read = true; while read { match reader.read_line(&mut line) { Ok(x) => { - line = line.replace("\n", ""); + line = line.replace('\n', ""); read = x != 0; if read { let elements = line_to_vec(&line); match &query.where_condition { Some(condition) => {}, - None => print_file_unconditional(&columns, &elements) + None => print_file_unconditional(columns, &elements) } line.clear(); } @@ -152,20 +149,17 @@ fn read_and_print_file(query: &Query, col_filter: i32, columns: &Vec ) { } } -fn print_file_unconditional(columns: &Vec, elements: &Vec ) { +fn print_file_unconditional(columns: &[usize], elements: &[String] ) { // Pre: Columns vector sorted incremental && Elements of line content vector // Post: print to stdout the correct columns if columns.is_empty(){ - let mut counter = 0; - for element in elements { + for (counter, element) in elements.iter().enumerate() { print!("{}",element); if counter < elements.len() - 1 { print!(","); } - - counter += 1; - } + } } else { let mut counter = 0; let mut found_count = 0; @@ -182,10 +176,10 @@ fn print_file_unconditional(columns: &Vec, elements: &Vec ) { counter += 1; } } - println!(""); + println!(); } -fn line_to_vec(line: &String) -> Vec { +fn line_to_vec(line: &str) -> Vec { let mut result: Vec = Vec::new(); let mut split = line.split(','); diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 7ebe6e7..7aa4fa4 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -14,14 +14,14 @@ use super::error::SELECT_MAL_FORMATEADO; pub fn build_query(text_query: &String, path: &String) -> Result { // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build - let args = text_to_vec(&text_query); + let args = text_to_vec(text_query); match vec_to_query(&args, path) { - Ok(x) => return validate_query(x), - Err(x) => return Err(x) + Ok(x) => validate_query(x), + Err(x) => Err(x) } } -fn merge_table_and_path(path: &String, table: &String) -> String { +fn merge_table_and_path(path: &String, table: &str) -> String { let mut table_full: String = path.to_string(); table_full.push('/'); table_full.push_str(table); @@ -30,9 +30,9 @@ fn merge_table_and_path(path: &String, table: &String) -> String { table_full } -fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) -> Result { +fn separate_args_delete(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < DELETE_MIN_LEN { - return Err(error::DELETE_MAL_FORMATEADO); + Err(error::DELETE_MAL_FORMATEADO) } else { result.table = Some(merge_table_and_path(path, &args[2])); @@ -64,9 +64,9 @@ fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) - } } -fn separate_args_insert(args: &Vec, path: &String, result: &mut Query) -> Result { +fn separate_args_insert(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < INSERT_MIN_LEN { - return Err(error::INSERT_MAL_FORMATEADO) + Err(error::INSERT_MAL_FORMATEADO) } else { result.table = Some(merge_table_and_path(path, &args[2])); @@ -90,7 +90,7 @@ fn separate_args_insert(args: &Vec, path: &String, result: &mut Query) - } } -fn separate_args_update(args: &Vec, path: &String, result: &mut Query) -> Result { +fn separate_args_update(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < UPDATE_MIN_LEN { result.table = Some(merge_table_and_path(path, &args[1])); @@ -119,13 +119,13 @@ fn separate_args_update(args: &Vec, path: &String, result: &mut Query) - */ Ok(0) } else { - return Err(error::UPDATE_MAL_FORMATEADO) + Err(error::UPDATE_MAL_FORMATEADO) } } -fn separate_args_select(args: &Vec, path: &String, result: &mut Query) -> Result { +fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < SELECT_MIN_LEN { - return Err(error::SELECT_MAL_FORMATEADO) + Err(error::SELECT_MAL_FORMATEADO) } else { let mut columns: Vec = Vec::new(); let mut counter = 1; @@ -209,7 +209,7 @@ fn check_operation_format(args: &Vec) -> Result { } } -fn check_delete_format(args: &Vec) -> Result { +fn check_delete_format(args: &[String]) -> Result { let non_valid_keywords = vec!["INSERT","INTO","VALUES","SELECT","ORDER","BY","UPDATE","SET"]; if args[1].eq("FROM") && args[3].eq("WHERE") && check_non_valid_keywords(args, non_valid_keywords) { Ok(QueryType::DELETE) @@ -218,10 +218,10 @@ fn check_delete_format(args: &Vec) -> Result { } } -fn check_insert_format(args: &Vec) -> Result { +fn check_insert_format(args: &[String]) -> Result { let non_valid_keywords = vec!["DELETE","FROM","SELECT","ORDER","BY","UPDATE","SET","WHERE","AND","OR","NOT"]; if args[1].eq("INTO") && check_non_valid_keywords(args, non_valid_keywords){ - if (args.len() - 3) % 2 != 0 || args.len() - 3 < 0 { + if (args.len() - 3) % 2 != 0 { Err(2) } else{ let mut counter = 0; @@ -242,7 +242,7 @@ fn check_insert_format(args: &Vec) -> Result { } } -fn check_select_format(args: &Vec) -> Result { +fn check_select_format(args: &[String]) -> Result { let non_valid_keywords = vec!["DELETE","INSERT","INTO","VALUES","UPDATE","SET"]; if check_non_valid_keywords(args, non_valid_keywords) { // TODO format select @@ -252,7 +252,7 @@ fn check_select_format(args: &Vec) -> Result { } } -fn check_update_format(args: &Vec) -> Result { +fn check_update_format(args: &[String]) -> Result { let non_valid_keywords = vec!["DELETE","FROM","INSERT","INTO","SELECT","VALUES","ORDER","BY"]; if args[2].eq("SET") && args.contains(&"WHERE".to_string()) && check_non_valid_keywords(args, non_valid_keywords) { Ok(QueryType::UPDATE) @@ -261,13 +261,13 @@ fn check_update_format(args: &Vec) -> Result { } } -fn check_non_valid_keywords(args: &Vec, non_valid_keywords: Vec<&str>) -> bool { +fn check_non_valid_keywords(args: &[String], non_valid_keywords: Vec<&str>) -> bool { // Checks if args contains any non valid keyword let mut result = true; let mut counter = 0; while counter < args.len() && result { - if non_valid_keywords.contains(&&args[counter].as_str()) { + if non_valid_keywords.contains(&args[counter].as_str()) { result = false; } else { counter += 1; @@ -297,7 +297,7 @@ fn validate_query(query: Query) -> Result { QueryType::UPDATE => validate_update_query(query), } }, - None => return Err(error::OPERACION_INVALIDA) + None => Err(error::OPERACION_INVALIDA) } } @@ -309,13 +309,13 @@ fn validate_delete_query(query: Query) -> Result { Ok(file) => { match get_columns(file) { Some(columns) => check_columns_contains_condition(columns,query), - None => return Err(error::ARCHIVO_VACIO) + None => Err(error::ARCHIVO_VACIO) } }, - Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + Err(_) => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) } }, - None => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + None => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) } } else { Err(error::DELETE_MAL_FORMATEADO) @@ -369,7 +369,7 @@ fn check_columns_contains_condition(columns: Vec, query: Query) -> Resul Err(error::ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS) } }, - None => return Err(error::NO_WHERE) + None => Err(error::NO_WHERE) } } @@ -377,20 +377,20 @@ fn get_where_columns(query: &Query) -> Option { match &query.where_condition { Some(cond) => { match &cond.column { - Some(col) => return Some(col.to_string()), - None => return None + Some(col) => Some(col.to_string()), + None => None } }, - None => return None + None => None } } fn text_to_vec(text_query: &String) -> Vec { // Text to vector. Tokenization by space, new line & coma let mut tmp_text_query = text_query.to_string(); - tmp_text_query = tmp_text_query.replace("\n", " "); - tmp_text_query = tmp_text_query.replace(",", ""); - tmp_text_query = tmp_text_query.replace(";", ""); + tmp_text_query = tmp_text_query.replace('\n', " "); + tmp_text_query = tmp_text_query.replace(',', ""); + tmp_text_query = tmp_text_query.replace(';', ""); let mut split = tmp_text_query.split(' '); let mut result: Vec = Vec::new(); @@ -411,7 +411,7 @@ fn text_to_vec(text_query: &String) -> Vec { fn vec_to_query(args: &Vec, path: &String) -> Result{ // Vec to non validated query let mut result: Query = build_empty_query(); - match check_operation_format(&args) { + match check_operation_format(args) { Ok(x) => { match &x { QueryType::DELETE => match separate_args_delete(args, path, &mut result){ @@ -446,7 +446,10 @@ pub fn get_file_first_line(query: &Query) -> Option { let mut line = String::new(); match reader.read_line(&mut line) { - Ok(_) => Some(line), + Ok(_) => { + line = line.replace('\n', ""); + Some(line) + }, Err(_) => None } }, diff --git a/src/query.rs b/src/query.rs index c3ef6aa..6135fc3 100644 --- a/src/query.rs +++ b/src/query.rs @@ -22,7 +22,7 @@ pub struct Query { } pub fn build_empty_query() -> Query { - return Query { + Query { operation: None, table: None, columns: None, From c19cfa47c6a2abe3c4c8621e91fddd30a1178f0b Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 23:23:29 -0300 Subject: [PATCH 18/58] WIP gdb INSERT INTO --- src/libs/exec.rs | 41 ++++++++++++++++++++++++++++++++++++++--- src/libs/parsing.rs | 8 ++++---- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 44d7bbb..520165a 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -1,5 +1,5 @@ -use std::io::{BufRead, BufReader}; -use std::fs::File; +use std::io::{BufRead, BufReader, Write}; +use std::fs::{File,OpenOptions}; //use crate::condition::operate_condition; use crate::query::query_type::QueryType; @@ -24,7 +24,35 @@ fn exec_query_delete(query: Query) { } fn exec_query_insert(query: Query) { - // TODO + match &query.table { + Some(table) => { + let total_columns = find_total_columns(&query); + let write_columns = find_print_columns(&query); + match &mut OpenOptions::new().append(true).open(table){ + Ok(file) => { + let mut write_line = String::new(); + let mut counter = 0; + let mut writen_elements = 0; + while counter < total_columns { + if write_columns.contains(&counter) { + if let Some(x) = &query.values { + write_line.push_str(&x[writen_elements].to_string()); + writen_elements += 1; + } + } + + counter += 1; + if counter < total_columns { + write_line.push(','); + } } + + file.write(write_line.as_bytes()); + }, + Err(_) => println!("ERROR en el programa") + } + }, + None => println!("ERROR en el programa") + } } fn exec_query_select(query: Query) { @@ -38,6 +66,13 @@ fn exec_query_select(query: Query) { } } +fn find_total_columns(query: &Query) -> usize { + match get_file_first_line(query){ + Some(line) => line_to_vec(&line).len(), + None => 0 + } +} + fn find_print_columns(query: &Query) -> Vec { let mut result: Vec = Vec::new(); match &query.columns { diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 7aa4fa4..5dc26bf 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -221,16 +221,16 @@ fn check_delete_format(args: &[String]) -> Result { fn check_insert_format(args: &[String]) -> Result { let non_valid_keywords = vec!["DELETE","FROM","SELECT","ORDER","BY","UPDATE","SET","WHERE","AND","OR","NOT"]; if args[1].eq("INTO") && check_non_valid_keywords(args, non_valid_keywords){ - if (args.len() - 3) % 2 != 0 { + if (args.len() - 4) % 2 != 0 { Err(2) } else{ let mut counter = 0; - let correct_value_len = (args.len() - 3)/2; // INSERT INTO a b c VALUES x y z. Len = 9. Correct len = 3. - while counter < correct_value_len && ! args[counter].eq("VALUES"){ + let correct_value_len = (args.len() - 4)/2; // INSERT INTO tabla a b c VALUES x y z. Len = 10. Correct len = 3. + while counter < correct_value_len && ! args[3 + counter].eq("VALUES"){ counter += 1; } - if counter == correct_value_len && args[counter].eq("VALUES") { + if counter == correct_value_len && args[3 + counter].eq("VALUES") { Ok(QueryType::INSERT) } else{ Err(error::INSERT_MAL_FORMATEADO) From d12be3eac0267ab51beb0237d1e7dad7f748dd02 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 23:31:52 -0300 Subject: [PATCH 19/58] Edit README entrega --- README.md | 26 +++++++++++++++++++++++--- src/libs/exec.rs | 3 ++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1081626..3c5d265 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,31 @@ ### Detalles de entrega -El trabajo no se encuentra completo. Las siguientes funcionalidades se encuentran pendientes: +El trabajo no se encuentra completo. -1. Logica booleana +Pendientes: -2. +1. Funcionalidad: Logica booleana en WHERE + +2. Funcionalidad: SELECT c/ ORDER BY + +3. Funcionalidad: SELECT c/ WHERE + +4. Funcionalidad: DELETE + +5. Funcionalidad: UPDATE + +6. Testing (mas test unitarios e integración) + +7. Cargo clippy sin warnings + +Funcionalidades probadas OK + +1. SELECT * FROM + +2. SELECT columnas FROM + +3. INSERT INTO ### Detalles de implementación diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 520165a..cb6873f 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -44,7 +44,8 @@ fn exec_query_insert(query: Query) { counter += 1; if counter < total_columns { write_line.push(','); - } } + } + } file.write(write_line.as_bytes()); }, From 4e31d73f8c67fc80d093ad38445cb40a1ebb7997 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Mon, 9 Sep 2024 16:33:45 -0300 Subject: [PATCH 20/58] INSERT INTO DEBUGGED --- README.md | 2 + src/condition.rs | 18 +- src/condition/condition_type.rs | 14 +- src/libs.rs | 2 +- src/libs/error.rs | 30 +-- src/libs/exec.rs | 165 +++++++------ src/libs/parsing.rs | 414 ++++++++++++++++++-------------- src/main.rs | 12 +- src/query.rs | 33 ++- src/query/query_type.rs | 12 +- 10 files changed, 378 insertions(+), 324 deletions(-) diff --git a/README.md b/README.md index 3c5d265..b04eb63 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ Pendientes: 7. Cargo clippy sin warnings +8. Documentación de funciones + Funcionalidades probadas OK 1. SELECT * FROM diff --git a/src/condition.rs b/src/condition.rs index 5377d4f..d667cf3 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -1,5 +1,5 @@ pub mod condition_type; -/* +/* pub mod complex_condition; use crate::libs::error; @@ -9,20 +9,20 @@ use condition_type::BooleanOperator; use condition_type::ConditionOperator; pub struct Condition { - pub condition: ConditionOperator, - pub column: Option, - pub value: Option, + pub condition: ConditionOperator, + pub column: Option, + pub value: Option, } pub fn build_condition(column: String, value: String, cond: ConditionOperator) -> Condition { Condition { - condition: cond, - column: Some(column), - value: Some(value), + condition: cond, + column: Some(column), + value: Some(value), } } -/* +/* pub fn operate_condition(filter: (&u32,&ConditionOperator,&String), elements: &Vec) -> bool { let (column, operator, value) = filter; match operator { @@ -33,4 +33,4 @@ pub fn operate_condition(filter: (&u32,&ConditionOperator,&String), elements: &V ConditionOperator::HigherEqual => {}, } } -*/ \ No newline at end of file +*/ diff --git a/src/condition/condition_type.rs b/src/condition/condition_type.rs index 68e318b..481d3ef 100644 --- a/src/condition/condition_type.rs +++ b/src/condition/condition_type.rs @@ -1,13 +1,13 @@ pub enum ConditionOperator { - Minor, // Int - MinorEqual, // Int - Equal, // Int and String - Higher, // Int - HigherEqual, // Int + Minor, // Int + MinorEqual, // Int + Equal, // Int and String + Higher, // Int + HigherEqual, // Int } pub enum BooleanOperator { AND, OR, - NOT -} \ No newline at end of file + NOT, +} diff --git a/src/libs.rs b/src/libs.rs index 1bd6d7c..93fd982 100644 --- a/src/libs.rs +++ b/src/libs.rs @@ -1,4 +1,4 @@ -// Dumb file for organize everything into libs +// Dumb file for organize everything into libs pub mod error; pub mod exec; pub mod parsing; diff --git a/src/libs/error.rs b/src/libs/error.rs index 60bc4d5..e247048 100644 --- a/src/libs/error.rs +++ b/src/libs/error.rs @@ -1,17 +1,17 @@ -pub static OPERACION_INVALIDA: u32 = 1; -pub static DELETE_MAL_FORMATEADO: u32 = 2; -pub static INSERT_MAL_FORMATEADO: u32 = 3; -pub static SELECT_MAL_FORMATEADO: u32 = 4; -pub static UPDATE_MAL_FORMATEADO: u32 = 5; -pub static ARCHIVO_NO_PUDO_SER_ABIERTO: u32 = 6; -pub static ARCHIVO_VACIO: u32 = 7; -pub static ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS: u32 = 8; -pub static WHERE_EN_DELETE_MAL_FORMATEADO: u32 = 9; -pub static WHERE_MAL_FORMATEADO: u32 = 10; -pub static ORDER_BY_MAL_FORMATEADO: u32 = 11; -pub static NO_WHERE: u32 = 12; +pub static OPERACION_INVALIDA: u32 = 1; +pub static DELETE_MAL_FORMATEADO: u32 = 2; +pub static INSERT_MAL_FORMATEADO: u32 = 3; +pub static SELECT_MAL_FORMATEADO: u32 = 4; +pub static UPDATE_MAL_FORMATEADO: u32 = 5; +pub static ARCHIVO_NO_PUDO_SER_ABIERTO: u32 = 6; +pub static ARCHIVO_VACIO: u32 = 7; +pub static ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS: u32 = 8; +pub static WHERE_EN_DELETE_MAL_FORMATEADO: u32 = 9; +pub static WHERE_MAL_FORMATEADO: u32 = 10; +pub static ORDER_BY_MAL_FORMATEADO: u32 = 11; +pub static NO_WHERE: u32 = 12; pub fn print_err(error_code: u32) { - // TODO print error - println!("ERROR. Codigo: {}",error_code) -} \ No newline at end of file + // TODO print error + println!("ERROR. Codigo: {}", error_code) +} diff --git a/src/libs/exec.rs b/src/libs/exec.rs index cb6873f..47970ef 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -1,5 +1,5 @@ +use std::fs::{File, OpenOptions}; use std::io::{BufRead, BufReader, Write}; -use std::fs::{File,OpenOptions}; //use crate::condition::operate_condition; use crate::query::query_type::QueryType; @@ -7,15 +7,15 @@ use crate::query::Query; use super::parsing::get_file_first_line; -pub fn exec_query(query: Query) { +pub fn exec_query(query: Query) { match &query.operation { Some(op) => match op { QueryType::DELETE => exec_query_delete(query), QueryType::INSERT => exec_query_insert(query), QueryType::SELECT => exec_query_select(query), - QueryType::UPDATE => exec_query_update(query), + QueryType::UPDATE => exec_query_update(query), }, - None => println!("Error en el programa") + None => println!("Error en el programa"), } } @@ -28,7 +28,7 @@ fn exec_query_insert(query: Query) { Some(table) => { let total_columns = find_total_columns(&query); let write_columns = find_print_columns(&query); - match &mut OpenOptions::new().append(true).open(table){ + match &mut OpenOptions::new().append(true).open(table) { Ok(file) => { let mut write_line = String::new(); let mut counter = 0; @@ -44,15 +44,16 @@ fn exec_query_insert(query: Query) { counter += 1; if counter < total_columns { write_line.push(','); - } - } + } + } - file.write(write_line.as_bytes()); - }, - Err(_) => println!("ERROR en el programa") + write_line.push('\n'); + let _ = file.write(write_line.as_bytes()); + } + Err(_) => println!("ERROR en el programa"), } - }, - None => println!("ERROR en el programa") + } + None => println!("ERROR en el programa"), } } @@ -62,15 +63,15 @@ fn exec_query_select(query: Query) { None => { let col_index = find_filter_column(&query); let print_columns: Vec = find_print_columns(&query); - read_and_print_file(&query, col_index, &print_columns ); + read_and_print_file(&query, col_index, &print_columns); } } } fn find_total_columns(query: &Query) -> usize { - match get_file_first_line(query){ + match get_file_first_line(query) { Some(line) => line_to_vec(&line).len(), - None => 0 + None => 0, } } @@ -82,83 +83,81 @@ fn find_print_columns(query: &Query) -> Vec { let table_columns: Vec = line_to_vec(&line); for element in cols { let mut counter = 0; - while ! table_columns[counter].eq(element) && counter < table_columns.len() { + while !table_columns[counter].eq(element) && counter < table_columns.len() { counter += 1; } if counter < table_columns.len() { result.push(counter); } } - + result - }, - None => result - }, - None => result + } + None => result, + }, + None => result, } } fn find_filter_column(query: &Query) -> i32 { let mut col_index_filter = -1; match &query.where_condition { - Some(x) => { - match &x.column { - Some(column) => { - match &query.table { - Some(table) => match File::open(table){ - Ok(file) => { - let mut reader: BufReader = BufReader::new(file); - let mut line = String::new(); - match reader.read_line(&mut line) { - Ok(_) => { - line = line.replace('\n', ""); - let mut split = line.split(','); - let mut element_opt = split.next(); - let mut counter = 0; - - while element_opt.is_some() && col_index_filter < 0 { - if let Some(x) = element_opt { - if x.eq(column) { - col_index_filter = counter; - } - } - counter += 1; - element_opt = split.next(); + Some(x) => match &x.column { + Some(column) => match &query.table { + Some(table) => match File::open(table) { + Ok(file) => { + let mut reader: BufReader = BufReader::new(file); + let mut line = String::new(); + match reader.read_line(&mut line) { + Ok(_) => { + line = line.replace('\n', ""); + let mut split = line.split(','); + let mut element_opt = split.next(); + let mut counter = 0; + + while element_opt.is_some() && col_index_filter < 0 { + if let Some(x) = element_opt { + if x.eq(column) { + col_index_filter = counter; } - }, - Err(_) => col_index_filter = -1, - } - }, - Err(_) => return -1 - }, - None => return -1 + } + counter += 1; + element_opt = split.next(); + } + } + Err(_) => col_index_filter = -1, + } } + Err(_) => return -1, }, - None => { col_index_filter = -1; } + None => return -1, + }, + None => { + col_index_filter = -1; } - }, - None => col_index_filter = -1 + }, + None => col_index_filter = -1, } col_index_filter } -fn read_and_print_file(query: &Query, col_filter: i32, columns: &[usize] ) { +fn read_and_print_file(query: &Query, col_filter: i32, columns: &[usize]) { match &query.table { Some(table) => match File::open(table) { Ok(f) => { let mut reader: BufReader = BufReader::new(f); let mut line = String::new(); - // Print header -/* match reader.read_line(&mut line) { - Ok(_) => { - line = line.replace('\n', ""); - println!("{}",line); - line.clear(); - }, - Err(_) => println!("Error en el programa") // TODO - } -*/ + // Print header + /* match reader.read_line(&mut line) { + Ok(_) => { + line = line.replace('\n', ""); + println!("{}",line); + line.clear(); + }, + Err(_) => println!("Error en el programa") // TODO + } + */ // Print other lines let mut read = true; while read { @@ -169,29 +168,29 @@ fn read_and_print_file(query: &Query, col_filter: i32, columns: &[usize] ) { if read { let elements = line_to_vec(&line); match &query.where_condition { - Some(condition) => {}, - None => print_file_unconditional(columns, &elements) + Some(condition) => {} + None => print_file_unconditional(columns, &elements), } line.clear(); } - }, - Err(_) => println!("Error en el programa") + } + Err(_) => println!("Error en el programa"), } } - }, - Err(_) => println!("Error en el programa") + } + Err(_) => println!("Error en el programa"), }, - None => println!("Error en el programa ") + None => println!("Error en el programa "), } } -fn print_file_unconditional(columns: &[usize], elements: &[String] ) { - // Pre: Columns vector sorted incremental && Elements of line content vector - // Post: print to stdout the correct columns +fn print_file_unconditional(columns: &[usize], elements: &[String]) { + // Pre: Columns vector sorted incremental && Elements of line content vector + // Post: print to stdout the correct columns - if columns.is_empty(){ + if columns.is_empty() { for (counter, element) in elements.iter().enumerate() { - print!("{}",element); + print!("{}", element); if counter < elements.len() - 1 { print!(","); } @@ -202,9 +201,9 @@ fn print_file_unconditional(columns: &[usize], elements: &[String] ) { while counter < elements.len() { if columns.contains(&counter) { if found_count == 0 { - print!("{}",elements[counter]); + print!("{}", elements[counter]); } else { - print!(",{}",elements[counter]); + print!(",{}", elements[counter]); } found_count += 1; } @@ -224,8 +223,8 @@ fn line_to_vec(line: &str) -> Vec { match element_opt { Some(x) => { result.push(x.to_string()); - }, - None => continue + } + None => continue, } element_opt = split.next(); @@ -233,9 +232,7 @@ fn line_to_vec(line: &str) -> Vec { result } -fn exec_query_select_order_by(query: Query) { - -} +fn exec_query_select_order_by(query: Query) {} fn exec_query_update(query: Query) { // TODO diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 5dc26bf..5c9aa02 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -1,43 +1,43 @@ -use std::io::{BufRead, BufReader}; use std::fs::File; +use std::io::{BufRead, BufReader}; +use crate::condition::build_condition; use crate::condition::condition_type::ConditionOperator; -use crate::condition::build_condition ; //use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, get_where_columns, tree_check, ComplexCondition, Condition}; // use crate::condition::Condition; use crate::libs::error; -use crate::query::{Query, DELETE_MIN_LEN, INSERT_MIN_LEN, SELECT_MIN_LEN, UPDATE_MIN_LEN}; -use crate::query::query_type::QueryType; use crate::query::build_empty_query; +use crate::query::query_type::QueryType; +use crate::query::{Query, DELETE_MIN_LEN, INSERT_MIN_LEN, SELECT_MIN_LEN, UPDATE_MIN_LEN}; use super::error::SELECT_MAL_FORMATEADO; pub fn build_query(text_query: &String, path: &String) -> Result { - // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build - let args = text_to_vec(text_query); - match vec_to_query(&args, path) { - Ok(x) => validate_query(x), - Err(x) => Err(x) + // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build + let args = text_to_vec(text_query); + match vec_to_query(&args, path) { + Ok(x) => validate_query(x), + Err(x) => Err(x), } } fn merge_table_and_path(path: &String, table: &str) -> String { let mut table_full: String = path.to_string(); table_full.push('/'); - table_full.push_str(table); + table_full.push_str(table); table_full.push_str(".csv"); table_full } -fn separate_args_delete(args: &[String], path: &String, result: &mut Query) -> Result { +fn separate_args_delete(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < DELETE_MIN_LEN { Err(error::DELETE_MAL_FORMATEADO) } else { result.table = Some(merge_table_and_path(path, &args[2])); if args.len() != DELETE_MIN_LEN { - return Err(error::DELETE_MAL_FORMATEADO) + return Err(error::DELETE_MAL_FORMATEADO); } else { /* TODO: Code for complex conditions match add_node_to_tree(args, &mut 4, build_empty_complex_condition()) { @@ -47,102 +47,121 @@ fn separate_args_delete(args: &[String], path: &String, result: &mut Query) -> R */ if args[5].eq("<") { - result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::Minor)) + result.where_condition = Some(build_condition( + args[4].to_string(), + args[6].to_string(), + ConditionOperator::Minor, + )) } else if args[5].eq("<=") { - result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::MinorEqual)) + result.where_condition = Some(build_condition( + args[4].to_string(), + args[6].to_string(), + ConditionOperator::MinorEqual, + )) } else if args[5].eq("=") { - result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::Equal)) + result.where_condition = Some(build_condition( + args[4].to_string(), + args[6].to_string(), + ConditionOperator::Equal, + )) } else if args[5].eq(">=") { - result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::HigherEqual)) + result.where_condition = Some(build_condition( + args[4].to_string(), + args[6].to_string(), + ConditionOperator::HigherEqual, + )) } else if args[5].eq(">") { - result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::Higher)) + result.where_condition = Some(build_condition( + args[4].to_string(), + args[6].to_string(), + ConditionOperator::Higher, + )) } else { - return Err(error::WHERE_MAL_FORMATEADO) + return Err(error::WHERE_MAL_FORMATEADO); } } - Ok(0) + Ok(0) } } -fn separate_args_insert(args: &[String], path: &String, result: &mut Query) -> Result { +fn separate_args_insert(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < INSERT_MIN_LEN { Err(error::INSERT_MAL_FORMATEADO) } else { - result.table = Some(merge_table_and_path(path, &args[2])); + result.table = Some(merge_table_and_path(path, &args[2])); let mut columns: Vec = Vec::new(); - let mut counter = 3; - while counter < args.len()/2 && ! args[counter].eq("VALUES") { + let mut counter = 3; + while counter < args.len() && !args[counter].eq("VALUES") { columns.push(args[counter].to_string()); counter += 1; } - + counter += 1; let mut values: Vec = Vec::new(); while counter < args.len() { values.push(args[counter].to_string()); counter += 1; } - + result.columns = Some(columns); result.values = Some(values); - Ok(0) + Ok(0) } } -fn separate_args_update(args: &[String], path: &String, result: &mut Query) -> Result { +fn separate_args_update(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < UPDATE_MIN_LEN { - result.table = Some(merge_table_and_path(path, &args[1])); + result.table = Some(merge_table_and_path(path, &args[1])); - let mut counter = 3; + let mut counter = 3; let mut columns: Vec = Vec::new(); let mut values: Vec = Vec::new(); - + while counter < args.len() && !args[counter].eq("WHERE") { if counter % 3 == 0 { columns.push(args[counter].to_string()); - } else if ( counter % 3 ) == 2 { + } else if (counter % 3) == 2 { values.push(args[counter].to_string()); - } + } counter += 1; } - + result.columns = Some(columns); result.values = Some(values); - /* TODO: Code for complex conditions - counter += 1; + /* TODO: Code for complex conditions + counter += 1; match add_node_to_tree(args, &mut counter, build_empty_complex_condition()) { Ok(cond) => result.where_condition = Some(cond), Err(x) => return Err(x) } */ - Ok(0) + Ok(0) } else { Err(error::UPDATE_MAL_FORMATEADO) } } -fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> Result { +fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < SELECT_MIN_LEN { Err(error::SELECT_MAL_FORMATEADO) } else { let mut columns: Vec = Vec::new(); - let mut counter = 1; + let mut counter = 1; while counter < args.len() && !args[counter].eq("FROM") { columns.push(args[counter].to_string()); counter += 1; } counter += 1; - - if ! &columns[0].eq("*") { + if !&columns[0].eq("*") { result.columns = Some(columns); } result.table = Some(merge_table_and_path(path, &args[counter])); counter += 1; - + if counter == args.len() { Ok(0) } else { @@ -152,43 +171,66 @@ fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> R Err(x) => return Err(x) } */ - if counter + 3 > args.len(){ + if counter + 3 > args.len() { return Err(SELECT_MAL_FORMATEADO); } else if args[counter].eq("WHERE") { counter += 1; if args[counter + 1].eq("<") { - result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::Minor)) + result.where_condition = Some(build_condition( + args[counter].to_string(), + args[counter + 2].to_string(), + ConditionOperator::Minor, + )) } else if args[counter + 1].eq("<=") { - result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::MinorEqual)) + result.where_condition = Some(build_condition( + args[counter].to_string(), + args[counter + 2].to_string(), + ConditionOperator::MinorEqual, + )) } else if args[counter + 1].eq("=") { - result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::Equal)) + result.where_condition = Some(build_condition( + args[counter].to_string(), + args[counter + 2].to_string(), + ConditionOperator::Equal, + )) } else if args[counter + 1].eq(">=") { - result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::HigherEqual)) + result.where_condition = Some(build_condition( + args[counter].to_string(), + args[counter + 2].to_string(), + ConditionOperator::HigherEqual, + )) } else if args[counter + 1].eq(">") { - result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::Higher)) + result.where_condition = Some(build_condition( + args[counter].to_string(), + args[counter + 2].to_string(), + ConditionOperator::Higher, + )) } else { - return Err(error::WHERE_MAL_FORMATEADO) + return Err(error::WHERE_MAL_FORMATEADO); } } - if counter < args.len() { + if counter < args.len() { if args[counter].eq("ORDER") && args[counter + 1].eq("BY") { - if counter + 3 == args.len() { // ORDER BY column + if counter + 3 == args.len() { + // ORDER BY column result.order_by = Some((args[counter + 2].to_string(), true)); - } else if counter + 4 == args.len() { // ORDER BY column ASC/DESC + } else if counter + 4 == args.len() { + // ORDER BY column ASC/DESC if args[counter + 3].eq("ASC") || args[counter + 3].eq("DESC") { - result.order_by = Some((args[counter + 2].to_string(), args[counter + 2].eq("ASC"))); + result.order_by = + Some((args[counter + 2].to_string(), args[counter + 2].eq("ASC"))); } else { - return Err(error::ORDER_BY_MAL_FORMATEADO) + return Err(error::ORDER_BY_MAL_FORMATEADO); } } else { - return Err(error::ORDER_BY_MAL_FORMATEADO) + return Err(error::ORDER_BY_MAL_FORMATEADO); } } else { - return Err(error::ORDER_BY_MAL_FORMATEADO) + return Err(error::ORDER_BY_MAL_FORMATEADO); } } - Ok(0) + Ok(0) } } } @@ -205,47 +247,53 @@ fn check_operation_format(args: &Vec) -> Result { } else if operation.eq("UPDATE") { check_update_format(args) } else { - Err(error::OPERACION_INVALIDA) + Err(error::OPERACION_INVALIDA) } } fn check_delete_format(args: &[String]) -> Result { - let non_valid_keywords = vec!["INSERT","INTO","VALUES","SELECT","ORDER","BY","UPDATE","SET"]; - if args[1].eq("FROM") && args[3].eq("WHERE") && check_non_valid_keywords(args, non_valid_keywords) { - Ok(QueryType::DELETE) + let non_valid_keywords = vec![ + "INSERT", "INTO", "VALUES", "SELECT", "ORDER", "BY", "UPDATE", "SET", + ]; + if args[1].eq("FROM") + && args[3].eq("WHERE") + && check_non_valid_keywords(args, non_valid_keywords) + { + Ok(QueryType::DELETE) } else { - Err(error::DELETE_MAL_FORMATEADO) + Err(error::DELETE_MAL_FORMATEADO) } } fn check_insert_format(args: &[String]) -> Result { - let non_valid_keywords = vec!["DELETE","FROM","SELECT","ORDER","BY","UPDATE","SET","WHERE","AND","OR","NOT"]; - if args[1].eq("INTO") && check_non_valid_keywords(args, non_valid_keywords){ - if (args.len() - 4) % 2 != 0 { + let non_valid_keywords = vec![ + "DELETE", "FROM", "SELECT", "ORDER", "BY", "UPDATE", "SET", "WHERE", "AND", "OR", "NOT", + ]; + if args[1].eq("INTO") && check_non_valid_keywords(args, non_valid_keywords) { + if (args.len() - 4) % 2 != 0 { Err(2) - } else{ + } else { let mut counter = 0; - let correct_value_len = (args.len() - 4)/2; // INSERT INTO tabla a b c VALUES x y z. Len = 10. Correct len = 3. - while counter < correct_value_len && ! args[3 + counter].eq("VALUES"){ + let correct_value_len = (args.len() - 4) / 2; // INSERT INTO tabla a b c VALUES x y z. Len = 10. Correct len = 3. + while counter < correct_value_len && !args[3 + counter].eq("VALUES") { counter += 1; - } - + } + if counter == correct_value_len && args[3 + counter].eq("VALUES") { Ok(QueryType::INSERT) - } else{ - Err(error::INSERT_MAL_FORMATEADO) - } + } else { + Err(error::INSERT_MAL_FORMATEADO) + } } - } - else { - Err(error::INSERT_MAL_FORMATEADO) + } else { + Err(error::INSERT_MAL_FORMATEADO) } } fn check_select_format(args: &[String]) -> Result { - let non_valid_keywords = vec!["DELETE","INSERT","INTO","VALUES","UPDATE","SET"]; + let non_valid_keywords = vec!["DELETE", "INSERT", "INTO", "VALUES", "UPDATE", "SET"]; if check_non_valid_keywords(args, non_valid_keywords) { - // TODO format select + // TODO format select Ok(QueryType::SELECT) } else { Err(error::SELECT_MAL_FORMATEADO) @@ -253,15 +301,20 @@ fn check_select_format(args: &[String]) -> Result { } fn check_update_format(args: &[String]) -> Result { - let non_valid_keywords = vec!["DELETE","FROM","INSERT","INTO","SELECT","VALUES","ORDER","BY"]; - if args[2].eq("SET") && args.contains(&"WHERE".to_string()) && check_non_valid_keywords(args, non_valid_keywords) { + let non_valid_keywords = vec![ + "DELETE", "FROM", "INSERT", "INTO", "SELECT", "VALUES", "ORDER", "BY", + ]; + if args[2].eq("SET") + && args.contains(&"WHERE".to_string()) + && check_non_valid_keywords(args, non_valid_keywords) + { Ok(QueryType::UPDATE) - } else{ + } else { Err(error::UPDATE_MAL_FORMATEADO) } } -fn check_non_valid_keywords(args: &[String], non_valid_keywords: Vec<&str>) -> bool { +fn check_non_valid_keywords(args: &[String], non_valid_keywords: Vec<&str>) -> bool { // Checks if args contains any non valid keyword let mut result = true; let mut counter = 0; @@ -277,63 +330,57 @@ fn check_non_valid_keywords(args: &[String], non_valid_keywords: Vec<&str>) -> result } -fn validate_query(query: Query) -> Result { - // Pre: Sintactical query OK +fn validate_query(query: Query) -> Result { + // Pre: Sintactical query OK // Post: Valid query for execution match &query.table { Some(table) => match File::open(table) { - Ok(_) => {}, - Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + Ok(_) => {} + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO), }, - None => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + None => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO), } match &query.operation { - Some(op) => { - match op { - QueryType::DELETE => validate_delete_query(query), - QueryType::INSERT => validate_insert_query(query), - QueryType::SELECT => validate_select_query(query), - QueryType::UPDATE => validate_update_query(query), - } + Some(op) => match op { + QueryType::DELETE => validate_delete_query(query), + QueryType::INSERT => validate_insert_query(query), + QueryType::SELECT => validate_select_query(query), + QueryType::UPDATE => validate_update_query(query), }, - None => Err(error::OPERACION_INVALIDA) + None => Err(error::OPERACION_INVALIDA), } } -fn validate_delete_query(query: Query) -> Result { +fn validate_delete_query(query: Query) -> Result { if query.columns.is_none() && query.values.is_none() && query.where_condition.is_some() { match &query.table { - Some(table) => { - match File::open(table) { - Ok(file) => { - match get_columns(file) { - Some(columns) => check_columns_contains_condition(columns,query), - None => Err(error::ARCHIVO_VACIO) - } - }, - Err(_) => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) - } + Some(table) => match File::open(table) { + Ok(file) => match get_columns(file) { + Some(columns) => check_columns_contains_condition(columns, query), + None => Err(error::ARCHIVO_VACIO), + }, + Err(_) => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO), }, - None => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + None => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO), } } else { Err(error::DELETE_MAL_FORMATEADO) } } -fn validate_insert_query(query: Query) -> Result { +fn validate_insert_query(query: Query) -> Result { // TODO Ok(query) } -fn validate_select_query(query: Query) -> Result { - // TODO +fn validate_select_query(query: Query) -> Result { + // TODO Ok(query) } -fn validate_update_query(query: Query) -> Result { - // TODO +fn validate_update_query(query: Query) -> Result { + // TODO Ok(query) } @@ -348,46 +395,44 @@ fn get_columns(file: File) -> Option> { while element_opt.is_some() { match element_opt { Some(x) => result.push(x.to_string()), - None => continue + None => continue, } element_opt = split.next(); } - + Some(result) - }, - Err(_) => None + } + Err(_) => None, } } -fn check_columns_contains_condition(columns: Vec, query: Query) -> Result { - // TODO +fn check_columns_contains_condition(columns: Vec, query: Query) -> Result { + // TODO match get_where_columns(&query) { Some(column) => { if columns.contains(&column) { - Ok(query) + Ok(query) } else { Err(error::ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS) } - }, - None => Err(error::NO_WHERE) + } + None => Err(error::NO_WHERE), } -} +} fn get_where_columns(query: &Query) -> Option { match &query.where_condition { - Some(cond) => { - match &cond.column { - Some(col) => Some(col.to_string()), - None => None - } + Some(cond) => match &cond.column { + Some(col) => Some(col.to_string()), + None => None, }, - None => None + None => None, } } fn text_to_vec(text_query: &String) -> Vec { // Text to vector. Tokenization by space, new line & coma - let mut tmp_text_query = text_query.to_string(); + let mut tmp_text_query = text_query.to_string(); tmp_text_query = tmp_text_query.replace('\n', " "); tmp_text_query = tmp_text_query.replace(',', ""); tmp_text_query = tmp_text_query.replace(';', ""); @@ -399,8 +444,8 @@ fn text_to_vec(text_query: &String) -> Vec { match element_opt { Some(x) => { result.push(x.to_string()); - }, - None => continue + } + None => continue, } element_opt = split.next(); @@ -408,32 +453,30 @@ fn text_to_vec(text_query: &String) -> Vec { result } -fn vec_to_query(args: &Vec, path: &String) -> Result{ - // Vec to non validated query - let mut result: Query = build_empty_query(); - match check_operation_format(args) { - Ok(x) => { - match &x { - QueryType::DELETE => match separate_args_delete(args, path, &mut result){ - Ok(_) => result.operation = Some(x), - Err(x) => return Err(x) - }, - QueryType::INSERT => match separate_args_insert(args, path, &mut result) { - Ok(_) => result.operation = Some(x), - Err(x) => return Err(x) - }, - QueryType::SELECT => match separate_args_select(args, path, &mut result) { - Ok(_) => result.operation = Some(x), - Err(x) => return Err(x) - }, - QueryType::UPDATE => match separate_args_update(args, path, &mut result) { - Ok(_) => result.operation = Some(x), - Err(x) => return Err(x) - } - } +fn vec_to_query(args: &Vec, path: &String) -> Result { + // Vec to non validated query + let mut result: Query = build_empty_query(); + match check_operation_format(args) { + Ok(x) => match &x { + QueryType::DELETE => match separate_args_delete(args, path, &mut result) { + Ok(_) => result.operation = Some(x), + Err(x) => return Err(x), + }, + QueryType::INSERT => match separate_args_insert(args, path, &mut result) { + Ok(_) => result.operation = Some(x), + Err(x) => return Err(x), + }, + QueryType::SELECT => match separate_args_select(args, path, &mut result) { + Ok(_) => result.operation = Some(x), + Err(x) => return Err(x), + }, + QueryType::UPDATE => match separate_args_update(args, path, &mut result) { + Ok(_) => result.operation = Some(x), + Err(x) => return Err(x), + }, }, - Err(x) => return Err(x) - } + Err(x) => return Err(x), + } Ok(result) } @@ -449,34 +492,47 @@ pub fn get_file_first_line(query: &Query) -> Option { Ok(_) => { line = line.replace('\n', ""); Some(line) - }, - Err(_) => None + } + Err(_) => None, } - }, - Err(_) => None + } + Err(_) => None, }, - None => None + None => None, } } - #[cfg(test)] mod tests { use super::*; - #[test] - fn test_text_to_vec1(){ + #[test] + fn test_text_to_vec1() { let rt1 = text_to_vec(&String::from("SELECT * FROM table")); - assert_eq!(rt1, vec!["SELECT","*","FROM","table"]); + assert_eq!(rt1, vec!["SELECT", "*", "FROM", "table"]); } - #[test] - fn test_text_to_vec2(){ - let rt2 = text_to_vec(&String::from("SELECT id, producto, id_cliente\nFROM ordenes\nWHERE cantidad > 1")); - assert_eq!(rt2, vec!["SELECT","id","producto","id_cliente","FROM","ordenes","WHERE","cantidad",">","1"]); + #[test] + fn test_text_to_vec2() { + let rt2 = text_to_vec(&String::from( + "SELECT id, producto, id_cliente\nFROM ordenes\nWHERE cantidad > 1", + )); + assert_eq!( + rt2, + vec![ + "SELECT", + "id", + "producto", + "id_cliente", + "FROM", + "ordenes", + "WHERE", + "cantidad", + ">", + "1" + ] + ); } - - } /* @@ -498,7 +554,7 @@ fn check_where_format(args: &Vec, start_position: usize) -> bool { } } else if args[counter].eq("AND") || args[counter].eq("OR") { if op_detected { - result = false; // AND OR , OR AND, OR OR, AND AND. Que estas haciendo ? + result = false; // AND OR , OR AND, OR OR, AND AND. Que estas haciendo ? } else { op_detected = true; counter += 1; @@ -514,26 +570,26 @@ fn check_where_format(args: &Vec, start_position: usize) -> bool { } fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) -> Result{ - // Asume query bien formateado + // Asume query bien formateado let mut table= String::from(path); table.push('/'); match &operation { QueryType::DELETE => table.push_str(&args[2]), QueryType::INSERT => table.push_str(&args[2]), - QueryType::SELECT => { - // Debo encontrar cual es la tabla (asumiendo query bien formateado) + QueryType::SELECT => { + // Debo encontrar cual es la tabla (asumiendo query bien formateado) let mut counter = 2; - while ! args[counter].eq("FROM"){ + while ! args[counter].eq("FROM"){ counter += 1; } table.push_str(&args[counter + 1]) }, QueryType::UPDATE => table.push_str(&args[1]), } - + match File::open(&table) { // TODO: Path::exist()? - Ok(_) => return Ok(table), - Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + Ok(_) => return Ok(table), + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) } } -*/ \ No newline at end of file +*/ diff --git a/src/main.rs b/src/main.rs index 6b8e678..97d3f98 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ pub mod condition; -pub mod query; pub mod libs; +pub mod query; use libs::error::print_err; use libs::exec::exec_query; @@ -11,11 +11,11 @@ fn main() { if args.len() < 3 { println!("Uso: cargo run -- ruta/a/tablas \"query\""); } else { - let path: &String = &args[1]; - let text_query: &String = &args[2]; - match build_query(text_query, path) { - Ok(x) => exec_query(x), - Err(x) => print_err(x) + let path: &String = &args[1]; + let text_query: &String = &args[2]; + match build_query(text_query, path) { + Ok(x) => exec_query(x), + Err(x) => print_err(x), } } } diff --git a/src/query.rs b/src/query.rs index 6135fc3..e15545f 100644 --- a/src/query.rs +++ b/src/query.rs @@ -6,28 +6,27 @@ use crate::condition::Condition; // use crate::condition::ComplexCondition; -pub static DELETE_MIN_LEN :usize = 7; // DELETE FROM tabla WHERE a < b -pub static INSERT_MIN_LEN :usize = 6; // INSERT INTO tabla col VALUES val -pub static SELECT_MIN_LEN :usize = 4; // SELECT * FROM tabla -pub static UPDATE_MIN_LEN :usize = 10; // UPDATE tabla SET col = valor WHERE a < b - +pub static DELETE_MIN_LEN: usize = 7; // DELETE FROM tabla WHERE a < b +pub static INSERT_MIN_LEN: usize = 6; // INSERT INTO tabla col VALUES val +pub static SELECT_MIN_LEN: usize = 4; // SELECT * FROM tabla +pub static UPDATE_MIN_LEN: usize = 10; // UPDATE tabla SET col = valor WHERE a < b pub struct Query { - pub operation: Option, // DELETE, INSERT, SELECT, UPDATE - pub table: Option, // DELETE, INSERT, SELECT, UPDATE - pub columns: Option>, // INSERT, SELECT, UPDATE - pub where_condition: Option, // DELETE (always), SELECT (sometimes), UPDATE (always) . - pub order_by: Option<(String,bool)>, // SELECT (sometimes) - pub values: Option> // INSERT, UPDATE (in update is set) + pub operation: Option, // DELETE, INSERT, SELECT, UPDATE + pub table: Option, // DELETE, INSERT, SELECT, UPDATE + pub columns: Option>, // INSERT, SELECT, UPDATE + pub where_condition: Option, // DELETE (always), SELECT (sometimes), UPDATE (always) . + pub order_by: Option<(String, bool)>, // SELECT (sometimes) + pub values: Option>, // INSERT, UPDATE (in update is set) } pub fn build_empty_query() -> Query { Query { - operation: None, - table: None, - columns: None, - where_condition: None, - order_by: None, - values: None, + operation: None, + table: None, + columns: None, + where_condition: None, + order_by: None, + values: None, } } diff --git a/src/query/query_type.rs b/src/query/query_type.rs index ffd21e2..8cfa19b 100644 --- a/src/query/query_type.rs +++ b/src/query/query_type.rs @@ -3,16 +3,16 @@ pub enum QueryType { DELETE, INSERT, SELECT, - UPDATE + UPDATE, } impl std::fmt::Display for QueryType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - QueryType::DELETE => write!(f,"DELETE"), - QueryType::INSERT => write!(f,"INSERT"), - QueryType::SELECT => write!(f,"SELECT"), - QueryType::UPDATE => write!(f,"UPDATE"), + QueryType::DELETE => write!(f, "DELETE"), + QueryType::INSERT => write!(f, "INSERT"), + QueryType::SELECT => write!(f, "SELECT"), + QueryType::UPDATE => write!(f, "UPDATE"), } } -} \ No newline at end of file +} From f8d4b7e7a016edbd502d9c40b70157ca6bab89a5 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Mon, 9 Sep 2024 17:46:44 -0300 Subject: [PATCH 21/58] WIP select WHERE --- src/condition.rs | 28 +++++++++++++++++++--------- src/libs/exec.rs | 26 +++++++++++++++++++------- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src/condition.rs b/src/condition.rs index d667cf3..9b4be76 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -22,15 +22,25 @@ pub fn build_condition(column: String, value: String, cond: ConditionOperator) - } } -/* -pub fn operate_condition(filter: (&u32,&ConditionOperator,&String), elements: &Vec) -> bool { - let (column, operator, value) = filter; +pub fn operate_condition(v1: &String, v2: &String, operator: &ConditionOperator ) -> bool { + if let Ok(x1) = v1.parse::() { + if let Ok(x2) = v2.parse::() { + match operator { + ConditionOperator::Minor => return x1 < x2, + ConditionOperator::MinorEqual => return x1 <= x2, + ConditionOperator::Equal => return x1 == x2, + ConditionOperator::Higher => return x1 > x2, + ConditionOperator::HigherEqual => return x1 >= x2, + } + }; + }; + match operator { - ConditionOperator::Minor => {}, - ConditionOperator::MinorEqual => {}, - ConditionOperator::Equal => {}, - ConditionOperator::Higher => {}, - ConditionOperator::HigherEqual => {}, + ConditionOperator::Minor => true, + ConditionOperator::MinorEqual => true, + ConditionOperator::Equal => v1.eq(v2), + ConditionOperator::Higher => true, + ConditionOperator::HigherEqual => true, } } -*/ + diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 47970ef..aa2afbe 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -1,6 +1,7 @@ use std::fs::{File, OpenOptions}; use std::io::{BufRead, BufReader, Write}; +use crate::condition::{self, operate_condition, Condition}; //use crate::condition::operate_condition; use crate::query::query_type::QueryType; use crate::query::Query; @@ -168,7 +169,7 @@ fn read_and_print_file(query: &Query, col_filter: i32, columns: &[usize]) { if read { let elements = line_to_vec(&line); match &query.where_condition { - Some(condition) => {} + Some(condition) => print_file_conditioned(columns, (col_filter, condition), &elements), None => print_file_unconditional(columns, &elements), } line.clear(); @@ -188,24 +189,24 @@ fn print_file_unconditional(columns: &[usize], elements: &[String]) { // Pre: Columns vector sorted incremental && Elements of line content vector // Post: print to stdout the correct columns - if columns.is_empty() { + if columns.is_empty() { // SELECT * FROM for (counter, element) in elements.iter().enumerate() { print!("{}", element); - if counter < elements.len() - 1 { + if counter < columns.len() - 1 { print!(","); } } - } else { + } else { // SELECT columns FROM let mut counter = 0; - let mut found_count = 0; + let mut first = true; while counter < elements.len() { if columns.contains(&counter) { - if found_count == 0 { + if first { print!("{}", elements[counter]); + first = false; } else { print!(",{}", elements[counter]); } - found_count += 1; } counter += 1; @@ -214,6 +215,17 @@ fn print_file_unconditional(columns: &[usize], elements: &[String]) { println!(); } +fn print_file_conditioned(columns: &[usize], filter: (i32, &Condition), elements: &[String]) { + let (col_filter,condition) = filter; + if let Some(value) = &condition.value { + if operate_condition(value, &elements[col_filter as usize], &condition.condition) { + print_file_unconditional(columns, elements) + } + } else { + print_file_unconditional(columns, elements) + } +} + fn line_to_vec(line: &str) -> Vec { let mut result: Vec = Vec::new(); let mut split = line.split(','); From ee7f6f9a799750cc22e6ad821a892493c76c5b26 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Mon, 9 Sep 2024 17:55:37 -0300 Subject: [PATCH 22/58] gdb OK SELECT * FROM --- src/libs/exec.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index aa2afbe..8324954 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -189,16 +189,18 @@ fn print_file_unconditional(columns: &[usize], elements: &[String]) { // Pre: Columns vector sorted incremental && Elements of line content vector // Post: print to stdout the correct columns + let mut first = true; if columns.is_empty() { // SELECT * FROM for (counter, element) in elements.iter().enumerate() { - print!("{}", element); - if counter < columns.len() - 1 { - print!(","); + if first { + print!("{}", element); + first = false; + } else { + print!(",{}", element); } } } else { // SELECT columns FROM let mut counter = 0; - let mut first = true; while counter < elements.len() { if columns.contains(&counter) { if first { From 79e92e02290b02b39568bcb09872e178d7c49afd Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Mon, 9 Sep 2024 18:05:09 -0300 Subject: [PATCH 23/58] SELECT c/ WHERE --- README.md | 16 ++++++++-------- src/libs/exec.rs | 2 +- src/libs/parsing.rs | 15 ++++++++++----- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index b04eb63..636d2c7 100644 --- a/README.md +++ b/README.md @@ -12,17 +12,15 @@ Pendientes: 2. Funcionalidad: SELECT c/ ORDER BY -3. Funcionalidad: SELECT c/ WHERE +3. Funcionalidad: DELETE -4. Funcionalidad: DELETE +4. Funcionalidad: UPDATE -5. Funcionalidad: UPDATE +5. Testing (mas test unitarios e integración) -6. Testing (mas test unitarios e integración) +6. Cargo clippy sin warnings -7. Cargo clippy sin warnings - -8. Documentación de funciones +7. Documentación de funciones Funcionalidades probadas OK @@ -30,7 +28,9 @@ Funcionalidades probadas OK 2. SELECT columnas FROM -3. INSERT INTO +3. SELECT c/ WHERE + +4. INSERT INTO ### Detalles de implementación diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 8324954..6d382f4 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -220,7 +220,7 @@ fn print_file_unconditional(columns: &[usize], elements: &[String]) { fn print_file_conditioned(columns: &[usize], filter: (i32, &Condition), elements: &[String]) { let (col_filter,condition) = filter; if let Some(value) = &condition.value { - if operate_condition(value, &elements[col_filter as usize], &condition.condition) { + if operate_condition(&elements[col_filter as usize], value, &condition.condition) { print_file_unconditional(columns, elements) } } else { diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 5c9aa02..df35d39 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -180,31 +180,36 @@ fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> R args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::Minor, - )) + )); + counter += 3; } else if args[counter + 1].eq("<=") { result.where_condition = Some(build_condition( args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::MinorEqual, - )) + )); + counter += 3; } else if args[counter + 1].eq("=") { result.where_condition = Some(build_condition( args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::Equal, - )) + )); + counter += 3; } else if args[counter + 1].eq(">=") { result.where_condition = Some(build_condition( args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::HigherEqual, - )) + )); + counter += 3; } else if args[counter + 1].eq(">") { result.where_condition = Some(build_condition( args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::Higher, - )) + )); + counter += 3; } else { return Err(error::WHERE_MAL_FORMATEADO); } From d6a3d399eef357c9b43e4451634e27cbbbe4502b Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Tue, 10 Sep 2024 17:41:32 -0300 Subject: [PATCH 24/58] WIP: Minor func para delete/update --- src/libs/exec.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 6d382f4..9767585 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -21,7 +21,26 @@ pub fn exec_query(query: Query) { } fn exec_query_delete(query: Query) { - // TODO + // CREATE .table.tmp + +} + +fn get_tmp_file_name(query: &Query) -> Option { + match &query.table { + Some(line) => { + let mut output = String::new(); + let last_item_index = line.split('/').enumerate().count() - 1; + for (counter, element) in line.split('/').enumerate() { + if counter == last_item_index { + output.push('.'); + } + + output.push_str(&element.to_string()); + } + Some(output) + }, + None => None + } } fn exec_query_insert(query: Query) { From 39d8ea3a06766445eaf5faaee66d0f4a7df4f64c Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Wed, 11 Sep 2024 00:37:45 -0300 Subject: [PATCH 25/58] WIP DELETE --- src/libs/exec.rs | 110 +++++++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 60 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 9767585..23a3739 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -9,45 +9,55 @@ use crate::query::Query; use super::parsing::get_file_first_line; pub fn exec_query(query: Query) { - match &query.operation { - Some(op) => match op { + if let Some(op) = &query.operation { + match op { QueryType::DELETE => exec_query_delete(query), QueryType::INSERT => exec_query_insert(query), QueryType::SELECT => exec_query_select(query), QueryType::UPDATE => exec_query_update(query), - }, - None => println!("Error en el programa"), + } } } fn exec_query_delete(query: Query) { // CREATE .table.tmp - + if let Some(cond) = &query.where_condition { + if let Some(table) = &query.table { + if let Ok(file) = File::open(table){ + if let Ok(tmp_file) = File::open(get_tmp_file_name(table)) { + let col_index = find_filter_column(&query); + let mut reader: BufReader = BufReader::new(file); + let mut line = String::new(); + + if let Ok(x) = reader.read_line(&mut line) { + + } + } + } + } + } } -fn get_tmp_file_name(query: &Query) -> Option { - match &query.table { - Some(line) => { - let mut output = String::new(); - let last_item_index = line.split('/').enumerate().count() - 1; - for (counter, element) in line.split('/').enumerate() { - if counter == last_item_index { - output.push('.'); - } +fn get_tmp_file_name(table: &String) -> String { + // Pre: Path and name to file. ruta/a/tablas/tabla.csv + // Post: same file but starting with period, as long as it's a hidden file + let mut output = String::new(); + let last_item_index = table.split('/').enumerate().count() - 1; + for (counter, element) in table.split('/').enumerate() { + if counter == last_item_index { + output.push('.'); + } - output.push_str(&element.to_string()); - } - Some(output) - }, - None => None + output.push_str(&element.to_string()); } + output } fn exec_query_insert(query: Query) { - match &query.table { - Some(table) => { - let total_columns = find_total_columns(&query); - let write_columns = find_print_columns(&query); + if let Some(table) = &query.table { + let total_columns = find_total_columns(&query); + let write_columns = find_print_columns(&query); + match &mut OpenOptions::new().append(true).open(table) { Ok(file) => { let mut write_line = String::new(); @@ -69,12 +79,10 @@ fn exec_query_insert(query: Query) { write_line.push('\n'); let _ = file.write(write_line.as_bytes()); - } + }, Err(_) => println!("ERROR en el programa"), } } - None => println!("ERROR en el programa"), - } } fn exec_query_select(query: Query) { @@ -162,45 +170,27 @@ fn find_filter_column(query: &Query) -> i32 { } fn read_and_print_file(query: &Query, col_filter: i32, columns: &[usize]) { - match &query.table { - Some(table) => match File::open(table) { - Ok(f) => { - let mut reader: BufReader = BufReader::new(f); - let mut line = String::new(); + if let Some(table) = &query.table { + if let Ok(f) = File::open(table) { + let mut reader: BufReader = BufReader::new(f); + let mut line = String::new(); - // Print header - /* match reader.read_line(&mut line) { - Ok(_) => { - line = line.replace('\n', ""); - println!("{}",line); - line.clear(); - }, - Err(_) => println!("Error en el programa") // TODO - } - */ - // Print other lines - let mut read = true; - while read { - match reader.read_line(&mut line) { - Ok(x) => { - line = line.replace('\n', ""); - read = x != 0; - if read { - let elements = line_to_vec(&line); - match &query.where_condition { - Some(condition) => print_file_conditioned(columns, (col_filter, condition), &elements), - None => print_file_unconditional(columns, &elements), - } - line.clear(); - } + let mut read = true; + while read { + if let Ok(x) = reader.read_line(&mut line) { + line = line.replace('\n', ""); + read = x != 0; + if read { + let elements = line_to_vec(&line); + match &query.where_condition { + Some(condition) => print_file_conditioned(columns, (col_filter, condition), &elements), + None => print_file_unconditional(columns, &elements), } - Err(_) => println!("Error en el programa"), + line.clear(); } } } - Err(_) => println!("Error en el programa"), - }, - None => println!("Error en el programa "), + } } } From 01893fdd58d2a16971dba7c518243cadec07ba22 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Wed, 11 Sep 2024 00:58:02 -0300 Subject: [PATCH 26/58] DELETE CREA TMP FILE OK --- src/libs/exec.rs | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 23a3739..d778dd6 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -6,6 +6,7 @@ use crate::condition::{self, operate_condition, Condition}; use crate::query::query_type::QueryType; use crate::query::Query; +use super::error; use super::parsing::get_file_first_line; pub fn exec_query(query: Query) { @@ -23,16 +24,32 @@ fn exec_query_delete(query: Query) { // CREATE .table.tmp if let Some(cond) = &query.where_condition { if let Some(table) = &query.table { - if let Ok(file) = File::open(table){ - if let Ok(tmp_file) = File::open(get_tmp_file_name(table)) { - let col_index = find_filter_column(&query); - let mut reader: BufReader = BufReader::new(file); - let mut line = String::new(); - - if let Ok(x) = reader.read_line(&mut line) { + if let Ok(mut tmp_file) = File::create(get_tmp_file_name(table)) { + if let Ok(file) = File::open(table){ + if let Some(value) = &cond.value { + let col_index = find_filter_column(&query); + let mut reader: BufReader = BufReader::new(file); + let mut line = String::new(); + let mut read = true; + while read { + if let Ok(x) = reader.read_line(&mut line) { + line = line.replace('\n', ""); + read = x != 0; + if read { + let elements = line_to_vec(&line); + if ! operate_condition(&elements[col_index as usize], value, &cond.condition) { + line.push('\n'); + if let Err(_error) = tmp_file.write(line.as_bytes()) { + println!("Error en delete") + } + } + } + line.clear(); + } + } } - } + } } } } @@ -49,6 +66,10 @@ fn get_tmp_file_name(table: &String) -> String { } output.push_str(&element.to_string()); + + if counter < last_item_index { + output.push('/'); + } } output } From cbf5ffc2aaa14b095c2167ded49d059936851516 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sat, 14 Sep 2024 12:53:43 -0300 Subject: [PATCH 27/58] DELETE OK --- README.md | 2 +- src/libs/exec.rs | 71 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 49 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 636d2c7..a87dde0 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Funcionalidades probadas OK 2. SELECT columnas FROM -3. SELECT c/ WHERE +3. SELECT c/ WHERE (basico) 4. INSERT INTO diff --git a/src/libs/exec.rs b/src/libs/exec.rs index d778dd6..59af291 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -1,4 +1,4 @@ -use std::fs::{File, OpenOptions}; +use std::fs::{remove_file, rename, File, OpenOptions}; use std::io::{BufRead, BufReader, Write}; use crate::condition::{self, operate_condition, Condition}; @@ -21,40 +21,65 @@ pub fn exec_query(query: Query) { } fn exec_query_delete(query: Query) { - // CREATE .table.tmp if let Some(cond) = &query.where_condition { - if let Some(table) = &query.table { - if let Ok(mut tmp_file) = File::create(get_tmp_file_name(table)) { - if let Ok(file) = File::open(table){ - if let Some(value) = &cond.value { - let col_index = find_filter_column(&query); - let mut reader: BufReader = BufReader::new(file); - let mut line = String::new(); + if let Some(value) = &cond.value { + if let Some(table) = &query.table { // Check conditions for query. if not, don't do anything + let tmp_file_name = get_tmp_file_name(table); + let mut valid_operation = true; + match File::open(table) { + Ok(file) => { + match File::create(&tmp_file_name) { + Ok(mut tmp_file) => { + let col_index = find_filter_column(&query); + let mut reader: BufReader = BufReader::new(file); + let mut line = String::new(); - let mut read = true; - while read { - if let Ok(x) = reader.read_line(&mut line) { - line = line.replace('\n', ""); - read = x != 0; - if read { - let elements = line_to_vec(&line); - if ! operate_condition(&elements[col_index as usize], value, &cond.condition) { - line.push('\n'); - if let Err(_error) = tmp_file.write(line.as_bytes()) { - println!("Error en delete") + let mut read = true; + while read { + if let Ok(x) = reader.read_line(&mut line) { + line = line.replace('\n', ""); + read = x != 0; + if read { + let elements = line_to_vec(&line); + if ! operate_condition(&elements[col_index as usize], value, &cond.condition) { + line.push('\n'); + if let Err(_error) = tmp_file.write(line.as_bytes()) { + println!("Error en delete") + } + } } + line.clear(); + } else{ + read = false; + valid_operation = false; } } - line.clear(); - } + }, + Err(_) => valid_operation = false } + }, + Err(_) => valid_operation = false + } + + if valid_operation { + if let Ok(_) = remove_file(table){ + let _ = rename(tmp_file_name, table); + } else { + let _ = remove_file(tmp_file_name); } - } + } + else { + let _ = remove_file(tmp_file_name); + } } } } } +fn remove_tmp_file(){ + +} + fn get_tmp_file_name(table: &String) -> String { // Pre: Path and name to file. ruta/a/tablas/tabla.csv // Post: same file but starting with period, as long as it's a hidden file From 341592c57171142f69a59b80b54bdf41bf3d1989 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sat, 14 Sep 2024 12:54:03 -0300 Subject: [PATCH 28/58] cargo fmt: DELETE OK --- src/condition.rs | 5 +- src/libs/exec.rs | 118 +++++++++++++++++++++++--------------------- src/libs/parsing.rs | 2 +- 3 files changed, 64 insertions(+), 61 deletions(-) diff --git a/src/condition.rs b/src/condition.rs index 9b4be76..c3a917a 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -22,7 +22,7 @@ pub fn build_condition(column: String, value: String, cond: ConditionOperator) - } } -pub fn operate_condition(v1: &String, v2: &String, operator: &ConditionOperator ) -> bool { +pub fn operate_condition(v1: &String, v2: &String, operator: &ConditionOperator) -> bool { if let Ok(x1) = v1.parse::() { if let Ok(x2) = v2.parse::() { match operator { @@ -32,7 +32,7 @@ pub fn operate_condition(v1: &String, v2: &String, operator: &ConditionOperator ConditionOperator::Higher => return x1 > x2, ConditionOperator::HigherEqual => return x1 >= x2, } - }; + }; }; match operator { @@ -43,4 +43,3 @@ pub fn operate_condition(v1: &String, v2: &String, operator: &ConditionOperator ConditionOperator::HigherEqual => true, } } - diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 59af291..7482959 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -23,52 +23,54 @@ pub fn exec_query(query: Query) { fn exec_query_delete(query: Query) { if let Some(cond) = &query.where_condition { if let Some(value) = &cond.value { - if let Some(table) = &query.table { // Check conditions for query. if not, don't do anything + if let Some(table) = &query.table { + // Check conditions for query. if not, don't do anything let tmp_file_name = get_tmp_file_name(table); let mut valid_operation = true; match File::open(table) { - Ok(file) => { - match File::create(&tmp_file_name) { - Ok(mut tmp_file) => { - let col_index = find_filter_column(&query); - let mut reader: BufReader = BufReader::new(file); - let mut line = String::new(); - - let mut read = true; - while read { - if let Ok(x) = reader.read_line(&mut line) { - line = line.replace('\n', ""); - read = x != 0; - if read { - let elements = line_to_vec(&line); - if ! operate_condition(&elements[col_index as usize], value, &cond.condition) { - line.push('\n'); - if let Err(_error) = tmp_file.write(line.as_bytes()) { - println!("Error en delete") - } + Ok(file) => match File::create(&tmp_file_name) { + Ok(mut tmp_file) => { + let col_index = find_filter_column(&query); + let mut reader: BufReader = BufReader::new(file); + let mut line = String::new(); + + let mut read = true; + while read { + if let Ok(x) = reader.read_line(&mut line) { + line = line.replace('\n', ""); + read = x != 0; + if read { + let elements = line_to_vec(&line); + if !operate_condition( + &elements[col_index as usize], + value, + &cond.condition, + ) { + line.push('\n'); + if let Err(_error) = tmp_file.write(line.as_bytes()) { + println!("Error en delete") } } - line.clear(); - } else{ - read = false; - valid_operation = false; } + line.clear(); + } else { + read = false; + valid_operation = false; } - }, - Err(_) => valid_operation = false + } } + Err(_) => valid_operation = false, }, - Err(_) => valid_operation = false + Err(_) => valid_operation = false, } if valid_operation { - if let Ok(_) = remove_file(table){ + if let Ok(_) = remove_file(table) { let _ = rename(tmp_file_name, table); } else { let _ = remove_file(tmp_file_name); } - } - else { + } else { let _ = remove_file(tmp_file_name); } } @@ -76,9 +78,7 @@ fn exec_query_delete(query: Query) { } } -fn remove_tmp_file(){ - -} +fn remove_tmp_file() {} fn get_tmp_file_name(table: &String) -> String { // Pre: Path and name to file. ruta/a/tablas/tabla.csv @@ -103,32 +103,32 @@ fn exec_query_insert(query: Query) { if let Some(table) = &query.table { let total_columns = find_total_columns(&query); let write_columns = find_print_columns(&query); - - match &mut OpenOptions::new().append(true).open(table) { - Ok(file) => { - let mut write_line = String::new(); - let mut counter = 0; - let mut writen_elements = 0; - while counter < total_columns { - if write_columns.contains(&counter) { - if let Some(x) = &query.values { - write_line.push_str(&x[writen_elements].to_string()); - writen_elements += 1; - } - } - counter += 1; - if counter < total_columns { - write_line.push(','); + match &mut OpenOptions::new().append(true).open(table) { + Ok(file) => { + let mut write_line = String::new(); + let mut counter = 0; + let mut writen_elements = 0; + while counter < total_columns { + if write_columns.contains(&counter) { + if let Some(x) = &query.values { + write_line.push_str(&x[writen_elements].to_string()); + writen_elements += 1; } } - write_line.push('\n'); - let _ = file.write(write_line.as_bytes()); - }, - Err(_) => println!("ERROR en el programa"), + counter += 1; + if counter < total_columns { + write_line.push(','); + } + } + + write_line.push('\n'); + let _ = file.write(write_line.as_bytes()); } + Err(_) => println!("ERROR en el programa"), } + } } fn exec_query_select(query: Query) { @@ -229,7 +229,9 @@ fn read_and_print_file(query: &Query, col_filter: i32, columns: &[usize]) { if read { let elements = line_to_vec(&line); match &query.where_condition { - Some(condition) => print_file_conditioned(columns, (col_filter, condition), &elements), + Some(condition) => { + print_file_conditioned(columns, (col_filter, condition), &elements) + } None => print_file_unconditional(columns, &elements), } line.clear(); @@ -245,7 +247,8 @@ fn print_file_unconditional(columns: &[usize], elements: &[String]) { // Post: print to stdout the correct columns let mut first = true; - if columns.is_empty() { // SELECT * FROM + if columns.is_empty() { + // SELECT * FROM for (counter, element) in elements.iter().enumerate() { if first { print!("{}", element); @@ -254,7 +257,8 @@ fn print_file_unconditional(columns: &[usize], elements: &[String]) { print!(",{}", element); } } - } else { // SELECT columns FROM + } else { + // SELECT columns FROM let mut counter = 0; while counter < elements.len() { if columns.contains(&counter) { @@ -273,7 +277,7 @@ fn print_file_unconditional(columns: &[usize], elements: &[String]) { } fn print_file_conditioned(columns: &[usize], filter: (i32, &Condition), elements: &[String]) { - let (col_filter,condition) = filter; + let (col_filter, condition) = filter; if let Some(value) = &condition.value { if operate_condition(&elements[col_filter as usize], value, &condition.condition) { print_file_unconditional(columns, elements) diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index df35d39..910338b 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -92,7 +92,7 @@ fn separate_args_insert(args: &[String], path: &String, result: &mut Query) -> R let mut columns: Vec = Vec::new(); let mut counter = 3; - while counter < args.len() && !args[counter].eq("VALUES") { + while counter < args.len() && !args[counter].eq("VALUES") { columns.push(args[counter].to_string()); counter += 1; } From 275db028fecc3ee2b36356602f92c9a43f807346 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sat, 14 Sep 2024 15:46:02 -0300 Subject: [PATCH 29/58] COMMIT PRE REFACTOR --- README.md | 13 +++--- src/libs/exec.rs | 100 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 88 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index a87dde0..e5ea552 100644 --- a/README.md +++ b/README.md @@ -12,15 +12,13 @@ Pendientes: 2. Funcionalidad: SELECT c/ ORDER BY -3. Funcionalidad: DELETE +3. Funcionalidad: UPDATE -4. Funcionalidad: UPDATE +4. Testing (mas test unitarios e integración) -5. Testing (mas test unitarios e integración) +5. Cargo clippy sin warnings -6. Cargo clippy sin warnings - -7. Documentación de funciones +6. Documentación de funciones Funcionalidades probadas OK @@ -32,6 +30,9 @@ Funcionalidades probadas OK 4. INSERT INTO +5. DELETE FROM WHERE (basico) + + ### Detalles de implementación Para la lógica booleana el objetivo era crear un arbol de condiciones formado por las relaciones de precedencia. diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 7482959..8800691 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -1,12 +1,11 @@ use std::fs::{remove_file, rename, File, OpenOptions}; use std::io::{BufRead, BufReader, Write}; -use crate::condition::{self, operate_condition, Condition}; +use crate::condition::{operate_condition, Condition}; //use crate::condition::operate_condition; use crate::query::query_type::QueryType; use crate::query::Query; -use super::error; use super::parsing::get_file_first_line; pub fn exec_query(query: Query) { @@ -48,7 +47,8 @@ fn exec_query_delete(query: Query) { ) { line.push('\n'); if let Err(_error) = tmp_file.write(line.as_bytes()) { - println!("Error en delete") + read = false; + valid_operation = false; } } } @@ -64,21 +64,28 @@ fn exec_query_delete(query: Query) { Err(_) => valid_operation = false, } - if valid_operation { - if let Ok(_) = remove_file(table) { - let _ = rename(tmp_file_name, table); - } else { - let _ = remove_file(tmp_file_name); - } - } else { - let _ = remove_file(tmp_file_name); + if let Err(_) = remove_old_file(table, &tmp_file_name, valid_operation) { + println!("Error en manipulación de archivos"); } } } } } -fn remove_tmp_file() {} +fn remove_old_file(file: &String, tmp_file: &String, valid_operation: bool) -> Result { + if valid_operation { + if let Ok(_) = remove_file(file) { + let _ = rename(tmp_file, file); + Ok(0) + } else { + let _ = remove_file(tmp_file); + Err(1) + } + } else { + let _ = remove_file(tmp_file); + Err(2) + } +} fn get_tmp_file_name(table: &String) -> String { // Pre: Path and name to file. ruta/a/tablas/tabla.csv @@ -246,13 +253,11 @@ fn print_file_unconditional(columns: &[usize], elements: &[String]) { // Pre: Columns vector sorted incremental && Elements of line content vector // Post: print to stdout the correct columns - let mut first = true; if columns.is_empty() { // SELECT * FROM for (counter, element) in elements.iter().enumerate() { - if first { + if counter == 0 { print!("{}", element); - first = false; } else { print!(",{}", element); } @@ -262,9 +267,8 @@ fn print_file_unconditional(columns: &[usize], elements: &[String]) { let mut counter = 0; while counter < elements.len() { if columns.contains(&counter) { - if first { + if counter == 0 { print!("{}", elements[counter]); - first = false; } else { print!(",{}", elements[counter]); } @@ -305,8 +309,66 @@ fn line_to_vec(line: &str) -> Vec { result } -fn exec_query_select_order_by(query: Query) {} +fn exec_query_select_order_by(query: Query) { + // TODO +} fn exec_query_update(query: Query) { - // TODO + if let Some(cond) = &query.where_condition { + if let Some(value) = &cond.value { + if let Some(columns) = &query.columns { + if let Some(values) = &query.values { + if let Some(table) = &query.table { + let tmp_file = get_tmp_file_name(table); + let mut valid_operation = true; + match File::open(table) { + Ok(file) => match File::create(&tmp_file) { + Ok(mut tmp_file) => { + let col_index = find_filter_column(&query); + let mut reader: BufReader = BufReader::new(file); + let mut line = String::new(); + + let mut read = true; + while read { + if let Ok(x) = reader.read_line(&mut line) { + line = line.replace('\n', ""); + read = x != 0; + if read { + let elements = line_to_vec(&line); + if !operate_condition( + &elements[col_index as usize], + value, + &cond.condition, + ) { + // Line not updated + line.push('\n'); + if let Err(_error) = + tmp_file.write(line.as_bytes()) + { + read = false; + valid_operation = false; + } + } else { // Updated Line + } + } + line.clear(); + } else { + read = false; + valid_operation = false; + } + } + } + Err(_) => valid_operation = false, + }, + Err(_) => valid_operation = false, + } + + if let Err(_) = remove_old_file(table, &tmp_file, valid_operation) { + println!("Error en manipulación de archivos"); + } + } + } + } + } + } } From 44796507c94929b6d83e844346eb7b5d34c44d80 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sat, 14 Sep 2024 16:58:22 -0300 Subject: [PATCH 30/58] query.columns to vec --- src/libs/exec.rs | 181 +++++++++++++++++++++------------------- src/libs/parsing.rs | 198 ++++++++++++++++++++++---------------------- src/query.rs | 2 +- 3 files changed, 195 insertions(+), 186 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 8800691..0d2b797 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -108,32 +108,34 @@ fn get_tmp_file_name(table: &String) -> String { fn exec_query_insert(query: Query) { if let Some(table) = &query.table { - let total_columns = find_total_columns(&query); - let write_columns = find_print_columns(&query); - - match &mut OpenOptions::new().append(true).open(table) { - Ok(file) => { - let mut write_line = String::new(); - let mut counter = 0; - let mut writen_elements = 0; - while counter < total_columns { - if write_columns.contains(&counter) { - if let Some(x) = &query.values { - write_line.push_str(&x[writen_elements].to_string()); - writen_elements += 1; + if let Some(write_columns) = &query.columns { + let total_columns = find_total_columns(&query); +// let write_columns = find_print_columns(&query); + + match &mut OpenOptions::new().append(true).open(table) { + Ok(file) => { + let mut write_line = String::new(); + let mut counter = 0; + let mut writen_elements = 0; + while counter < total_columns { + if write_columns.contains(&counter) { + if let Some(x) = &query.values { + write_line.push_str(&x[writen_elements].to_string()); + writen_elements += 1; + } } - } - counter += 1; - if counter < total_columns { - write_line.push(','); + counter += 1; + if counter < total_columns { + write_line.push(','); + } } - } - write_line.push('\n'); - let _ = file.write(write_line.as_bytes()); + write_line.push('\n'); + let _ = file.write(write_line.as_bytes()); + } + Err(_) => println!("ERROR en el programa"), } - Err(_) => println!("ERROR en el programa"), } } } @@ -143,8 +145,8 @@ fn exec_query_select(query: Query) { Some(_) => exec_query_select_order_by(query), None => { let col_index = find_filter_column(&query); - let print_columns: Vec = find_print_columns(&query); - read_and_print_file(&query, col_index, &print_columns); +// let print_columns: Vec = find_print_columns(&query); + read_and_print_file(&query, col_index); } } } @@ -156,30 +158,6 @@ fn find_total_columns(query: &Query) -> usize { } } -fn find_print_columns(query: &Query) -> Vec { - let mut result: Vec = Vec::new(); - match &query.columns { - Some(cols) => match get_file_first_line(query) { - Some(line) => { - let table_columns: Vec = line_to_vec(&line); - for element in cols { - let mut counter = 0; - while !table_columns[counter].eq(element) && counter < table_columns.len() { - counter += 1; - } - if counter < table_columns.len() { - result.push(counter); - } - } - - result - } - None => result, - }, - None => result, - } -} - fn find_filter_column(query: &Query) -> i32 { let mut col_index_filter = -1; match &query.where_condition { @@ -222,72 +200,77 @@ fn find_filter_column(query: &Query) -> i32 { col_index_filter } -fn read_and_print_file(query: &Query, col_filter: i32, columns: &[usize]) { +fn read_and_print_file(query: &Query, col_filter: i32) { if let Some(table) = &query.table { if let Ok(f) = File::open(table) { - let mut reader: BufReader = BufReader::new(f); - let mut line = String::new(); - - let mut read = true; - while read { - if let Ok(x) = reader.read_line(&mut line) { - line = line.replace('\n', ""); - read = x != 0; - if read { - let elements = line_to_vec(&line); - match &query.where_condition { - Some(condition) => { - print_file_conditioned(columns, (col_filter, condition), &elements) + + let mut reader: BufReader = BufReader::new(f); + let mut line = String::new(); + + let mut read = true; + while read { + if let Ok(x) = reader.read_line(&mut line) { + line = line.replace('\n', ""); + read = x != 0; + if read { + let elements = line_to_vec(&line); + match &query.where_condition { + Some(condition) => { + print_file_conditioned(&query.columns, (col_filter, condition), &elements) + } + None => print_file_unconditional(&query.columns, &elements), } - None => print_file_unconditional(columns, &elements), + line.clear(); } - line.clear(); } - } - } + } + } } } -fn print_file_unconditional(columns: &[usize], elements: &[String]) { +fn print_file_unconditional(columns_opt: &Option>, elements: &[String]) { // Pre: Columns vector sorted incremental && Elements of line content vector // Post: print to stdout the correct columns - if columns.is_empty() { - // SELECT * FROM - for (counter, element) in elements.iter().enumerate() { - if counter == 0 { - print!("{}", element); - } else { - print!(",{}", element); + match columns_opt { + Some(columns) => { + // SELECT columns FROM + let mut counter = 0; + while counter < elements.len() { + if columns.contains(&counter) { + if counter == 0 { + print!("{}", elements[counter]); + } else { + print!(",{}", elements[counter]); + } + } + + counter += 1; } - } - } else { - // SELECT columns FROM - let mut counter = 0; - while counter < elements.len() { - if columns.contains(&counter) { + }, + None => { + for (counter, element) in elements.iter().enumerate() { if counter == 0 { - print!("{}", elements[counter]); + print!("{}", element); } else { - print!(",{}", elements[counter]); + print!(",{}", element); } } - - counter += 1; } } + println!(); } -fn print_file_conditioned(columns: &[usize], filter: (i32, &Condition), elements: &[String]) { +fn print_file_conditioned(columns_opt: &Option>, filter: (i32, &Condition), elements: &[String]) { let (col_filter, condition) = filter; if let Some(value) = &condition.value { if operate_condition(&elements[col_filter as usize], value, &condition.condition) { - print_file_unconditional(columns, elements) + print_file_unconditional(columns_opt, elements) } } else { - print_file_unconditional(columns, elements) + print_file_unconditional(columns_opt, elements) } } @@ -372,3 +355,29 @@ fn exec_query_update(query: Query) { } } } + +/* +fn find_print_columns(query: &Query) -> Vec { + let mut result: Vec = Vec::new(); + match &query.columns { + Some(cols) => match get_file_first_line(query) { + Some(line) => { + let table_columns: Vec = line_to_vec(&line); + for element in cols { + let mut counter = 0; + while !table_columns[counter].eq(element) && counter < table_columns.len() { + counter += 1; + } + if counter < table_columns.len() { + result.push(counter); + } + } + + result + } + None => result, + }, + None => result, + } +} +*/ diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 910338b..2132187 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -14,7 +14,7 @@ use super::error::SELECT_MAL_FORMATEADO; pub fn build_query(text_query: &String, path: &String) -> Result { // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build - let args = text_to_vec(text_query); + let args = text_to_vec(text_query, false); match vec_to_query(&args, path) { Ok(x) => validate_query(x), Err(x) => Err(x), @@ -90,10 +90,10 @@ fn separate_args_insert(args: &[String], path: &String, result: &mut Query) -> R } else { result.table = Some(merge_table_and_path(path, &args[2])); - let mut columns: Vec = Vec::new(); + let mut string_columns: Vec = Vec::new(); let mut counter = 3; while counter < args.len() && !args[counter].eq("VALUES") { - columns.push(args[counter].to_string()); + string_columns.push(args[counter].to_string()); counter += 1; } @@ -104,30 +104,40 @@ fn separate_args_insert(args: &[String], path: &String, result: &mut Query) -> R counter += 1; } - result.columns = Some(columns); + match get_columns_position(&result, &string_columns){ + Ok(x) => result.columns = Some(x), + Err(x) => return Err(x) + } result.values = Some(values); + Ok(0) } } fn separate_args_update(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < UPDATE_MIN_LEN { - result.table = Some(merge_table_and_path(path, &args[1])); + match File::open(merge_table_and_path(path, &args[1])){ + Ok(_) => result.table = Some(merge_table_and_path(path, &args[1])), + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + } - let mut counter = 3; - let mut columns: Vec = Vec::new(); + let mut counter: usize = 3; + let mut string_columns: Vec = Vec::new(); let mut values: Vec = Vec::new(); while counter < args.len() && !args[counter].eq("WHERE") { if counter % 3 == 0 { - columns.push(args[counter].to_string()); + string_columns.push(args[counter].to_string()); } else if (counter % 3) == 2 { values.push(args[counter].to_string()); } counter += 1; } - result.columns = Some(columns); + match get_columns_position(&result, &string_columns){ + Ok(x) => result.columns = Some(x), + Err(x) => return Err(x) + } result.values = Some(values); /* TODO: Code for complex conditions @@ -147,19 +157,26 @@ fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> R if args.len() < SELECT_MIN_LEN { Err(error::SELECT_MAL_FORMATEADO) } else { - let mut columns: Vec = Vec::new(); + let mut string_columns: Vec = Vec::new(); let mut counter = 1; while counter < args.len() && !args[counter].eq("FROM") { - columns.push(args[counter].to_string()); + string_columns.push(args[counter].to_string()); counter += 1; } counter += 1; - if !&columns[0].eq("*") { - result.columns = Some(columns); + match File::open(merge_table_and_path(path, &args[counter])){ + Ok(_) => result.table = Some(merge_table_and_path(path, &args[counter])), + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) } - result.table = Some(merge_table_and_path(path, &args[counter])); + if !&string_columns[0].eq("*") { + match get_columns_position(&result, &string_columns){ + Ok(x) => result.columns = Some(x), + Err(x) => return Err(x) + } + } + counter += 1; if counter == args.len() { @@ -240,6 +257,41 @@ fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> R } } +fn get_columns_position(query: &Query, string_cols: &Vec ) -> Result,u32> { + // From string + match get_file_first_line(query) { + Some(line) => { + let mut result: Vec = Vec::new(); + let columns = text_to_vec(&line, true); + + let mut counter = 0; + while counter < string_cols.len() && columns.contains(&columns[counter]){ + match find_column_position(&columns[counter], &columns){ + Ok(x) => { + result.push(x); + counter += 1; + }, + Err(x) => return Err(x) + } + } + Ok(result) + }, + None => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + } +} + +fn find_column_position(column_name: &String ,columns: &Vec) -> Result { + let mut counter = 0; + while counter < columns.len() { + if column_name.eq(&columns[counter]) { + return Ok(counter) + } else{ + counter += 1; + } + } + Err(error::ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS) +} + fn check_operation_format(args: &Vec) -> Result { // Check correct operation sintaxis let operation = &args[0]; @@ -435,11 +487,38 @@ fn get_where_columns(query: &Query) -> Option { } } -fn text_to_vec(text_query: &String) -> Vec { +pub fn get_file_first_line(query: &Query) -> Option { + // Pre: query + // Post: File first line, if any + match &query.table { + Some(table) => match File::open(table) { + Ok(f) => { + let mut reader: BufReader = BufReader::new(f); + let mut line = String::new(); + + match reader.read_line(&mut line) { + Ok(_) => { + line = line.replace('\n', ""); + Some(line) + } + Err(_) => None, + } + } + Err(_) => None, + }, + None => None, + } +} + +fn text_to_vec(text_query: &String, coma: bool) -> Vec { // Text to vector. Tokenization by space, new line & coma let mut tmp_text_query = text_query.to_string(); tmp_text_query = tmp_text_query.replace('\n', " "); - tmp_text_query = tmp_text_query.replace(',', ""); + if (!coma){ + tmp_text_query = tmp_text_query.replace(',', ""); + } else { + tmp_text_query = tmp_text_query.replace(',', " "); + } tmp_text_query = tmp_text_query.replace(';', ""); let mut split = tmp_text_query.split(' '); @@ -459,7 +538,8 @@ fn text_to_vec(text_query: &String) -> Vec { } fn vec_to_query(args: &Vec, path: &String) -> Result { - // Vec to non validated query + // Pre: Vec of queries tokens & path to tables + // Post: Vec to non validated query let mut result: Query = build_empty_query(); match check_operation_format(args) { Ok(x) => match &x { @@ -486,34 +566,13 @@ fn vec_to_query(args: &Vec, path: &String) -> Result { Ok(result) } -pub fn get_file_first_line(query: &Query) -> Option { - match &query.table { - Some(table) => match File::open(table) { - Ok(f) => { - let mut reader: BufReader = BufReader::new(f); - let mut line = String::new(); - - match reader.read_line(&mut line) { - Ok(_) => { - line = line.replace('\n', ""); - Some(line) - } - Err(_) => None, - } - } - Err(_) => None, - }, - None => None, - } -} - #[cfg(test)] mod tests { use super::*; #[test] fn test_text_to_vec1() { - let rt1 = text_to_vec(&String::from("SELECT * FROM table")); + let rt1 = text_to_vec(&String::from("SELECT * FROM table"), false); assert_eq!(rt1, vec!["SELECT", "*", "FROM", "table"]); } @@ -521,7 +580,7 @@ mod tests { fn test_text_to_vec2() { let rt2 = text_to_vec(&String::from( "SELECT id, producto, id_cliente\nFROM ordenes\nWHERE cantidad > 1", - )); + ), false); assert_eq!( rt2, vec![ @@ -539,62 +598,3 @@ mod tests { ); } } - -/* -fn check_where_format(args: &Vec, start_position: usize) -> bool { - let mut result = true; - - let mut counter: usize = start_position; - - let mut not_detected: bool = false; - let mut op_detected: bool = false; - - while counter < args.len() && result { - if args[counter].eq("NOT") { - if not_detected || op_detected { - result = false; // NOT NOT. Que estas haciendo ? - } else { - not_detected = true; - counter += 1; - } - } else if args[counter].eq("AND") || args[counter].eq("OR") { - if op_detected { - result = false; // AND OR , OR AND, OR OR, AND AND. Que estas haciendo ? - } else { - op_detected = true; - counter += 1; - } - } else if counter + 3 > args.len() { - result = false; - } else { - - } - } - - result -} - -fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) -> Result{ - // Asume query bien formateado - let mut table= String::from(path); - table.push('/'); - match &operation { - QueryType::DELETE => table.push_str(&args[2]), - QueryType::INSERT => table.push_str(&args[2]), - QueryType::SELECT => { - // Debo encontrar cual es la tabla (asumiendo query bien formateado) - let mut counter = 2; - while ! args[counter].eq("FROM"){ - counter += 1; - } - table.push_str(&args[counter + 1]) - }, - QueryType::UPDATE => table.push_str(&args[1]), - } - - match File::open(&table) { // TODO: Path::exist()? - Ok(_) => return Ok(table), - Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) - } -} -*/ diff --git a/src/query.rs b/src/query.rs index e15545f..a3132c6 100644 --- a/src/query.rs +++ b/src/query.rs @@ -14,7 +14,7 @@ pub static UPDATE_MIN_LEN: usize = 10; // UPDATE tabla SET col = valor WHERE a < pub struct Query { pub operation: Option, // DELETE, INSERT, SELECT, UPDATE pub table: Option, // DELETE, INSERT, SELECT, UPDATE - pub columns: Option>, // INSERT, SELECT, UPDATE + pub columns: Option>, // INSERT, SELECT, UPDATE pub where_condition: Option, // DELETE (always), SELECT (sometimes), UPDATE (always) . pub order_by: Option<(String, bool)>, // SELECT (sometimes) pub values: Option>, // INSERT, UPDATE (in update is set) From 1d5f935441399e2d824f300d3be6a3d85e2506a3 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sat, 14 Sep 2024 18:03:31 -0300 Subject: [PATCH 31/58] OK: UPDATE clientes SET nombre = jose WHERE id = 9 --- src/libs/exec.rs | 52 +++++++++++++++----------------- src/libs/parsing.rs | 72 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 83 insertions(+), 41 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 0d2b797..3f404c2 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -314,16 +314,15 @@ fn exec_query_update(query: Query) { let mut read = true; while read { if let Ok(x) = reader.read_line(&mut line) { - line = line.replace('\n', ""); read = x != 0; if read { + line = line.replace('\n', ""); let elements = line_to_vec(&line); if !operate_condition( &elements[col_index as usize], value, &cond.condition, - ) { - // Line not updated + ) { // Line not updated line.push('\n'); if let Err(_error) = tmp_file.write(line.as_bytes()) @@ -331,7 +330,13 @@ fn exec_query_update(query: Query) { read = false; valid_operation = false; } - } else { // Updated Line + } else { // Update Line + if let Err(_error) = + tmp_file.write(update_line(&elements, columns, values).as_bytes()) + { + read = false; + valid_operation = false; + } } } line.clear(); @@ -356,28 +361,19 @@ fn exec_query_update(query: Query) { } } -/* -fn find_print_columns(query: &Query) -> Vec { - let mut result: Vec = Vec::new(); - match &query.columns { - Some(cols) => match get_file_first_line(query) { - Some(line) => { - let table_columns: Vec = line_to_vec(&line); - for element in cols { - let mut counter = 0; - while !table_columns[counter].eq(element) && counter < table_columns.len() { - counter += 1; - } - if counter < table_columns.len() { - result.push(counter); - } - } - - result - } - None => result, - }, - None => result, +fn update_line(elements: &[String], columns: &[usize], values: &[String]) -> String { + let mut result = String::new(); + let mut writen_counter = 0; + for (counter, element) in elements.iter().enumerate() { + if counter > 0 { + result.push(','); + } + if columns.contains(&counter){ + result.push_str(&values[writen_counter].to_string()); + writen_counter += 1; + } else { + result.push_str(&element.to_string()); + } } -} -*/ + result +} \ No newline at end of file diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 2132187..5a3500c 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -34,7 +34,10 @@ fn separate_args_delete(args: &[String], path: &String, result: &mut Query) -> R if args.len() < DELETE_MIN_LEN { Err(error::DELETE_MAL_FORMATEADO) } else { - result.table = Some(merge_table_and_path(path, &args[2])); + match File::open(merge_table_and_path(path, &args[2])){ + Ok(_) => result.table = Some(merge_table_and_path(path, &args[2])), + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + } if args.len() != DELETE_MIN_LEN { return Err(error::DELETE_MAL_FORMATEADO); @@ -88,7 +91,10 @@ fn separate_args_insert(args: &[String], path: &String, result: &mut Query) -> R if args.len() < INSERT_MIN_LEN { Err(error::INSERT_MAL_FORMATEADO) } else { - result.table = Some(merge_table_and_path(path, &args[2])); + match File::open(merge_table_and_path(path, &args[2])){ + Ok(_) => result.table = Some(merge_table_and_path(path, &args[2])), + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + } let mut string_columns: Vec = Vec::new(); let mut counter = 3; @@ -116,6 +122,8 @@ fn separate_args_insert(args: &[String], path: &String, result: &mut Query) -> R fn separate_args_update(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < UPDATE_MIN_LEN { + Err(error::UPDATE_MAL_FORMATEADO) + } else { match File::open(merge_table_and_path(path, &args[1])){ Ok(_) => result.table = Some(merge_table_and_path(path, &args[1])), Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) @@ -147,10 +155,43 @@ fn separate_args_update(args: &[String], path: &String, result: &mut Query) -> R Err(x) => return Err(x) } */ + if args[8].eq("<") { + result.where_condition = Some(build_condition( + args[7].to_string(), + args[9].to_string(), + ConditionOperator::Minor, + )) + } else if args[8].eq("<=") { + result.where_condition = Some(build_condition( + args[7].to_string(), + args[9].to_string(), + ConditionOperator::MinorEqual, + )) + } else if args[8].eq("=") { + result.where_condition = Some(build_condition( + args[7].to_string(), + args[9].to_string(), + ConditionOperator::Equal, + )) + } else if args[8].eq(">=") { + result.where_condition = Some(build_condition( + args[7].to_string(), + args[9].to_string(), + ConditionOperator::HigherEqual, + )) + } else if args[8].eq(">") { + result.where_condition = Some(build_condition( + args[7].to_string(), + args[9].to_string(), + ConditionOperator::Higher, + )) + } else { + return Err(error::WHERE_MAL_FORMATEADO); + } + + Ok(0) - } else { - Err(error::UPDATE_MAL_FORMATEADO) - } + } } fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> Result { @@ -265,13 +306,18 @@ fn get_columns_position(query: &Query, string_cols: &Vec ) -> Result { - result.push(x); - counter += 1; - }, - Err(x) => return Err(x) + while counter < string_cols.len() { + if columns.contains(&string_cols[counter]) { + match find_column_position(&string_cols[counter], &columns){ + Ok(x) => { + result.push(x); + counter += 1; + }, + Err(x) => return Err(x) + } + } + else { + return Err(error::ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS) } } Ok(result) @@ -514,7 +560,7 @@ fn text_to_vec(text_query: &String, coma: bool) -> Vec { // Text to vector. Tokenization by space, new line & coma let mut tmp_text_query = text_query.to_string(); tmp_text_query = tmp_text_query.replace('\n', " "); - if (!coma){ + if !coma { tmp_text_query = tmp_text_query.replace(',', ""); } else { tmp_text_query = tmp_text_query.replace(',', " "); From f3728ec651608c0fff274cdfdfd0a99f246098f4 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sat, 14 Sep 2024 18:03:57 -0300 Subject: [PATCH 32/58] fmtOK: UPDATE clientes SET nombre = jose WHERE id = 9 --- src/libs/exec.rs | 75 +++++++++++++++++++++++++-------------------- src/libs/parsing.rs | 73 ++++++++++++++++++++++--------------------- src/query.rs | 2 +- 3 files changed, 78 insertions(+), 72 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 3f404c2..35c1fe2 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -110,7 +110,7 @@ fn exec_query_insert(query: Query) { if let Some(table) = &query.table { if let Some(write_columns) = &query.columns { let total_columns = find_total_columns(&query); -// let write_columns = find_print_columns(&query); + // let write_columns = find_print_columns(&query); match &mut OpenOptions::new().append(true).open(table) { Ok(file) => { @@ -145,7 +145,7 @@ fn exec_query_select(query: Query) { Some(_) => exec_query_select_order_by(query), None => { let col_index = find_filter_column(&query); -// let print_columns: Vec = find_print_columns(&query); + // let print_columns: Vec = find_print_columns(&query); read_and_print_file(&query, col_index); } } @@ -203,28 +203,28 @@ fn find_filter_column(query: &Query) -> i32 { fn read_and_print_file(query: &Query, col_filter: i32) { if let Some(table) = &query.table { if let Ok(f) = File::open(table) { - - let mut reader: BufReader = BufReader::new(f); - let mut line = String::new(); - - let mut read = true; - while read { - if let Ok(x) = reader.read_line(&mut line) { - line = line.replace('\n', ""); - read = x != 0; - if read { - let elements = line_to_vec(&line); - match &query.where_condition { - Some(condition) => { - print_file_conditioned(&query.columns, (col_filter, condition), &elements) - } - None => print_file_unconditional(&query.columns, &elements), - } - line.clear(); + let mut reader: BufReader = BufReader::new(f); + let mut line = String::new(); + + let mut read = true; + while read { + if let Ok(x) = reader.read_line(&mut line) { + line = line.replace('\n', ""); + read = x != 0; + if read { + let elements = line_to_vec(&line); + match &query.where_condition { + Some(condition) => print_file_conditioned( + &query.columns, + (col_filter, condition), + &elements, + ), + None => print_file_unconditional(&query.columns, &elements), } + line.clear(); } - } - + } + } } } } @@ -248,7 +248,7 @@ fn print_file_unconditional(columns_opt: &Option>, elements: &[String counter += 1; } - }, + } None => { for (counter, element) in elements.iter().enumerate() { if counter == 0 { @@ -263,7 +263,11 @@ fn print_file_unconditional(columns_opt: &Option>, elements: &[String println!(); } -fn print_file_conditioned(columns_opt: &Option>, filter: (i32, &Condition), elements: &[String]) { +fn print_file_conditioned( + columns_opt: &Option>, + filter: (i32, &Condition), + elements: &[String], +) { let (col_filter, condition) = filter; if let Some(value) = &condition.value { if operate_condition(&elements[col_filter as usize], value, &condition.condition) { @@ -322,7 +326,8 @@ fn exec_query_update(query: Query) { &elements[col_index as usize], value, &cond.condition, - ) { // Line not updated + ) { + // Line not updated line.push('\n'); if let Err(_error) = tmp_file.write(line.as_bytes()) @@ -330,10 +335,12 @@ fn exec_query_update(query: Query) { read = false; valid_operation = false; } - } else { // Update Line - if let Err(_error) = - tmp_file.write(update_line(&elements, columns, values).as_bytes()) - { + } else { + // Update Line + if let Err(_error) = tmp_file.write( + update_line(&elements, columns, values) + .as_bytes(), + ) { read = false; valid_operation = false; } @@ -368,12 +375,12 @@ fn update_line(elements: &[String], columns: &[usize], values: &[String]) -> Str if counter > 0 { result.push(','); } - if columns.contains(&counter){ - result.push_str(&values[writen_counter].to_string()); - writen_counter += 1; + if columns.contains(&counter) { + result.push_str(&values[writen_counter].to_string()); + writen_counter += 1; } else { - result.push_str(&element.to_string()); + result.push_str(&element.to_string()); } } result -} \ No newline at end of file +} diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 5a3500c..fade4e9 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -34,9 +34,9 @@ fn separate_args_delete(args: &[String], path: &String, result: &mut Query) -> R if args.len() < DELETE_MIN_LEN { Err(error::DELETE_MAL_FORMATEADO) } else { - match File::open(merge_table_and_path(path, &args[2])){ + match File::open(merge_table_and_path(path, &args[2])) { Ok(_) => result.table = Some(merge_table_and_path(path, &args[2])), - Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO), } if args.len() != DELETE_MIN_LEN { @@ -91,9 +91,9 @@ fn separate_args_insert(args: &[String], path: &String, result: &mut Query) -> R if args.len() < INSERT_MIN_LEN { Err(error::INSERT_MAL_FORMATEADO) } else { - match File::open(merge_table_and_path(path, &args[2])){ + match File::open(merge_table_and_path(path, &args[2])) { Ok(_) => result.table = Some(merge_table_and_path(path, &args[2])), - Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO), } let mut string_columns: Vec = Vec::new(); @@ -110,9 +110,9 @@ fn separate_args_insert(args: &[String], path: &String, result: &mut Query) -> R counter += 1; } - match get_columns_position(&result, &string_columns){ + match get_columns_position(&result, &string_columns) { Ok(x) => result.columns = Some(x), - Err(x) => return Err(x) + Err(x) => return Err(x), } result.values = Some(values); @@ -124,9 +124,9 @@ fn separate_args_update(args: &[String], path: &String, result: &mut Query) -> R if args.len() < UPDATE_MIN_LEN { Err(error::UPDATE_MAL_FORMATEADO) } else { - match File::open(merge_table_and_path(path, &args[1])){ + match File::open(merge_table_and_path(path, &args[1])) { Ok(_) => result.table = Some(merge_table_and_path(path, &args[1])), - Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO), } let mut counter: usize = 3; @@ -142,9 +142,9 @@ fn separate_args_update(args: &[String], path: &String, result: &mut Query) -> R counter += 1; } - match get_columns_position(&result, &string_columns){ + match get_columns_position(&result, &string_columns) { Ok(x) => result.columns = Some(x), - Err(x) => return Err(x) + Err(x) => return Err(x), } result.values = Some(values); @@ -189,9 +189,8 @@ fn separate_args_update(args: &[String], path: &String, result: &mut Query) -> R return Err(error::WHERE_MAL_FORMATEADO); } - Ok(0) - } + } } fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> Result { @@ -206,18 +205,18 @@ fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> R } counter += 1; - match File::open(merge_table_and_path(path, &args[counter])){ + match File::open(merge_table_and_path(path, &args[counter])) { Ok(_) => result.table = Some(merge_table_and_path(path, &args[counter])), - Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO), } if !&string_columns[0].eq("*") { - match get_columns_position(&result, &string_columns){ + match get_columns_position(&result, &string_columns) { Ok(x) => result.columns = Some(x), - Err(x) => return Err(x) + Err(x) => return Err(x), } } - + counter += 1; if counter == args.len() { @@ -298,40 +297,39 @@ fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> R } } -fn get_columns_position(query: &Query, string_cols: &Vec ) -> Result,u32> { - // From string +fn get_columns_position(query: &Query, string_cols: &Vec) -> Result, u32> { + // From string match get_file_first_line(query) { Some(line) => { let mut result: Vec = Vec::new(); let columns = text_to_vec(&line, true); - + let mut counter = 0; while counter < string_cols.len() { if columns.contains(&string_cols[counter]) { - match find_column_position(&string_cols[counter], &columns){ + match find_column_position(&string_cols[counter], &columns) { Ok(x) => { result.push(x); counter += 1; - }, - Err(x) => return Err(x) - } - } - else { - return Err(error::ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS) + } + Err(x) => return Err(x), + } + } else { + return Err(error::ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS); } } Ok(result) - }, - None => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + } + None => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO), } } -fn find_column_position(column_name: &String ,columns: &Vec) -> Result { +fn find_column_position(column_name: &String, columns: &Vec) -> Result { let mut counter = 0; while counter < columns.len() { if column_name.eq(&columns[counter]) { - return Ok(counter) - } else{ + return Ok(counter); + } else { counter += 1; } } @@ -534,7 +532,7 @@ fn get_where_columns(query: &Query) -> Option { } pub fn get_file_first_line(query: &Query) -> Option { - // Pre: query + // Pre: query // Post: File first line, if any match &query.table { Some(table) => match File::open(table) { @@ -585,7 +583,7 @@ fn text_to_vec(text_query: &String, coma: bool) -> Vec { fn vec_to_query(args: &Vec, path: &String) -> Result { // Pre: Vec of queries tokens & path to tables - // Post: Vec to non validated query + // Post: Vec to non validated query let mut result: Query = build_empty_query(); match check_operation_format(args) { Ok(x) => match &x { @@ -624,9 +622,10 @@ mod tests { #[test] fn test_text_to_vec2() { - let rt2 = text_to_vec(&String::from( - "SELECT id, producto, id_cliente\nFROM ordenes\nWHERE cantidad > 1", - ), false); + let rt2 = text_to_vec( + &String::from("SELECT id, producto, id_cliente\nFROM ordenes\nWHERE cantidad > 1"), + false, + ); assert_eq!( rt2, vec![ diff --git a/src/query.rs b/src/query.rs index a3132c6..b1be240 100644 --- a/src/query.rs +++ b/src/query.rs @@ -14,7 +14,7 @@ pub static UPDATE_MIN_LEN: usize = 10; // UPDATE tabla SET col = valor WHERE a < pub struct Query { pub operation: Option, // DELETE, INSERT, SELECT, UPDATE pub table: Option, // DELETE, INSERT, SELECT, UPDATE - pub columns: Option>, // INSERT, SELECT, UPDATE + pub columns: Option>, // INSERT, SELECT, UPDATE pub where_condition: Option, // DELETE (always), SELECT (sometimes), UPDATE (always) . pub order_by: Option<(String, bool)>, // SELECT (sometimes) pub values: Option>, // INSERT, UPDATE (in update is set) From 62b1b15ae5c0fcc1149eb3032a24b4dd9e8073ed Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sat, 14 Sep 2024 23:57:19 -0300 Subject: [PATCH 33/58] OK CLIPPY + FMT --- src/libs/exec.rs | 14 ++++++++------ src/libs/parsing.rs | 21 +++++++++------------ 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 35c1fe2..5c517d8 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -64,7 +64,7 @@ fn exec_query_delete(query: Query) { Err(_) => valid_operation = false, } - if let Err(_) = remove_old_file(table, &tmp_file_name, valid_operation) { + if remove_old_file(table, &tmp_file_name, valid_operation).is_err() { println!("Error en manipulación de archivos"); } } @@ -74,8 +74,10 @@ fn exec_query_delete(query: Query) { fn remove_old_file(file: &String, tmp_file: &String, valid_operation: bool) -> Result { if valid_operation { - if let Ok(_) = remove_file(file) { - let _ = rename(tmp_file, file); + if remove_file(file).is_ok() { + if rename(tmp_file, file).is_err() { + return Err(3); + } Ok(0) } else { let _ = remove_file(tmp_file); @@ -87,7 +89,7 @@ fn remove_old_file(file: &String, tmp_file: &String, valid_operation: bool) -> R } } -fn get_tmp_file_name(table: &String) -> String { +fn get_tmp_file_name(table: &str) -> String { // Pre: Path and name to file. ruta/a/tablas/tabla.csv // Post: same file but starting with period, as long as it's a hidden file let mut output = String::new(); @@ -97,7 +99,7 @@ fn get_tmp_file_name(table: &String) -> String { output.push('.'); } - output.push_str(&element.to_string()); + output.push_str(element); if counter < last_item_index { output.push('/'); @@ -358,7 +360,7 @@ fn exec_query_update(query: Query) { Err(_) => valid_operation = false, } - if let Err(_) = remove_old_file(table, &tmp_file, valid_operation) { + if remove_old_file(table, &tmp_file, valid_operation).is_err() { println!("Error en manipulación de archivos"); } } diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index fade4e9..d053c3f 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -110,7 +110,7 @@ fn separate_args_insert(args: &[String], path: &String, result: &mut Query) -> R counter += 1; } - match get_columns_position(&result, &string_columns) { + match get_columns_position(result, &string_columns) { Ok(x) => result.columns = Some(x), Err(x) => return Err(x), } @@ -142,7 +142,7 @@ fn separate_args_update(args: &[String], path: &String, result: &mut Query) -> R counter += 1; } - match get_columns_position(&result, &string_columns) { + match get_columns_position(result, &string_columns) { Ok(x) => result.columns = Some(x), Err(x) => return Err(x), } @@ -211,7 +211,7 @@ fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> R } if !&string_columns[0].eq("*") { - match get_columns_position(&result, &string_columns) { + match get_columns_position(result, &string_columns) { Ok(x) => result.columns = Some(x), Err(x) => return Err(x), } @@ -297,7 +297,7 @@ fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> R } } -fn get_columns_position(query: &Query, string_cols: &Vec) -> Result, u32> { +fn get_columns_position(query: &Query, string_cols: &[String]) -> Result, u32> { // From string match get_file_first_line(query) { Some(line) => { @@ -320,11 +320,11 @@ fn get_columns_position(query: &Query, string_cols: &Vec) -> Result return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO), + None => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO), } } -fn find_column_position(column_name: &String, columns: &Vec) -> Result { +fn find_column_position(column_name: &String, columns: &[String]) -> Result { let mut counter = 0; while counter < columns.len() { if column_name.eq(&columns[counter]) { @@ -336,7 +336,7 @@ fn find_column_position(column_name: &String, columns: &Vec) -> Result) -> Result { +fn check_operation_format(args: &[String]) -> Result { // Check correct operation sintaxis let operation = &args[0]; if operation.eq("DELETE") { @@ -523,10 +523,7 @@ fn check_columns_contains_condition(columns: Vec, query: Query) -> Resul fn get_where_columns(query: &Query) -> Option { match &query.where_condition { - Some(cond) => match &cond.column { - Some(col) => Some(col.to_string()), - None => None, - }, + Some(cond) => cond.column.as_ref().map(|col| col.to_string()), None => None, } } @@ -581,7 +578,7 @@ fn text_to_vec(text_query: &String, coma: bool) -> Vec { result } -fn vec_to_query(args: &Vec, path: &String) -> Result { +fn vec_to_query(args: &[String], path: &String) -> Result { // Pre: Vec of queries tokens & path to tables // Post: Vec to non validated query let mut result: Query = build_empty_query(); From a05a53342a9788b80ef1bd326bf637472090404c Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 15 Sep 2024 23:42:50 -0300 Subject: [PATCH 34/58] WIP: SORT BY --- src/libs/exec.rs | 480 ++++++++++++++++++++++++++++++++------------ src/libs/parsing.rs | 2 +- 2 files changed, 351 insertions(+), 131 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 5c517d8..8e70543 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -1,12 +1,15 @@ +use std::fmt::format; use std::fs::{remove_file, rename, File, OpenOptions}; -use std::io::{BufRead, BufReader, Write}; +use std::io::{BufRead, BufReader, Seek, Write}; use crate::condition::{operate_condition, Condition}; //use crate::condition::operate_condition; use crate::query::query_type::QueryType; use crate::query::Query; -use super::parsing::get_file_first_line; +use super::parsing::{self, get_file_first_line, text_to_vec}; + +static FILE_SORT_BUFFER: usize = 20; pub fn exec_query(query: Query) { if let Some(op) = &query.operation { @@ -72,42 +75,6 @@ fn exec_query_delete(query: Query) { } } -fn remove_old_file(file: &String, tmp_file: &String, valid_operation: bool) -> Result { - if valid_operation { - if remove_file(file).is_ok() { - if rename(tmp_file, file).is_err() { - return Err(3); - } - Ok(0) - } else { - let _ = remove_file(tmp_file); - Err(1) - } - } else { - let _ = remove_file(tmp_file); - Err(2) - } -} - -fn get_tmp_file_name(table: &str) -> String { - // Pre: Path and name to file. ruta/a/tablas/tabla.csv - // Post: same file but starting with period, as long as it's a hidden file - let mut output = String::new(); - let last_item_index = table.split('/').enumerate().count() - 1; - for (counter, element) in table.split('/').enumerate() { - if counter == last_item_index { - output.push('.'); - } - - output.push_str(element); - - if counter < last_item_index { - output.push('/'); - } - } - output -} - fn exec_query_insert(query: Query) { if let Some(table) = &query.table { if let Some(write_columns) = &query.columns { @@ -144,15 +111,241 @@ fn exec_query_insert(query: Query) { fn exec_query_select(query: Query) { match &query.order_by { - Some(_) => exec_query_select_order_by(query), + Some((column, asc)) => { + let col_index: i32 = find_filter_column(&query); + if read_and_save_file(&query, col_index).is_ok() { + if let Some(column_number) = find_column(&query, column) { + if let Ok(tmp_files) = sort_and_print_file(column_number, &query, asc) { + file_cleanup(tmp_files); + } + } + } + } None => { - let col_index = find_filter_column(&query); - // let print_columns: Vec = find_print_columns(&query); + let col_index: i32 = find_filter_column(&query); read_and_print_file(&query, col_index); } } } +fn sort_and_print_file( + column_number: usize, + query: &Query, + asc: &bool, +) -> Result, u32> { + // Pre: Column number for sorting + // Post: Separates into files, sort them and print them in correct order. Result name of files for cleanup + match &query.table { + None => Err(3), + Some(table) => { + let tmp_unsorted_filename = get_tmp_file_name(table); + match File::open(tmp_unsorted_filename) { + Err(_) => Err(3), + Ok(unsorted_file) => { + let mut reader: BufReader = BufReader::new(unsorted_file); + let mut line = String::new(); + let mut actually_sorting_elements: Vec> = Vec::new(); + + let mut sorted_files: Vec = Vec::new(); + let mut sorted_filenames: Vec = Vec::new(); + let mut counter = 0; + + let mut read = true; + let mut valid_operation = true; + while read { + if let Ok(x) = reader.read_line(&mut line) { + line = line.replace('\n', ""); + read = x != 0; + + let element = text_to_vec(line, true); + if counter < FILE_SORT_BUFFER { + actually_sorting_elements.insert( + find_sorted_position( + &actually_sorting_elements, + &element, + column_number, + asc, + ), + element, + ); + } else { + let mut new_file = String::from(format!(".{}", sorted_files.len())); + new_file.push_str(&tmp_unsorted_filename); + match File::create(new_file) { + Ok(f) => { + for element in actually_sorting_elements { + let mut write_line = String::new(); + for (counter, word) in element.iter().enumerate() { + if counter == 0 { + f.write(word.as_bytes()); + } else { + f.write(format!(",{}", &word)); + } + } + } + sorted_files.push(f); + sorted_filenames.push(new_file); + actually_sorting_elements.clear(); + } + Err(_) => { + read = false; + valid_operation = false; + } + } + } + } else { + valid_operation = false; + read = false; + } + } + + if valid_operation { + Ok(sorted_filenames) + } else { + Err(3) + } + } + } + } + } +} + +fn file_cleanup(files: Vec) { + for file in files { + let _ = remove_file(file); + } +} + +fn find_sorted_position( + sorted_vec: &Vec>, + new_element: &Vec, + column_number: usize, + asc: &bool, +) -> usize { + // Insert into shifts everything to right. +} + +fn exec_query_update(query: Query) { + if let Some(cond) = &query.where_condition { + if let Some(value) = &cond.value { + if let Some(columns) = &query.columns { + if let Some(values) = &query.values { + if let Some(table) = &query.table { + let tmp_file = get_tmp_file_name(table); + let mut valid_operation = true; + match File::open(table) { + Ok(file) => match File::create(&tmp_file) { + Ok(mut tmp_file) => { + let col_index = find_filter_column(&query); + let mut reader: BufReader = BufReader::new(file); + let mut line = String::new(); + + let mut read = true; + while read { + if let Ok(x) = reader.read_line(&mut line) { + read = x != 0; + if read { + line = line.replace('\n', ""); + let elements = line_to_vec(&line); + if !operate_condition( + &elements[col_index as usize], + value, + &cond.condition, + ) { + // Line not updated + line.push('\n'); + if let Err(_error) = + tmp_file.write(line.as_bytes()) + { + read = false; + valid_operation = false; + } + } else { + // Update Line + if let Err(_error) = tmp_file.write( + update_line(&elements, columns, values) + .as_bytes(), + ) { + read = false; + valid_operation = false; + } + } + } + line.clear(); + } else { + read = false; + valid_operation = false; + } + } + } + Err(_) => valid_operation = false, + }, + Err(_) => valid_operation = false, + } + + if remove_old_file(table, &tmp_file, valid_operation).is_err() { + println!("Error en manipulación de archivos"); + } + } + } + } + } + } +} + +fn update_line(elements: &[String], columns: &[usize], values: &[String]) -> String { + let mut result = String::new(); + let mut writen_counter = 0; + for (counter, element) in elements.iter().enumerate() { + if counter > 0 { + result.push(','); + } + if columns.contains(&counter) { + result.push_str(&values[writen_counter].to_string()); + writen_counter += 1; + } else { + result.push_str(&element.to_string()); + } + } + result +} + +fn remove_old_file(file: &String, tmp_file: &String, valid_operation: bool) -> Result { + if valid_operation { + if remove_file(file).is_ok() { + if rename(tmp_file, file).is_err() { + return Err(3); + } + Ok(0) + } else { + let _ = remove_file(tmp_file); + Err(1) + } + } else { + let _ = remove_file(tmp_file); + Err(2) + } +} + +fn get_tmp_file_name(table: &str) -> String { + // Pre: Path and name to file. ruta/a/tablas/tabla.csv + // Post: same file but starting with period, as long as it's a hidden file + let mut output = String::new(); + let last_item_index = table.split('/').enumerate().count() - 1; + for (counter, element) in table.split('/').enumerate() { + if counter == last_item_index { + output.push('.'); + } + + output.push_str(element); + + if counter < last_item_index { + output.push('/'); + } + } + output +} + fn find_total_columns(query: &Query) -> usize { match get_file_first_line(query) { Some(line) => line_to_vec(&line).len(), @@ -202,6 +395,25 @@ fn find_filter_column(query: &Query) -> i32 { col_index_filter } +fn find_column(query: &Query, column: &String) -> Option { + match get_file_first_line(query) { + Some(line) => { + let args = parsing::text_to_vec(&line, true); + let mut counter = 0; + while counter < args.len() && !args[counter].eq(column) { + counter += 1 + } + + if counter == args.len() { + return None; + } else { + return Some(counter); + } + } + None => return None, + } +} + fn read_and_print_file(query: &Query, col_filter: i32) { if let Some(table) = &query.table { if let Ok(f) = File::open(table) { @@ -231,6 +443,53 @@ fn read_and_print_file(query: &Query, col_filter: i32) { } } +fn read_and_save_file(query: &Query, col_filter: i32) -> Result { + // Pre: query, filter and + // Post: + if let Some(table) = &query.table { + let tmp_file_name = get_tmp_file_name(table); + if let Ok(f) = File::open(table) { + match File::create(tmp_file_name) { + Ok(mut tmp_f) => { + let mut line = String::new(); + let mut reader: BufReader = BufReader::new(f); + + let mut read = true; + while read { + if let Ok(x) = reader.read_line(&mut line) { + line = line.replace('\n', ""); + read = x != 0; + if read { + let elements = line_to_vec(&line); + match &query.where_condition { + Some(condition) => save_file_conditioned( + &query.columns, + (col_filter, condition), + &elements, + &mut tmp_f, + ), + None => save_file_unconditional( + &query.columns, + &elements, + &mut tmp_f, + ), + } + line.clear(); + } + } + } + return Ok(0); + } + Err(_) => Err(1), + } + } else { + return Err(1); + } + } else { + return Err(1); + } +} + fn print_file_unconditional(columns_opt: &Option>, elements: &[String]) { // Pre: Columns vector sorted incremental && Elements of line content vector // Post: print to stdout the correct columns @@ -280,6 +539,56 @@ fn print_file_conditioned( } } +fn save_file_unconditional(columns_opt: &Option>, elements: &[String], file: &mut File) { + // Pre: Columns vector sorted incremental && Elements of line content vector + // Post: print to stdout the correct columns + + match columns_opt { + Some(columns) => { + // SELECT columns FROM + let mut counter = 0; + while counter < elements.len() { + if columns.contains(&counter) { + if counter == 0 { + file.write(elements[counter].as_bytes()); + } else { + file.write(format!(",{}", elements[counter]).as_bytes()); + } + } + + counter += 1; + } + } + None => { + for (counter, element) in elements.iter().enumerate() { + if counter == 0 { + file.write(element.as_bytes()); + } else { + file.write(format!(",{}", element).as_bytes()); + } + } + } + } + + println!(); +} + +fn save_file_conditioned( + columns_opt: &Option>, + filter: (i32, &Condition), + elements: &[String], + file: &mut File, +) { + let (col_filter, condition) = filter; + if let Some(value) = &condition.value { + if operate_condition(&elements[col_filter as usize], value, &condition.condition) { + save_file_unconditional(columns_opt, elements, file) + } + } else { + save_file_unconditional(columns_opt, elements, file) + } +} + fn line_to_vec(line: &str) -> Vec { let mut result: Vec = Vec::new(); let mut split = line.split(','); @@ -297,92 +606,3 @@ fn line_to_vec(line: &str) -> Vec { } result } - -fn exec_query_select_order_by(query: Query) { - // TODO -} - -fn exec_query_update(query: Query) { - if let Some(cond) = &query.where_condition { - if let Some(value) = &cond.value { - if let Some(columns) = &query.columns { - if let Some(values) = &query.values { - if let Some(table) = &query.table { - let tmp_file = get_tmp_file_name(table); - let mut valid_operation = true; - match File::open(table) { - Ok(file) => match File::create(&tmp_file) { - Ok(mut tmp_file) => { - let col_index = find_filter_column(&query); - let mut reader: BufReader = BufReader::new(file); - let mut line = String::new(); - - let mut read = true; - while read { - if let Ok(x) = reader.read_line(&mut line) { - read = x != 0; - if read { - line = line.replace('\n', ""); - let elements = line_to_vec(&line); - if !operate_condition( - &elements[col_index as usize], - value, - &cond.condition, - ) { - // Line not updated - line.push('\n'); - if let Err(_error) = - tmp_file.write(line.as_bytes()) - { - read = false; - valid_operation = false; - } - } else { - // Update Line - if let Err(_error) = tmp_file.write( - update_line(&elements, columns, values) - .as_bytes(), - ) { - read = false; - valid_operation = false; - } - } - } - line.clear(); - } else { - read = false; - valid_operation = false; - } - } - } - Err(_) => valid_operation = false, - }, - Err(_) => valid_operation = false, - } - - if remove_old_file(table, &tmp_file, valid_operation).is_err() { - println!("Error en manipulación de archivos"); - } - } - } - } - } - } -} - -fn update_line(elements: &[String], columns: &[usize], values: &[String]) -> String { - let mut result = String::new(); - let mut writen_counter = 0; - for (counter, element) in elements.iter().enumerate() { - if counter > 0 { - result.push(','); - } - if columns.contains(&counter) { - result.push_str(&values[writen_counter].to_string()); - writen_counter += 1; - } else { - result.push_str(&element.to_string()); - } - } - result -} diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index d053c3f..a4c2691 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -551,7 +551,7 @@ pub fn get_file_first_line(query: &Query) -> Option { } } -fn text_to_vec(text_query: &String, coma: bool) -> Vec { +pub fn text_to_vec(text_query: &String, coma: bool) -> Vec { // Text to vector. Tokenization by space, new line & coma let mut tmp_text_query = text_query.to_string(); tmp_text_query = tmp_text_query.replace('\n', " "); From 4b605fa35e5019d6c8af40f1cb03ef485d54b20c Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Tue, 17 Sep 2024 18:53:15 -0300 Subject: [PATCH 35/58] VUELVO A DESARROLLO --- src/libs/exec.rs | 182 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 179 insertions(+), 3 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 8e70543..15abf7b 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -1,12 +1,14 @@ +use std::collections::btree_map::Range; use std::fmt::format; use std::fs::{remove_file, rename, File, OpenOptions}; use std::io::{BufRead, BufReader, Seek, Write}; -use crate::condition::{operate_condition, Condition}; +use crate::condition::{self, operate_condition, Condition}; //use crate::condition::operate_condition; use crate::query::query_type::QueryType; -use crate::query::Query; +use crate::query::{self, Query}; +use super::error; use super::parsing::{self, get_file_first_line, text_to_vec}; static FILE_SORT_BUFFER: usize = 20; @@ -109,6 +111,7 @@ fn exec_query_insert(query: Query) { } } +/* fn exec_query_select(query: Query) { match &query.order_by { Some((column, asc)) => { @@ -127,6 +130,25 @@ fn exec_query_select(query: Query) { } } } +*/ + +fn exec_query_select(query: Query) { + match &query.order_by { + Some((column, asc)) => { + print_header(&query); + let col_index: i32 = find_filter_column(&query); + + if let Ok(mut files) = read_into_sorted_files(&query, col_index as usize, &asc) { + + } + } + None => { + let col_index: i32 = find_filter_column(&query); + read_and_print_file(&query, col_index); + } + } +} + fn sort_and_print_file( column_number: usize, @@ -157,7 +179,7 @@ fn sort_and_print_file( line = line.replace('\n', ""); read = x != 0; - let element = text_to_vec(line, true); + let element = text_to_vec(&line, true); if counter < FILE_SORT_BUFFER { actually_sorting_elements.insert( find_sorted_position( @@ -414,6 +436,42 @@ fn find_column(query: &Query, column: &String) -> Option { } } +fn print_header(query: &Query) { + if let Some(table) = &query.table { + if let Ok(file) = File::open(table) { + let mut reader: BufReader = BufReader::new(file); + let mut line = String::new(); + + if let Ok(x) = reader.read_line(&mut line) { + if x > 0 { + match &query.columns { + Some(columns) => { + line = line.replace('\n', ""); + let args = text_to_vec(&line, true); + let mut counter = 0; + let mut first = true; + for arg in args { + if columns.contains(&counter) { + if first { + print!("{}",arg); + first = false; + } else{ + print!(",{}",arg); + } + + } + counter += 1 + } + println!(); + }, + None => println!("{}",line) + } + } + } + } + } +} + fn read_and_print_file(query: &Query, col_filter: i32) { if let Some(table) = &query.table { if let Ok(f) = File::open(table) { @@ -443,6 +501,124 @@ fn read_and_print_file(query: &Query, col_filter: i32) { } } +fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result,u32> { + // Pre: Query, the col index for sorting and bool of ascending/descending + // Post: Vec of tmp_files + match &query.table { + None => Err(3), + Some(table) => { + let tmp_file_name = get_tmp_file_name(table); + match File::open(table) { + Err(_) => return Err(3), + Ok(table_file) => { + let mut tmp_files: Vec = Vec::new(); + let mut lines_buffer: Vec> = Vec::new(); + + let mut reader: BufReader = BufReader::new(table_file); + let mut line = String::new(); + + let mut read :bool = true; + let mut valid_operation :bool = true; + if reader.read_line(&mut line).is_ok() { + line.clear(); + while read { + match reader.read_line(&mut line) { + Err(_) => { + read = false; + valid_operation = false; + }, + Ok(x) => { + line = line.replace('\n', ""); + read = x != 0; + if read { + let elements = text_to_vec(&line, true); + match &query.where_condition { + Some(condition) => insert_conditioned(&elements,&mut lines_buffer,col_index,condition, asc), + None => insert_unconditioned(elements, &query.columns, &mut lines_buffer, &col_index, asc) } + line.clear(); + } + + if lines_buffer.len() == FILE_SORT_BUFFER { + let mut new_tmp_file_name = String::from(&tmp_file_name); + new_tmp_file_name.push_str(format!(".{}",&tmp_files.len()).as_str()); + match File::open(new_tmp_file_name) { + Ok(mut tmp_f) => { + for elements in &lines_buffer { + let mut first = true; + for element in elements { + if first { + tmp_f.write(element.as_bytes()); + first = false; + } else { + tmp_f.write(format!(",{}",element).as_bytes()); + } + } + } + tmp_f.seek(std::io::SeekFrom::Start(0)); + tmp_files.push(tmp_f); + }, + Err(_) => { + read = false; + valid_operation = false; + } + } + + lines_buffer.clear(); + } + } + } + } + + if valid_operation { + return Ok(tmp_files) + } else { + return Err(3) + } + } else { + return Err(error::ARCHIVO_VACIO) + } + } + } + } + } +} + +fn insert_conditioned(elements: &[String], columns_opt: &Option>, lines_buffer: &mut Vec>, col_index: &usize, filter: &Condition) { +let (col_filter, condition) = filter; + if let Some(value) = &condition.value { + if operate_condition(&elements[col_filter as usize], value, &condition.condition) { + print_file_unconditional(columns_opt, elements) + } + } else { + print_file_unconditional(columns_opt, elements) + } +} + +fn insert_unconditioned(elements: Vec, columns_opt: &Option>, lines_buffer: &mut Vec>, col_index: &usize, asc: &bool) { + let position: usize = find_insert_position(&elements, lines_buffer, col_index, asc); + + match columns_opt { + Some(columns) => { // SELECT columns FROM + let mut vector:Vec = Vec::new(); + + let mut counter = 0; + while counter < elements.len() { + if columns.contains(&counter) { + vector.push(elements[counter].to_string()); + } + + counter += 1; + } + lines_buffer.insert(position, vector); + } + None => lines_buffer.insert(position, elements), + } +} + +fn find_insert_position(elements: &[String], lines_buffer: &mut Vec>, col_index: &usize, asc: &bool) -> usize { + +} + fn read_and_save_file(query: &Query, col_filter: i32) -> Result { // Pre: query, filter and // Post: From 8703b52818801c2030b50d84e93d9f9b325afc33 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Tue, 17 Sep 2024 19:33:25 -0300 Subject: [PATCH 36/58] gdb: SELECT * FROM ORDER BY --- src/libs/exec.rs | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 15abf7b..abf86a3 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -1,5 +1,3 @@ -use std::collections::btree_map::Range; -use std::fmt::format; use std::fs::{remove_file, rename, File, OpenOptions}; use std::io::{BufRead, BufReader, Seek, Write}; @@ -149,7 +147,7 @@ fn exec_query_select(query: Query) { } } - +/* fn sort_and_print_file( column_number: usize, query: &Query, @@ -231,6 +229,7 @@ fn sort_and_print_file( } } } +*/ fn file_cleanup(files: Vec) { for file in files { @@ -245,6 +244,7 @@ fn find_sorted_position( asc: &bool, ) -> usize { // Insert into shifts everything to right. + 0 } fn exec_query_update(query: Query) { @@ -533,8 +533,10 @@ fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result if read { let elements = text_to_vec(&line, true); match &query.where_condition { - Some(condition) => insert_conditioned(&elements,&mut lines_buffer,col_index,condition, asc), - None => insert_unconditioned(elements, &query.columns, &mut lines_buffer, &col_index, asc) } + Some(condition) => {}, +// insert_conditioned(&elements,&mut lines_buffer,&col_index,condition, asc), + None => insert_unconditioned(elements, &query.columns, &mut lines_buffer, &col_index, asc) + } line.clear(); } @@ -547,7 +549,7 @@ fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result let mut first = true; for element in elements { if first { - tmp_f.write(element.as_bytes()); + let _ = tmp_f.write(element.as_bytes()); first = false; } else { tmp_f.write(format!(",{}",element).as_bytes()); @@ -583,6 +585,7 @@ fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result } } +/* fn insert_conditioned(elements: &[String], columns_opt: &Option>, lines_buffer: &mut Vec>, col_index: &usize, filter: &Condition) { let (col_filter, condition) = filter; if let Some(value) = &condition.value { @@ -593,9 +596,10 @@ let (col_filter, condition) = filter; print_file_unconditional(columns_opt, elements) } } +*/ fn insert_unconditioned(elements: Vec, columns_opt: &Option>, lines_buffer: &mut Vec>, col_index: &usize, asc: &bool) { - let position: usize = find_insert_position(&elements, lines_buffer, col_index, asc); + let position: usize = find_insert_position(&elements, lines_buffer, 0,lines_buffer.len() - 1,*col_index, asc); match columns_opt { Some(columns) => { // SELECT columns FROM @@ -615,8 +619,26 @@ fn insert_unconditioned(elements: Vec, columns_opt: &Option>, } } -fn find_insert_position(elements: &[String], lines_buffer: &mut Vec>, col_index: &usize, asc: &bool) -> usize { - +fn find_insert_position(elements: &Vec, lines_buffer: &Vec>, min_pos: usize, max_pos: usize , col_index: usize, asc: &bool) -> usize { + if max_pos - min_pos < 1 { + min_pos + } else { + if elements[col_index] > lines_buffer[(min_pos+max_pos)/2][col_index] { + if *asc { + find_insert_position(elements, lines_buffer, (min_pos+max_pos)/2, max_pos, col_index, asc) + } else { + find_insert_position(elements, lines_buffer, min_pos, (min_pos+max_pos)/2, col_index, asc) + } + } else if elements[col_index] < lines_buffer[(min_pos+max_pos)/2][col_index] { + if *asc { + find_insert_position(elements, lines_buffer, min_pos, (min_pos+max_pos)/2, col_index, asc) + } else { + find_insert_position(elements, lines_buffer, (min_pos+max_pos)/2, max_pos, col_index, asc) + } + } else { + (min_pos+max_pos)/2 + } + } } fn read_and_save_file(query: &Query, col_filter: i32) -> Result { From 9fe9d5e36db1a180bde5553d9a9abdd6a6302d55 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Tue, 17 Sep 2024 23:58:39 -0300 Subject: [PATCH 37/58] gdb: SORT BY. b search test OK --- src/libs/exec.rs | 224 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 199 insertions(+), 25 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index abf86a3..70adcc8 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -1,5 +1,7 @@ -use std::fs::{remove_file, rename, File, OpenOptions}; -use std::io::{BufRead, BufReader, Seek, Write}; +use std::collections::btree_map::Range; +use std::fs::{read, remove_file, rename, File, OpenOptions}; +use std::io::{BufRead, BufReader, Read, Seek, Write}; +use std::iter; use crate::condition::{self, operate_condition, Condition}; //use crate::condition::operate_condition; @@ -134,10 +136,11 @@ fn exec_query_select(query: Query) { match &query.order_by { Some((column, asc)) => { print_header(&query); - let col_index: i32 = find_filter_column(&query); - - if let Ok(mut files) = read_into_sorted_files(&query, col_index as usize, &asc) { - + let col_filter: i32 = find_filter_column(&query); + if let Some(col_index) = find_column(&query, column) { + if let Ok(files) = read_into_sorted_files(&query, col_index as usize, &asc) { + print_sorted_files(files, &col_index, &asc); + } } } None => { @@ -147,6 +150,137 @@ fn exec_query_select(query: Query) { } } +fn print_sorted_files(files: Vec, col_index: &usize, asc: &bool) { + // Pre: Name of tmp_files, column for ordering and selector of asc/desc + // Post: Prints from tmp_files in order + if let Some(mut readers) = create_readers(files){ + if let Some(mut lines_buffer) = readers_read_first_line(&mut readers) { + // While there are lines to be printed + while let Some(elements) = get_next_line(&mut lines_buffer, &mut readers, *col_index, asc) { + let mut counter = 0; + for element in elements { + if counter == 0 { + print!("{}",element); + } else { + print!(",{}",element); + } + counter += 1; + } + } + } + } +} + + +fn get_next_line(lines_buffer: &mut Vec>, readers: &mut Vec<(usize,BufReader)>, col_index: usize, asc: &bool) -> Option> { + // Post: Next line in order, if not fully read + let mut line = String::new(); + match find_available_reader(&readers) { + None => None, + Some(mut candidate) => { + let mut counter = candidate + 1; + while counter < readers.len() { + if readers[counter].0 < FILE_SORT_BUFFER && counter != candidate { + if *asc { + if lines_buffer[counter][col_index] < lines_buffer[candidate][col_index] { + candidate = counter; + } + } else { + if lines_buffer[counter][col_index] > lines_buffer[candidate][col_index] { + candidate = counter; + } + } + } + + counter += 1; + } + + if counter == readers.len() { + None + } else { + let new_line: Vec; + match readers[candidate].1.read_line(&mut line){ + Err(_) => new_line = Vec::new(), + Ok(read_result) => { + if read_result == 0 { + new_line = Vec::new(); // If this happen, then never read again from here + readers[candidate].0 = FILE_SORT_BUFFER; + } else { + lines_buffer.push(text_to_vec(&line, true)); + let len = lines_buffer.len(); + lines_buffer.swap(candidate,len - 1); + match lines_buffer.pop() { + Some(x) => { + new_line = x; + readers[candidate].0 += 1; + }, + None => { + new_line = Vec::new(); // If this happen, then never read again from here + readers[candidate].0 = FILE_SORT_BUFFER; + } + } + } + } + } + + Some(new_line) + } + } + } +} + +fn find_available_reader(readers: &Vec<(usize,BufReader)>) -> Option { + // Pre: Readers + // Post: First available reader position + let mut counter = 0; + while counter < readers.len() && ! &readers[counter].0 < FILE_SORT_BUFFER { + counter += 1; + } + + if counter == readers.len() { + None + } else { + Some(counter) + } +} + +fn readers_read_first_line(readers: &mut Vec<(usize,BufReader)>) -> Option>> { + let mut result: Vec> = Vec::new(); + let mut line = String::new(); + + for reader in readers { + if reader.1.read_line(&mut line).is_ok() { + result.push(text_to_vec(&line, true)); + reader.0 += 1; + } else { + return None + } + } + Some(result) +} + +fn create_readers(files: Vec) -> Option)>> { + let mut valid = true; + let mut readers: Vec<(usize,BufReader)> = Vec::new(); + + let mut counter = 0; + while counter < files.len() && valid{ + match File::open(&files[counter]) { + Err(_) => valid = false, + Ok(file) => { + readers.push((0,BufReader::new(file))); + counter += 1; + } + } + } + + if valid { + Some(readers) + } else { + None + } +} + /* fn sort_and_print_file( column_number: usize, @@ -501,7 +635,7 @@ fn read_and_print_file(query: &Query, col_filter: i32) { } } -fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result,u32> { +fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result,u32> { // Pre: Query, the col index for sorting and bool of ascending/descending // Post: Vec of tmp_files match &query.table { @@ -511,7 +645,7 @@ fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result match File::open(table) { Err(_) => return Err(3), Ok(table_file) => { - let mut tmp_files: Vec = Vec::new(); + let mut tmp_filenames: Vec = Vec::new(); let mut lines_buffer: Vec> = Vec::new(); let mut reader: BufReader = BufReader::new(table_file); @@ -542,8 +676,9 @@ fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result if lines_buffer.len() == FILE_SORT_BUFFER { let mut new_tmp_file_name = String::from(&tmp_file_name); - new_tmp_file_name.push_str(format!(".{}",&tmp_files.len()).as_str()); - match File::open(new_tmp_file_name) { + new_tmp_file_name.push_str(format!(".{}",&tmp_filenames.len()).as_str()); + + match File::open(&new_tmp_file_name) { Ok(mut tmp_f) => { for elements in &lines_buffer { let mut first = true; @@ -556,8 +691,7 @@ fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result } } } - tmp_f.seek(std::io::SeekFrom::Start(0)); - tmp_files.push(tmp_f); + tmp_filenames.push(new_tmp_file_name); }, Err(_) => { read = false; @@ -572,7 +706,7 @@ fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result } if valid_operation { - return Ok(tmp_files) + return Ok(tmp_filenames) } else { return Err(3) } @@ -599,8 +733,14 @@ let (col_filter, condition) = filter; */ fn insert_unconditioned(elements: Vec, columns_opt: &Option>, lines_buffer: &mut Vec>, col_index: &usize, asc: &bool) { - let position: usize = find_insert_position(&elements, lines_buffer, 0,lines_buffer.len() - 1,*col_index, asc); + let position: usize; + if lines_buffer.len() > 0 { + position = find_insert_position(&elements, lines_buffer, 0,lines_buffer.len() - 1,*col_index, asc); + } else { + position = 0; + } + match columns_opt { Some(columns) => { // SELECT columns FROM let mut vector:Vec = Vec::new(); @@ -620,23 +760,22 @@ fn insert_unconditioned(elements: Vec, columns_opt: &Option>, } fn find_insert_position(elements: &Vec, lines_buffer: &Vec>, min_pos: usize, max_pos: usize , col_index: usize, asc: &bool) -> usize { - if max_pos - min_pos < 1 { + if max_pos - min_pos <= 1 { min_pos } else { - if elements[col_index] > lines_buffer[(min_pos+max_pos)/2][col_index] { - if *asc { - find_insert_position(elements, lines_buffer, (min_pos+max_pos)/2, max_pos, col_index, asc) + let med = (min_pos+max_pos)/2; + if *asc { + if elements[col_index] < lines_buffer[med][col_index] { + find_insert_position(elements, lines_buffer, min_pos, med, col_index, asc) } else { - find_insert_position(elements, lines_buffer, min_pos, (min_pos+max_pos)/2, col_index, asc) + find_insert_position(elements, lines_buffer, med, max_pos, col_index, asc) } - } else if elements[col_index] < lines_buffer[(min_pos+max_pos)/2][col_index] { - if *asc { - find_insert_position(elements, lines_buffer, min_pos, (min_pos+max_pos)/2, col_index, asc) + } else { + if elements[col_index] < lines_buffer[med][col_index] { + find_insert_position(elements, lines_buffer, med, max_pos, col_index, asc) } else { - find_insert_position(elements, lines_buffer, (min_pos+max_pos)/2, max_pos, col_index, asc) + find_insert_position(elements, lines_buffer, min_pos, med, col_index, asc) } - } else { - (min_pos+max_pos)/2 } } } @@ -804,3 +943,38 @@ fn line_to_vec(line: &str) -> Vec { } result } + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_bsearch1() { + let elements = vec![String::from("4"),String::from("jorge"),String::from("martell")]; + let lines_buffer = vec![ + vec![String::from("1"),String::from("diego"),String::from("mayor")], + vec![String::from("3"),String::from("pamela"),String::from("ureta")], + vec![String::from("5"),String::from("lucas"),String::from("catini")] + ]; + let rt1 = find_insert_position(&elements, &lines_buffer, 0, lines_buffer.len() - 1, 0, &true); + assert_eq!(rt1, 1); + } + + #[test] + fn test_bsearch2() { + let elements = vec![String::from("4"),String::from("Jorge"),String::from("martell")]; + let lines_buffer = vec![ + vec![String::from("4"),String::from("María"),String::from("Rodríguez")], + vec![String::from("10"),String::from("Manuel"),String::from("Allen")], + vec![String::from("6"),String::from("Laura"),String::from("Fernández")], + vec![String::from("5"),String::from("José"),String::from("López")], + vec![String::from("7"),String::from("Diego"),String::from("Torres")], + vec![String::from("3"),String::from("Carlos"),String::from("Gómez")], + vec![String::from("2"),String::from("Ana"),String::from("López")], + ]; + let rt2 = find_insert_position(&elements, &lines_buffer, 0, lines_buffer.len() - 1, 1, &false); + assert_eq!(rt2, 3); + } + +} From cb0cec72a8cf3fcd0cdfa09004fbfeada27a2de0 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Thu, 19 Sep 2024 17:16:10 -0300 Subject: [PATCH 38/58] gdb: ORDER BY. refactor line buffer to list --- src/libs/exec.rs | 56 +++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 70adcc8..b762bf5 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -1,4 +1,5 @@ use std::collections::btree_map::Range; +use std::collections::LinkedList; use std::fs::{read, remove_file, rename, File, OpenOptions}; use std::io::{BufRead, BufReader, Read, Seek, Write}; use std::iter; @@ -646,7 +647,7 @@ fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result Err(_) => return Err(3), Ok(table_file) => { let mut tmp_filenames: Vec = Vec::new(); - let mut lines_buffer: Vec> = Vec::new(); + let mut lines_buffer: LinkedList> = Vec::new(); let mut reader: BufReader = BufReader::new(table_file); let mut line = String::new(); @@ -675,30 +676,7 @@ fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result } if lines_buffer.len() == FILE_SORT_BUFFER { - let mut new_tmp_file_name = String::from(&tmp_file_name); - new_tmp_file_name.push_str(format!(".{}",&tmp_filenames.len()).as_str()); - - match File::open(&new_tmp_file_name) { - Ok(mut tmp_f) => { - for elements in &lines_buffer { - let mut first = true; - for element in elements { - if first { - let _ = tmp_f.write(element.as_bytes()); - first = false; - } else { - tmp_f.write(format!(",{}",element).as_bytes()); - } - } - } - tmp_filenames.push(new_tmp_file_name); - }, - Err(_) => { - read = false; - valid_operation = false; - } - } - + write_to_tmp_file(&tmp_file_name, &mut tmp_filenames, &lines_buffer, &mut read, &mut valid_operation); lines_buffer.clear(); } } @@ -706,6 +684,7 @@ fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result } if valid_operation { + write_to_tmp_file(&tmp_file_name, &mut tmp_filenames, &lines_buffer, &mut read, &mut valid_operation); return Ok(tmp_filenames) } else { return Err(3) @@ -719,6 +698,33 @@ fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result } } +fn write_to_tmp_file(tmp_file_name: &String, tmp_filenames: &mut Vec, lines_buffer: &Vec>, read: &mut bool, valid_operation: &mut bool ) { + let mut new_tmp_file_name = String::from(tmp_file_name); + new_tmp_file_name.push_str(format!(".{}",&tmp_filenames.len()).as_str()); + + match File::create(&new_tmp_file_name) { + Ok(mut tmp_f) => { + for elements in lines_buffer { + let mut first = true; + for element in elements { + if first { + let _ = tmp_f.write(element.as_bytes()); + first = false; + } else { + let _ = tmp_f.write(format!(",{}",element).as_bytes()); + } + } + let _ = tmp_f.write("\n".as_bytes()); + } + tmp_filenames.push(new_tmp_file_name); + }, + Err(_) => { + *read = false; + *valid_operation = false; + } + } +} + /* fn insert_conditioned(elements: &[String], columns_opt: &Option>, lines_buffer: &mut Vec>, col_index: &usize, filter: &Condition) { let (col_filter, condition) = filter; From d1d541e4ecb73d68c24abd9d128f2e72f67aaf44 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Thu, 19 Sep 2024 17:45:45 -0300 Subject: [PATCH 39/58] ORDER BY funciona, solo que compara por STRINGS --- src/libs/exec.rs | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index b762bf5..f091d9b 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -647,7 +647,7 @@ fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result Err(_) => return Err(3), Ok(table_file) => { let mut tmp_filenames: Vec = Vec::new(); - let mut lines_buffer: LinkedList> = Vec::new(); + let mut lines_buffer: Vec> = Vec::new(); // list maybe better ? let mut reader: BufReader = BufReader::new(table_file); let mut line = String::new(); @@ -741,10 +741,10 @@ let (col_filter, condition) = filter; fn insert_unconditioned(elements: Vec, columns_opt: &Option>, lines_buffer: &mut Vec>, col_index: &usize, asc: &bool) { let position: usize; - if lines_buffer.len() > 0 { - position = find_insert_position(&elements, lines_buffer, 0,lines_buffer.len() - 1,*col_index, asc); - } else { + if lines_buffer.is_empty() { position = 0; + } else { + position = find_insert_position(&elements, lines_buffer, 0,lines_buffer.len() - 1,*col_index, asc); } match columns_opt { @@ -766,8 +766,28 @@ fn insert_unconditioned(elements: Vec, columns_opt: &Option>, } fn find_insert_position(elements: &Vec, lines_buffer: &Vec>, min_pos: usize, max_pos: usize , col_index: usize, asc: &bool) -> usize { - if max_pos - min_pos <= 1 { - min_pos + if min_pos == max_pos { + if elements[col_index] < lines_buffer[min_pos][col_index] { + if *asc { min_pos } + else { min_pos + 1 } + } else { + if *asc { min_pos + 1 } + else { min_pos } + } + } else if min_pos + 1 == max_pos { + if elements[col_index] < lines_buffer[min_pos][col_index] { + if *asc { + find_insert_position(elements, lines_buffer, min_pos, min_pos, col_index, asc) + } else { + find_insert_position(elements, lines_buffer, max_pos, max_pos, col_index, asc) + } + } else { + if *asc { + find_insert_position(elements, lines_buffer, max_pos, max_pos, col_index, asc) + } else { + find_insert_position(elements, lines_buffer, min_pos, min_pos, col_index, asc) + } + } } else { let med = (min_pos+max_pos)/2; if *asc { From 3a926065ef679970ee83ae05270286f0d6a33b5c Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sat, 21 Sep 2024 11:50:58 -0300 Subject: [PATCH 40/58] OK order, WIP: Print output --- src/condition.rs | 8 ++++---- src/libs/exec.rs | 19 +++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/condition.rs b/src/condition.rs index c3a917a..a81ff52 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -36,10 +36,10 @@ pub fn operate_condition(v1: &String, v2: &String, operator: &ConditionOperator) }; match operator { - ConditionOperator::Minor => true, - ConditionOperator::MinorEqual => true, + ConditionOperator::Minor => v1 < v2, + ConditionOperator::MinorEqual => v1 <= v2, ConditionOperator::Equal => v1.eq(v2), - ConditionOperator::Higher => true, - ConditionOperator::HigherEqual => true, + ConditionOperator::Higher => v1 > v2, + ConditionOperator::HigherEqual => v1 >= v2, } } diff --git a/src/libs/exec.rs b/src/libs/exec.rs index f091d9b..2496fcb 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -740,12 +740,12 @@ let (col_filter, condition) = filter; fn insert_unconditioned(elements: Vec, columns_opt: &Option>, lines_buffer: &mut Vec>, col_index: &usize, asc: &bool) { - let position: usize; + let position; if lines_buffer.is_empty() { position = 0; } else { position = find_insert_position(&elements, lines_buffer, 0,lines_buffer.len() - 1,*col_index, asc); - } + } match columns_opt { Some(columns) => { // SELECT columns FROM @@ -766,16 +766,19 @@ fn insert_unconditioned(elements: Vec, columns_opt: &Option>, } fn find_insert_position(elements: &Vec, lines_buffer: &Vec>, min_pos: usize, max_pos: usize , col_index: usize, asc: &bool) -> usize { + let less_than_minor = operate_condition(&elements[col_index], &lines_buffer[min_pos][col_index], &condition::condition_type::ConditionOperator::Minor); + let less_than_med = operate_condition(&elements[col_index], &lines_buffer[(min_pos+max_pos)/2][col_index], &condition::condition_type::ConditionOperator::Minor); + if min_pos == max_pos { - if elements[col_index] < lines_buffer[min_pos][col_index] { + if less_than_minor { if *asc { min_pos } else { min_pos + 1 } } else { if *asc { min_pos + 1 } - else { min_pos } + else { min_pos } } } else if min_pos + 1 == max_pos { - if elements[col_index] < lines_buffer[min_pos][col_index] { + if less_than_minor { if *asc { find_insert_position(elements, lines_buffer, min_pos, min_pos, col_index, asc) } else { @@ -791,19 +794,19 @@ fn find_insert_position(elements: &Vec, lines_buffer: &Vec>, } else { let med = (min_pos+max_pos)/2; if *asc { - if elements[col_index] < lines_buffer[med][col_index] { + if less_than_med{ find_insert_position(elements, lines_buffer, min_pos, med, col_index, asc) } else { find_insert_position(elements, lines_buffer, med, max_pos, col_index, asc) } } else { - if elements[col_index] < lines_buffer[med][col_index] { + if less_than_med { find_insert_position(elements, lines_buffer, med, max_pos, col_index, asc) } else { find_insert_position(elements, lines_buffer, min_pos, med, col_index, asc) } } - } + } } fn read_and_save_file(query: &Query, col_filter: i32) -> Result { From 47e7ffa323624997911cb1b99ed85664945a26ac Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sat, 21 Sep 2024 13:03:46 -0300 Subject: [PATCH 41/58] OK order by. Si campo vacio entonces es primero, quiza TODO --- src/libs/exec.rs | 89 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 76 insertions(+), 13 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 2496fcb..b2d2986 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -167,13 +167,76 @@ fn print_sorted_files(files: Vec, col_index: &usize, asc: &bool) { } counter += 1; } + println!(); } } } } +fn get_next_line(lines_buffer: &mut Vec>, readers: &mut Vec>, col_index: usize, asc: &bool) -> Option> { + // Pre: Lines buffer, readers, col index for sorting and ascending/descending bool + // Post: Next line, if not fully read + + let mut line = String::new(); + match find_next_line(lines_buffer,col_index,asc) { + Some(reader_index) => { + match &readers[reader_index].read_line(&mut line){ + Ok(x) => { + if *x > 0 { + lines_buffer.push(text_to_vec(&line, true)); + } else { + let empty_line_buf: Vec = Vec::new(); + lines_buffer.push(empty_line_buf); + } + return Some( lines_buffer.swap_remove(reader_index) ) + }, + Err(_) => { + let empty_line_buf: Vec = Vec::new(); + lines_buffer.push(empty_line_buf); + return Some( lines_buffer.swap_remove(reader_index) ) + }, + } + }, + None => return None + } +} + +fn find_next_line(lines_buffer: &mut Vec>, col_index: usize, asc: &bool) -> Option { + // Pre: Lines buffer, col index and ascending/descending + // Post: Index of next line, if any -fn get_next_line(lines_buffer: &mut Vec>, readers: &mut Vec<(usize,BufReader)>, col_index: usize, asc: &bool) -> Option> { + // Find first line + let mut candidate = 0; + while candidate < lines_buffer.len() && lines_buffer[candidate].is_empty() { + candidate += 1; + } + + if candidate == lines_buffer.len() { + None + } else { + // Find lower line + let mut counter = candidate + 1; + while counter < lines_buffer.len() { + counter += 1; + + if *asc { + if operate_condition(&lines_buffer[counter][col_index], &lines_buffer[candidate][col_index], &condition::condition_type::ConditionOperator::Minor) { + candidate = counter; + } + } else{ + if operate_condition(&lines_buffer[counter][col_index], &lines_buffer[candidate][col_index], &condition::condition_type::ConditionOperator::Higher) { + candidate = counter; + } + } + } + + Some(candidate) + } + +} + +/* +fn get_next_line(lines_buffer: &mut Vec>, readers: &mut Vec>, col_index: usize, asc: &bool) -> Option> { // Post: Next line in order, if not fully read let mut line = String::new(); match find_available_reader(&readers) { @@ -230,7 +293,7 @@ fn get_next_line(lines_buffer: &mut Vec>, readers: &mut Vec<(usize,B } } -fn find_available_reader(readers: &Vec<(usize,BufReader)>) -> Option { +fn find_available_reader(readers: &Vec>) -> Option { // Pre: Readers // Post: First available reader position let mut counter = 0; @@ -244,32 +307,31 @@ fn find_available_reader(readers: &Vec<(usize,BufReader)>) -> Option)>) -> Option>> { +fn readers_read_first_line(readers: &mut Vec>) -> Option>> { let mut result: Vec> = Vec::new(); let mut line = String::new(); for reader in readers { - if reader.1.read_line(&mut line).is_ok() { - result.push(text_to_vec(&line, true)); - reader.0 += 1; - } else { - return None + match reader.read_line(&mut line){ + Ok(_) => result.push(text_to_vec(&line, true)), + Err(_) => return None } } Some(result) } -fn create_readers(files: Vec) -> Option)>> { +fn create_readers(files: Vec) -> Option>> { let mut valid = true; - let mut readers: Vec<(usize,BufReader)> = Vec::new(); + let mut readers: Vec> = Vec::new(); let mut counter = 0; while counter < files.len() && valid{ match File::open(&files[counter]) { Err(_) => valid = false, Ok(file) => { - readers.push((0,BufReader::new(file))); + readers.push(BufReader::new(file)); counter += 1; } } @@ -364,7 +426,7 @@ fn sort_and_print_file( } } } -*/ + fn file_cleanup(files: Vec) { for file in files { @@ -381,6 +443,7 @@ fn find_sorted_position( // Insert into shifts everything to right. 0 } +*/ fn exec_query_update(query: Query) { if let Some(cond) = &query.where_condition { @@ -599,7 +662,7 @@ fn print_header(query: &Query) { } println!(); }, - None => println!("{}",line) + None => print!("{}",line) } } } From 71269aba329d01d0f2e6e49dae3d5b6ae2c3d7ea Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sat, 21 Sep 2024 13:10:39 -0300 Subject: [PATCH 42/58] Minor: Si no contiene columna de orden, entonces no imprimas nada --- src/libs/exec.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index b2d2986..0d930d8 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -136,9 +136,9 @@ fn exec_query_select(query: Query) { fn exec_query_select(query: Query) { match &query.order_by { Some((column, asc)) => { - print_header(&query); let col_filter: i32 = find_filter_column(&query); if let Some(col_index) = find_column(&query, column) { + print_header(&query); if let Ok(files) = read_into_sorted_files(&query, col_index as usize, &asc) { print_sorted_files(files, &col_index, &asc); } @@ -627,7 +627,16 @@ fn find_column(query: &Query, column: &String) -> Option { if counter == args.len() { return None; } else { - return Some(counter); + match &query.columns { + None => return Some(counter), + Some(cols) => { + if cols.contains(&counter) { + return Some(counter) + } else { + return None + } + } + } } } None => return None, From fcbcbc970b223d25df732e199b0c335a1003b72e Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sat, 21 Sep 2024 13:33:02 -0300 Subject: [PATCH 43/58] Minor bug: Imprimia coma al final de las lineas --- src/libs/exec.rs | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 0d930d8..4f2d586 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -1,13 +1,10 @@ -use std::collections::btree_map::Range; -use std::collections::LinkedList; -use std::fs::{read, remove_file, rename, File, OpenOptions}; -use std::io::{BufRead, BufReader, Read, Seek, Write}; -use std::iter; +use std::fs::{remove_file, rename, File, OpenOptions}; +use std::io::{BufRead, BufReader, Write}; use crate::condition::{self, operate_condition, Condition}; //use crate::condition::operate_condition; use crate::query::query_type::QueryType; -use crate::query::{self, Query}; +use crate::query::Query; use super::error; use super::parsing::{self, get_file_first_line, text_to_vec}; @@ -140,7 +137,8 @@ fn exec_query_select(query: Query) { if let Some(col_index) = find_column(&query, column) { print_header(&query); if let Ok(files) = read_into_sorted_files(&query, col_index as usize, &asc) { - print_sorted_files(files, &col_index, &asc); + print_sorted_files(&files, &col_index, &asc); + file_cleanup(&files); } } } @@ -151,7 +149,13 @@ fn exec_query_select(query: Query) { } } -fn print_sorted_files(files: Vec, col_index: &usize, asc: &bool) { +fn file_cleanup(files: &Vec) { + for file in files { + let _ = remove_file(file); + } +} + +fn print_sorted_files(files: &Vec, col_index: &usize, asc: &bool) { // Pre: Name of tmp_files, column for ordering and selector of asc/desc // Post: Prints from tmp_files in order if let Some(mut readers) = create_readers(files){ @@ -160,12 +164,14 @@ fn print_sorted_files(files: Vec, col_index: &usize, asc: &bool) { while let Some(elements) = get_next_line(&mut lines_buffer, &mut readers, *col_index, asc) { let mut counter = 0; for element in elements { - if counter == 0 { - print!("{}",element); - } else { - print!(",{}",element); + if ! element.eq("") { + if counter == 0 { + print!("{}",element); + } else { + print!(",{}",element); + } + counter += 1; } - counter += 1; } println!(); } @@ -183,6 +189,7 @@ fn get_next_line(lines_buffer: &mut Vec>, readers: &mut Vec { if *x > 0 { + let _ = line.replace('\n',""); lines_buffer.push(text_to_vec(&line, true)); } else { let empty_line_buf: Vec = Vec::new(); @@ -315,14 +322,17 @@ fn readers_read_first_line(readers: &mut Vec>) -> Option result.push(text_to_vec(&line, true)), + Ok(_) => { + let _ = line.replace('\n', ""); + result.push(text_to_vec(&line, true)) + }, Err(_) => return None } } Some(result) } -fn create_readers(files: Vec) -> Option>> { +fn create_readers(files: &Vec) -> Option>> { let mut valid = true; let mut readers: Vec> = Vec::new(); From f20e7dfa5292951140a3c53ba47d3bc84c5c2096 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sat, 21 Sep 2024 13:59:36 -0300 Subject: [PATCH 44/58] FIN order by. funciona OK con buffers muy chiquitos y manejando varios archivos --- src/libs/exec.rs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 4f2d586..ef1a234 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -9,7 +9,7 @@ use crate::query::Query; use super::error; use super::parsing::{self, get_file_first_line, text_to_vec}; -static FILE_SORT_BUFFER: usize = 20; +static FILE_SORT_BUFFER: usize = 3; pub fn exec_query(query: Query) { if let Some(op) = &query.operation { @@ -224,17 +224,18 @@ fn find_next_line(lines_buffer: &mut Vec>, col_index: usize, asc: &b // Find lower line let mut counter = candidate + 1; while counter < lines_buffer.len() { - counter += 1; - - if *asc { - if operate_condition(&lines_buffer[counter][col_index], &lines_buffer[candidate][col_index], &condition::condition_type::ConditionOperator::Minor) { - candidate = counter; - } - } else{ - if operate_condition(&lines_buffer[counter][col_index], &lines_buffer[candidate][col_index], &condition::condition_type::ConditionOperator::Higher) { - candidate = counter; - } + if ! lines_buffer[counter].is_empty() { + if *asc { + if operate_condition(&lines_buffer[counter][col_index], &lines_buffer[candidate][col_index], &condition::condition_type::ConditionOperator::Minor) { + candidate = counter; + } + } else{ + if operate_condition(&lines_buffer[counter][col_index], &lines_buffer[candidate][col_index], &condition::condition_type::ConditionOperator::Higher) { + candidate = counter; + } + } } + counter += 1; } Some(candidate) @@ -324,7 +325,8 @@ fn readers_read_first_line(readers: &mut Vec>) -> Option { let _ = line.replace('\n', ""); - result.push(text_to_vec(&line, true)) + result.push(text_to_vec(&line, true)); + line.clear(); }, Err(_) => return None } @@ -766,7 +768,9 @@ fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result } if valid_operation { - write_to_tmp_file(&tmp_file_name, &mut tmp_filenames, &lines_buffer, &mut read, &mut valid_operation); + if ! lines_buffer.is_empty() { + write_to_tmp_file(&tmp_file_name, &mut tmp_filenames, &lines_buffer, &mut read, &mut valid_operation); + } return Ok(tmp_filenames) } else { return Err(3) From de91654b2b6c94a2425905db632d3c5718fb4f38 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sat, 21 Sep 2024 14:22:46 -0300 Subject: [PATCH 45/58] README, clippy y format --- README.md | 18 ++- src/libs/exec.rs | 406 ++++++++++++++++++++++++++++++----------------- 2 files changed, 275 insertions(+), 149 deletions(-) diff --git a/README.md b/README.md index e5ea552..5825aec 100644 --- a/README.md +++ b/README.md @@ -10,15 +10,13 @@ Pendientes: 1. Funcionalidad: Logica booleana en WHERE -2. Funcionalidad: SELECT c/ ORDER BY +2. Funcionalidad: SELECT c/ ORDER BY condicionado ( con WHERE, se implementará primero la logica booleana y luego este punto ) -3. Funcionalidad: UPDATE +3. Testing (mas test unitarios e integración) -4. Testing (mas test unitarios e integración) +4. Documentación de funciones -5. Cargo clippy sin warnings - -6. Documentación de funciones +5. Refactor de funciones para que tengan menos de 30 lineas. Por una cuestión de tiempos se deja para el final. Funcionalidades probadas OK @@ -30,11 +28,17 @@ Funcionalidades probadas OK 4. INSERT INTO -5. DELETE FROM WHERE (basico) +5. UPDATE + +6. DELETE FROM WHERE (basico) +7. SELECT c/ ORDER BY incondicional ### Detalles de implementación Para la lógica booleana el objetivo era crear un arbol de condiciones formado por las relaciones de precedencia. Dicho objetivo no pudo ser implementado. Se implementó lógica de condiciones simples ( no compuestas ) + +Para en ORDER BY no cargar las tablas completas en memoria se eligió "Full external sort" (https://cs186berkeley.net/notes/note8/) + diff --git a/src/libs/exec.rs b/src/libs/exec.rs index ef1a234..5f31a32 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -109,7 +109,7 @@ fn exec_query_insert(query: Query) { } } -/* +/* fn exec_query_select(query: Query) { match &query.order_by { Some((column, asc)) => { @@ -133,13 +133,13 @@ fn exec_query_select(query: Query) { fn exec_query_select(query: Query) { match &query.order_by { Some((column, asc)) => { - let col_filter: i32 = find_filter_column(&query); + let _col_filter: i32 = find_filter_column(&query); if let Some(col_index) = find_column(&query, column) { print_header(&query); - if let Ok(files) = read_into_sorted_files(&query, col_index as usize, &asc) { - print_sorted_files(&files, &col_index, &asc); + if let Ok(files) = read_into_sorted_files(&query, col_index, asc) { + print_sorted_files(&files, &col_index, asc); file_cleanup(&files); - } + } } } None => { @@ -155,21 +155,23 @@ fn file_cleanup(files: &Vec) { } } -fn print_sorted_files(files: &Vec, col_index: &usize, asc: &bool) { +fn print_sorted_files(files: &[String], col_index: &usize, asc: &bool) { // Pre: Name of tmp_files, column for ordering and selector of asc/desc - // Post: Prints from tmp_files in order - if let Some(mut readers) = create_readers(files){ + // Post: Prints from tmp_files in order + if let Some(mut readers) = create_readers(files) { if let Some(mut lines_buffer) = readers_read_first_line(&mut readers) { - // While there are lines to be printed - while let Some(elements) = get_next_line(&mut lines_buffer, &mut readers, *col_index, asc) { + // While there are lines to be printed + while let Some(elements) = + get_next_line(&mut lines_buffer, &mut readers, *col_index, asc) + { let mut counter = 0; for element in elements { - if ! element.eq("") { + if !element.eq("") { if counter == 0 { - print!("{}",element); + print!("{}", element); } else { - print!(",{}",element); - } + print!(",{}", element); + } counter += 1; } } @@ -179,38 +181,41 @@ fn print_sorted_files(files: &Vec, col_index: &usize, asc: &bool) { } } -fn get_next_line(lines_buffer: &mut Vec>, readers: &mut Vec>, col_index: usize, asc: &bool) -> Option> { +fn get_next_line( + lines_buffer: &mut Vec>, + readers: &mut [BufReader], + col_index: usize, + asc: &bool, +) -> Option> { // Pre: Lines buffer, readers, col index for sorting and ascending/descending bool // Post: Next line, if not fully read - + let mut line = String::new(); - match find_next_line(lines_buffer,col_index,asc) { - Some(reader_index) => { - match &readers[reader_index].read_line(&mut line){ - Ok(x) => { - if *x > 0 { - let _ = line.replace('\n',""); - lines_buffer.push(text_to_vec(&line, true)); - } else { - let empty_line_buf: Vec = Vec::new(); - lines_buffer.push(empty_line_buf); - } - return Some( lines_buffer.swap_remove(reader_index) ) - }, - Err(_) => { + match find_next_line(lines_buffer, col_index, asc) { + Some(reader_index) => match &readers[reader_index].read_line(&mut line) { + Ok(x) => { + if *x > 0 { + let _ = line.replace('\n', ""); + lines_buffer.push(text_to_vec(&line, true)); + } else { let empty_line_buf: Vec = Vec::new(); lines_buffer.push(empty_line_buf); - return Some( lines_buffer.swap_remove(reader_index) ) - }, + } + Some(lines_buffer.swap_remove(reader_index)) + } + Err(_) => { + let empty_line_buf: Vec = Vec::new(); + lines_buffer.push(empty_line_buf); + Some(lines_buffer.swap_remove(reader_index)) } }, - None => return None + None => None, } } -fn find_next_line(lines_buffer: &mut Vec>, col_index: usize, asc: &bool) -> Option { +fn find_next_line(lines_buffer: &mut [Vec], col_index: usize, asc: &bool) -> Option { // Pre: Lines buffer, col index and ascending/descending - // Post: Index of next line, if any + // Post: Index of next line, if any // Find first line let mut candidate = 0; @@ -224,26 +229,31 @@ fn find_next_line(lines_buffer: &mut Vec>, col_index: usize, asc: &b // Find lower line let mut counter = candidate + 1; while counter < lines_buffer.len() { - if ! lines_buffer[counter].is_empty() { + if !lines_buffer[counter].is_empty() { if *asc { - if operate_condition(&lines_buffer[counter][col_index], &lines_buffer[candidate][col_index], &condition::condition_type::ConditionOperator::Minor) { - candidate = counter; - } - } else{ - if operate_condition(&lines_buffer[counter][col_index], &lines_buffer[candidate][col_index], &condition::condition_type::ConditionOperator::Higher) { + if operate_condition( + &lines_buffer[counter][col_index], + &lines_buffer[candidate][col_index], + &condition::condition_type::ConditionOperator::Minor, + ) { candidate = counter; - } - } + } + } else if operate_condition( + &lines_buffer[counter][col_index], + &lines_buffer[candidate][col_index], + &condition::condition_type::ConditionOperator::Higher, + ) { + candidate = counter; + } } counter += 1; } - + Some(candidate) } - } -/* +/* fn get_next_line(lines_buffer: &mut Vec>, readers: &mut Vec>, col_index: usize, asc: &bool) -> Option> { // Post: Next line in order, if not fully read let mut line = String::new(); @@ -270,7 +280,7 @@ fn get_next_line(lines_buffer: &mut Vec>, readers: &mut Vec; + let new_line: Vec; match readers[candidate].1.read_line(&mut line){ Err(_) => new_line = Vec::new(), Ok(read_result) => { @@ -290,7 +300,7 @@ fn get_next_line(lines_buffer: &mut Vec>, readers: &mut Vec>) -> Option { let _ = line.replace('\n', ""); result.push(text_to_vec(&line, true)); line.clear(); - }, - Err(_) => return None + } + Err(_) => return None, } } Some(result) } -fn create_readers(files: &Vec) -> Option>> { +fn create_readers(files: &[String]) -> Option>> { let mut valid = true; let mut readers: Vec> = Vec::new(); let mut counter = 0; - while counter < files.len() && valid{ + while counter < files.len() && valid { match File::open(&files[counter]) { Err(_) => valid = false, Ok(file) => { readers.push(BufReader::new(file)); - counter += 1; + counter += 1; } } } @@ -356,7 +366,7 @@ fn create_readers(files: &Vec) -> Option>> { } } -/* +/* fn sort_and_print_file( column_number: usize, query: &Query, @@ -637,21 +647,21 @@ fn find_column(query: &Query, column: &String) -> Option { } if counter == args.len() { - return None; + None } else { match &query.columns { - None => return Some(counter), + None => Some(counter), Some(cols) => { if cols.contains(&counter) { - return Some(counter) + Some(counter) } else { - return None + None } } } } } - None => return None, + None => None, } } @@ -667,24 +677,21 @@ fn print_header(query: &Query) { Some(columns) => { line = line.replace('\n', ""); let args = text_to_vec(&line, true); - let mut counter = 0; let mut first = true; - for arg in args { + for (counter, arg) in args.into_iter().enumerate() { if columns.contains(&counter) { if first { - print!("{}",arg); + print!("{}", arg); first = false; - } else{ - print!(",{}",arg); + } else { + print!(",{}", arg); } - } - counter += 1 } println!(); - }, - None => print!("{}",line) - } + } + None => print!("{}", line), + } } } } @@ -720,24 +727,24 @@ fn read_and_print_file(query: &Query, col_filter: i32) { } } -fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result,u32> { +fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result, u32> { // Pre: Query, the col index for sorting and bool of ascending/descending - // Post: Vec of tmp_files + // Post: Vec of tmp_files match &query.table { None => Err(3), Some(table) => { let tmp_file_name = get_tmp_file_name(table); match File::open(table) { - Err(_) => return Err(3), + Err(_) => Err(3), Ok(table_file) => { let mut tmp_filenames: Vec = Vec::new(); - let mut lines_buffer: Vec> = Vec::new(); // list maybe better ? + let mut lines_buffer: Vec> = Vec::new(); // list maybe better ? let mut reader: BufReader = BufReader::new(table_file); let mut line = String::new(); - - let mut read :bool = true; - let mut valid_operation :bool = true; + + let mut read: bool = true; + let mut valid_operation: bool = true; if reader.read_line(&mut line).is_ok() { line.clear(); while read { @@ -745,22 +752,34 @@ fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result Err(_) => { read = false; valid_operation = false; - }, + } Ok(x) => { line = line.replace('\n', ""); read = x != 0; if read { let elements = text_to_vec(&line, true); match &query.where_condition { - Some(condition) => {}, -// insert_conditioned(&elements,&mut lines_buffer,&col_index,condition, asc), - None => insert_unconditioned(elements, &query.columns, &mut lines_buffer, &col_index, asc) + Some(_condition) => {} + // insert_conditioned(&elements,&mut lines_buffer,&col_index,condition, asc), + None => insert_unconditioned( + elements, + &query.columns, + &mut lines_buffer, + &col_index, + asc, + ), } line.clear(); } - + if lines_buffer.len() == FILE_SORT_BUFFER { - write_to_tmp_file(&tmp_file_name, &mut tmp_filenames, &lines_buffer, &mut read, &mut valid_operation); + write_to_tmp_file( + &tmp_file_name, + &mut tmp_filenames, + &lines_buffer, + &mut read, + &mut valid_operation, + ); lines_buffer.clear(); } } @@ -768,25 +787,37 @@ fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result } if valid_operation { - if ! lines_buffer.is_empty() { - write_to_tmp_file(&tmp_file_name, &mut tmp_filenames, &lines_buffer, &mut read, &mut valid_operation); + if !lines_buffer.is_empty() { + write_to_tmp_file( + &tmp_file_name, + &mut tmp_filenames, + &lines_buffer, + &mut read, + &mut valid_operation, + ); } - return Ok(tmp_filenames) + Ok(tmp_filenames) } else { - return Err(3) + Err(3) } } else { - return Err(error::ARCHIVO_VACIO) + Err(error::ARCHIVO_VACIO) } - } + } } } } } -fn write_to_tmp_file(tmp_file_name: &String, tmp_filenames: &mut Vec, lines_buffer: &Vec>, read: &mut bool, valid_operation: &mut bool ) { +fn write_to_tmp_file( + tmp_file_name: &String, + tmp_filenames: &mut Vec, + lines_buffer: &Vec>, + read: &mut bool, + valid_operation: &mut bool, +) { let mut new_tmp_file_name = String::from(tmp_file_name); - new_tmp_file_name.push_str(format!(".{}",&tmp_filenames.len()).as_str()); + new_tmp_file_name.push_str(format!(".{}", &tmp_filenames.len()).as_str()); match File::create(&new_tmp_file_name) { Ok(mut tmp_f) => { @@ -797,13 +828,13 @@ fn write_to_tmp_file(tmp_file_name: &String, tmp_filenames: &mut Vec, li let _ = tmp_f.write(element.as_bytes()); first = false; } else { - let _ = tmp_f.write(format!(",{}",element).as_bytes()); + let _ = tmp_f.write(format!(",{}", element).as_bytes()); } } let _ = tmp_f.write("\n".as_bytes()); } tmp_filenames.push(new_tmp_file_name); - }, + } Err(_) => { *read = false; *valid_operation = false; @@ -811,7 +842,7 @@ fn write_to_tmp_file(tmp_file_name: &String, tmp_filenames: &mut Vec, li } } -/* +/* fn insert_conditioned(elements: &[String], columns_opt: &Option>, lines_buffer: &mut Vec>, col_index: &usize, filter: &Condition) { let (col_filter, condition) = filter; if let Some(value) = &condition.value { @@ -824,18 +855,30 @@ let (col_filter, condition) = filter; } */ -fn insert_unconditioned(elements: Vec, columns_opt: &Option>, lines_buffer: &mut Vec>, col_index: &usize, asc: &bool) { - - let position; - if lines_buffer.is_empty() { - position = 0; +fn insert_unconditioned( + elements: Vec, + columns_opt: &Option>, + lines_buffer: &mut Vec>, + col_index: &usize, + asc: &bool, +) { + let position: usize = if lines_buffer.is_empty() { + 0 } else { - position = find_insert_position(&elements, lines_buffer, 0,lines_buffer.len() - 1,*col_index, asc); - } + find_insert_position( + &elements, + lines_buffer, + 0, + lines_buffer.len() - 1, + *col_index, + asc, + ) + }; match columns_opt { - Some(columns) => { // SELECT columns FROM - let mut vector:Vec = Vec::new(); + Some(columns) => { + // SELECT columns FROM + let mut vector: Vec = Vec::new(); let mut counter = 0; while counter < elements.len() { @@ -851,50 +894,66 @@ fn insert_unconditioned(elements: Vec, columns_opt: &Option>, } } -fn find_insert_position(elements: &Vec, lines_buffer: &Vec>, min_pos: usize, max_pos: usize , col_index: usize, asc: &bool) -> usize { - let less_than_minor = operate_condition(&elements[col_index], &lines_buffer[min_pos][col_index], &condition::condition_type::ConditionOperator::Minor); - let less_than_med = operate_condition(&elements[col_index], &lines_buffer[(min_pos+max_pos)/2][col_index], &condition::condition_type::ConditionOperator::Minor); - - if min_pos == max_pos { +fn find_insert_position( + elements: &Vec, + lines_buffer: &Vec>, + min_pos: usize, + max_pos: usize, + col_index: usize, + asc: &bool, +) -> usize { + let less_than_minor = operate_condition( + &elements[col_index], + &lines_buffer[min_pos][col_index], + &condition::condition_type::ConditionOperator::Minor, + ); + let less_than_med = operate_condition( + &elements[col_index], + &lines_buffer[(min_pos + max_pos) / 2][col_index], + &condition::condition_type::ConditionOperator::Minor, + ); + + if min_pos == max_pos { if less_than_minor { - if *asc { min_pos } - else { min_pos + 1 } + if *asc { + min_pos + } else { + min_pos + 1 + } + } else if *asc { + min_pos + 1 } else { - if *asc { min_pos + 1 } - else { min_pos } + min_pos } } else if min_pos + 1 == max_pos { if less_than_minor { - if *asc { + if *asc { find_insert_position(elements, lines_buffer, min_pos, min_pos, col_index, asc) } else { find_insert_position(elements, lines_buffer, max_pos, max_pos, col_index, asc) } + } else if *asc { + find_insert_position(elements, lines_buffer, max_pos, max_pos, col_index, asc) } else { - if *asc { - find_insert_position(elements, lines_buffer, max_pos, max_pos, col_index, asc) - } else { - find_insert_position(elements, lines_buffer, min_pos, min_pos, col_index, asc) - } + find_insert_position(elements, lines_buffer, min_pos, min_pos, col_index, asc) } } else { - let med = (min_pos+max_pos)/2; + let med = (min_pos + max_pos) / 2; if *asc { - if less_than_med{ + if less_than_med { find_insert_position(elements, lines_buffer, min_pos, med, col_index, asc) } else { find_insert_position(elements, lines_buffer, med, max_pos, col_index, asc) } + } else if less_than_med { + find_insert_position(elements, lines_buffer, med, max_pos, col_index, asc) } else { - if less_than_med { - find_insert_position(elements, lines_buffer, med, max_pos, col_index, asc) - } else { - find_insert_position(elements, lines_buffer, min_pos, med, col_index, asc) - } + find_insert_position(elements, lines_buffer, min_pos, med, col_index, asc) } - } + } } +/* fn read_and_save_file(query: &Query, col_filter: i32) -> Result { // Pre: query, filter and // Post: @@ -941,6 +1000,7 @@ fn read_and_save_file(query: &Query, col_filter: i32) -> Result { return Err(1); } } +*/ fn print_file_unconditional(columns_opt: &Option>, elements: &[String]) { // Pre: Columns vector sorted incremental && Elements of line content vector @@ -991,6 +1051,7 @@ fn print_file_conditioned( } } +/* fn save_file_unconditional(columns_opt: &Option>, elements: &[String], file: &mut File) { // Pre: Columns vector sorted incremental && Elements of line content vector // Post: print to stdout the correct columns @@ -1040,6 +1101,7 @@ fn save_file_conditioned( save_file_unconditional(columns_opt, elements, file) } } +*/ fn line_to_vec(line: &str) -> Vec { let mut result: Vec = Vec::new(); @@ -1059,37 +1121,97 @@ fn line_to_vec(line: &str) -> Vec { result } - #[cfg(test)] mod tests { use super::*; #[test] fn test_bsearch1() { - let elements = vec![String::from("4"),String::from("jorge"),String::from("martell")]; + let elements = vec![ + String::from("4"), + String::from("jorge"), + String::from("martell"), + ]; let lines_buffer = vec![ - vec![String::from("1"),String::from("diego"),String::from("mayor")], - vec![String::from("3"),String::from("pamela"),String::from("ureta")], - vec![String::from("5"),String::from("lucas"),String::from("catini")] + vec![ + String::from("1"), + String::from("diego"), + String::from("mayor"), + ], + vec![ + String::from("3"), + String::from("pamela"), + String::from("ureta"), + ], + vec![ + String::from("5"), + String::from("lucas"), + String::from("catini"), + ], ]; - let rt1 = find_insert_position(&elements, &lines_buffer, 0, lines_buffer.len() - 1, 0, &true); + let rt1 = find_insert_position( + &elements, + &lines_buffer, + 0, + lines_buffer.len() - 1, + 0, + &true, + ); assert_eq!(rt1, 1); } #[test] fn test_bsearch2() { - let elements = vec![String::from("4"),String::from("Jorge"),String::from("martell")]; + let elements = vec![ + String::from("4"), + String::from("Jorge"), + String::from("martell"), + ]; let lines_buffer = vec![ - vec![String::from("4"),String::from("María"),String::from("Rodríguez")], - vec![String::from("10"),String::from("Manuel"),String::from("Allen")], - vec![String::from("6"),String::from("Laura"),String::from("Fernández")], - vec![String::from("5"),String::from("José"),String::from("López")], - vec![String::from("7"),String::from("Diego"),String::from("Torres")], - vec![String::from("3"),String::from("Carlos"),String::from("Gómez")], - vec![String::from("2"),String::from("Ana"),String::from("López")], + vec![ + String::from("4"), + String::from("María"), + String::from("Rodríguez"), + ], + vec![ + String::from("10"), + String::from("Manuel"), + String::from("Allen"), + ], + vec![ + String::from("6"), + String::from("Laura"), + String::from("Fernández"), + ], + vec![ + String::from("5"), + String::from("José"), + String::from("López"), + ], + vec![ + String::from("7"), + String::from("Diego"), + String::from("Torres"), + ], + vec![ + String::from("3"), + String::from("Carlos"), + String::from("Gómez"), + ], + vec![ + String::from("2"), + String::from("Ana"), + String::from("López"), + ], ]; - let rt2 = find_insert_position(&elements, &lines_buffer, 0, lines_buffer.len() - 1, 1, &false); + let rt2 = find_insert_position( + &elements, + &lines_buffer, + 0, + lines_buffer.len() - 1, + 1, + &false, + ); assert_eq!(rt2, 3); } - } From b6511303a5934e70260bf00472a0bf8e0dd921d4 Mon Sep 17 00:00:00 2001 From: sttesta3 <128648082+sttesta3@users.noreply.github.com> Date: Sat, 21 Sep 2024 14:39:01 -0300 Subject: [PATCH 46/58] Minor: Explicacion pendientes en parseo --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 5825aec..77d06a0 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ Pendientes: 5. Refactor de funciones para que tengan menos de 30 lineas. Por una cuestión de tiempos se deja para el final. +6. Terminar trabajo sobre el parseo ( TODOs & funcion para imprimir errores ). Se decide para poder avanzar con las funcionalidades implementar las mismas tal que, en caso de haber un error, simplemente no ejecutarán nada. + Funcionalidades probadas OK 1. SELECT * FROM @@ -36,6 +38,8 @@ Funcionalidades probadas OK ### Detalles de implementación +Para la logica del programa se decidio dividir en dos etapas: parseo y ejecucción. El punto del parseo es que se encuentre cualquier error previo a ejecucción del query, tal que no sea posible dañar la base de datos por error humano. De encontrarse un error se debe imprimir + Para la lógica booleana el objetivo era crear un arbol de condiciones formado por las relaciones de precedencia. Dicho objetivo no pudo ser implementado. Se implementó lógica de condiciones simples ( no compuestas ) From f30a8bb238a08c8c684499617525970a7619c286 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 22 Sep 2024 01:23:29 -0300 Subject: [PATCH 47/58] COMMIT PARA REFACTOR --- src/condition.rs | 8 +- src/condition/complex_condition.rs | 167 +++++++++------------- src/condition/condition_type.rs | 20 ++- src/libs/parsing.rs | 216 ++++++++++++----------------- src/query.rs | 14 +- 5 files changed, 182 insertions(+), 243 deletions(-) diff --git a/src/condition.rs b/src/condition.rs index a81ff52..34eb690 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -1,20 +1,20 @@ pub mod condition_type; -/* pub mod complex_condition; +use condition_type::BooleanOperator; +/* use crate::libs::error; -use condition_type::BooleanOperator; */ use condition_type::ConditionOperator; pub struct Condition { pub condition: ConditionOperator, - pub column: Option, + pub column: Option, pub value: Option, } -pub fn build_condition(column: String, value: String, cond: ConditionOperator) -> Condition { +pub fn build_condition(column: usize, value: String, cond: ConditionOperator) -> Condition { Condition { condition: cond, column: Some(column), diff --git a/src/condition/complex_condition.rs b/src/condition/complex_condition.rs index 0f41a05..5e5d9fd 100644 --- a/src/condition/complex_condition.rs +++ b/src/condition/complex_condition.rs @@ -1,52 +1,54 @@ -use crate::query::Query; -use crate::libs::error; -use super::BooleanOperator; +use std::borrow::BorrowMut; + +use crate::{libs::error::WHERE_MAL_FORMATEADO, query::Query}; +use super::{condition_type::{self, ConditionOperator}, BooleanOperator, Condition}; pub struct ComplexCondition { // Tree of complex conditions - pub operator: Option, - pub condition: Option, - pub left_cond: Option>, // Oldest condition ( first to be found ) - pub right_cond: Option> // Newest condition ( last to be found ) + pub operator: BooleanOperator, + pub left_cond: Option>, // Oldest condition ( first to be found ) + pub left_simple: Option, + pub right_cond: Option>, // Newest condition ( last to be found ) + pub right_simple: Option, } -pub fn build_empty_complex_condition() -> ComplexCondition { - return ComplexCondition { - operator: None, - condition: None, +pub fn build_simple_condition(left: Option) -> ComplexCondition { + ComplexCondition { + operator: BooleanOperator::I, + left_simple: left, + left_cond: None, - right_cond: None + right_simple: None, + right_cond: None, } } -pub fn build_complex_condition(operator: BooleanOperator, left: Option>, right: Option>) -> ComplexCondition { - return ComplexCondition { - operator: Some(operator), - condition: None, +pub fn build_complex_condition(op: BooleanOperator, left: Option>, right: Option>) -> ComplexCondition { + ComplexCondition { + operator: op, left_cond: left, - right_cond: right + right_cond: right, + + left_simple: None, + right_simple: None } } -pub fn tree_check(root: ComplexCondition) -> bool { +pub fn tree_check(root: &ComplexCondition) -> bool { // In Order valid check ( no None leafs ) match &root.operator { - Some(op) => { - match op { - BooleanOperator::OR => tree_check_or_and(root), - BooleanOperator::AND => tree_check_or_and(root), - BooleanOperator::NOT => tree_check_not(root) - } - }, - None => return true + BooleanOperator::OR => tree_check_or_and(&root), + BooleanOperator::AND => tree_check_or_and(&root), + BooleanOperator::NOT => tree_check_not_i(&root), + BooleanOperator::I => tree_check_not_i(&root) } } -fn tree_check_or_and(root: ComplexCondition) -> bool { - match root.left_cond { +fn tree_check_or_and(root: &ComplexCondition) -> bool { + match &root.left_cond { Some(left) => { - match root.right_cond { - Some(right) => return tree_check(*left) && tree_check(*right), + match &root.right_cond { + Some(right) => return tree_check(&*left) && tree_check(&*right), None => return false } }, @@ -54,83 +56,37 @@ fn tree_check_or_and(root: ComplexCondition) -> bool { } } -fn tree_check_not(root: ComplexCondition) -> bool { - match root.left_cond { +fn tree_check_not_i(root: &ComplexCondition) -> bool { + match &root.left_cond { Some(left) => { match root.right_cond { Some(_) => return false, - None => return tree_check(*left) + None => return tree_check(&*left) } }, None => return false } } -pub fn add_node_to_tree(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { - if *start_position == args.len() || args[*start_position].eq("ORDER") { - if tree_check(root) { - Ok(root) - } else { - Err(error::WHERE_MAL_FORMATEADO) - } - } else if args[*start_position].eq("OR") { - add_node_to_tree_or(args, &mut start_position, root) - } else if args[*start_position].eq("AND") { - add_node_to_tree_and(args, &mut start_position, root) - } else if args[*start_position].eq("NOT") { - add_node_to_tree_not(args, &mut start_position, root) - } else if check_valid_args_for_basic_condition(args, *start_position) { - match root.operator { - Some(op) => { - - }, - None => return Err(error::WHERE_MAL_FORMATEADO) // C1 C2 - } +pub fn add_node_to_tree(mut new_node: ComplexCondition, root: &mut ComplexCondition) -> Result { + // Pre: Previous root and new node + // Post: If success new root, else Error + if check_precedence(&new_node.operator, &root.operator) { // IM new root + new_node.left_cond = Some(Box::new(*root)); + Ok(new_node) + } else if root.left_cond.is_none() { // IM RIGHT SON + Err(WHERE_MAL_FORMATEADO) } else { - Err(error::WHERE_MAL_FORMATEADO) - } -} - -fn add_node_to_tree_or(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { - let new_root = build_complex_condition(BooleanOperator::OR, Some(Box::new(root)), None ); - *start_position += 1; - add_node_to_tree(args, start_position, new_root) -} - -fn add_node_to_tree_and(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { - match root.operator { - Some(op) => { - match op { - BooleanOperator::OR => { - match root.left_cond { - Some(x) => {}, - None => return Err(error::WHERE_MAL_FORMATEADO) - } - }, - BooleanOperator::AND => { - let new_root = build_complex_condition(BooleanOperator::AND, Some(Box::new(root)), None ); - *start_position += 1; - add_node_to_tree(args, start_position , new_root) - }, - BooleanOperator::NOT => { - let new_root = build_complex_condition(BooleanOperator::AND, Some(Box::new(root)), None ); - *start_position += 1; - add_node_to_tree(args, start_position, new_root) - }, + match root.right_cond.as_deref() { + Some(mut x) => add_node_to_tree(new_node, x.borrow_mut()), + None => { + root.right_cond = Some(Box::new(new_node)); + return Ok(*root) } - }, - None => { - let new_root = build_complex_condition(BooleanOperator::AND, Some(Box::new(root)), None ); - *start_position += 1; - add_node_to_tree(args, start_position, new_root) } } } -fn add_node_to_tree_not(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { - -} - fn check_valid_args_for_basic_condition(args: &Vec, start_position: usize) -> bool { if start_position + 3 > args.len() { false @@ -153,14 +109,25 @@ fn check_valid_args_for_basic_condition(args: &Vec, start_position: usiz } } -pub fn get_where_columns(query: &Query, vec: Vec, node: &ComplexCondition) -> Vec { - match node.operator { - Some(_) => {}, - None => { - match node.condition { - Some(_) => {}, - None => return vec +pub fn check_precedence(op1: &BooleanOperator, op2: &BooleanOperator) -> bool { + // Pre: Operators + // Post: True if it's higher on the tree, false if not + match op1 { + BooleanOperator::OR => true, + BooleanOperator::AND => { + if *op2 == BooleanOperator::OR { + false + } else { + true } - } + }, + BooleanOperator::NOT => { + if *op2 == BooleanOperator::OR || *op2 == BooleanOperator::AND { + false + } else { + true + } + }, + BooleanOperator::I => false, } } \ No newline at end of file diff --git a/src/condition/condition_type.rs b/src/condition/condition_type.rs index 481d3ef..1208d80 100644 --- a/src/condition/condition_type.rs +++ b/src/condition/condition_type.rs @@ -1,13 +1,21 @@ pub enum ConditionOperator { - Minor, // Int - MinorEqual, // Int - Equal, // Int and String - Higher, // Int - HigherEqual, // Int + Minor, + MinorEqual, + Equal, + Higher, + HigherEqual, } pub enum BooleanOperator { AND, OR, - NOT, + NOT, // NOT. Left child + I // identity. } + +impl PartialEq for BooleanOperator { + fn eq(&self, other: &Self) -> bool { + self == other + } +} +impl Eq for BooleanOperator {} \ No newline at end of file diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index a4c2691..8401ad8 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -1,16 +1,17 @@ use std::fs::File; use std::io::{BufRead, BufReader}; -use crate::condition::build_condition; -use crate::condition::condition_type::ConditionOperator; +use crate::condition::{build_condition, Condition}; +use crate::condition::complex_condition::{add_node_to_tree, build_complex_condition, build_simple_condition, ComplexCondition, tree_check, check_precedence}; +use crate::condition::condition_type::{BooleanOperator, ConditionOperator}; //use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, get_where_columns, tree_check, ComplexCondition, Condition}; // use crate::condition::Condition; use crate::libs::error; -use crate::query::build_empty_query; +use crate::query::{self, build_empty_query}; use crate::query::query_type::QueryType; use crate::query::{Query, DELETE_MIN_LEN, INSERT_MIN_LEN, SELECT_MIN_LEN, UPDATE_MIN_LEN}; -use super::error::SELECT_MAL_FORMATEADO; +use super::error::{DELETE_MAL_FORMATEADO, SELECT_MAL_FORMATEADO, WHERE_MAL_FORMATEADO}; pub fn build_query(text_query: &String, path: &String) -> Result { // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build @@ -41,48 +42,16 @@ fn separate_args_delete(args: &[String], path: &String, result: &mut Query) -> R if args.len() != DELETE_MIN_LEN { return Err(error::DELETE_MAL_FORMATEADO); - } else { - /* TODO: Code for complex conditions - match add_node_to_tree(args, &mut 4, build_empty_complex_condition()) { + } else if args[3].eq("WHERE") { + let mut counter: usize = 4; + match parse_where_condition(&result, args, &mut counter) { Ok(cond) => result.where_condition = Some(cond), Err(x) => return Err(x) - } - */ - - if args[5].eq("<") { - result.where_condition = Some(build_condition( - args[4].to_string(), - args[6].to_string(), - ConditionOperator::Minor, - )) - } else if args[5].eq("<=") { - result.where_condition = Some(build_condition( - args[4].to_string(), - args[6].to_string(), - ConditionOperator::MinorEqual, - )) - } else if args[5].eq("=") { - result.where_condition = Some(build_condition( - args[4].to_string(), - args[6].to_string(), - ConditionOperator::Equal, - )) - } else if args[5].eq(">=") { - result.where_condition = Some(build_condition( - args[4].to_string(), - args[6].to_string(), - ConditionOperator::HigherEqual, - )) - } else if args[5].eq(">") { - result.where_condition = Some(build_condition( - args[4].to_string(), - args[6].to_string(), - ConditionOperator::Higher, - )) - } else { - return Err(error::WHERE_MAL_FORMATEADO); - } + } + } else{ + return Err(DELETE_MAL_FORMATEADO); } + Ok(0) } } @@ -148,46 +117,10 @@ fn separate_args_update(args: &[String], path: &String, result: &mut Query) -> R } result.values = Some(values); - /* TODO: Code for complex conditions - counter += 1; - match add_node_to_tree(args, &mut counter, build_empty_complex_condition()) { + match parse_where_condition(&result, args, &mut counter) { Ok(cond) => result.where_condition = Some(cond), Err(x) => return Err(x) } - */ - if args[8].eq("<") { - result.where_condition = Some(build_condition( - args[7].to_string(), - args[9].to_string(), - ConditionOperator::Minor, - )) - } else if args[8].eq("<=") { - result.where_condition = Some(build_condition( - args[7].to_string(), - args[9].to_string(), - ConditionOperator::MinorEqual, - )) - } else if args[8].eq("=") { - result.where_condition = Some(build_condition( - args[7].to_string(), - args[9].to_string(), - ConditionOperator::Equal, - )) - } else if args[8].eq(">=") { - result.where_condition = Some(build_condition( - args[7].to_string(), - args[9].to_string(), - ConditionOperator::HigherEqual, - )) - } else if args[8].eq(">") { - result.where_condition = Some(build_condition( - args[7].to_string(), - args[9].to_string(), - ConditionOperator::Higher, - )) - } else { - return Err(error::WHERE_MAL_FORMATEADO); - } Ok(0) } @@ -222,55 +155,10 @@ fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> R if counter == args.len() { Ok(0) } else { - /* TODO: Code for complex conditions - match add_node_to_tree(args, &mut counter, build_empty_complex_condition()) { + match parse_where_condition(&result, args, &mut counter) { Ok(cond) => result.where_condition = Some(cond), Err(x) => return Err(x) } - */ - if counter + 3 > args.len() { - return Err(SELECT_MAL_FORMATEADO); - } else if args[counter].eq("WHERE") { - counter += 1; - if args[counter + 1].eq("<") { - result.where_condition = Some(build_condition( - args[counter].to_string(), - args[counter + 2].to_string(), - ConditionOperator::Minor, - )); - counter += 3; - } else if args[counter + 1].eq("<=") { - result.where_condition = Some(build_condition( - args[counter].to_string(), - args[counter + 2].to_string(), - ConditionOperator::MinorEqual, - )); - counter += 3; - } else if args[counter + 1].eq("=") { - result.where_condition = Some(build_condition( - args[counter].to_string(), - args[counter + 2].to_string(), - ConditionOperator::Equal, - )); - counter += 3; - } else if args[counter + 1].eq(">=") { - result.where_condition = Some(build_condition( - args[counter].to_string(), - args[counter + 2].to_string(), - ConditionOperator::HigherEqual, - )); - counter += 3; - } else if args[counter + 1].eq(">") { - result.where_condition = Some(build_condition( - args[counter].to_string(), - args[counter + 2].to_string(), - ConditionOperator::Higher, - )); - counter += 3; - } else { - return Err(error::WHERE_MAL_FORMATEADO); - } - } if counter < args.len() { if args[counter].eq("ORDER") && args[counter + 1].eq("BY") { @@ -324,6 +212,82 @@ fn get_columns_position(query: &Query, string_cols: &[String]) -> Result Result { + // Pre: Query args and counter + // Post: Complex condition for query + if args[*counter].eq("AND") || args[*counter].eq("OR") { + Err(WHERE_MAL_FORMATEADO) + } else { + match get_condition_node(query,args,counter) { + Err(x) => Err(x), + Ok(mut root) => { // Initial root + if &root.operator == &BooleanOperator::AND || &root.operator == &BooleanOperator::OR { + return Err(WHERE_MAL_FORMATEADO); + } else { + while *counter < args.len() && ! args[*counter].eq("ORDER") { + let opt_node = get_condition_node(query,args,counter) ; + if opt_node.is_err() { + return opt_node; + } else if let Ok(new_node) = opt_node { + let add_opt = add_node_to_tree(new_node, &mut root); + if add_opt.is_err() { + return add_opt; + } else if let Ok(new_root) = add_opt { + root = new_root; + } + } + } + } + if tree_check(&root) { + Ok(root) + } else { + Err(WHERE_MAL_FORMATEADO) + } + } + } + } +} + +fn get_condition_node(query: &Query, args: &[String], counter: &mut usize) -> Result { + // Pre: Query args and counter of args + // Post: New node && increments counter + let new_node: ComplexCondition; + if args[*counter].eq("AND") { + new_node = build_complex_condition(BooleanOperator::AND, None, None); + *counter += 1; + } else if args[*counter].eq("OR") { + new_node = build_complex_condition(BooleanOperator::OR, None, None); + *counter += 1; + } else if args[*counter].eq("NOT") { + new_node = build_complex_condition(BooleanOperator::NOT, None, None); + *counter += 1; + } else if *counter + 3 < args.len() { + match get_columns_position(query, &[args[*counter].to_string()]) { + Err(x) => return Err(x), + Ok(x) => { + let simple_condition: Condition = if args[*counter + 2].eq("<") { + build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::Minor) + } else if args[*counter + 2].eq("<=") { + build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::MinorEqual) + } else if args[*counter + 2].eq("=") { + build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::Equal) + } else if args[*counter + 2].eq(">=") { + build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::HigherEqual) + } else if args[*counter + 2].eq(">") { + build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::Higher) + } else { + return Err(WHERE_MAL_FORMATEADO) + }; + new_node = build_simple_condition(Some(simple_condition)); + *counter += 3; + } + } + } else { + return Err(WHERE_MAL_FORMATEADO) + } + Ok(new_node) +} + fn find_column_position(column_name: &String, columns: &[String]) -> Result { let mut counter = 0; while counter < columns.len() { diff --git a/src/query.rs b/src/query.rs index b1be240..17edcd7 100644 --- a/src/query.rs +++ b/src/query.rs @@ -2,7 +2,7 @@ pub mod query_type; use query_type::QueryType; -use crate::condition::Condition; +use crate::condition::{complex_condition::ComplexCondition, Condition}; // use crate::condition::ComplexCondition; @@ -12,12 +12,12 @@ pub static SELECT_MIN_LEN: usize = 4; // SELECT * FROM tabla pub static UPDATE_MIN_LEN: usize = 10; // UPDATE tabla SET col = valor WHERE a < b pub struct Query { - pub operation: Option, // DELETE, INSERT, SELECT, UPDATE - pub table: Option, // DELETE, INSERT, SELECT, UPDATE - pub columns: Option>, // INSERT, SELECT, UPDATE - pub where_condition: Option, // DELETE (always), SELECT (sometimes), UPDATE (always) . - pub order_by: Option<(String, bool)>, // SELECT (sometimes) - pub values: Option>, // INSERT, UPDATE (in update is set) + pub operation: Option, // DELETE, INSERT, SELECT, UPDATE + pub table: Option, // DELETE, INSERT, SELECT, UPDATE + pub columns: Option>, // INSERT, SELECT, UPDATE + pub where_condition: Option, // DELETE (always), SELECT (sometimes), UPDATE (always) . + pub order_by: Option<(String, bool)>, // SELECT (sometimes) + pub values: Option>, // INSERT, UPDATE (in update is set) } pub fn build_empty_query() -> Query { From ec004e568590da5360b33019a74b77f0b6c561a1 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 22 Sep 2024 21:40:39 -0300 Subject: [PATCH 48/58] FIN CODE: Vector booleano --- README.md | 6 +- src/condition.rs | 16 ++-- src/libs/parsing.rs | 200 +++++++++++++++++++++++++++++--------------- src/query.rs | 15 ++-- 4 files changed, 157 insertions(+), 80 deletions(-) diff --git a/README.md b/README.md index 5825aec..5dcc780 100644 --- a/README.md +++ b/README.md @@ -36,9 +36,11 @@ Funcionalidades probadas OK ### Detalles de implementación -Para la lógica booleana el objetivo era crear un arbol de condiciones formado por las relaciones de precedencia. +Logica booleana: Se implemento por medio de un vector de vectores. Por cada OR se pushea un nuevo vector, donde en este vector se pushearán las expresiones simples y las negaciones ( los ANDs no son pusheados, ya que sería redundante ). -Dicho objetivo no pudo ser implementado. Se implementó lógica de condiciones simples ( no compuestas ) +Esta implementación tiene como problema que un query con el condicional WHERE A AND AND AND {...} B resulta en WHERE A AND B. Como solución simple se planteó un chequeo en parseo que si se encuentra un condicional AND, se chequeará que el largo sea tal que el condicional sea válido, y que el proximo elemento no sea AND u OR. + +Para la lógica booleana tambien se considero un arbol binario de expresiones booleanas (https://en.wikipedia.org/wiki/Binary_expression_tree). No se logró implementar debido a problemas con el manejo de memoria en Rust, aunque en mi opinión es la mejor implementación posible. Para en ORDER BY no cargar las tablas completas en memoria se eligió "Full external sort" (https://cs186berkeley.net/notes/note8/) diff --git a/src/condition.rs b/src/condition.rs index 34eb690..4c613b8 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -1,10 +1,8 @@ pub mod condition_type; -pub mod complex_condition; -use condition_type::BooleanOperator; +// pub mod complex_condition; +// use condition_type::BooleanOperator; +// use crate::libs::error; -/* -use crate::libs::error; -*/ use condition_type::ConditionOperator; @@ -14,6 +12,14 @@ pub struct Condition { pub value: Option, } +pub fn build_not_condition() -> Condition { + Condition { + condition: ConditionOperator::Equal, + column: None, + value: None + } +} + pub fn build_condition(column: usize, value: String, cond: ConditionOperator) -> Condition { Condition { condition: cond, diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 8401ad8..41562f5 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -1,8 +1,8 @@ use std::fs::File; use std::io::{BufRead, BufReader}; -use crate::condition::{build_condition, Condition}; -use crate::condition::complex_condition::{add_node_to_tree, build_complex_condition, build_simple_condition, ComplexCondition, tree_check, check_precedence}; +use crate::condition::{build_not_condition, build_condition, Condition}; +//use crate::condition::complex_condition::{add_node_to_tree, build_complex_condition, build_simple_condition, ComplexCondition, tree_check, check_precedence}; use crate::condition::condition_type::{BooleanOperator, ConditionOperator}; //use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, get_where_columns, tree_check, ComplexCondition, Condition}; // use crate::condition::Condition; @@ -212,80 +212,106 @@ fn get_columns_position(query: &Query, string_cols: &[String]) -> Result Result { +fn parse_where_condition(query: &Query, args: &[String], counter: &mut usize) -> Result>,u32> { // Pre: Query args and counter // Post: Complex condition for query if args[*counter].eq("AND") || args[*counter].eq("OR") { Err(WHERE_MAL_FORMATEADO) } else { - match get_condition_node(query,args,counter) { - Err(x) => Err(x), - Ok(mut root) => { // Initial root - if &root.operator == &BooleanOperator::AND || &root.operator == &BooleanOperator::OR { - return Err(WHERE_MAL_FORMATEADO); - } else { - while *counter < args.len() && ! args[*counter].eq("ORDER") { - let opt_node = get_condition_node(query,args,counter) ; - if opt_node.is_err() { - return opt_node; - } else if let Ok(new_node) = opt_node { - let add_opt = add_node_to_tree(new_node, &mut root); - if add_opt.is_err() { - return add_opt; - } else if let Ok(new_root) = add_opt { - root = new_root; - } - } - } - } - if tree_check(&root) { - Ok(root) - } else { - Err(WHERE_MAL_FORMATEADO) - } + // Parse into boolean vector + let mut result: Vec> = Vec::new(); + result.push(Vec::new()); + while *counter < args.len() && ! args[*counter].eq("ORDER") { + match parse_next_condition(query, args, counter, &mut result) { + Ok(_) => continue, + Err(x) => return Err(x) } } + + // Check valid result + if check_valid_bool(&result){ + Ok(result) + } else { + Err(WHERE_MAL_FORMATEADO) + } } } -fn get_condition_node(query: &Query, args: &[String], counter: &mut usize) -> Result { - // Pre: Query args and counter of args - // Post: New node && increments counter - let new_node: ComplexCondition; - if args[*counter].eq("AND") { - new_node = build_complex_condition(BooleanOperator::AND, None, None); +fn parse_next_condition(query: &Query, args: &[String], counter: &mut usize, vec: &mut Vec> ) -> Result { + if args[*counter].eq("OR") { + if ! *counter + 3 < args.len() { + return Err(WHERE_MAL_FORMATEADO); + } else if args[*counter + 1].eq("AND") || args[*counter + 1].eq("OR") { + return Err(WHERE_MAL_FORMATEADO); + } + vec.push(Vec::new()); *counter += 1; - } else if args[*counter].eq("OR") { - new_node = build_complex_condition(BooleanOperator::OR, None, None); + } else if args[*counter].eq("AND") { + if ! *counter + 3 < args.len() { + return Err(WHERE_MAL_FORMATEADO); + } else if args[*counter + 1].eq("AND") || args[*counter + 1].eq("OR") { + return Err(WHERE_MAL_FORMATEADO); + } *counter += 1; } else if args[*counter].eq("NOT") { - new_node = build_complex_condition(BooleanOperator::NOT, None, None); + if ! *counter + 3 < args.len() { + return Err(WHERE_MAL_FORMATEADO); + } else if args[*counter + 1].eq("AND") || args[*counter + 1].eq("OR") { + return Err(WHERE_MAL_FORMATEADO); + } + let position = vec.len() - 1; + vec[position].push(build_not_condition()); // String vacio *counter += 1; } else if *counter + 3 < args.len() { match get_columns_position(query, &[args[*counter].to_string()]) { Err(x) => return Err(x), Ok(x) => { - let simple_condition: Condition = if args[*counter + 2].eq("<") { + let simple_condition: Condition = if args[*counter + 1].eq("<") { build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::Minor) - } else if args[*counter + 2].eq("<=") { + } else if args[*counter + 1].eq("<=") { build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::MinorEqual) - } else if args[*counter + 2].eq("=") { + } else if args[*counter + 1].eq("=") { build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::Equal) - } else if args[*counter + 2].eq(">=") { + } else if args[*counter + 1].eq(">=") { build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::HigherEqual) - } else if args[*counter + 2].eq(">") { + } else if args[*counter + 1].eq(">") { build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::Higher) } else { return Err(WHERE_MAL_FORMATEADO) }; - new_node = build_simple_condition(Some(simple_condition)); + let position = vec.len() - 1; + vec[position].push(simple_condition); *counter += 3; } } } else { return Err(WHERE_MAL_FORMATEADO) } - Ok(new_node) + + Ok(0) +} + +fn check_valid_bool(boolean_expresion: &Vec>) -> bool { + // Pre: Boolean vector + // Post: Bool for valid or invalid + let mut valid = true; + let mut counter = 0; + let mut sub_counter; + let mut open_not = false; + while counter < boolean_expresion.len() && valid { + valid = boolean_expresion[counter].is_empty(); + + sub_counter = 0; + while sub_counter < boolean_expresion[counter].len() && valid { + open_not = ! ( open_not && boolean_expresion[counter][sub_counter].value.is_some() ); + sub_counter += 1; + } + + valid = ! open_not; + counter += 1; + } + + valid } fn find_column_position(column_name: &String, columns: &[String]) -> Result { @@ -422,7 +448,7 @@ fn validate_delete_query(query: Query) -> Result { match &query.table { Some(table) => match File::open(table) { Ok(file) => match get_columns(file) { - Some(columns) => check_columns_contains_condition(columns, query), + Some(_) => Ok(query), None => Err(error::ARCHIVO_VACIO), }, Err(_) => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO), @@ -471,27 +497,6 @@ fn get_columns(file: File) -> Option> { } } -fn check_columns_contains_condition(columns: Vec, query: Query) -> Result { - // TODO - match get_where_columns(&query) { - Some(column) => { - if columns.contains(&column) { - Ok(query) - } else { - Err(error::ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS) - } - } - None => Err(error::NO_WHERE), - } -} - -fn get_where_columns(query: &Query) -> Option { - match &query.where_condition { - Some(cond) => cond.column.as_ref().map(|col| col.to_string()), - None => None, - } -} - pub fn get_file_first_line(query: &Query) -> Option { // Pre: query // Post: File first line, if any @@ -604,3 +609,66 @@ mod tests { ); } } + +/* +fn check_columns_contains_condition(columns: Vec, query: Query) -> Result { + // TODO + match get_where_columns(&query) { + Some(column) => { + if columns.contains(&column) { + Ok(query) + } else { + Err(error::ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS) + } + } + None => Err(error::NO_WHERE), + } +} + +fn get_where_columns(query: &Query) -> Option { + match &query.where_condition { + Some(cond) => cond.column.as_ref().map(|col| col.to_string()), + None => None, + } +} + +fn get_condition_node(query: &Query, args: &[String], counter: &mut usize) -> Result { + // Pre: Query args and counter of args + // Post: New node && increments counter + let new_node: ComplexCondition; + if args[*counter].eq("AND") { + new_node = build_complex_condition(BooleanOperator::AND, None, None); + *counter += 1; + } else if args[*counter].eq("OR") { + new_node = build_complex_condition(BooleanOperator::OR, None, None); + *counter += 1; + } else if args[*counter].eq("NOT") { + new_node = build_complex_condition(BooleanOperator::NOT, None, None); + *counter += 1; + } else if *counter + 3 < args.len() { + match get_columns_position(query, &[args[*counter].to_string()]) { + Err(x) => return Err(x), + Ok(x) => { + let simple_condition: Condition = if args[*counter + 2].eq("<") { + build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::Minor) + } else if args[*counter + 2].eq("<=") { + build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::MinorEqual) + } else if args[*counter + 2].eq("=") { + build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::Equal) + } else if args[*counter + 2].eq(">=") { + build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::HigherEqual) + } else if args[*counter + 2].eq(">") { + build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::Higher) + } else { + return Err(WHERE_MAL_FORMATEADO) + }; + new_node = build_simple_condition(Some(simple_condition)); + *counter += 3; + } + } + } else { + return Err(WHERE_MAL_FORMATEADO) + } + Ok(new_node) +} +*/ diff --git a/src/query.rs b/src/query.rs index 17edcd7..9754348 100644 --- a/src/query.rs +++ b/src/query.rs @@ -2,7 +2,8 @@ pub mod query_type; use query_type::QueryType; -use crate::condition::{complex_condition::ComplexCondition, Condition}; +use crate::condition::Condition; +//use crate::complex_condition::ComplexCondition, // use crate::condition::ComplexCondition; @@ -12,12 +13,12 @@ pub static SELECT_MIN_LEN: usize = 4; // SELECT * FROM tabla pub static UPDATE_MIN_LEN: usize = 10; // UPDATE tabla SET col = valor WHERE a < b pub struct Query { - pub operation: Option, // DELETE, INSERT, SELECT, UPDATE - pub table: Option, // DELETE, INSERT, SELECT, UPDATE - pub columns: Option>, // INSERT, SELECT, UPDATE - pub where_condition: Option, // DELETE (always), SELECT (sometimes), UPDATE (always) . - pub order_by: Option<(String, bool)>, // SELECT (sometimes) - pub values: Option>, // INSERT, UPDATE (in update is set) + pub operation: Option, // DELETE, INSERT, SELECT, UPDATE + pub table: Option, // DELETE, INSERT, SELECT, UPDATE + pub columns: Option>, // INSERT, SELECT, UPDATE + pub where_condition: Option>>, // DELETE (always), SELECT (sometimes), UPDATE (always) . + pub order_by: Option<(String, bool)>, // SELECT (sometimes) + pub values: Option>, // INSERT, UPDATE (in update is set) } pub fn build_empty_query() -> Query { From ca908ee66d42e27e55708f6d88a7b796118b76d7 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 22 Sep 2024 23:18:07 -0300 Subject: [PATCH 49/58] CODE OK: Funciones adaptadas --- src/condition.rs | 43 +++++++++++++++++++ src/libs/exec.rs | 108 +++++++++++++++++++++-------------------------- 2 files changed, 91 insertions(+), 60 deletions(-) diff --git a/src/condition.rs b/src/condition.rs index 4c613b8..3d33f55 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -29,6 +29,8 @@ pub fn build_condition(column: usize, value: String, cond: ConditionOperator) -> } pub fn operate_condition(v1: &String, v2: &String, operator: &ConditionOperator) -> bool { + // Pre: Strings and operator + // Post: Bool if condition applies or not ( operates string and int ) if let Ok(x1) = v1.parse::() { if let Ok(x2) = v2.parse::() { match operator { @@ -49,3 +51,44 @@ pub fn operate_condition(v1: &String, v2: &String, operator: &ConditionOperator) ConditionOperator::HigherEqual => v1 >= v2, } } + +pub fn operate_full_condition(elements: &[String], condition: &Vec>) -> bool { + // Pre: Line to vec and condition (bool vector). + // Post: Bool if condition applies or not + + let mut or_valid = false; + let mut or_counter = 0; + + let mut and_valid ; + let mut and_counter; + let mut not_detected ; + + while or_counter < condition.len() && ! or_valid { + and_valid = true; + and_counter = 0; + not_detected = false; + while and_counter < condition[or_counter].len() && and_valid { + match &condition[or_counter][and_counter].column { + None => not_detected = ! not_detected, + Some(column) => match &condition[or_counter][and_counter].value { + None => return false, + Some(value) => { + if not_detected { + and_valid = ! operate_condition(&elements[*column], value, &condition[or_counter][and_counter].condition) + } else { + and_valid = operate_condition(&elements[*column], value, &condition[or_counter][and_counter].condition); + } + } + } + } + + and_counter += 1; + } + + or_valid = and_valid; + + or_counter += 1; + } + + or_valid +} \ No newline at end of file diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 5f31a32..610fb4f 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -1,7 +1,7 @@ use std::fs::{remove_file, rename, File, OpenOptions}; use std::io::{BufRead, BufReader, Write}; -use crate::condition::{self, operate_condition, Condition}; +use crate::condition::{self, operate_condition, operate_full_condition, Condition}; //use crate::condition::operate_condition; use crate::query::query_type::QueryType; use crate::query::Query; @@ -24,52 +24,48 @@ pub fn exec_query(query: Query) { fn exec_query_delete(query: Query) { if let Some(cond) = &query.where_condition { - if let Some(value) = &cond.value { - if let Some(table) = &query.table { - // Check conditions for query. if not, don't do anything - let tmp_file_name = get_tmp_file_name(table); - let mut valid_operation = true; - match File::open(table) { - Ok(file) => match File::create(&tmp_file_name) { - Ok(mut tmp_file) => { - let col_index = find_filter_column(&query); - let mut reader: BufReader = BufReader::new(file); - let mut line = String::new(); - - let mut read = true; - while read { - if let Ok(x) = reader.read_line(&mut line) { - line = line.replace('\n', ""); - read = x != 0; - if read { - let elements = line_to_vec(&line); - if !operate_condition( - &elements[col_index as usize], - value, - &cond.condition, - ) { - line.push('\n'); - if let Err(_error) = tmp_file.write(line.as_bytes()) { - read = false; - valid_operation = false; - } + if let Some(table) = &query.table { + // Check conditions for query. if not, don't do anything + let tmp_file_name = get_tmp_file_name(table); + let mut valid_operation = true; + match File::open(table) { + Ok(file) => match File::create(&tmp_file_name) { + Ok(mut tmp_file) => { + let mut reader: BufReader = BufReader::new(file); + let mut line = String::new(); + + let mut read = true; + while read { + if let Ok(x) = reader.read_line(&mut line) { + line = line.replace('\n', ""); + read = x != 0; + if read { + let elements = line_to_vec(&line); + if !operate_full_condition( + &elements, + cond + ) { + line.push('\n'); + if let Err(_error) = tmp_file.write(line.as_bytes()) { + read = false; + valid_operation = false; } } - line.clear(); - } else { - read = false; - valid_operation = false; } + line.clear(); + } else { + read = false; + valid_operation = false; } } - Err(_) => valid_operation = false, - }, + } Err(_) => valid_operation = false, - } - - if remove_old_file(table, &tmp_file_name, valid_operation).is_err() { - println!("Error en manipulación de archivos"); - } + }, + Err(_) => valid_operation = false, + } + + if remove_old_file(table, &tmp_file_name, valid_operation).is_err() { + println!("Error en manipulación de archivos"); } } } @@ -133,7 +129,6 @@ fn exec_query_select(query: Query) { fn exec_query_select(query: Query) { match &query.order_by { Some((column, asc)) => { - let _col_filter: i32 = find_filter_column(&query); if let Some(col_index) = find_column(&query, column) { print_header(&query); if let Ok(files) = read_into_sorted_files(&query, col_index, asc) { @@ -143,8 +138,8 @@ fn exec_query_select(query: Query) { } } None => { - let col_index: i32 = find_filter_column(&query); - read_and_print_file(&query, col_index); +// let col_index: i32 = find_filter_column(&query); + read_and_print_file(&query); } } } @@ -469,7 +464,6 @@ fn find_sorted_position( fn exec_query_update(query: Query) { if let Some(cond) = &query.where_condition { - if let Some(value) = &cond.value { if let Some(columns) = &query.columns { if let Some(values) = &query.values { if let Some(table) = &query.table { @@ -478,7 +472,6 @@ fn exec_query_update(query: Query) { match File::open(table) { Ok(file) => match File::create(&tmp_file) { Ok(mut tmp_file) => { - let col_index = find_filter_column(&query); let mut reader: BufReader = BufReader::new(file); let mut line = String::new(); @@ -489,10 +482,9 @@ fn exec_query_update(query: Query) { if read { line = line.replace('\n', ""); let elements = line_to_vec(&line); - if !operate_condition( - &elements[col_index as usize], - value, - &cond.condition, + if !operate_full_condition( + &elements, + cond ) { // Line not updated line.push('\n'); @@ -531,7 +523,6 @@ fn exec_query_update(query: Query) { } } } - } } } @@ -595,6 +586,7 @@ fn find_total_columns(query: &Query) -> usize { } } +/* fn find_filter_column(query: &Query) -> i32 { let mut col_index_filter = -1; match &query.where_condition { @@ -636,6 +628,7 @@ fn find_filter_column(query: &Query) -> i32 { } col_index_filter } +*/ fn find_column(query: &Query, column: &String) -> Option { match get_file_first_line(query) { @@ -698,7 +691,7 @@ fn print_header(query: &Query) { } } -fn read_and_print_file(query: &Query, col_filter: i32) { +fn read_and_print_file(query: &Query) { if let Some(table) = &query.table { if let Ok(f) = File::open(table) { let mut reader: BufReader = BufReader::new(f); @@ -714,7 +707,7 @@ fn read_and_print_file(query: &Query, col_filter: i32) { match &query.where_condition { Some(condition) => print_file_conditioned( &query.columns, - (col_filter, condition), + &condition, &elements, ), None => print_file_unconditional(&query.columns, &elements), @@ -1038,15 +1031,10 @@ fn print_file_unconditional(columns_opt: &Option>, elements: &[String fn print_file_conditioned( columns_opt: &Option>, - filter: (i32, &Condition), + condition: &Vec>, elements: &[String], ) { - let (col_filter, condition) = filter; - if let Some(value) = &condition.value { - if operate_condition(&elements[col_filter as usize], value, &condition.condition) { - print_file_unconditional(columns_opt, elements) - } - } else { + if operate_full_condition(&elements, condition) { print_file_unconditional(columns_opt, elements) } } From 347452dc403f5918dae9ce84b773204525db66c9 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 22 Sep 2024 23:28:45 -0300 Subject: [PATCH 50/58] gdb OK: SELECT * FROM clientes WHERE id <= 8 AND id >= 4 --- src/libs/parsing.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 41562f5..7a134b0 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -154,7 +154,8 @@ fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> R if counter == args.len() { Ok(0) - } else { + } else if args[counter].eq("WHERE") { + counter += 1; match parse_where_condition(&result, args, &mut counter) { Ok(cond) => result.where_condition = Some(cond), Err(x) => return Err(x) @@ -182,6 +183,9 @@ fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> R } Ok(0) } + else { + Err(WHERE_MAL_FORMATEADO) + } } } @@ -239,7 +243,7 @@ fn parse_where_condition(query: &Query, args: &[String], counter: &mut usize) -> fn parse_next_condition(query: &Query, args: &[String], counter: &mut usize, vec: &mut Vec> ) -> Result { if args[*counter].eq("OR") { - if ! *counter + 3 < args.len() { + if ! *counter + 2 < args.len() { return Err(WHERE_MAL_FORMATEADO); } else if args[*counter + 1].eq("AND") || args[*counter + 1].eq("OR") { return Err(WHERE_MAL_FORMATEADO); @@ -247,14 +251,14 @@ fn parse_next_condition(query: &Query, args: &[String], counter: &mut usize, vec vec.push(Vec::new()); *counter += 1; } else if args[*counter].eq("AND") { - if ! *counter + 3 < args.len() { + if ! *counter + 2 < args.len() { return Err(WHERE_MAL_FORMATEADO); } else if args[*counter + 1].eq("AND") || args[*counter + 1].eq("OR") { return Err(WHERE_MAL_FORMATEADO); } *counter += 1; } else if args[*counter].eq("NOT") { - if ! *counter + 3 < args.len() { + if ! *counter + 2 < args.len() { return Err(WHERE_MAL_FORMATEADO); } else if args[*counter + 1].eq("AND") || args[*counter + 1].eq("OR") { return Err(WHERE_MAL_FORMATEADO); @@ -262,7 +266,7 @@ fn parse_next_condition(query: &Query, args: &[String], counter: &mut usize, vec let position = vec.len() - 1; vec[position].push(build_not_condition()); // String vacio *counter += 1; - } else if *counter + 3 < args.len() { + } else if *counter + 2 < args.len() { match get_columns_position(query, &[args[*counter].to_string()]) { Err(x) => return Err(x), Ok(x) => { From 1b005bb4ad27f7f3c19116de9fd15d7df5f18e94 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 22 Sep 2024 23:41:01 -0300 Subject: [PATCH 51/58] OK: SELECT * FROM clientes WHERE id < 8 AND id > 4 OR nombre = Juan ORDER BY nombre --- src/libs/exec.rs | 716 ++++++++++++++++++++++++----------------------- 1 file changed, 363 insertions(+), 353 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 610fb4f..0782a2a 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -105,27 +105,6 @@ fn exec_query_insert(query: Query) { } } -/* -fn exec_query_select(query: Query) { - match &query.order_by { - Some((column, asc)) => { - let col_index: i32 = find_filter_column(&query); - if read_and_save_file(&query, col_index).is_ok() { - if let Some(column_number) = find_column(&query, column) { - if let Ok(tmp_files) = sort_and_print_file(column_number, &query, asc) { - file_cleanup(tmp_files); - } - } - } - } - None => { - let col_index: i32 = find_filter_column(&query); - read_and_print_file(&query, col_index); - } - } -} -*/ - fn exec_query_select(query: Query) { match &query.order_by { Some((column, asc)) => { @@ -248,80 +227,6 @@ fn find_next_line(lines_buffer: &mut [Vec], col_index: usize, asc: &bool } } -/* -fn get_next_line(lines_buffer: &mut Vec>, readers: &mut Vec>, col_index: usize, asc: &bool) -> Option> { - // Post: Next line in order, if not fully read - let mut line = String::new(); - match find_available_reader(&readers) { - None => None, - Some(mut candidate) => { - let mut counter = candidate + 1; - while counter < readers.len() { - if readers[counter].0 < FILE_SORT_BUFFER && counter != candidate { - if *asc { - if lines_buffer[counter][col_index] < lines_buffer[candidate][col_index] { - candidate = counter; - } - } else { - if lines_buffer[counter][col_index] > lines_buffer[candidate][col_index] { - candidate = counter; - } - } - } - - counter += 1; - } - - if counter == readers.len() { - None - } else { - let new_line: Vec; - match readers[candidate].1.read_line(&mut line){ - Err(_) => new_line = Vec::new(), - Ok(read_result) => { - if read_result == 0 { - new_line = Vec::new(); // If this happen, then never read again from here - readers[candidate].0 = FILE_SORT_BUFFER; - } else { - lines_buffer.push(text_to_vec(&line, true)); - let len = lines_buffer.len(); - lines_buffer.swap(candidate,len - 1); - match lines_buffer.pop() { - Some(x) => { - new_line = x; - readers[candidate].0 += 1; - }, - None => { - new_line = Vec::new(); // If this happen, then never read again from here - readers[candidate].0 = FILE_SORT_BUFFER; - } - } - } - } - } - - Some(new_line) - } - } - } -} - -fn find_available_reader(readers: &Vec>) -> Option { - // Pre: Readers - // Post: First available reader position - let mut counter = 0; - while counter < readers.len() && ! &readers[counter].0 < FILE_SORT_BUFFER { - counter += 1; - } - - if counter == readers.len() { - None - } else { - Some(counter) - } -} -*/ - fn readers_read_first_line(readers: &mut Vec>) -> Option>> { let mut result: Vec> = Vec::new(); let mut line = String::new(); @@ -362,104 +267,6 @@ fn create_readers(files: &[String]) -> Option>> { } /* -fn sort_and_print_file( - column_number: usize, - query: &Query, - asc: &bool, -) -> Result, u32> { - // Pre: Column number for sorting - // Post: Separates into files, sort them and print them in correct order. Result name of files for cleanup - match &query.table { - None => Err(3), - Some(table) => { - let tmp_unsorted_filename = get_tmp_file_name(table); - match File::open(tmp_unsorted_filename) { - Err(_) => Err(3), - Ok(unsorted_file) => { - let mut reader: BufReader = BufReader::new(unsorted_file); - let mut line = String::new(); - let mut actually_sorting_elements: Vec> = Vec::new(); - - let mut sorted_files: Vec = Vec::new(); - let mut sorted_filenames: Vec = Vec::new(); - let mut counter = 0; - - let mut read = true; - let mut valid_operation = true; - while read { - if let Ok(x) = reader.read_line(&mut line) { - line = line.replace('\n', ""); - read = x != 0; - - let element = text_to_vec(&line, true); - if counter < FILE_SORT_BUFFER { - actually_sorting_elements.insert( - find_sorted_position( - &actually_sorting_elements, - &element, - column_number, - asc, - ), - element, - ); - } else { - let mut new_file = String::from(format!(".{}", sorted_files.len())); - new_file.push_str(&tmp_unsorted_filename); - match File::create(new_file) { - Ok(f) => { - for element in actually_sorting_elements { - let mut write_line = String::new(); - for (counter, word) in element.iter().enumerate() { - if counter == 0 { - f.write(word.as_bytes()); - } else { - f.write(format!(",{}", &word)); - } - } - } - sorted_files.push(f); - sorted_filenames.push(new_file); - actually_sorting_elements.clear(); - } - Err(_) => { - read = false; - valid_operation = false; - } - } - } - } else { - valid_operation = false; - read = false; - } - } - - if valid_operation { - Ok(sorted_filenames) - } else { - Err(3) - } - } - } - } - } -} - - -fn file_cleanup(files: Vec) { - for file in files { - let _ = remove_file(file); - } -} - -fn find_sorted_position( - sorted_vec: &Vec>, - new_element: &Vec, - column_number: usize, - asc: &bool, -) -> usize { - // Insert into shifts everything to right. - 0 -} */ fn exec_query_update(query: Query) { @@ -586,50 +393,6 @@ fn find_total_columns(query: &Query) -> usize { } } -/* -fn find_filter_column(query: &Query) -> i32 { - let mut col_index_filter = -1; - match &query.where_condition { - Some(x) => match &x.column { - Some(column) => match &query.table { - Some(table) => match File::open(table) { - Ok(file) => { - let mut reader: BufReader = BufReader::new(file); - let mut line = String::new(); - match reader.read_line(&mut line) { - Ok(_) => { - line = line.replace('\n', ""); - let mut split = line.split(','); - let mut element_opt = split.next(); - let mut counter = 0; - - while element_opt.is_some() && col_index_filter < 0 { - if let Some(x) = element_opt { - if x.eq(column) { - col_index_filter = counter; - } - } - counter += 1; - element_opt = split.next(); - } - } - Err(_) => col_index_filter = -1, - } - } - Err(_) => return -1, - }, - None => return -1, - }, - None => { - col_index_filter = -1; - } - }, - None => col_index_filter = -1, - } - col_index_filter -} -*/ - fn find_column(query: &Query, column: &String) -> Option { match get_file_first_line(query) { Some(line) => { @@ -752,8 +515,14 @@ fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result if read { let elements = text_to_vec(&line, true); match &query.where_condition { - Some(_condition) => {} - // insert_conditioned(&elements,&mut lines_buffer,&col_index,condition, asc), + Some(cond) => insert_conditioned( + elements, + cond, + &query.columns, + &mut lines_buffer, + &col_index, + asc, + ), None => insert_unconditioned( elements, &query.columns, @@ -835,19 +604,6 @@ fn write_to_tmp_file( } } -/* -fn insert_conditioned(elements: &[String], columns_opt: &Option>, lines_buffer: &mut Vec>, col_index: &usize, filter: &Condition) { -let (col_filter, condition) = filter; - if let Some(value) = &condition.value { - if operate_condition(&elements[col_filter as usize], value, &condition.condition) { - print_file_unconditional(columns_opt, elements) - } - } else { - print_file_unconditional(columns_opt, elements) - } -} -*/ - fn insert_unconditioned( elements: Vec, columns_opt: &Option>, @@ -887,6 +643,19 @@ fn insert_unconditioned( } } +fn insert_conditioned( + elements: Vec, + condition: &Vec>, + columns_opt: &Option>, + lines_buffer: &mut Vec>, + col_index: &usize, + asc: &bool) { + + if operate_full_condition(&elements, condition){ + insert_unconditioned(elements, columns_opt, lines_buffer, col_index, asc); + } +} + fn find_insert_position( elements: &Vec, lines_buffer: &Vec>, @@ -946,55 +715,6 @@ fn find_insert_position( } } -/* -fn read_and_save_file(query: &Query, col_filter: i32) -> Result { - // Pre: query, filter and - // Post: - if let Some(table) = &query.table { - let tmp_file_name = get_tmp_file_name(table); - if let Ok(f) = File::open(table) { - match File::create(tmp_file_name) { - Ok(mut tmp_f) => { - let mut line = String::new(); - let mut reader: BufReader = BufReader::new(f); - - let mut read = true; - while read { - if let Ok(x) = reader.read_line(&mut line) { - line = line.replace('\n', ""); - read = x != 0; - if read { - let elements = line_to_vec(&line); - match &query.where_condition { - Some(condition) => save_file_conditioned( - &query.columns, - (col_filter, condition), - &elements, - &mut tmp_f, - ), - None => save_file_unconditional( - &query.columns, - &elements, - &mut tmp_f, - ), - } - line.clear(); - } - } - } - return Ok(0); - } - Err(_) => Err(1), - } - } else { - return Err(1); - } - } else { - return Err(1); - } -} -*/ - fn print_file_unconditional(columns_opt: &Option>, elements: &[String]) { // Pre: Columns vector sorted incremental && Elements of line content vector // Post: print to stdout the correct columns @@ -1039,58 +759,6 @@ fn print_file_conditioned( } } -/* -fn save_file_unconditional(columns_opt: &Option>, elements: &[String], file: &mut File) { - // Pre: Columns vector sorted incremental && Elements of line content vector - // Post: print to stdout the correct columns - - match columns_opt { - Some(columns) => { - // SELECT columns FROM - let mut counter = 0; - while counter < elements.len() { - if columns.contains(&counter) { - if counter == 0 { - file.write(elements[counter].as_bytes()); - } else { - file.write(format!(",{}", elements[counter]).as_bytes()); - } - } - - counter += 1; - } - } - None => { - for (counter, element) in elements.iter().enumerate() { - if counter == 0 { - file.write(element.as_bytes()); - } else { - file.write(format!(",{}", element).as_bytes()); - } - } - } - } - - println!(); -} - -fn save_file_conditioned( - columns_opt: &Option>, - filter: (i32, &Condition), - elements: &[String], - file: &mut File, -) { - let (col_filter, condition) = filter; - if let Some(value) = &condition.value { - if operate_condition(&elements[col_filter as usize], value, &condition.condition) { - save_file_unconditional(columns_opt, elements, file) - } - } else { - save_file_unconditional(columns_opt, elements, file) - } -} -*/ - fn line_to_vec(line: &str) -> Vec { let mut result: Vec = Vec::new(); let mut split = line.split(','); @@ -1203,3 +871,345 @@ mod tests { assert_eq!(rt2, 3); } } + +/* +fn find_filter_column(query: &Query) -> i32 { + let mut col_index_filter = -1; + match &query.where_condition { + Some(x) => match &x.column { + Some(column) => match &query.table { + Some(table) => match File::open(table) { + Ok(file) => { + let mut reader: BufReader = BufReader::new(file); + let mut line = String::new(); + match reader.read_line(&mut line) { + Ok(_) => { + line = line.replace('\n', ""); + let mut split = line.split(','); + let mut element_opt = split.next(); + let mut counter = 0; + + while element_opt.is_some() && col_index_filter < 0 { + if let Some(x) = element_opt { + if x.eq(column) { + col_index_filter = counter; + } + } + counter += 1; + element_opt = split.next(); + } + } + Err(_) => col_index_filter = -1, + } + } + Err(_) => return -1, + }, + None => return -1, + }, + None => { + col_index_filter = -1; + } + }, + None => col_index_filter = -1, + } + col_index_filter +} + +fn save_file_unconditional(columns_opt: &Option>, elements: &[String], file: &mut File) { + // Pre: Columns vector sorted incremental && Elements of line content vector + // Post: print to stdout the correct columns + + match columns_opt { + Some(columns) => { + // SELECT columns FROM + let mut counter = 0; + while counter < elements.len() { + if columns.contains(&counter) { + if counter == 0 { + file.write(elements[counter].as_bytes()); + } else { + file.write(format!(",{}", elements[counter]).as_bytes()); + } + } + + counter += 1; + } + } + None => { + for (counter, element) in elements.iter().enumerate() { + if counter == 0 { + file.write(element.as_bytes()); + } else { + file.write(format!(",{}", element).as_bytes()); + } + } + } + } + + println!(); +} + +fn save_file_conditioned( + columns_opt: &Option>, + filter: (i32, &Condition), + elements: &[String], + file: &mut File, +) { + let (col_filter, condition) = filter; + if let Some(value) = &condition.value { + if operate_condition(&elements[col_filter as usize], value, &condition.condition) { + save_file_unconditional(columns_opt, elements, file) + } + } else { + save_file_unconditional(columns_opt, elements, file) + } +} + +fn read_and_save_file(query: &Query, col_filter: i32) -> Result { + // Pre: query, filter and + // Post: + if let Some(table) = &query.table { + let tmp_file_name = get_tmp_file_name(table); + if let Ok(f) = File::open(table) { + match File::create(tmp_file_name) { + Ok(mut tmp_f) => { + let mut line = String::new(); + let mut reader: BufReader = BufReader::new(f); + + let mut read = true; + while read { + if let Ok(x) = reader.read_line(&mut line) { + line = line.replace('\n', ""); + read = x != 0; + if read { + let elements = line_to_vec(&line); + match &query.where_condition { + Some(condition) => save_file_conditioned( + &query.columns, + (col_filter, condition), + &elements, + &mut tmp_f, + ), + None => save_file_unconditional( + &query.columns, + &elements, + &mut tmp_f, + ), + } + line.clear(); + } + } + } + return Ok(0); + } + Err(_) => Err(1), + } + } else { + return Err(1); + } + } else { + return Err(1); + } +} + +fn sort_and_print_file( + column_number: usize, + query: &Query, + asc: &bool, +) -> Result, u32> { + // Pre: Column number for sorting + // Post: Separates into files, sort them and print them in correct order. Result name of files for cleanup + match &query.table { + None => Err(3), + Some(table) => { + let tmp_unsorted_filename = get_tmp_file_name(table); + match File::open(tmp_unsorted_filename) { + Err(_) => Err(3), + Ok(unsorted_file) => { + let mut reader: BufReader = BufReader::new(unsorted_file); + let mut line = String::new(); + let mut actually_sorting_elements: Vec> = Vec::new(); + + let mut sorted_files: Vec = Vec::new(); + let mut sorted_filenames: Vec = Vec::new(); + let mut counter = 0; + + let mut read = true; + let mut valid_operation = true; + while read { + if let Ok(x) = reader.read_line(&mut line) { + line = line.replace('\n', ""); + read = x != 0; + + let element = text_to_vec(&line, true); + if counter < FILE_SORT_BUFFER { + actually_sorting_elements.insert( + find_sorted_position( + &actually_sorting_elements, + &element, + column_number, + asc, + ), + element, + ); + } else { + let mut new_file = String::from(format!(".{}", sorted_files.len())); + new_file.push_str(&tmp_unsorted_filename); + match File::create(new_file) { + Ok(f) => { + for element in actually_sorting_elements { + let mut write_line = String::new(); + for (counter, word) in element.iter().enumerate() { + if counter == 0 { + f.write(word.as_bytes()); + } else { + f.write(format!(",{}", &word)); + } + } + } + sorted_files.push(f); + sorted_filenames.push(new_file); + actually_sorting_elements.clear(); + } + Err(_) => { + read = false; + valid_operation = false; + } + } + } + } else { + valid_operation = false; + read = false; + } + } + + if valid_operation { + Ok(sorted_filenames) + } else { + Err(3) + } + } + } + } + } +} + + +fn file_cleanup(files: Vec) { + for file in files { + let _ = remove_file(file); + } +} + +fn find_sorted_position( + sorted_vec: &Vec>, + new_element: &Vec, + column_number: usize, + asc: &bool, +) -> usize { + // Insert into shifts everything to right. + 0 +} + +fn insert_conditioned(elements: &[String], columns_opt: &Option>, lines_buffer: &mut Vec>, col_index: &usize, filter: &Condition) { +let (col_filter, condition) = filter; + if let Some(value) = &condition.value { + if operate_condition(&elements[col_filter as usize], value, &condition.condition) { + print_file_unconditional(columns_opt, elements) + } + } else { + print_file_unconditional(columns_opt, elements) + } +} + +fn exec_query_select(query: Query) { + match &query.order_by { + Some((column, asc)) => { + let col_index: i32 = find_filter_column(&query); + if read_and_save_file(&query, col_index).is_ok() { + if let Some(column_number) = find_column(&query, column) { + if let Ok(tmp_files) = sort_and_print_file(column_number, &query, asc) { + file_cleanup(tmp_files); + } + } + } + } + None => { + let col_index: i32 = find_filter_column(&query); + read_and_print_file(&query, col_index); + } + } +} + +fn get_next_line(lines_buffer: &mut Vec>, readers: &mut Vec>, col_index: usize, asc: &bool) -> Option> { + // Post: Next line in order, if not fully read + let mut line = String::new(); + match find_available_reader(&readers) { + None => None, + Some(mut candidate) => { + let mut counter = candidate + 1; + while counter < readers.len() { + if readers[counter].0 < FILE_SORT_BUFFER && counter != candidate { + if *asc { + if lines_buffer[counter][col_index] < lines_buffer[candidate][col_index] { + candidate = counter; + } + } else { + if lines_buffer[counter][col_index] > lines_buffer[candidate][col_index] { + candidate = counter; + } + } + } + + counter += 1; + } + + if counter == readers.len() { + None + } else { + let new_line: Vec; + match readers[candidate].1.read_line(&mut line){ + Err(_) => new_line = Vec::new(), + Ok(read_result) => { + if read_result == 0 { + new_line = Vec::new(); // If this happen, then never read again from here + readers[candidate].0 = FILE_SORT_BUFFER; + } else { + lines_buffer.push(text_to_vec(&line, true)); + let len = lines_buffer.len(); + lines_buffer.swap(candidate,len - 1); + match lines_buffer.pop() { + Some(x) => { + new_line = x; + readers[candidate].0 += 1; + }, + None => { + new_line = Vec::new(); // If this happen, then never read again from here + readers[candidate].0 = FILE_SORT_BUFFER; + } + } + } + } + } + + Some(new_line) + } + } + } +} + +fn find_available_reader(readers: &Vec>) -> Option { + // Pre: Readers + // Post: First available reader position + let mut counter = 0; + while counter < readers.len() && ! &readers[counter].0 < FILE_SORT_BUFFER { + counter += 1; + } + + if counter == readers.len() { + None + } else { + Some(counter) + } +} +*/ From fa2b4210d2e7ad24cbf6c049d70313c013a95393 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 22 Sep 2024 23:46:44 -0300 Subject: [PATCH 52/58] OK: SELECT * FROM clientes WHERE AND AND AND AND --- README.md | 28 ++++++++-------------------- src/condition/condition_type.rs | 4 +++- src/libs/parsing.rs | 6 +++--- 3 files changed, 14 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 5dcc780..02ea620 100644 --- a/README.md +++ b/README.md @@ -4,35 +4,23 @@ ### Detalles de entrega -El trabajo no se encuentra completo. - Pendientes: -1. Funcionalidad: Logica booleana en WHERE - -2. Funcionalidad: SELECT c/ ORDER BY condicionado ( con WHERE, se implementará primero la logica booleana y luego este punto ) - -3. Testing (mas test unitarios e integración) +1. Testing (mas test unitarios e integración) -4. Documentación de funciones +2. Documentación de funciones -5. Refactor de funciones para que tengan menos de 30 lineas. Por una cuestión de tiempos se deja para el final. +3. Refactor de funciones para que tengan menos de 30 lineas. Por una cuestión de tiempos se deja para el final. Funcionalidades probadas OK -1. SELECT * FROM - -2. SELECT columnas FROM - -3. SELECT c/ WHERE (basico) - -4. INSERT INTO +1. SELECT -5. UPDATE +2. INSERT INTO -6. DELETE FROM WHERE (basico) +3. UPDATE -7. SELECT c/ ORDER BY incondicional +4. DELETE FROM ### Detalles de implementación @@ -40,7 +28,7 @@ Logica booleana: Se implemento por medio de un vector de vectores. Por cada OR s Esta implementación tiene como problema que un query con el condicional WHERE A AND AND AND {...} B resulta en WHERE A AND B. Como solución simple se planteó un chequeo en parseo que si se encuentra un condicional AND, se chequeará que el largo sea tal que el condicional sea válido, y que el proximo elemento no sea AND u OR. -Para la lógica booleana tambien se considero un arbol binario de expresiones booleanas (https://en.wikipedia.org/wiki/Binary_expression_tree). No se logró implementar debido a problemas con el manejo de memoria en Rust, aunque en mi opinión es la mejor implementación posible. +Para la lógica booleana tambien se considero un arbol binario de expresiones booleanas (https://en.wikipedia.org/wiki/Binary_expression_tree). No se logró implementar debido a problemas con el manejo de memoria en Rust, aunque en mi opinión creo que es la mejor implementación posible. Para en ORDER BY no cargar las tablas completas en memoria se eligió "Full external sort" (https://cs186berkeley.net/notes/note8/) diff --git a/src/condition/condition_type.rs b/src/condition/condition_type.rs index 1208d80..148594f 100644 --- a/src/condition/condition_type.rs +++ b/src/condition/condition_type.rs @@ -13,9 +13,11 @@ pub enum BooleanOperator { I // identity. } +/* impl PartialEq for BooleanOperator { fn eq(&self, other: &Self) -> bool { self == other } } -impl Eq for BooleanOperator {} \ No newline at end of file +impl Eq for BooleanOperator {} +*/ \ No newline at end of file diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 7a134b0..19c2e70 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -3,15 +3,15 @@ use std::io::{BufRead, BufReader}; use crate::condition::{build_not_condition, build_condition, Condition}; //use crate::condition::complex_condition::{add_node_to_tree, build_complex_condition, build_simple_condition, ComplexCondition, tree_check, check_precedence}; -use crate::condition::condition_type::{BooleanOperator, ConditionOperator}; +use crate::condition::condition_type::ConditionOperator; //use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, get_where_columns, tree_check, ComplexCondition, Condition}; // use crate::condition::Condition; use crate::libs::error; -use crate::query::{self, build_empty_query}; +use crate::query::build_empty_query; use crate::query::query_type::QueryType; use crate::query::{Query, DELETE_MIN_LEN, INSERT_MIN_LEN, SELECT_MIN_LEN, UPDATE_MIN_LEN}; -use super::error::{DELETE_MAL_FORMATEADO, SELECT_MAL_FORMATEADO, WHERE_MAL_FORMATEADO}; +use super::error::{DELETE_MAL_FORMATEADO, WHERE_MAL_FORMATEADO}; pub fn build_query(text_query: &String, path: &String) -> Result { // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build From 823beaf1ff3bdb34115d972eafb31ecd7d21e9bc Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Mon, 23 Sep 2024 00:07:02 -0300 Subject: [PATCH 53/58] FMT + Clippy 1 warning --- README.md | 1 - src/condition.rs | 43 ++++++----- src/condition/condition_type.rs | 18 ++--- src/libs/exec.rs | 127 +++++++++++++++---------------- src/libs/parsing.rs | 129 ++++++++++++++++++-------------- src/query.rs | 14 ++-- 6 files changed, 172 insertions(+), 160 deletions(-) diff --git a/README.md b/README.md index 02ea620..0cd7af8 100644 --- a/README.md +++ b/README.md @@ -31,4 +31,3 @@ Esta implementación tiene como problema que un query con el condicional WHERE A Para la lógica booleana tambien se considero un arbol binario de expresiones booleanas (https://en.wikipedia.org/wiki/Binary_expression_tree). No se logró implementar debido a problemas con el manejo de memoria en Rust, aunque en mi opinión creo que es la mejor implementación posible. Para en ORDER BY no cargar las tablas completas en memoria se eligió "Full external sort" (https://cs186berkeley.net/notes/note8/) - diff --git a/src/condition.rs b/src/condition.rs index 3d33f55..6a79490 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -3,7 +3,6 @@ pub mod condition_type; // use condition_type::BooleanOperator; // use crate::libs::error; - use condition_type::ConditionOperator; pub struct Condition { @@ -14,9 +13,9 @@ pub struct Condition { pub fn build_not_condition() -> Condition { Condition { - condition: ConditionOperator::Equal, - column: None, - value: None + condition: ConditionOperator::Equal, + column: None, + value: None, } } @@ -52,34 +51,42 @@ pub fn operate_condition(v1: &String, v2: &String, operator: &ConditionOperator) } } -pub fn operate_full_condition(elements: &[String], condition: &Vec>) -> bool { - // Pre: Line to vec and condition (bool vector). +pub fn operate_full_condition(elements: &[String], condition: &[Vec]) -> bool { + // Pre: Line to vec and condition (bool vector). // Post: Bool if condition applies or not - let mut or_valid = false; - let mut or_counter = 0; + let mut or_valid = false; + let mut or_counter = 0; - let mut and_valid ; - let mut and_counter; - let mut not_detected ; + let mut and_valid; + let mut and_counter; + let mut not_detected; - while or_counter < condition.len() && ! or_valid { + while or_counter < condition.len() && !or_valid { and_valid = true; and_counter = 0; not_detected = false; while and_counter < condition[or_counter].len() && and_valid { match &condition[or_counter][and_counter].column { - None => not_detected = ! not_detected, + None => not_detected = !not_detected, Some(column) => match &condition[or_counter][and_counter].value { None => return false, Some(value) => { if not_detected { - and_valid = ! operate_condition(&elements[*column], value, &condition[or_counter][and_counter].condition) + and_valid = !operate_condition( + &elements[*column], + value, + &condition[or_counter][and_counter].condition, + ) } else { - and_valid = operate_condition(&elements[*column], value, &condition[or_counter][and_counter].condition); + and_valid = operate_condition( + &elements[*column], + value, + &condition[or_counter][and_counter].condition, + ); } } - } + }, } and_counter += 1; @@ -87,8 +94,8 @@ pub fn operate_full_condition(elements: &[String], condition: &Vec bool { self == other } } impl Eq for BooleanOperator {} -*/ \ No newline at end of file +*/ diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 0782a2a..8e9e4ca 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -33,7 +33,7 @@ fn exec_query_delete(query: Query) { Ok(mut tmp_file) => { let mut reader: BufReader = BufReader::new(file); let mut line = String::new(); - + let mut read = true; while read { if let Ok(x) = reader.read_line(&mut line) { @@ -41,10 +41,7 @@ fn exec_query_delete(query: Query) { read = x != 0; if read { let elements = line_to_vec(&line); - if !operate_full_condition( - &elements, - cond - ) { + if !operate_full_condition(&elements, cond) { line.push('\n'); if let Err(_error) = tmp_file.write(line.as_bytes()) { read = false; @@ -63,7 +60,7 @@ fn exec_query_delete(query: Query) { }, Err(_) => valid_operation = false, } - + if remove_old_file(table, &tmp_file_name, valid_operation).is_err() { println!("Error en manipulación de archivos"); } @@ -117,7 +114,7 @@ fn exec_query_select(query: Query) { } } None => { -// let col_index: i32 = find_filter_column(&query); + // let col_index: i32 = find_filter_column(&query); read_and_print_file(&query); } } @@ -271,65 +268,61 @@ fn create_readers(files: &[String]) -> Option>> { fn exec_query_update(query: Query) { if let Some(cond) = &query.where_condition { - if let Some(columns) = &query.columns { - if let Some(values) = &query.values { - if let Some(table) = &query.table { - let tmp_file = get_tmp_file_name(table); - let mut valid_operation = true; - match File::open(table) { - Ok(file) => match File::create(&tmp_file) { - Ok(mut tmp_file) => { - let mut reader: BufReader = BufReader::new(file); - let mut line = String::new(); - - let mut read = true; - while read { - if let Ok(x) = reader.read_line(&mut line) { - read = x != 0; - if read { - line = line.replace('\n', ""); - let elements = line_to_vec(&line); - if !operate_full_condition( - &elements, - cond + if let Some(columns) = &query.columns { + if let Some(values) = &query.values { + if let Some(table) = &query.table { + let tmp_file = get_tmp_file_name(table); + let mut valid_operation = true; + match File::open(table) { + Ok(file) => match File::create(&tmp_file) { + Ok(mut tmp_file) => { + let mut reader: BufReader = BufReader::new(file); + let mut line = String::new(); + + let mut read = true; + while read { + if let Ok(x) = reader.read_line(&mut line) { + read = x != 0; + if read { + line = line.replace('\n', ""); + let elements = line_to_vec(&line); + if !operate_full_condition(&elements, cond) { + // Line not updated + line.push('\n'); + if let Err(_error) = tmp_file.write(line.as_bytes()) + { + read = false; + valid_operation = false; + } + } else { + // Update Line + if let Err(_error) = tmp_file.write( + update_line(&elements, columns, values) + .as_bytes(), ) { - // Line not updated - line.push('\n'); - if let Err(_error) = - tmp_file.write(line.as_bytes()) - { - read = false; - valid_operation = false; - } - } else { - // Update Line - if let Err(_error) = tmp_file.write( - update_line(&elements, columns, values) - .as_bytes(), - ) { - read = false; - valid_operation = false; - } + read = false; + valid_operation = false; } } - line.clear(); - } else { - read = false; - valid_operation = false; } + line.clear(); + } else { + read = false; + valid_operation = false; } } - Err(_) => valid_operation = false, - }, + } Err(_) => valid_operation = false, - } + }, + Err(_) => valid_operation = false, + } - if remove_old_file(table, &tmp_file, valid_operation).is_err() { - println!("Error en manipulación de archivos"); - } + if remove_old_file(table, &tmp_file, valid_operation).is_err() { + println!("Error en manipulación de archivos"); } } } + } } } @@ -468,11 +461,9 @@ fn read_and_print_file(query: &Query) { if read { let elements = line_to_vec(&line); match &query.where_condition { - Some(condition) => print_file_conditioned( - &query.columns, - &condition, - &elements, - ), + Some(condition) => { + print_file_conditioned(&query.columns, condition, &elements) + } None => print_file_unconditional(&query.columns, &elements), } line.clear(); @@ -645,15 +636,15 @@ fn insert_unconditioned( fn insert_conditioned( elements: Vec, - condition: &Vec>, + condition: &[Vec], columns_opt: &Option>, lines_buffer: &mut Vec>, col_index: &usize, - asc: &bool) { - - if operate_full_condition(&elements, condition){ + asc: &bool, +) { + if operate_full_condition(&elements, condition) { insert_unconditioned(elements, columns_opt, lines_buffer, col_index, asc); - } + } } fn find_insert_position( @@ -751,10 +742,10 @@ fn print_file_unconditional(columns_opt: &Option>, elements: &[String fn print_file_conditioned( columns_opt: &Option>, - condition: &Vec>, + condition: &[Vec], elements: &[String], ) { - if operate_full_condition(&elements, condition) { + if operate_full_condition(elements, condition) { print_file_unconditional(columns_opt, elements) } } @@ -872,7 +863,7 @@ mod tests { } } -/* +/* fn find_filter_column(query: &Query) -> i32 { let mut col_index_filter = -1; match &query.where_condition { diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 19c2e70..35fea44 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -1,7 +1,7 @@ use std::fs::File; use std::io::{BufRead, BufReader}; -use crate::condition::{build_not_condition, build_condition, Condition}; +use crate::condition::{build_condition, build_not_condition, Condition}; //use crate::condition::complex_condition::{add_node_to_tree, build_complex_condition, build_simple_condition, ComplexCondition, tree_check, check_precedence}; use crate::condition::condition_type::ConditionOperator; //use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, get_where_columns, tree_check, ComplexCondition, Condition}; @@ -44,14 +44,14 @@ fn separate_args_delete(args: &[String], path: &String, result: &mut Query) -> R return Err(error::DELETE_MAL_FORMATEADO); } else if args[3].eq("WHERE") { let mut counter: usize = 4; - match parse_where_condition(&result, args, &mut counter) { + match parse_where_condition(result, args, &mut counter) { Ok(cond) => result.where_condition = Some(cond), - Err(x) => return Err(x) - } - } else{ + Err(x) => return Err(x), + } + } else { return Err(DELETE_MAL_FORMATEADO); } - + Ok(0) } } @@ -117,9 +117,9 @@ fn separate_args_update(args: &[String], path: &String, result: &mut Query) -> R } result.values = Some(values); - match parse_where_condition(&result, args, &mut counter) { + match parse_where_condition(result, args, &mut counter) { Ok(cond) => result.where_condition = Some(cond), - Err(x) => return Err(x) + Err(x) => return Err(x), } Ok(0) @@ -156,9 +156,9 @@ fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> R Ok(0) } else if args[counter].eq("WHERE") { counter += 1; - match parse_where_condition(&result, args, &mut counter) { + match parse_where_condition(result, args, &mut counter) { Ok(cond) => result.where_condition = Some(cond), - Err(x) => return Err(x) + Err(x) => return Err(x), } if counter < args.len() { @@ -182,8 +182,7 @@ fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> R } } Ok(0) - } - else { + } else { Err(WHERE_MAL_FORMATEADO) } } @@ -216,86 +215,102 @@ fn get_columns_position(query: &Query, string_cols: &[String]) -> Result Result>,u32> { +fn parse_where_condition( + query: &Query, + args: &[String], + counter: &mut usize, +) -> Result>, u32> { // Pre: Query args and counter - // Post: Complex condition for query + // Post: Complex condition for query if args[*counter].eq("AND") || args[*counter].eq("OR") { - Err(WHERE_MAL_FORMATEADO) + Err(WHERE_MAL_FORMATEADO) } else { - // Parse into boolean vector + // Parse into boolean vector let mut result: Vec> = Vec::new(); result.push(Vec::new()); - while *counter < args.len() && ! args[*counter].eq("ORDER") { + while *counter < args.len() && !args[*counter].eq("ORDER") { match parse_next_condition(query, args, counter, &mut result) { Ok(_) => continue, - Err(x) => return Err(x) + Err(x) => return Err(x), } } - // Check valid result - if check_valid_bool(&result){ + // Check valid result + if check_valid_bool(&result) { Ok(result) } else { - Err(WHERE_MAL_FORMATEADO) + Err(WHERE_MAL_FORMATEADO) } } } -fn parse_next_condition(query: &Query, args: &[String], counter: &mut usize, vec: &mut Vec> ) -> Result { - if args[*counter].eq("OR") { - if ! *counter + 2 < args.len() { - return Err(WHERE_MAL_FORMATEADO); - } else if args[*counter + 1].eq("AND") || args[*counter + 1].eq("OR") { - return Err(WHERE_MAL_FORMATEADO); - } +fn parse_next_condition( + query: &Query, + args: &[String], + counter: &mut usize, + vec: &mut Vec>, +) -> Result { + if !*counter + 2 < args.len() { + return Err(WHERE_MAL_FORMATEADO); + } else if args[*counter + 1].eq("AND") || args[*counter + 1].eq("OR") { + return Err(WHERE_MAL_FORMATEADO); + } else if args[*counter].eq("OR") { vec.push(Vec::new()); *counter += 1; } else if args[*counter].eq("AND") { - if ! *counter + 2 < args.len() { - return Err(WHERE_MAL_FORMATEADO); - } else if args[*counter + 1].eq("AND") || args[*counter + 1].eq("OR") { - return Err(WHERE_MAL_FORMATEADO); - } *counter += 1; } else if args[*counter].eq("NOT") { - if ! *counter + 2 < args.len() { - return Err(WHERE_MAL_FORMATEADO); - } else if args[*counter + 1].eq("AND") || args[*counter + 1].eq("OR") { - return Err(WHERE_MAL_FORMATEADO); - } let position = vec.len() - 1; - vec[position].push(build_not_condition()); // String vacio + vec[position].push(build_not_condition()); // String vacio *counter += 1; - } else if *counter + 2 < args.len() { + } else { match get_columns_position(query, &[args[*counter].to_string()]) { Err(x) => return Err(x), Ok(x) => { let simple_condition: Condition = if args[*counter + 1].eq("<") { - build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::Minor) + build_condition( + x[0], + args[*counter + 2].to_string(), + ConditionOperator::Minor, + ) } else if args[*counter + 1].eq("<=") { - build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::MinorEqual) + build_condition( + x[0], + args[*counter + 2].to_string(), + ConditionOperator::MinorEqual, + ) } else if args[*counter + 1].eq("=") { - build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::Equal) + build_condition( + x[0], + args[*counter + 2].to_string(), + ConditionOperator::Equal, + ) } else if args[*counter + 1].eq(">=") { - build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::HigherEqual) + build_condition( + x[0], + args[*counter + 2].to_string(), + ConditionOperator::HigherEqual, + ) } else if args[*counter + 1].eq(">") { - build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::Higher) + build_condition( + x[0], + args[*counter + 2].to_string(), + ConditionOperator::Higher, + ) } else { - return Err(WHERE_MAL_FORMATEADO) + return Err(WHERE_MAL_FORMATEADO); }; let position = vec.len() - 1; vec[position].push(simple_condition); *counter += 3; } } - } else { - return Err(WHERE_MAL_FORMATEADO) } Ok(0) } -fn check_valid_bool(boolean_expresion: &Vec>) -> bool { +fn check_valid_bool(boolean_expresion: &[Vec]) -> bool { // Pre: Boolean vector // Post: Bool for valid or invalid let mut valid = true; @@ -307,12 +322,12 @@ fn check_valid_bool(boolean_expresion: &Vec>) -> bool { sub_counter = 0; while sub_counter < boolean_expresion[counter].len() && valid { - open_not = ! ( open_not && boolean_expresion[counter][sub_counter].value.is_some() ); + open_not = !(open_not && boolean_expresion[counter][sub_counter].value.is_some()); sub_counter += 1; - } + } - valid = ! open_not; - counter += 1; + valid = !open_not; + counter += 1; } valid @@ -614,7 +629,7 @@ mod tests { } } -/* +/* fn check_columns_contains_condition(columns: Vec, query: Query) -> Result { // TODO match get_where_columns(&query) { @@ -644,10 +659,10 @@ fn get_condition_node(query: &Query, args: &[String], counter: &mut usize) -> Re new_node = build_complex_condition(BooleanOperator::AND, None, None); *counter += 1; } else if args[*counter].eq("OR") { - new_node = build_complex_condition(BooleanOperator::OR, None, None); + new_node = build_complex_condition(BooleanOperator::OR, None, None); *counter += 1; } else if args[*counter].eq("NOT") { - new_node = build_complex_condition(BooleanOperator::NOT, None, None); + new_node = build_complex_condition(BooleanOperator::NOT, None, None); *counter += 1; } else if *counter + 3 < args.len() { match get_columns_position(query, &[args[*counter].to_string()]) { @@ -664,7 +679,7 @@ fn get_condition_node(query: &Query, args: &[String], counter: &mut usize) -> Re } else if args[*counter + 2].eq(">") { build_condition(x[0], args[*counter + 2].to_string(), ConditionOperator::Higher) } else { - return Err(WHERE_MAL_FORMATEADO) + return Err(WHERE_MAL_FORMATEADO) }; new_node = build_simple_condition(Some(simple_condition)); *counter += 3; diff --git a/src/query.rs b/src/query.rs index 9754348..4bcca37 100644 --- a/src/query.rs +++ b/src/query.rs @@ -3,7 +3,7 @@ pub mod query_type; use query_type::QueryType; use crate::condition::Condition; -//use crate::complex_condition::ComplexCondition, +//use crate::complex_condition::ComplexCondition, // use crate::condition::ComplexCondition; @@ -13,12 +13,12 @@ pub static SELECT_MIN_LEN: usize = 4; // SELECT * FROM tabla pub static UPDATE_MIN_LEN: usize = 10; // UPDATE tabla SET col = valor WHERE a < b pub struct Query { - pub operation: Option, // DELETE, INSERT, SELECT, UPDATE - pub table: Option, // DELETE, INSERT, SELECT, UPDATE - pub columns: Option>, // INSERT, SELECT, UPDATE - pub where_condition: Option>>, // DELETE (always), SELECT (sometimes), UPDATE (always) . - pub order_by: Option<(String, bool)>, // SELECT (sometimes) - pub values: Option>, // INSERT, UPDATE (in update is set) + pub operation: Option, // DELETE, INSERT, SELECT, UPDATE + pub table: Option, // DELETE, INSERT, SELECT, UPDATE + pub columns: Option>, // INSERT, SELECT, UPDATE + pub where_condition: Option>>, // DELETE (always), SELECT (sometimes), UPDATE (always) . + pub order_by: Option<(String, bool)>, // SELECT (sometimes) + pub values: Option>, // INSERT, UPDATE (in update is set) } pub fn build_empty_query() -> Query { From f663419fdc3bd773c41b0ae14b7866cb685c30ea Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Mon, 23 Sep 2024 20:27:26 -0300 Subject: [PATCH 54/58] WIP: doc --- src/condition.rs | 14 +++++--- src/libs/exec.rs | 39 +++++++++++++++-------- src/libs/parsing.rs | 78 ++++++++++++++++++++++++++++++++------------- src/query.rs | 4 +-- 4 files changed, 91 insertions(+), 44 deletions(-) diff --git a/src/condition.rs b/src/condition.rs index 6a79490..aa2c7ff 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -11,6 +11,7 @@ pub struct Condition { pub value: Option, } +/// Constructor for not condition pub fn build_not_condition() -> Condition { Condition { condition: ConditionOperator::Equal, @@ -19,6 +20,7 @@ pub fn build_not_condition() -> Condition { } } +/// Constructor for general condition (simple expression, non boolean) pub fn build_condition(column: usize, value: String, cond: ConditionOperator) -> Condition { Condition { condition: cond, @@ -27,9 +29,11 @@ pub fn build_condition(column: usize, value: String, cond: ConditionOperator) -> } } +/// Returns string (or int if it's parseable as int) comparison +/// +/// Pre: Strings and operator +/// Post: True if condition applies pub fn operate_condition(v1: &String, v2: &String, operator: &ConditionOperator) -> bool { - // Pre: Strings and operator - // Post: Bool if condition applies or not ( operates string and int ) if let Ok(x1) = v1.parse::() { if let Ok(x2) = v2.parse::() { match operator { @@ -51,9 +55,11 @@ pub fn operate_condition(v1: &String, v2: &String, operator: &ConditionOperator) } } +/// Returns the result of applying the condition to the lineW +/// +/// Pre: Line to vec and condition (bool vector). +/// Post: Bool if condition applies or not pub fn operate_full_condition(elements: &[String], condition: &[Vec]) -> bool { - // Pre: Line to vec and condition (bool vector). - // Post: Bool if condition applies or not let mut or_valid = false; let mut or_counter = 0; diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 8e9e4ca..d7d7133 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -11,6 +11,8 @@ use super::parsing::{self, get_file_first_line, text_to_vec}; static FILE_SORT_BUFFER: usize = 3; +/// Main execution function, execs query +/// By definition, if something is wrong with the query, then it should do nothing pub fn exec_query(query: Query) { if let Some(op) = &query.operation { match op { @@ -22,6 +24,7 @@ pub fn exec_query(query: Query) { } } +/// Exec query: Special case for delete fn exec_query_delete(query: Query) { if let Some(cond) = &query.where_condition { if let Some(table) = &query.table { @@ -68,6 +71,7 @@ fn exec_query_delete(query: Query) { } } +/// Exec query: Special case for insert fn exec_query_insert(query: Query) { if let Some(table) = &query.table { if let Some(write_columns) = &query.columns { @@ -102,6 +106,7 @@ fn exec_query_insert(query: Query) { } } +/// Exec query: Special case for select fn exec_query_select(query: Query) { match &query.order_by { Some((column, asc)) => { @@ -120,15 +125,18 @@ fn exec_query_select(query: Query) { } } +/// Cleans tmp files +/// Pre: filenames +/// Post: Cleans files fn file_cleanup(files: &Vec) { for file in files { let _ = remove_file(file); } } +/// Pre: Name of tmp_files, column for ordering and selector of asc/desc +/// Post: Prints from tmp_files in order fn print_sorted_files(files: &[String], col_index: &usize, asc: &bool) { - // Pre: Name of tmp_files, column for ordering and selector of asc/desc - // Post: Prints from tmp_files in order if let Some(mut readers) = create_readers(files) { if let Some(mut lines_buffer) = readers_read_first_line(&mut readers) { // While there are lines to be printed @@ -152,15 +160,15 @@ fn print_sorted_files(files: &[String], col_index: &usize, asc: &bool) { } } +/// Gets next sorted line from mem's buffer and replace it with the next line on that file +/// Pre: Lines buffer, readers, col index for sorting and ascending/descending bool +/// Post: Next line, if not fully read fn get_next_line( lines_buffer: &mut Vec>, readers: &mut [BufReader], col_index: usize, asc: &bool, ) -> Option> { - // Pre: Lines buffer, readers, col index for sorting and ascending/descending bool - // Post: Next line, if not fully read - let mut line = String::new(); match find_next_line(lines_buffer, col_index, asc) { Some(reader_index) => match &readers[reader_index].read_line(&mut line) { @@ -184,10 +192,10 @@ fn get_next_line( } } +/// Find next sorted line's index to be printed +/// Pre: Lines buffer, col index and ascending/descending +/// Post: Index of next line, if any fn find_next_line(lines_buffer: &mut [Vec], col_index: usize, asc: &bool) -> Option { - // Pre: Lines buffer, col index and ascending/descending - // Post: Index of next line, if any - // Find first line let mut candidate = 0; while candidate < lines_buffer.len() && lines_buffer[candidate].is_empty() { @@ -224,6 +232,9 @@ fn find_next_line(lines_buffer: &mut [Vec], col_index: usize, asc: &bool } } +/// Read first line from all files +/// Pre: Lines buffer, col index and ascending/descending +/// Post: Index of next line, if any fn readers_read_first_line(readers: &mut Vec>) -> Option>> { let mut result: Vec> = Vec::new(); let mut line = String::new(); @@ -241,6 +252,9 @@ fn readers_read_first_line(readers: &mut Vec>) -> Option Option>> { let mut valid = true; let mut readers: Vec> = Vec::new(); @@ -263,9 +277,6 @@ fn create_readers(files: &[String]) -> Option>> { } } -/* -*/ - fn exec_query_update(query: Query) { if let Some(cond) = &query.where_condition { if let Some(columns) = &query.columns { @@ -706,10 +717,9 @@ fn find_insert_position( } } +/// Pre: Columns vector sorted && Elements of line content vector +/// Post: print to stdout the correct columns fn print_file_unconditional(columns_opt: &Option>, elements: &[String]) { - // Pre: Columns vector sorted incremental && Elements of line content vector - // Post: print to stdout the correct columns - match columns_opt { Some(columns) => { // SELECT columns FROM @@ -750,6 +760,7 @@ fn print_file_conditioned( } } +/// Aux function. Tokenizer for special cases fn line_to_vec(line: &str) -> Vec { let mut result: Vec = Vec::new(); let mut split = line.split(','); diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 35fea44..d2988c2 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -13,8 +13,8 @@ use crate::query::{Query, DELETE_MIN_LEN, INSERT_MIN_LEN, SELECT_MIN_LEN, UPDATE use super::error::{DELETE_MAL_FORMATEADO, WHERE_MAL_FORMATEADO}; +/// Build query for execution pub fn build_query(text_query: &String, path: &String) -> Result { - // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build let args = text_to_vec(text_query, false); match vec_to_query(&args, path) { Ok(x) => validate_query(x), @@ -22,6 +22,12 @@ pub fn build_query(text_query: &String, path: &String) -> Result { } } +/// Merge table and path. Aux funcion +/// +/// ``` +/// let result = merge_table_and_path(String::from("tablas"), "clientes.csv"); +/// assert!(result,String::from("tablas/clientes.csv")); +/// ``` fn merge_table_and_path(path: &String, table: &str) -> String { let mut table_full: String = path.to_string(); table_full.push('/'); @@ -31,7 +37,8 @@ fn merge_table_and_path(path: &String, table: &str) -> String { table_full } -fn separate_args_delete(args: &[String], path: &String, result: &mut Query) -> Result { +/// Parse args from vec to query (special case for delete) +fn parse_args_delete(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < DELETE_MIN_LEN { Err(error::DELETE_MAL_FORMATEADO) } else { @@ -56,7 +63,8 @@ fn separate_args_delete(args: &[String], path: &String, result: &mut Query) -> R } } -fn separate_args_insert(args: &[String], path: &String, result: &mut Query) -> Result { +/// Parse args from vec to query (special case for insert) +fn parse_args_insert(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < INSERT_MIN_LEN { Err(error::INSERT_MAL_FORMATEADO) } else { @@ -89,7 +97,8 @@ fn separate_args_insert(args: &[String], path: &String, result: &mut Query) -> R } } -fn separate_args_update(args: &[String], path: &String, result: &mut Query) -> Result { +/// Parse args from vec to query (special case for update) +fn parse_args_update(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < UPDATE_MIN_LEN { Err(error::UPDATE_MAL_FORMATEADO) } else { @@ -126,7 +135,8 @@ fn separate_args_update(args: &[String], path: &String, result: &mut Query) -> R } } -fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> Result { +/// Parse args from vec to query (special case for select) +fn parse_args_select(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < SELECT_MIN_LEN { Err(error::SELECT_MAL_FORMATEADO) } else { @@ -188,8 +198,9 @@ fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> R } } +/// Aux Function. parse from string columns to the index of the columns in the table +/// All columns should be in the table fn get_columns_position(query: &Query, string_cols: &[String]) -> Result, u32> { - // From string match get_file_first_line(query) { Some(line) => { let mut result: Vec = Vec::new(); @@ -215,13 +226,19 @@ fn get_columns_position(query: &Query, string_cols: &[String]) -> Result, counter = 8 fn parse_where_condition( query: &Query, args: &[String], counter: &mut usize, ) -> Result>, u32> { - // Pre: Query args and counter - // Post: Complex condition for query if args[*counter].eq("AND") || args[*counter].eq("OR") { Err(WHERE_MAL_FORMATEADO) } else { @@ -244,6 +261,8 @@ fn parse_where_condition( } } +/// Pre: Query, args, position counter and wip vector +/// Post: Parses the next simple condition into boolean vector fn parse_next_condition( query: &Query, args: &[String], @@ -310,9 +329,9 @@ fn parse_next_condition( Ok(0) } +// Pre: Boolean vector (parsed boolean condition) +// Post: Bool for valid or invalid result fn check_valid_bool(boolean_expresion: &[Vec]) -> bool { - // Pre: Boolean vector - // Post: Bool for valid or invalid let mut valid = true; let mut counter = 0; let mut sub_counter; @@ -333,6 +352,8 @@ fn check_valid_bool(boolean_expresion: &[Vec]) -> bool { valid } + +/// find column position fn find_column_position(column_name: &String, columns: &[String]) -> Result { let mut counter = 0; while counter < columns.len() { @@ -345,8 +366,8 @@ fn find_column_position(column_name: &String, columns: &[String]) -> Result Result { - // Check correct operation sintaxis let operation = &args[0]; if operation.eq("DELETE") { check_delete_format(args) @@ -361,6 +382,7 @@ fn check_operation_format(args: &[String]) -> Result { } } +/// Check correct operation sintaxis (special case for delete) fn check_delete_format(args: &[String]) -> Result { let non_valid_keywords = vec![ "INSERT", "INTO", "VALUES", "SELECT", "ORDER", "BY", "UPDATE", "SET", @@ -375,6 +397,7 @@ fn check_delete_format(args: &[String]) -> Result { } } +/// Check correct operation sintaxis (special case for insert) fn check_insert_format(args: &[String]) -> Result { let non_valid_keywords = vec![ "DELETE", "FROM", "SELECT", "ORDER", "BY", "UPDATE", "SET", "WHERE", "AND", "OR", "NOT", @@ -400,6 +423,7 @@ fn check_insert_format(args: &[String]) -> Result { } } +/// Check correct operation sintaxis (special case for select) fn check_select_format(args: &[String]) -> Result { let non_valid_keywords = vec!["DELETE", "INSERT", "INTO", "VALUES", "UPDATE", "SET"]; if check_non_valid_keywords(args, non_valid_keywords) { @@ -410,6 +434,7 @@ fn check_select_format(args: &[String]) -> Result { } } +/// Check correct operation sintaxis (special case for update) fn check_update_format(args: &[String]) -> Result { let non_valid_keywords = vec![ "DELETE", "FROM", "INSERT", "INTO", "SELECT", "VALUES", "ORDER", "BY", @@ -424,8 +449,8 @@ fn check_update_format(args: &[String]) -> Result { } } +/// Check if args for query contains non valid keywords fn check_non_valid_keywords(args: &[String], non_valid_keywords: Vec<&str>) -> bool { - // Checks if args contains any non valid keyword let mut result = true; let mut counter = 0; @@ -440,9 +465,9 @@ fn check_non_valid_keywords(args: &[String], non_valid_keywords: Vec<&str>) -> b result } +/// Pre: Sintactical query OK +/// Post: Valid query for execution fn validate_query(query: Query) -> Result { - // Pre: Sintactical query OK - // Post: Valid query for execution match &query.table { Some(table) => match File::open(table) { Ok(_) => {} @@ -462,6 +487,7 @@ fn validate_query(query: Query) -> Result { } } +/// Validate query: Special case for delete fn validate_delete_query(query: Query) -> Result { if query.columns.is_none() && query.values.is_none() && query.where_condition.is_some() { match &query.table { @@ -479,21 +505,25 @@ fn validate_delete_query(query: Query) -> Result { } } +/// Validate query: Special case for insert fn validate_insert_query(query: Query) -> Result { // TODO Ok(query) } +/// Validate query: Special case for select fn validate_select_query(query: Query) -> Result { // TODO Ok(query) } +/// Validate query: Special case for update fn validate_update_query(query: Query) -> Result { // TODO Ok(query) } +/// AUX: Get columns from file fn get_columns(file: File) -> Option> { let mut result: Vec = Vec::new(); let mut reader: BufReader = BufReader::new(file); @@ -516,9 +546,10 @@ fn get_columns(file: File) -> Option> { } } +/// AUX: Get first line from file +/// Pre: query +/// Post: File first line, if any pub fn get_file_first_line(query: &Query) -> Option { - // Pre: query - // Post: File first line, if any match &query.table { Some(table) => match File::open(table) { Ok(f) => { @@ -539,8 +570,8 @@ pub fn get_file_first_line(query: &Query) -> Option { } } +/// Tokenization of text query by space, new line & coma pub fn text_to_vec(text_query: &String, coma: bool) -> Vec { - // Text to vector. Tokenization by space, new line & coma let mut tmp_text_query = text_query.to_string(); tmp_text_query = tmp_text_query.replace('\n', " "); if !coma { @@ -566,25 +597,26 @@ pub fn text_to_vec(text_query: &String, coma: bool) -> Vec { result } +/// Parses vector of tokens into query +/// Pre: Vec of tokens from query & path to tables +/// Post: Vec to non validated query fn vec_to_query(args: &[String], path: &String) -> Result { - // Pre: Vec of queries tokens & path to tables - // Post: Vec to non validated query let mut result: Query = build_empty_query(); match check_operation_format(args) { Ok(x) => match &x { - QueryType::DELETE => match separate_args_delete(args, path, &mut result) { + QueryType::DELETE => match parse_args_delete(args, path, &mut result) { Ok(_) => result.operation = Some(x), Err(x) => return Err(x), }, - QueryType::INSERT => match separate_args_insert(args, path, &mut result) { + QueryType::INSERT => match parse_args_insert(args, path, &mut result) { Ok(_) => result.operation = Some(x), Err(x) => return Err(x), }, - QueryType::SELECT => match separate_args_select(args, path, &mut result) { + QueryType::SELECT => match parse_args_select(args, path, &mut result) { Ok(_) => result.operation = Some(x), Err(x) => return Err(x), }, - QueryType::UPDATE => match separate_args_update(args, path, &mut result) { + QueryType::UPDATE => match parse_args_update(args, path, &mut result) { Ok(_) => result.operation = Some(x), Err(x) => return Err(x), }, diff --git a/src/query.rs b/src/query.rs index 4bcca37..596830f 100644 --- a/src/query.rs +++ b/src/query.rs @@ -3,15 +3,13 @@ pub mod query_type; use query_type::QueryType; use crate::condition::Condition; -//use crate::complex_condition::ComplexCondition, - -// use crate::condition::ComplexCondition; pub static DELETE_MIN_LEN: usize = 7; // DELETE FROM tabla WHERE a < b pub static INSERT_MIN_LEN: usize = 6; // INSERT INTO tabla col VALUES val pub static SELECT_MIN_LEN: usize = 4; // SELECT * FROM tabla pub static UPDATE_MIN_LEN: usize = 10; // UPDATE tabla SET col = valor WHERE a < b +/// Represents a SQL query pub struct Query { pub operation: Option, // DELETE, INSERT, SELECT, UPDATE pub table: Option, // DELETE, INSERT, SELECT, UPDATE From 6a22baa9a4201dbae0730b783c7b00d39d2da26d Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Mon, 23 Sep 2024 21:05:28 -0300 Subject: [PATCH 55/58] PEND DOC: Examples --- src/libs/error.rs | 27 +++++++++++++++------------ src/libs/exec.rs | 37 ++++++++++++++++++++++++------------- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/libs/error.rs b/src/libs/error.rs index e247048..6c9c4cd 100644 --- a/src/libs/error.rs +++ b/src/libs/error.rs @@ -1,15 +1,18 @@ -pub static OPERACION_INVALIDA: u32 = 1; -pub static DELETE_MAL_FORMATEADO: u32 = 2; -pub static INSERT_MAL_FORMATEADO: u32 = 3; -pub static SELECT_MAL_FORMATEADO: u32 = 4; -pub static UPDATE_MAL_FORMATEADO: u32 = 5; -pub static ARCHIVO_NO_PUDO_SER_ABIERTO: u32 = 6; -pub static ARCHIVO_VACIO: u32 = 7; -pub static ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS: u32 = 8; -pub static WHERE_EN_DELETE_MAL_FORMATEADO: u32 = 9; -pub static WHERE_MAL_FORMATEADO: u32 = 10; -pub static ORDER_BY_MAL_FORMATEADO: u32 = 11; -pub static NO_WHERE: u32 = 12; +pub static OPERACION_INVALIDA: u32 = 101; +pub static DELETE_MAL_FORMATEADO: u32 = 102; +pub static INSERT_MAL_FORMATEADO: u32 = 103; +pub static SELECT_MAL_FORMATEADO: u32 = 104; +pub static UPDATE_MAL_FORMATEADO: u32 = 105; +pub static WHERE_EN_DELETE_MAL_FORMATEADO: u32 = 109; +pub static WHERE_MAL_FORMATEADO: u32 = 110; +pub static ORDER_BY_MAL_FORMATEADO: u32 = 111; +pub static NO_WHERE: u32 = 112; +pub static ARCHIVO_NO_PUDO_SER_ABIERTO: u32 = 201; +pub static ARCHIVO_VACIO: u32 = 202; +pub static ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS: u32 = 301; +pub static ERROR_RENOMBRADO_ARCHIVO_TEMPORAL: u32 = 401; +pub static ERROR_INTERCAMBIANDO_TEMPORAL_POR_OFICIAL: u32 = 402; +pub static ERROR_OPERACION_INVALIDA_EN_EJECUCCION: u32 = 403; pub fn print_err(error_code: u32) { // TODO print error diff --git a/src/libs/exec.rs b/src/libs/exec.rs index d7d7133..456ddeb 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -65,7 +65,7 @@ fn exec_query_delete(query: Query) { } if remove_old_file(table, &tmp_file_name, valid_operation).is_err() { - println!("Error en manipulación de archivos"); + println!("ERROR: limpieza de archivos temporales"); } } } @@ -76,7 +76,6 @@ fn exec_query_insert(query: Query) { if let Some(table) = &query.table { if let Some(write_columns) = &query.columns { let total_columns = find_total_columns(&query); - // let write_columns = find_print_columns(&query); match &mut OpenOptions::new().append(true).open(table) { Ok(file) => { @@ -100,7 +99,7 @@ fn exec_query_insert(query: Query) { write_line.push('\n'); let _ = file.write(write_line.as_bytes()); } - Err(_) => println!("ERROR en el programa"), + Err(_) => println!("Error: Manipulación de archivo temporal en INSERT"), } } } @@ -119,7 +118,6 @@ fn exec_query_select(query: Query) { } } None => { - // let col_index: i32 = find_filter_column(&query); read_and_print_file(&query); } } @@ -130,7 +128,9 @@ fn exec_query_select(query: Query) { /// Post: Cleans files fn file_cleanup(files: &Vec) { for file in files { - let _ = remove_file(file); + if let Err(_) = remove_file(file){ + println!("ERROR: Limpieza de archivos temporales"); + } } } @@ -329,7 +329,7 @@ fn exec_query_update(query: Query) { } if remove_old_file(table, &tmp_file, valid_operation).is_err() { - println!("Error en manipulación de archivos"); + println!("ERROR: Manipulación de archivo temporal en UPDATE"); } } } @@ -358,22 +358,23 @@ fn remove_old_file(file: &String, tmp_file: &String, valid_operation: bool) -> R if valid_operation { if remove_file(file).is_ok() { if rename(tmp_file, file).is_err() { - return Err(3); + return Err(error::ERROR_RENOMBRADO_ARCHIVO_TEMPORAL); } Ok(0) } else { let _ = remove_file(tmp_file); - Err(1) + Err(error::ERROR_INTERCAMBIANDO_TEMPORAL_POR_OFICIAL) } } else { let _ = remove_file(tmp_file); - Err(2) + Err(error::ERROR_OPERACION_INVALIDA_EN_EJECUCCION) } } +/// Returns tmp filename from official file +/// Pre: Path and name to file. ruta/a/tablas/tabla.csv +/// Post: same file but starting with period, as long as it's a hidden file fn get_tmp_file_name(table: &str) -> String { - // Pre: Path and name to file. ruta/a/tablas/tabla.csv - // Post: same file but starting with period, as long as it's a hidden file let mut output = String::new(); let last_item_index = table.split('/').enumerate().count() - 1; for (counter, element) in table.split('/').enumerate() { @@ -425,6 +426,7 @@ fn find_column(query: &Query, column: &String) -> Option { } } +/// Print header of function. fn print_header(query: &Query) { if let Some(table) = &query.table { if let Ok(file) = File::open(table) { @@ -485,9 +487,12 @@ fn read_and_print_file(query: &Query) { } } +/// Exec query line by line, sorting the output in buffer memory and printing to tmp files +/// PD: Similar to Cassandra Write Path :D +/// +/// Pre: Query, the col index for sorting and bool of ascending/descending +/// Post: Vec of tmp_files fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result, u32> { - // Pre: Query, the col index for sorting and bool of ascending/descending - // Post: Vec of tmp_files match &query.table { None => Err(3), Some(table) => { @@ -573,6 +578,7 @@ fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result } } +/// Write the buffer to file fn write_to_tmp_file( tmp_file_name: &String, tmp_filenames: &mut Vec, @@ -606,6 +612,7 @@ fn write_to_tmp_file( } } +/// Insert line to buffer in sorted position (special case: no boolean condition) fn insert_unconditioned( elements: Vec, columns_opt: &Option>, @@ -645,6 +652,7 @@ fn insert_unconditioned( } } +/// Insert line to buffer in sorted position (special case: there's a boolean condition) fn insert_conditioned( elements: Vec, condition: &[Vec], @@ -658,6 +666,7 @@ fn insert_conditioned( } } +/// Binary search of elements position. fn find_insert_position( elements: &Vec, lines_buffer: &Vec>, @@ -717,6 +726,7 @@ fn find_insert_position( } } +/// Print line to stdout ( special case, no SORT BY condition ) /// Pre: Columns vector sorted && Elements of line content vector /// Post: print to stdout the correct columns fn print_file_unconditional(columns_opt: &Option>, elements: &[String]) { @@ -750,6 +760,7 @@ fn print_file_unconditional(columns_opt: &Option>, elements: &[String println!(); } +/// Print line to stdout with a boolean condition( special case, no SORT BY condition ) fn print_file_conditioned( columns_opt: &Option>, condition: &[Vec], From 50554c2f7a031e3a5aeeaff6ea07acb3ec669620 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Tue, 24 Sep 2024 19:56:34 -0300 Subject: [PATCH 56/58] OK: SELECT ORDER BY s WHERE FMT CLIPPY + GitHub Actions --- src/condition.rs | 11 ++- src/libs/exec.rs | 22 +++--- src/libs/parsing.rs | 178 +++++++++++++++++++++++--------------------- src/query.rs | 2 +- 4 files changed, 112 insertions(+), 101 deletions(-) diff --git a/src/condition.rs b/src/condition.rs index aa2c7ff..b27a6bf 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -11,7 +11,7 @@ pub struct Condition { pub value: Option, } -/// Constructor for not condition +/// Constructor for not condition pub fn build_not_condition() -> Condition { Condition { condition: ConditionOperator::Equal, @@ -20,7 +20,7 @@ pub fn build_not_condition() -> Condition { } } -/// Constructor for general condition (simple expression, non boolean) +/// Constructor for general condition (simple expression, non boolean) pub fn build_condition(column: usize, value: String, cond: ConditionOperator) -> Condition { Condition { condition: cond, @@ -30,9 +30,9 @@ pub fn build_condition(column: usize, value: String, cond: ConditionOperator) -> } /// Returns string (or int if it's parseable as int) comparison -/// +/// /// Pre: Strings and operator -/// Post: True if condition applies +/// Post: True if condition applies pub fn operate_condition(v1: &String, v2: &String, operator: &ConditionOperator) -> bool { if let Ok(x1) = v1.parse::() { if let Ok(x2) = v2.parse::() { @@ -56,11 +56,10 @@ pub fn operate_condition(v1: &String, v2: &String, operator: &ConditionOperator) } /// Returns the result of applying the condition to the lineW -/// +/// /// Pre: Line to vec and condition (bool vector). /// Post: Bool if condition applies or not pub fn operate_full_condition(elements: &[String], condition: &[Vec]) -> bool { - let mut or_valid = false; let mut or_counter = 0; diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 456ddeb..6556baf 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -125,10 +125,10 @@ fn exec_query_select(query: Query) { /// Cleans tmp files /// Pre: filenames -/// Post: Cleans files +/// Post: Cleans files fn file_cleanup(files: &Vec) { for file in files { - if let Err(_) = remove_file(file){ + if remove_file(file).is_err() { println!("ERROR: Limpieza de archivos temporales"); } } @@ -232,7 +232,7 @@ fn find_next_line(lines_buffer: &mut [Vec], col_index: usize, asc: &bool } } -/// Read first line from all files +/// Read first line from all files /// Pre: Lines buffer, col index and ascending/descending /// Post: Index of next line, if any fn readers_read_first_line(readers: &mut Vec>) -> Option>> { @@ -371,7 +371,7 @@ fn remove_old_file(file: &String, tmp_file: &String, valid_operation: bool) -> R } } -/// Returns tmp filename from official file +/// Returns tmp filename from official file /// Pre: Path and name to file. ruta/a/tablas/tabla.csv /// Post: same file but starting with period, as long as it's a hidden file fn get_tmp_file_name(table: &str) -> String { @@ -426,7 +426,7 @@ fn find_column(query: &Query, column: &String) -> Option { } } -/// Print header of function. +/// Print header of function. fn print_header(query: &Query) { if let Some(table) = &query.table { if let Ok(file) = File::open(table) { @@ -487,9 +487,9 @@ fn read_and_print_file(query: &Query) { } } -/// Exec query line by line, sorting the output in buffer memory and printing to tmp files -/// PD: Similar to Cassandra Write Path :D -/// +/// Exec query line by line, sorting the output in buffer memory and printing to tmp files +/// PD: Similar to Cassandra Write Path :D +/// /// Pre: Query, the col index for sorting and bool of ascending/descending /// Post: Vec of tmp_files fn read_into_sorted_files(query: &Query, col_index: usize, asc: &bool) -> Result, u32> { @@ -612,7 +612,7 @@ fn write_to_tmp_file( } } -/// Insert line to buffer in sorted position (special case: no boolean condition) +/// Insert line to buffer in sorted position (special case: no boolean condition) fn insert_unconditioned( elements: Vec, columns_opt: &Option>, @@ -652,7 +652,7 @@ fn insert_unconditioned( } } -/// Insert line to buffer in sorted position (special case: there's a boolean condition) +/// Insert line to buffer in sorted position (special case: there's a boolean condition) fn insert_conditioned( elements: Vec, condition: &[Vec], @@ -666,7 +666,7 @@ fn insert_conditioned( } } -/// Binary search of elements position. +/// Binary search of elements position. fn find_insert_position( elements: &Vec, lines_buffer: &Vec>, diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index d2988c2..b50d21c 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -11,7 +11,7 @@ use crate::query::build_empty_query; use crate::query::query_type::QueryType; use crate::query::{Query, DELETE_MIN_LEN, INSERT_MIN_LEN, SELECT_MIN_LEN, UPDATE_MIN_LEN}; -use super::error::{DELETE_MAL_FORMATEADO, WHERE_MAL_FORMATEADO}; +use super::error::{DELETE_MAL_FORMATEADO, ORDER_BY_MAL_FORMATEADO, WHERE_MAL_FORMATEADO}; /// Build query for execution pub fn build_query(text_query: &String, path: &String) -> Result { @@ -23,7 +23,7 @@ pub fn build_query(text_query: &String, path: &String) -> Result { } /// Merge table and path. Aux funcion -/// +/// /// ``` /// let result = merge_table_and_path(String::from("tablas"), "clientes.csv"); /// assert!(result,String::from("tablas/clientes.csv")); @@ -163,37 +163,25 @@ fn parse_args_select(args: &[String], path: &String, result: &mut Query) -> Resu counter += 1; if counter == args.len() { - Ok(0) + return Ok(0); } else if args[counter].eq("WHERE") { counter += 1; match parse_where_condition(result, args, &mut counter) { Ok(cond) => result.where_condition = Some(cond), Err(x) => return Err(x), } + } - if counter < args.len() { - if args[counter].eq("ORDER") && args[counter + 1].eq("BY") { - if counter + 3 == args.len() { - // ORDER BY column - result.order_by = Some((args[counter + 2].to_string(), true)); - } else if counter + 4 == args.len() { - // ORDER BY column ASC/DESC - if args[counter + 3].eq("ASC") || args[counter + 3].eq("DESC") { - result.order_by = - Some((args[counter + 2].to_string(), args[counter + 2].eq("ASC"))); - } else { - return Err(error::ORDER_BY_MAL_FORMATEADO); - } - } else { - return Err(error::ORDER_BY_MAL_FORMATEADO); - } - } else { - return Err(error::ORDER_BY_MAL_FORMATEADO); - } - } + if counter == args.len() { Ok(0) } else { - Err(WHERE_MAL_FORMATEADO) + match parse_order_by(args, &mut counter) { + Ok(cond) => { + result.order_by = Some(cond); + Ok(0) + } + Err(x) => Err(x), + } } } } @@ -226,11 +214,35 @@ fn get_columns_position(query: &Query, string_cols: &[String]) -> Result Result<(String, bool), u32> { + if *counter + 3 == args.len() || *counter + 4 == args.len() { + if args[*counter].eq("ORDER") && args[*counter + 1].eq("BY") { + let column = args[*counter + 2].to_string(); + let mut asc = true; + if *counter + 4 == args.len() { + if args[*counter + 3].eq("DESC") { + asc = false; + } else if !args[*counter + 3].eq("ASC") { + return Err(ORDER_BY_MAL_FORMATEADO); + } + } + Ok((column, asc)) + } else { + Err(ORDER_BY_MAL_FORMATEADO) + } + } else { + Err(ORDER_BY_MAL_FORMATEADO) + } +} + +/// Parse boolean where condition, advancing the counter /// /// Pre: Query args and counter in next position to WHERE /// Post: Complex condition for query and counter at the next position of the last element of condition -/// +/// /// EXAMPLE: /// Pre: parse_where_condition(query, vec!["SELECT","*","FROM","tabla","WHERE","id","<","5","ORDER","BY","id"],5); /// Post: Result, counter = 8 @@ -261,7 +273,7 @@ fn parse_where_condition( } } -/// Pre: Query, args, position counter and wip vector +/// Pre: Query, args, position counter and wip vector /// Post: Parses the next simple condition into boolean vector fn parse_next_condition( query: &Query, @@ -269,64 +281,65 @@ fn parse_next_condition( counter: &mut usize, vec: &mut Vec>, ) -> Result { - if !*counter + 2 < args.len() { - return Err(WHERE_MAL_FORMATEADO); - } else if args[*counter + 1].eq("AND") || args[*counter + 1].eq("OR") { - return Err(WHERE_MAL_FORMATEADO); - } else if args[*counter].eq("OR") { - vec.push(Vec::new()); - *counter += 1; - } else if args[*counter].eq("AND") { - *counter += 1; - } else if args[*counter].eq("NOT") { - let position = vec.len() - 1; - vec[position].push(build_not_condition()); // String vacio - *counter += 1; + if *counter + 2 >= args.len() { + Err(WHERE_MAL_FORMATEADO) } else { - match get_columns_position(query, &[args[*counter].to_string()]) { - Err(x) => return Err(x), - Ok(x) => { - let simple_condition: Condition = if args[*counter + 1].eq("<") { - build_condition( - x[0], - args[*counter + 2].to_string(), - ConditionOperator::Minor, - ) - } else if args[*counter + 1].eq("<=") { - build_condition( - x[0], - args[*counter + 2].to_string(), - ConditionOperator::MinorEqual, - ) - } else if args[*counter + 1].eq("=") { - build_condition( - x[0], - args[*counter + 2].to_string(), - ConditionOperator::Equal, - ) - } else if args[*counter + 1].eq(">=") { - build_condition( - x[0], - args[*counter + 2].to_string(), - ConditionOperator::HigherEqual, - ) - } else if args[*counter + 1].eq(">") { - build_condition( - x[0], - args[*counter + 2].to_string(), - ConditionOperator::Higher, - ) - } else { - return Err(WHERE_MAL_FORMATEADO); - }; - let position = vec.len() - 1; - vec[position].push(simple_condition); - *counter += 3; + if args[*counter + 1].eq("AND") || args[*counter + 1].eq("OR") { + return Err(WHERE_MAL_FORMATEADO); + } else if args[*counter].eq("OR") { + vec.push(Vec::new()); + *counter += 1; + } else if args[*counter].eq("AND") { + *counter += 1; + } else if args[*counter].eq("NOT") { + let position = vec.len() - 1; + vec[position].push(build_not_condition()); // String vacio + *counter += 1; + } else { + match get_columns_position(query, &[args[*counter].to_string()]) { + Err(x) => return Err(x), + Ok(x) => { + let simple_condition: Condition = if args[*counter + 1].eq("<") { + build_condition( + x[0], + args[*counter + 2].to_string(), + ConditionOperator::Minor, + ) + } else if args[*counter + 1].eq("<=") { + build_condition( + x[0], + args[*counter + 2].to_string(), + ConditionOperator::MinorEqual, + ) + } else if args[*counter + 1].eq("=") { + build_condition( + x[0], + args[*counter + 2].to_string(), + ConditionOperator::Equal, + ) + } else if args[*counter + 1].eq(">=") { + build_condition( + x[0], + args[*counter + 2].to_string(), + ConditionOperator::HigherEqual, + ) + } else if args[*counter + 1].eq(">") { + build_condition( + x[0], + args[*counter + 2].to_string(), + ConditionOperator::Higher, + ) + } else { + return Err(WHERE_MAL_FORMATEADO); + }; + let position = vec.len() - 1; + vec[position].push(simple_condition); + *counter += 3; + } } } - } - - Ok(0) + Ok(0) + } } // Pre: Boolean vector (parsed boolean condition) @@ -352,7 +365,6 @@ fn check_valid_bool(boolean_expresion: &[Vec]) -> bool { valid } - /// find column position fn find_column_position(column_name: &String, columns: &[String]) -> Result { let mut counter = 0; diff --git a/src/query.rs b/src/query.rs index 596830f..2132594 100644 --- a/src/query.rs +++ b/src/query.rs @@ -9,7 +9,7 @@ pub static INSERT_MIN_LEN: usize = 6; // INSERT INTO tabla col VALUES val pub static SELECT_MIN_LEN: usize = 4; // SELECT * FROM tabla pub static UPDATE_MIN_LEN: usize = 10; // UPDATE tabla SET col = valor WHERE a < b -/// Represents a SQL query +/// Represents a SQL query pub struct Query { pub operation: Option, // DELETE, INSERT, SELECT, UPDATE pub table: Option, // DELETE, INSERT, SELECT, UPDATE From afafe593781ec2c75e745e34a2f61618195e1e4c Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Tue, 24 Sep 2024 21:14:48 -0300 Subject: [PATCH 57/58] OK: Print err y doc --- src/libs/error.rs | 110 ++++++++++++++++++++++++++++++++++++++++++-- src/libs/exec.rs | 15 ++++-- src/libs/parsing.rs | 50 ++++++++++++-------- 3 files changed, 151 insertions(+), 24 deletions(-) diff --git a/src/libs/error.rs b/src/libs/error.rs index 6c9c4cd..80f2924 100644 --- a/src/libs/error.rs +++ b/src/libs/error.rs @@ -3,10 +3,10 @@ pub static DELETE_MAL_FORMATEADO: u32 = 102; pub static INSERT_MAL_FORMATEADO: u32 = 103; pub static SELECT_MAL_FORMATEADO: u32 = 104; pub static UPDATE_MAL_FORMATEADO: u32 = 105; -pub static WHERE_EN_DELETE_MAL_FORMATEADO: u32 = 109; pub static WHERE_MAL_FORMATEADO: u32 = 110; pub static ORDER_BY_MAL_FORMATEADO: u32 = 111; pub static NO_WHERE: u32 = 112; +pub static FALTA_ARCHIVO: u32 = 200; pub static ARCHIVO_NO_PUDO_SER_ABIERTO: u32 = 201; pub static ARCHIVO_VACIO: u32 = 202; pub static ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS: u32 = 301; @@ -14,7 +14,111 @@ pub static ERROR_RENOMBRADO_ARCHIVO_TEMPORAL: u32 = 401; pub static ERROR_INTERCAMBIANDO_TEMPORAL_POR_OFICIAL: u32 = 402; pub static ERROR_OPERACION_INVALIDA_EN_EJECUCCION: u32 = 403; +pub static CODE_INVALID_TABLE: &str = "INVALID_TABLE"; +pub static CODE_INVALID_COLUMN: &str = "INVALID_TABLE"; +pub static CODE_INVALID_SYNTAX: &str = "INVALID_SYNTAX"; +pub static CODE_ERROR: &str = "ERROR"; + +pub static TEXTO_OP_INV: &str = "OPERACION INVALIDA"; +pub static TEXTO_DELETE_MF: &str = "DELETE MAL FORMATEADO"; +pub static TEXTO_INSERT_MF: &str = "INSERT MAL FORMATEADO"; +pub static TEXTO_SELECT_MF: &str = "SELECT MAL FORMATEADO"; +pub static TEXTO_UPDATE_MF: &str = "UPDATE MAL FORMATEADO"; +pub static TEXTO_WHERE_MF: &str = "WHERE MAL FORMATEADO"; +pub static TEXTO_ORDERBY_MF: &str = "ORDER BY MAL FORMATEADO"; +pub static TEXTO_NO_WHERE: &str = "OPERACION REQUIERE WHERE"; +pub static TEXTO_FALTA_ARCHIVO: &str = "FALTA ARCHIVO EN QUERY"; +pub static TEXTO_ARCHIVO_NOPEN: &str = "ARCHIVO NO PUDO SER ABIERTO"; +pub static TEXTO_ARCHIVO_VACIO: &str = "ARCHIVO VACIO"; +pub static TEXTO_ARCHIVO_NO_CONTIENE_COLUMNAS: &str = + "EL ARCHIVO NO CONTIENE TODAS LAS COLUMNAS SOLICITADAS"; +pub static TEXTO_ERROR_RENOMBRADO_TEMP: &str = "ERROR RENOMBRADO ARCHIVO TEMPORAL"; +pub static TEXTO_ERROR_INTERCAMBIANDO_TEMP: &str = "ERROR INTERCAMBIANDO TEMPORAL POR OFICIAL"; +pub static TEXTO_ERROR_OPERACION_INVALIDA_EN_EJECUCCION: &str = "OPERACION INVALIDA EN EJECUCCION"; +pub static TEXTO_ERROR_DESCONOCIDO: &str = "ERROR DESCONOCIDO"; + pub fn print_err(error_code: u32) { - // TODO print error - println!("ERROR. Codigo: {}", error_code) + println!( + "{}: {}", + get_text_code(&error_code), + get_description(&error_code) + ); +} + +fn get_text_code(error_code: &u32) -> &str { + if error_code / 100 == 1 { + CODE_INVALID_SYNTAX + } else if error_code / 100 == 2 { + CODE_INVALID_TABLE + } else if error_code / 100 == 3 { + CODE_INVALID_COLUMN + } else { + CODE_ERROR + } +} + +fn get_description(error_code: &u32) -> &str { + if error_code / 100 == 1 { + get_description_syntax(error_code) + } else if error_code / 100 == 2 { + get_description_table(error_code) + } else if error_code / 100 == 3 { + get_description_column(error_code) + } else { + get_description_error(error_code) + } +} + +fn get_description_syntax(error_code: &u32) -> &str { + if *error_code == OPERACION_INVALIDA { + TEXTO_OP_INV + } else if *error_code == DELETE_MAL_FORMATEADO { + TEXTO_DELETE_MF + } else if *error_code == INSERT_MAL_FORMATEADO { + TEXTO_INSERT_MF + } else if *error_code == SELECT_MAL_FORMATEADO { + TEXTO_SELECT_MF + } else if *error_code == UPDATE_MAL_FORMATEADO { + TEXTO_UPDATE_MF + } else if *error_code == WHERE_MAL_FORMATEADO { + TEXTO_WHERE_MF + } else if *error_code == ORDER_BY_MAL_FORMATEADO { + TEXTO_ORDERBY_MF + } else if *error_code == NO_WHERE { + TEXTO_NO_WHERE + } else { + TEXTO_ERROR_DESCONOCIDO + } +} + +fn get_description_table(error_code: &u32) -> &str { + if *error_code == FALTA_ARCHIVO { + TEXTO_FALTA_ARCHIVO + } else if *error_code == ARCHIVO_NO_PUDO_SER_ABIERTO { + TEXTO_ARCHIVO_NOPEN + } else if *error_code == ARCHIVO_VACIO { + TEXTO_ARCHIVO_VACIO + } else { + TEXTO_ERROR_DESCONOCIDO + } +} + +fn get_description_column(error_code: &u32) -> &str { + if *error_code == ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS { + TEXTO_ARCHIVO_NO_CONTIENE_COLUMNAS + } else { + TEXTO_ERROR_DESCONOCIDO + } +} + +fn get_description_error(error_code: &u32) -> &str { + if *error_code == ERROR_INTERCAMBIANDO_TEMPORAL_POR_OFICIAL { + TEXTO_ERROR_INTERCAMBIANDO_TEMP + } else if *error_code == ERROR_RENOMBRADO_ARCHIVO_TEMPORAL { + TEXTO_ERROR_RENOMBRADO_TEMP + } else if *error_code == ERROR_OPERACION_INVALIDA_EN_EJECUCCION { + TEXTO_ERROR_OPERACION_INVALIDA_EN_EJECUCCION + } else { + TEXTO_ERROR_DESCONOCIDO + } } diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 6556baf..6990bb2 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -277,6 +277,7 @@ fn create_readers(files: &[String]) -> Option>> { } } +/// Exec query: Special case for update fn exec_query_update(query: Query) { if let Some(cond) = &query.where_condition { if let Some(columns) = &query.columns { @@ -337,6 +338,7 @@ fn exec_query_update(query: Query) { } } +/// Exec query: Special case for select fn update_line(elements: &[String], columns: &[usize], values: &[String]) -> String { let mut result = String::new(); let mut writen_counter = 0; @@ -354,6 +356,7 @@ fn update_line(elements: &[String], columns: &[usize], values: &[String]) -> Str result } +/// Aux Function. Remove old tmp file fn remove_old_file(file: &String, tmp_file: &String, valid_operation: bool) -> Result { if valid_operation { if remove_file(file).is_ok() { @@ -391,6 +394,7 @@ fn get_tmp_file_name(table: &str) -> String { output } +/// Aux function. Total number of columns in table fn find_total_columns(query: &Query) -> usize { match get_file_first_line(query) { Some(line) => line_to_vec(&line).len(), @@ -398,6 +402,10 @@ fn find_total_columns(query: &Query) -> usize { } } +/// Find column index given it's name +/// +/// Pre: Valid query and column for text +/// Post: Index if any fn find_column(query: &Query, column: &String) -> Option { match get_file_first_line(query) { Some(line) => { @@ -460,6 +468,7 @@ fn print_header(query: &Query) { } } +/// Function for printing file ( special select case when no sort by ) fn read_and_print_file(query: &Query) { if let Some(table) = &query.table { if let Ok(f) = File::open(table) { @@ -826,13 +835,13 @@ mod tests { 0, &true, ); - assert_eq!(rt1, 1); + assert_eq!(rt1, 2); } #[test] fn test_bsearch2() { let elements = vec![ - String::from("4"), + String::from("1"), String::from("Jorge"), String::from("martell"), ]; @@ -881,7 +890,7 @@ mod tests { 1, &false, ); - assert_eq!(rt2, 3); + assert_eq!(rt2, 4); } } diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index b50d21c..b842ec9 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -338,8 +338,8 @@ fn parse_next_condition( } } } - Ok(0) - } + Ok(0) + } } // Pre: Boolean vector (parsed boolean condition) @@ -502,16 +502,7 @@ fn validate_query(query: Query) -> Result { /// Validate query: Special case for delete fn validate_delete_query(query: Query) -> Result { if query.columns.is_none() && query.values.is_none() && query.where_condition.is_some() { - match &query.table { - Some(table) => match File::open(table) { - Ok(file) => match get_columns(file) { - Some(_) => Ok(query), - None => Err(error::ARCHIVO_VACIO), - }, - Err(_) => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO), - }, - None => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO), - } + validate_table(query) } else { Err(error::DELETE_MAL_FORMATEADO) } @@ -519,20 +510,43 @@ fn validate_delete_query(query: Query) -> Result { /// Validate query: Special case for insert fn validate_insert_query(query: Query) -> Result { - // TODO - Ok(query) + if query.values.is_some() && query.columns.is_some() && query.where_condition.is_none() { + validate_table(query) + } else { + Err(error::INSERT_MAL_FORMATEADO) + } } /// Validate query: Special case for select fn validate_select_query(query: Query) -> Result { - // TODO - Ok(query) + if query.values.is_none() { + validate_table(query) + } else { + Err(error::SELECT_MAL_FORMATEADO) + } } /// Validate query: Special case for update fn validate_update_query(query: Query) -> Result { - // TODO - Ok(query) + if query.values.is_some() && query.columns.is_some() && query.where_condition.is_some() { + validate_table(query) + } else { + Err(error::UPDATE_MAL_FORMATEADO) + } +} + +/// Validate if table is valid +fn validate_table(query: Query) -> Result { + match &query.table { + Some(table) => match File::open(table) { + Ok(file) => match get_columns(file) { + Some(_) => Ok(query), + None => Err(error::ARCHIVO_VACIO), + }, + Err(_) => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO), + }, + None => Err(error::FALTA_ARCHIVO), + } } /// AUX: Get columns from file From 7c9f6677ad7a91e5d63471ad9a960d80fa0185f1 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Tue, 24 Sep 2024 21:31:47 -0300 Subject: [PATCH 58/58] Minor: Correcciones de prints y errores --- src/libs/exec.rs | 5 +++-- src/libs/parsing.rs | 8 ++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 6990bb2..c15e2bc 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -107,10 +107,10 @@ fn exec_query_insert(query: Query) { /// Exec query: Special case for select fn exec_query_select(query: Query) { + print_header(&query); match &query.order_by { Some((column, asc)) => { if let Some(col_index) = find_column(&query, column) { - print_header(&query); if let Ok(files) = read_into_sorted_files(&query, col_index, asc) { print_sorted_files(&files, &col_index, asc); file_cleanup(&files); @@ -475,7 +475,8 @@ fn read_and_print_file(query: &Query) { let mut reader: BufReader = BufReader::new(f); let mut line = String::new(); - let mut read = true; + let mut read = reader.read_line(&mut line).is_ok(); + line.clear(); while read { if let Ok(x) = reader.read_line(&mut line) { line = line.replace('\n', ""); diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index b842ec9..00d73b6 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -11,7 +11,9 @@ use crate::query::build_empty_query; use crate::query::query_type::QueryType; use crate::query::{Query, DELETE_MIN_LEN, INSERT_MIN_LEN, SELECT_MIN_LEN, UPDATE_MIN_LEN}; -use super::error::{DELETE_MAL_FORMATEADO, ORDER_BY_MAL_FORMATEADO, WHERE_MAL_FORMATEADO}; +use super::error::{ + DELETE_MAL_FORMATEADO, ORDER_BY_MAL_FORMATEADO, SELECT_MAL_FORMATEADO, WHERE_MAL_FORMATEADO, +}; /// Build query for execution pub fn build_query(text_query: &String, path: &String) -> Result { @@ -174,7 +176,7 @@ fn parse_args_select(args: &[String], path: &String, result: &mut Query) -> Resu if counter == args.len() { Ok(0) - } else { + } else if args[counter].eq("ORDER") { match parse_order_by(args, &mut counter) { Ok(cond) => { result.order_by = Some(cond); @@ -182,6 +184,8 @@ fn parse_args_select(args: &[String], path: &String, result: &mut Query) -> Resu } Err(x) => Err(x), } + } else { + Err(SELECT_MAL_FORMATEADO) } } }