Skip to content

Commit d9edc25

Browse files
committed
Change Value::Long() to u64, use u64 instead of usize
The tokenizer emits a separate Token for +/- signs, so the value of Value::Long() (as well as of parse_literal_int()) may never be negative. Also we have been using both u64 and usize to represent a parsed unsigned number. Change to using u64 for consistency.
1 parent 0407ed2 commit d9edc25

File tree

4 files changed

+34
-46
lines changed

4 files changed

+34
-46
lines changed

src/sqlast/sqltype.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
use super::SQLObjectName;
22

3-
/// SQL datatypes for literals in SQL statements
3+
/// SQL data types
44
#[derive(Debug, Clone, PartialEq)]
55
pub enum SQLType {
66
/// Fixed-length character type e.g. CHAR(10)
7-
Char(Option<usize>),
7+
Char(Option<u64>),
88
/// Variable-length character type e.g. VARCHAR(10)
9-
Varchar(Option<usize>),
9+
Varchar(Option<u64>),
1010
/// Uuid type
1111
Uuid,
1212
/// Large character object e.g. CLOB(1000)
13-
Clob(usize),
13+
Clob(u64),
1414
/// Fixed-length binary type e.g. BINARY(10)
15-
Binary(usize),
15+
Binary(u64),
1616
/// Variable-length binary type e.g. VARBINARY(10)
17-
Varbinary(usize),
17+
Varbinary(u64),
1818
/// Large binary object e.g. BLOB(1000)
19-
Blob(usize),
19+
Blob(u64),
2020
/// Decimal type with optional precision and scale e.g. DECIMAL(10,2)
21-
Decimal(Option<usize>, Option<usize>),
21+
Decimal(Option<u64>, Option<u64>),
2222
/// Floating point with optional precision e.g. FLOAT(8)
23-
Float(Option<usize>),
23+
Float(Option<u64>),
2424
/// Small integer
2525
SmallInt,
2626
/// Integer
@@ -87,7 +87,7 @@ impl ToString for SQLType {
8787
}
8888
}
8989

