1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use std::fmt;
use std::io::BufRead;
use std::str;

use das::SetStatement;
use dds::{
    AlterDatabaseStatement, AlterTableStatement, CreateIndexStatement, CreateTableStatement,
    DropDatabaseStatement, DropEventStatement, DropFunctionStatement, DropIndexStatement,
    DropLogfileGroupStatement, DropProcedureStatement, DropServerStatement,
    DropSpatialReferenceSystemStatement, DropTableStatement, DropTablespaceStatement,
    DropTriggerStatement, DropViewStatement, RenameTableStatement, TruncateTableStatement,
};
use dms::{
    CompoundSelectStatement, DeleteStatement, InsertStatement, SelectStatement, UpdateStatement,
};
use nom::branch::alt;
use nom::combinator::map;
use nom::Offset;

pub struct Parser;

impl Parser {
    pub fn parse(config: &ParseConfig, input: &str) -> Result<Statement, String> {
        let input = input.trim();

        let dds_parser = alt((
            map(AlterDatabaseStatement::parse, Statement::AlterDatabase),
            map(AlterTableStatement::parse, Statement::AlterTable),
            map(CreateIndexStatement::parse, Statement::CreateIndex),
            map(CreateTableStatement::parse, Statement::CreateTable),
            map(DropDatabaseStatement::parse, Statement::DropDatabase),
            map(DropEventStatement::parse, Statement::DropEvent),
            map(DropFunctionStatement::parse, Statement::DropFunction),
            map(DropIndexStatement::parse, Statement::DropIndex),
            map(
                DropLogfileGroupStatement::parse,
                Statement::DropLogfileGroup,
            ),
            map(DropProcedureStatement::parse, Statement::DropProcedure),
            map(DropServerStatement::parse, Statement::DropServer),
            map(
                DropSpatialReferenceSystemStatement::parse,
                Statement::DropSpatialReferenceSystem,
            ),
            map(DropTableStatement::parse, Statement::DropTable),
            map(DropTablespaceStatement::parse, Statement::DropTableSpace),
            map(DropTriggerStatement::parse, Statement::DropTrigger),
            map(DropViewStatement::parse, Statement::DropView),
            map(RenameTableStatement::parse, Statement::RenameTable),
            map(TruncateTableStatement::parse, Statement::TruncateTable),
        ));

        let das_parser = alt((map(SetStatement::parse, Statement::Set),));

        let dms_parser = alt((
            map(SelectStatement::parse, Statement::Select),
            map(CompoundSelectStatement::parse, Statement::CompoundSelect),
            map(InsertStatement::parse, Statement::Insert),
            map(DeleteStatement::parse, Statement::Delete),
            map(UpdateStatement::parse, Statement::Update),
        ));

        let mut parser = alt((dds_parser, dms_parser, das_parser));

        match parser(input) {
            Ok(result) => Ok(result.1),
            Err(nom::Err::Error(err)) => {
                if config.log_with_backtrace {
                    println!(">>>>>>>>>>>>>>>>>>>>");
                    for error in &err.errors {
                        println!("{:?} :: {:?}", error.0, error.1)
                    }
                    println!("<<<<<<<<<<<<<<<<<<<<");
                }

                let msg = err.errors[0].0;
                let err_msg = format!("failed to parse sql, error near `{}`", msg);
                Err(err_msg)
            }
            _ => Err(String::from("failed to parse sql: other error")),
        }
    }
}

#[derive(Default)]
pub struct ParseConfig {
    pub log_with_backtrace: bool,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum Statement {
    // DDS
    AlterDatabase(AlterDatabaseStatement),
    AlterTable(AlterTableStatement),
    CreateIndex(CreateIndexStatement),
    CreateTable(CreateTableStatement),
    DropDatabase(DropDatabaseStatement),
    DropEvent(DropEventStatement),
    DropFunction(DropFunctionStatement),
    DropIndex(DropIndexStatement),
    DropLogfileGroup(DropLogfileGroupStatement),
    DropProcedure(DropProcedureStatement),
    DropServer(DropServerStatement),
    DropSpatialReferenceSystem(DropSpatialReferenceSystemStatement),
    DropTable(DropTableStatement),
    DropTableSpace(DropTablespaceStatement),
    DropTrigger(DropTriggerStatement),
    DropView(DropViewStatement),
    RenameTable(RenameTableStatement),
    TruncateTable(TruncateTableStatement),
    // DAS
    Set(SetStatement),
    // HISTORY
    Insert(InsertStatement),
    CompoundSelect(CompoundSelectStatement),
    Select(SelectStatement),
    Delete(DeleteStatement),
    Update(UpdateStatement),
}

impl fmt::Display for Statement {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            // FIXME add all
            Statement::Select(ref select) => write!(f, "{}", select),
            Statement::Insert(ref insert) => write!(f, "{}", insert),
            Statement::CreateTable(ref create) => write!(f, "{}", create),
            Statement::Delete(ref delete) => write!(f, "{}", delete),
            Statement::DropTable(ref drop) => write!(f, "{}", drop),
            Statement::DropDatabase(ref drop) => write!(f, "{}", drop),
            Statement::TruncateTable(ref drop) => write!(f, "{}", drop),
            Statement::Update(ref update) => write!(f, "{}", update),
            Statement::Set(ref set) => write!(f, "{}", set),
            _ => unimplemented!(),
        }
    }
}