2015-02-22 21:39:17 +00:00
|
|
|
extern crate phf_codegen;
|
|
|
|
|
2016-01-03 07:19:20 +00:00
|
|
|
use std::ascii::AsciiExt;
|
2015-02-22 21:39:17 +00:00
|
|
|
use std::env;
|
|
|
|
use std::fs::File;
|
|
|
|
use std::io::{Write, BufWriter};
|
2015-03-26 02:11:40 +00:00
|
|
|
use std::path::Path;
|
|
|
|
use std::convert::AsRef;
|
2015-02-22 21:39:17 +00:00
|
|
|
|
2016-02-12 04:56:15 +00:00
|
|
|
const ERRCODES_TXT: &'static str = include_str!("errcodes.txt");
|
2016-01-03 07:19:20 +00:00
|
|
|
|
|
|
|
struct Code {
|
|
|
|
code: String,
|
|
|
|
variant: String,
|
|
|
|
}
|
2015-02-22 21:39:17 +00:00
|
|
|
|
|
|
|
fn main() {
|
2015-03-26 02:11:40 +00:00
|
|
|
let path = env::var_os("OUT_DIR").unwrap();
|
|
|
|
let path: &Path = path.as_ref();
|
|
|
|
let path = path.join("sqlstate.rs");
|
2015-02-22 21:39:17 +00:00
|
|
|
let mut file = BufWriter::new(File::create(&path).unwrap());
|
|
|
|
|
2016-01-03 07:19:20 +00:00
|
|
|
let codes = parse_codes();
|
|
|
|
|
|
|
|
make_enum(&codes, &mut file);
|
|
|
|
make_map(&codes, &mut file);
|
|
|
|
make_impl(&codes, &mut file);
|
2015-12-06 02:57:00 +00:00
|
|
|
|
|
|
|
println!("cargo:rerun-if-changed=build.rs");
|
2016-02-12 04:58:25 +00:00
|
|
|
println!("cargo:rerun-if-changed=errcodes.txt");
|
2015-02-22 21:39:17 +00:00
|
|
|
}
|
|
|
|
|
2016-01-03 07:19:20 +00:00
|
|
|
fn parse_codes() -> Vec<Code> {
|
|
|
|
let mut codes = vec![];
|
|
|
|
|
|
|
|
for line in ERRCODES_TXT.lines() {
|
|
|
|
if line.starts_with("#") || line.starts_with("Section") || line.trim().is_empty() {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut it = line.split_whitespace();
|
|
|
|
let code = it.next().unwrap().to_owned();
|
|
|
|
it.next();
|
|
|
|
it.next();
|
|
|
|
// for 2202E
|
|
|
|
let name = match it.next() {
|
|
|
|
Some(name) => name,
|
|
|
|
None => continue,
|
|
|
|
};
|
|
|
|
let variant = match variant_name(&code) {
|
|
|
|
Some(variant) => variant,
|
|
|
|
None => snake_to_camel(&name),
|
|
|
|
};
|
|
|
|
|
|
|
|
codes.push(Code {
|
|
|
|
code: code,
|
|
|
|
variant: variant,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
codes
|
|
|
|
}
|
|
|
|
|
|
|
|
fn snake_to_camel(s: &str) -> String {
|
|
|
|
let mut out = String::new();
|
|
|
|
|
|
|
|
let mut upper = true;
|
|
|
|
for ch in s.chars() {
|
|
|
|
if ch == '_' {
|
|
|
|
upper = true;
|
|
|
|
} else {
|
|
|
|
let ch = if upper {
|
|
|
|
upper = false;
|
|
|
|
ch.to_ascii_uppercase()
|
|
|
|
} else {
|
|
|
|
ch
|
|
|
|
};
|
|
|
|
out.push(ch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out
|
|
|
|
}
|
|
|
|
|
|
|
|
fn variant_name(code: &str) -> Option<String> {
|
|
|
|
match code {
|
|
|
|
"01004" => Some("WarningStringDataRightTruncation".to_owned()),
|
|
|
|
"22001" => Some("DataStringDataRightTruncation".to_owned()),
|
|
|
|
"2F002" => Some("SqlRoutineModifyingSqlDataNotPermitted".to_owned()),
|
|
|
|
"38002" => Some("ForeignRoutineModifyingSqlDataNotPermitted".to_owned()),
|
|
|
|
"2F003" => Some("SqlRoutineProhibitedSqlStatementAttempted".to_owned()),
|
|
|
|
"38003" => Some("ForeignRoutineProhibitedSqlStatementAttempted".to_owned()),
|
|
|
|
"2F004" => Some("SqlRoutineReadingSqlDataNotPermitted".to_owned()),
|
|
|
|
"38004" => Some("ForeignRoutineReadingSqlDataNotPermitted".to_owned()),
|
|
|
|
"22004" => Some("DataNullValueNotAllowed".to_owned()),
|
|
|
|
"39004" => Some("ExternalRoutineInvocationNullValueNotAllowed".to_owned()),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn make_enum(codes: &[Code], file: &mut BufWriter<File>) {
|
2015-02-22 21:45:17 +00:00
|
|
|
write!(file,
|
|
|
|
r#"/// SQLSTATE error codes
|
2016-02-12 03:56:44 +00:00
|
|
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
2015-02-22 21:39:17 +00:00
|
|
|
pub enum SqlState {{
|
|
|
|
"#
|
|
|
|
).unwrap();
|
|
|
|
|
2016-01-03 07:19:20 +00:00
|
|
|
for code in codes {
|
2015-02-22 21:39:17 +00:00
|
|
|
write!(file,
|
2015-04-01 06:52:03 +00:00
|
|
|
" /// `{}`
|
|
|
|
{},\n",
|
2016-01-03 07:19:20 +00:00
|
|
|
code.code, code.variant).unwrap();
|
2015-02-22 21:39:17 +00:00
|
|
|
}
|
|
|
|
|
2015-02-22 21:45:17 +00:00
|
|
|
write!(file,
|
2015-04-01 06:52:03 +00:00
|
|
|
" /// An unknown code
|
2016-01-03 05:52:26 +00:00
|
|
|
Other(String)
|
2015-02-22 21:39:17 +00:00
|
|
|
}}
|
2015-02-22 21:45:17 +00:00
|
|
|
"
|
2015-02-22 21:39:17 +00:00
|
|
|
).unwrap();
|
|
|
|
}
|
|
|
|
|
2016-01-03 07:19:20 +00:00
|
|
|
fn make_map(codes: &[Code], file: &mut BufWriter<File>) {
|
2015-02-22 21:39:17 +00:00
|
|
|
write!(file, "static SQLSTATE_MAP: phf::Map<&'static str, SqlState> = ").unwrap();
|
|
|
|
let mut builder = phf_codegen::Map::new();
|
2016-01-03 07:19:20 +00:00
|
|
|
for code in codes {
|
|
|
|
builder.entry(&*code.code, &format!("SqlState::{}", code.variant));
|
2015-02-22 21:39:17 +00:00
|
|
|
}
|
|
|
|
builder.build(file).unwrap();
|
|
|
|
write!(file, ";\n").unwrap();
|
|
|
|
}
|
|
|
|
|
2016-01-03 07:19:20 +00:00
|
|
|
fn make_impl(codes: &[Code], file: &mut BufWriter<File>) {
|
2015-02-22 21:39:17 +00:00
|
|
|
write!(file, r#"
|
|
|
|
impl SqlState {{
|
|
|
|
/// Creates a `SqlState` from its error code.
|
|
|
|
pub fn from_code(s: String) -> SqlState {{
|
|
|
|
match SQLSTATE_MAP.get(&*s) {{
|
|
|
|
Some(state) => state.clone(),
|
2016-01-03 05:52:26 +00:00
|
|
|
None => SqlState::Other(s)
|
2015-02-22 21:39:17 +00:00
|
|
|
}}
|
|
|
|
}}
|
|
|
|
|
|
|
|
/// Returns the error code corresponding to the `SqlState`.
|
|
|
|
pub fn code(&self) -> &str {{
|
2015-02-22 22:43:56 +00:00
|
|
|
match *self {{"#
|
2015-02-22 21:39:17 +00:00
|
|
|
).unwrap();
|
|
|
|
|
2016-01-03 07:19:20 +00:00
|
|
|
for code in codes {
|
2015-02-22 21:39:17 +00:00
|
|
|
write!(file, r#"
|
|
|
|
SqlState::{} => "{}","#,
|
2016-01-03 07:19:20 +00:00
|
|
|
code.variant, code.code).unwrap();
|
2015-02-22 21:39:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
write!(file, r#"
|
2016-01-03 05:52:26 +00:00
|
|
|
SqlState::Other(ref s) => s,
|
2015-02-22 21:39:17 +00:00
|
|
|
}}
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
"#
|
|
|
|
).unwrap();
|
|
|
|
}
|