90-
fn format_type_with_optional_length(sql_type: &str, len: &Option<usize>) -> String {
90+
fn format_type_with_optional_length(sql_type: &str, len: &Option<u64>) -> String {
9191
let mut s = sql_type.to_string();
9292
if let Some(len) = len {
9393
s += &format!("({})", len);

src/sqlast/value.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
/// SQL values such as int, double, string, timestamp
1+
/// Primitive SQL values such as number and string
22
#[derive(Debug, Clone, PartialEq)]
33
pub enum Value {
4-
/// Literal signed long
5-
Long(i64),
6-
/// Literal floating point value
4+
/// Unsigned integer value
5+
Long(u64),
6+
/// Unsigned floating point value
77
Double(f64),
88
/// 'string value'
99
SingleQuotedString(String),
1010
/// N'string value'
1111
NationalStringLiteral(String),
12-
/// Boolean value true or false,
12+
/// Boolean value true or false
1313
Boolean(bool),
1414
/// NULL value in insert statements,
1515
Null,

src/sqlparser.rs

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -351,14 +351,8 @@ impl Parser {
351351
let rows = if self.parse_keyword("UNBOUNDED") {
352352
None
353353
} else {
354-
let rows = self.parse_literal_int()?;
355-
if rows < 0 {
356-
parser_err!(format!(
357-
"The number of rows must be non-negative, got {}",
358-
rows
359-
))?;
360-
}
361-
Some(rows as u64)
354+
let rows = self.parse_literal_uint()?;
355+
Some(rows)
362356
};
363357
if self.parse_keyword("PRECEDING") {
364358
Ok(SQLWindowFrameBound::Preceding(rows))
@@ -1059,9 +1053,9 @@ impl Parser {
10591053
Ok(n) => Ok(Value::Double(n)),
10601054
Err(e) => parser_err!(format!("Could not parse '{}' as f64: {}", n, e)),
10611055
},
1062-
Token::Number(ref n) => match n.parse::<i64>() {
1056+
Token::Number(ref n) => match n.parse::<u64>() {
10631057
Ok(n) => Ok(Value::Long(n)),
1064-
Err(e) => parser_err!(format!("Could not parse '{}' as i64: {}", n, e)),
1058+
Err(e) => parser_err!(format!("Could not parse '{}' as u64: {}", n, e)),
10651059
},
10661060
Token::SingleQuotedString(ref s) => Ok(Value::SingleQuotedString(s.to_string())),
10671061
Token::NationalStringLiteral(ref s) => {
@@ -1073,13 +1067,13 @@ impl Parser {
10731067
}
10741068
}
10751069

1076-
/// Parse a literal integer/long
1077-
pub fn parse_literal_int(&mut self) -> Result<i64, ParserError> {
1070+
/// Parse an unsigned literal integer/long
1071+
pub fn parse_literal_uint(&mut self) -> Result<u64, ParserError> {
10781072
match self.next_token() {
1079-
Some(Token::Number(s)) => s.parse::<i64>().map_err(|e| {
1080-
ParserError::ParserError(format!("Could not parse '{}' as i64: {}", s, e))
1073+
Some(Token::Number(s)) => s.parse::<u64>().map_err(|e| {
1074+
ParserError::ParserError(format!("Could not parse '{}' as u64: {}", s, e))
10811075
}),
1082-
other => parser_err!(format!("Expected literal int, found {:?}", other)),
1076+
other => self.expected("literal int", other),
10831077
}
10841078
}
10851079

@@ -1258,34 +1252,28 @@ impl Parser {
12581252
}
12591253
}
12601254

1261-
pub fn parse_precision(&mut self) -> Result<usize, ParserError> {
1262-
//TODO: error handling
1263-
Ok(self.parse_optional_precision()?.unwrap())
1264-
}
1265-
1266-
pub fn parse_optional_precision(&mut self) -> Result<Option<usize>, ParserError> {
1255+
pub fn parse_optional_precision(&mut self) -> Result<Option<u64>, ParserError> {
12671256
if self.consume_token(&Token::LParen) {
1268-
let n = self.parse_literal_int()?;
1269-
//TODO: check return value of reading rparen
1257+
let n = self.parse_literal_uint()?;
12701258
self.expect_token(&Token::RParen)?;
1271-
Ok(Some(n as usize))
1259+
Ok(Some(n))
12721260
} else {
12731261
Ok(None)
12741262
}
12751263
}
12761264

12771265
pub fn parse_optional_precision_scale(
12781266
&mut self,
1279-
) -> Result<(Option<usize>, Option<usize>), ParserError> {
1267+
) -> Result<(Option<u64>, Option<u64>), ParserError> {
12801268
if self.consume_token(&Token::LParen) {
1281-
let n = self.parse_literal_int()?;
1269+
let n = self.parse_literal_uint()?;
12821270
let scale = if self.consume_token(&Token::Comma) {
1283-
Some(self.parse_literal_int()? as usize)
1271+
Some(self.parse_literal_uint()?)
12841272
} else {
12851273
None
12861274
};
12871275
self.expect_token(&Token::RParen)?;
1288-
Ok((Some(n as usize), scale))
1276+
Ok((Some(n), scale))
12891277
} else {
12901278
Ok((None, None))
12911279
}
@@ -1725,15 +1713,15 @@ impl Parser {
17251713
if self.parse_keyword("ALL") {
17261714
Ok(None)
17271715
} else {
1728-
self.parse_literal_int()
1716+
self.parse_literal_uint()
17291717
.map(|n| Some(ASTNode::SQLValue(Value::Long(n))))
17301718
}
17311719
}
17321720

17331721
/// Parse an OFFSET clause
17341722
pub fn parse_offset(&mut self) -> Result<ASTNode, ParserError> {
17351723
let value = self
1736-
.parse_literal_int()
1724+
.parse_literal_uint()
17371725
.map(|n| ASTNode::SQLValue(Value::Long(n)))?;
17381726
self.expect_one_of_keywords(&["ROW", "ROWS"])?;
17391727
Ok(value)

src/sqltokenizer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use super::dialect::Dialect;
2929
pub enum Token {
3030
/// A keyword (like SELECT) or an optionally quoted SQL identifier
3131
SQLWord(SQLWord),
32-
/// Numeric literal
32+
/// An unsigned numeric literal
3333
Number(String),
3434
/// A character that could not be tokenized
3535
Char(char),

0 commit comments

Comments
 (0)