diff --git a/vsql/ast.v b/vsql/ast.v index cc2bc22..c30b86b 100644 --- a/vsql/ast.v +++ b/vsql/ast.v @@ -28,9 +28,7 @@ type Expr = BinaryExpr | CastExpr | CoalesceExpr | CountAllExpr - | CurrentCatalogExpr | CurrentDateExpr - | CurrentSchemaExpr | CurrentTimeExpr | CurrentTimestampExpr | Identifier @@ -39,7 +37,6 @@ type Expr = BinaryExpr | NextValueExpr | NoExpr | NullIfExpr - | Parameter | Predicate | QualifiedAsteriskExpr | QueryExpression @@ -48,6 +45,7 @@ type Expr = BinaryExpr | TrimExpr | TruthExpr | UnaryExpr + | UnsignedValueSpecification | UntypedNullExpr | Value @@ -57,7 +55,7 @@ fn (e Expr) str() string { fn (e Expr) pstr(params map[string]Value) string { return match e { - Predicate { + Predicate, UnsignedValueSpecification { e.pstr(params) } BinaryExpr { @@ -75,12 +73,6 @@ fn (e Expr) pstr(params map[string]Value) string { CountAllExpr { e.pstr(params) } - CurrentCatalogExpr { - e.str() - } - CurrentSchemaExpr { - e.str() - } CurrentDateExpr { e.str() } @@ -108,9 +100,6 @@ fn (e Expr) pstr(params map[string]Value) string { NullIfExpr { e.pstr(params) } - Parameter { - e.pstr(params) - } QualifiedAsteriskExpr { e.str() } @@ -628,26 +617,6 @@ fn (c Correlation) str() string { return s } -// Parameter is :foo. The colon is not included in the name. Parameters are case -// sensitive. -struct Parameter { - name string -} - -fn (e Parameter) str() string { - return ':${e.name}' -} - -fn (e Parameter) pstr(params map[string]Value) string { - p := params[e.name] - - if p.typ.typ != .is_numeric && (p.typ.uses_string() || p.typ.uses_time()) { - return '\'${p.str()}\'' - } - - return p.str() -} - struct UniqueConstraintDefinition { columns []Identifier } @@ -909,22 +878,6 @@ fn (e NextValueExpr) str() string { return 'NEXT VALUE FOR ${e.name}' } -// CURRENT_CATALOG -struct CurrentCatalogExpr { -} - -fn (e CurrentCatalogExpr) str() string { - return 'CURRENT_CATALOG' -} - -// CURRENT_SCHEMA -struct CurrentSchemaExpr { -} - -fn (e CurrentSchemaExpr) str() string { - return 'CURRENT_SCHEMA' -} - // SET SCHEMA struct SetSchemaStmt { schema_name Expr diff --git a/vsql/eval.v b/vsql/eval.v index 46946b2..ec6b890 100644 --- a/vsql/eval.v +++ b/vsql/eval.v @@ -117,11 +117,6 @@ fn eval_as_type(conn &Connection, data Row, e Expr, params map[string]Value) !Ty TruthExpr { return new_type('BOOLEAN', 0, 0) } - Parameter { - p := params[e.name] or { return sqlstate_42p02(e.name) } - - return eval_as_type(conn, data, p, params) - } Value { return e.typ } @@ -166,7 +161,10 @@ fn eval_as_type(conn &Connection, data Row, e Expr, params map[string]Value) !Ty LocalTimestampExpr { return new_type('TIMESTAMP WITHOUT TIME ZONE', 0, 0) } - SubstringExpr, TrimExpr, CurrentCatalogExpr, CurrentSchemaExpr { + UnsignedValueSpecification { + return e.eval_type(conn, data, params) + } + SubstringExpr, TrimExpr { return new_type('CHARACTER VARYING', 0, 0) } UntypedNullExpr { @@ -177,7 +175,7 @@ fn eval_as_type(conn &Connection, data Row, e Expr, params map[string]Value) !Ty fn eval_as_value(mut conn Connection, data Row, e Expr, params map[string]Value) !Value { match e { - Predicate { + Predicate, UnsignedValueSpecification { return e.eval(mut conn, data, params) } BinaryExpr { @@ -204,9 +202,6 @@ fn eval_as_value(mut conn Connection, data Row, e Expr, params map[string]Value) NullIfExpr { return eval_nullif(mut conn, data, e, params) } - Parameter { - return params[e.name] or { return sqlstate_42p02(e.name) } - } SubstringExpr { return eval_substring(mut conn, data, e, params) } @@ -224,17 +219,11 @@ fn eval_as_value(mut conn Connection, data Row, e Expr, params map[string]Value) // ValuesOperation. return sqlstate_42601('missing or invalid expression provided') } - CurrentCatalogExpr { - return new_varchar_value(conn.current_catalog) - } CurrentDateExpr { now, _ := conn.now() return new_date_value(now.strftime('%Y-%m-%d')) } - CurrentSchemaExpr { - return new_varchar_value(conn.current_schema) - } CurrentTimeExpr { if e.prec > 6 { return sqlstate_42601('${e}: cannot have precision greater than 6') diff --git a/vsql/expr.v b/vsql/expr.v index 7da0e68..e27469e 100644 --- a/vsql/expr.v +++ b/vsql/expr.v @@ -12,7 +12,7 @@ fn expr_is_agg(conn &Connection, e Expr, row Row, params map[string]Value) !bool return nested_agg_unsupported(e) } } - Predicate { + Predicate, UnsignedValueSpecification { return e.is_agg(conn, row, params) } CallExpr { @@ -36,9 +36,9 @@ fn expr_is_agg(conn &Connection, e Expr, row Row, params map[string]Value) !bool CountAllExpr { return true } - Identifier, Parameter, Value, NoExpr, RowExpr, QualifiedAsteriskExpr, QueryExpression, + Identifier, Value, NoExpr, RowExpr, QualifiedAsteriskExpr, QueryExpression, CurrentDateExpr, CurrentTimeExpr, CurrentTimestampExpr, LocalTimeExpr, LocalTimestampExpr, - UntypedNullExpr, NextValueExpr, CurrentCatalogExpr, CurrentSchemaExpr { + UntypedNullExpr, NextValueExpr { return false } CoalesceExpr { @@ -107,7 +107,7 @@ fn resolve_identifiers(conn &Connection, e Expr, tables map[string]Table) !Expr return BinaryExpr{resolve_identifiers(conn, e.left, tables)!, e.op, resolve_identifiers(conn, e.right, tables)!} } - Predicate { + Predicate, UnsignedValueSpecification { return e.resolve_identifiers(conn, tables) } CallExpr { @@ -159,9 +159,8 @@ fn resolve_identifiers(conn &Connection, e Expr, tables map[string]Table) !Expr QualifiedAsteriskExpr { return QualifiedAsteriskExpr{resolve_identifiers(conn, e.table_name, tables)! as Identifier} } - CountAllExpr, Parameter, Value, NoExpr, QueryExpression, CurrentDateExpr, CurrentTimeExpr, - CurrentTimestampExpr, LocalTimeExpr, LocalTimestampExpr, UntypedNullExpr, - CurrentSchemaExpr, CurrentCatalogExpr { + CountAllExpr, Value, NoExpr, QueryExpression, CurrentDateExpr, CurrentTimeExpr, + CurrentTimestampExpr, LocalTimeExpr, LocalTimestampExpr, UntypedNullExpr { // These don't have any Expr properties to recurse. return e } diff --git a/vsql/grammar.v b/vsql/grammar.v index b5ea7bf..391f2a3 100644 --- a/vsql/grammar.v +++ b/vsql/grammar.v @@ -12,6 +12,7 @@ type EarleyValue = BetweenPredicate | CreateTableStmt | DerivedColumn | Expr + | GeneralValueSpecification | Identifier | IdentifierChain | InsertStmt @@ -36,6 +37,7 @@ type EarleyValue = BetweenPredicate | TablePrimaryBody | TableReference | Type + | UnsignedValueSpecification | Value | []Expr | []Identifier @@ -958,6 +960,9 @@ fn get_grammar() map[string]EarleyRule { mut rule_non_reserved_word_ := &EarleyRule{ name: '' } + mut rule_nonparenthesized_value_expression_primary_1_ := &EarleyRule{ + name: '' + } mut rule_nonparenthesized_value_expression_primary_2_ := &EarleyRule{ name: '' } @@ -1444,6 +1449,9 @@ fn get_grammar() map[string]EarleyRule { mut rule_simple_table_ := &EarleyRule{ name: '' } + mut rule_simple_value_specification_2_ := &EarleyRule{ + name: '' + } mut rule_simple_value_specification_ := &EarleyRule{ name: '' } @@ -1753,6 +1761,9 @@ fn get_grammar() map[string]EarleyRule { mut rule_unsigned_value_specification_1_ := &EarleyRule{ name: '' } + mut rule_unsigned_value_specification_2_ := &EarleyRule{ + name: '' + } mut rule_unsigned_value_specification_ := &EarleyRule{ name: '' } @@ -1786,6 +1797,9 @@ fn get_grammar() map[string]EarleyRule { mut rule_value_expression_ := &EarleyRule{ name: '' } + mut rule_value_specification_2_ := &EarleyRule{ + name: '' + } mut rule_value_specification_ := &EarleyRule{ name: '' } @@ -7508,6 +7522,12 @@ fn get_grammar() map[string]EarleyRule { }, ]} + rule_nonparenthesized_value_expression_primary_1_.productions << &EarleyProduction{[ + &EarleyRuleOrString{ + rule: rule_unsigned_value_specification_ + }, + ]} + rule_nonparenthesized_value_expression_primary_2_.productions << &EarleyProduction{[ &EarleyRuleOrString{ rule: rule_column_reference_ @@ -7516,7 +7536,7 @@ fn get_grammar() map[string]EarleyRule { rule_nonparenthesized_value_expression_primary_.productions << &EarleyProduction{[ &EarleyRuleOrString{ - rule: rule_unsigned_value_specification_ + rule: rule_nonparenthesized_value_expression_primary_1_ }, ]} rule_nonparenthesized_value_expression_primary_.productions << &EarleyProduction{[ @@ -9100,6 +9120,12 @@ fn get_grammar() map[string]EarleyRule { }, ]} + rule_simple_value_specification_2_.productions << &EarleyProduction{[ + &EarleyRuleOrString{ + rule: rule_host_parameter_name_ + }, + ]} + rule_simple_value_specification_.productions << &EarleyProduction{[ &EarleyRuleOrString{ rule: rule_literal_ @@ -9107,7 +9133,7 @@ fn get_grammar() map[string]EarleyRule { ]} rule_simple_value_specification_.productions << &EarleyProduction{[ &EarleyRuleOrString{ - rule: rule_host_parameter_name_ + rule: rule_simple_value_specification_2_ }, ]} @@ -10083,6 +10109,12 @@ fn get_grammar() map[string]EarleyRule { }, ]} + rule_unsigned_value_specification_2_.productions << &EarleyProduction{[ + &EarleyRuleOrString{ + rule: rule_general_value_specification_ + }, + ]} + rule_unsigned_value_specification_.productions << &EarleyProduction{[ &EarleyRuleOrString{ rule: rule_unsigned_value_specification_1_ @@ -10090,7 +10122,7 @@ fn get_grammar() map[string]EarleyRule { ]} rule_unsigned_value_specification_.productions << &EarleyProduction{[ &EarleyRuleOrString{ - rule: rule_general_value_specification_ + rule: rule_unsigned_value_specification_2_ }, ]} @@ -10209,6 +10241,12 @@ fn get_grammar() map[string]EarleyRule { }, ]} + rule_value_specification_2_.productions << &EarleyProduction{[ + &EarleyRuleOrString{ + rule: rule_general_value_specification_ + }, + ]} + rule_value_specification_.productions << &EarleyProduction{[ &EarleyRuleOrString{ rule: rule_literal_ @@ -10216,7 +10254,7 @@ fn get_grammar() map[string]EarleyRule { ]} rule_value_specification_.productions << &EarleyProduction{[ &EarleyRuleOrString{ - rule: rule_general_value_specification_ + rule: rule_value_specification_2_ }, ]} @@ -13359,6 +13397,7 @@ fn get_grammar() map[string]EarleyRule { rules[''] = rule_next_value_expression_1_ rules[''] = rule_next_value_expression_ rules[''] = rule_non_reserved_word_ + rules[''] = rule_nonparenthesized_value_expression_primary_1_ rules[''] = rule_nonparenthesized_value_expression_primary_2_ rules[''] = rule_nonparenthesized_value_expression_primary_ rules[''] = rule_not_equals_operator_ @@ -13521,6 +13560,7 @@ fn get_grammar() map[string]EarleyRule { rules[''] = rule_similar_predicate_1_ rules[''] = rule_similar_predicate_ rules[''] = rule_simple_table_ + rules[''] = rule_simple_value_specification_2_ rules[''] = rule_simple_value_specification_ rules[''] = rule_solidus_ rules[''] = rule_sort_key_ @@ -13624,6 +13664,7 @@ fn get_grammar() map[string]EarleyRule { rules[''] = rule_unsigned_literal_ rules[''] = rule_unsigned_numeric_literal_ rules[''] = rule_unsigned_value_specification_1_ + rules[''] = rule_unsigned_value_specification_2_ rules[''] = rule_unsigned_value_specification_ rules[''] = rule_update_source_ rules[''] = rule_update_statement_searched_1_ @@ -13635,6 +13676,7 @@ fn get_grammar() map[string]EarleyRule { rules[''] = rule_value_expression_list_ rules[''] = rule_value_expression_primary_ rules[''] = rule_value_expression_ + rules[''] = rule_value_specification_2_ rules[''] = rule_value_specification_ rules[''] = rule_where_clause_1_ rules[''] = rule_where_clause_ @@ -14658,6 +14700,11 @@ fn parse_ast_name(children []EarleyValue, name string) ![]EarleyValue { EarleyValue(parse_next_value_expression(children[3] as Identifier)!), ] } + '' { + return [ + EarleyValue(parse_nonparenthesized_value_expression_primary_1(children[0] as UnsignedValueSpecification)!), + ] + } '' { return [ EarleyValue(parse_identifier_to_expr(children[0] as Identifier)!), @@ -14954,6 +15001,11 @@ fn parse_ast_name(children []EarleyValue, name string) ![]EarleyValue { EarleyValue(parse_similar_pred(children[0] as Expr, children[1] as SimilarPredicate)!), ] } + '' { + return [ + EarleyValue(parse_simple_value_specification_2(children[0] as GeneralValueSpecification)!), + ] + } '' { return [EarleyValue(parse_sort_list1(children[0] as SortSpecification)!)] } @@ -15131,7 +15183,14 @@ fn parse_ast_name(children []EarleyValue, name string) ![]EarleyValue { ] } '' { - return [EarleyValue(parse_value_to_expr(children[0] as Value)!)] + return [ + EarleyValue(parse_unsigned_value_specification_1(children[0] as Value)!), + ] + } + '' { + return [ + EarleyValue(parse_unsigned_value_specification_2(children[0] as GeneralValueSpecification)!), + ] } '' { return [ @@ -15152,6 +15211,11 @@ fn parse_ast_name(children []EarleyValue, name string) ![]EarleyValue { EarleyValue(parse_append_exprs1(children[0] as []Expr, children[2] as Expr)!), ] } + '' { + return [ + EarleyValue(parse_value_specification_2(children[0] as GeneralValueSpecification)!), + ] + } '' { return [EarleyValue(parse_expr(children[1] as Expr)!)] } diff --git a/vsql/std_literal.v b/vsql/std_literal.v index 3ae5477..6fdaff3 100644 --- a/vsql/std_literal.v +++ b/vsql/std_literal.v @@ -91,3 +91,7 @@ fn parse_time_literal(v Value) !Value { fn parse_timestamp_literal(v Value) !Value { return new_timestamp_value(v.string_value()) } + +fn parse_value_to_expr(v Value) !Expr { + return v +} diff --git a/vsql/std_names_and_identifiers.v b/vsql/std_names_and_identifiers.v index b548517..e765355 100644 --- a/vsql/std_names_and_identifiers.v +++ b/vsql/std_names_and_identifiers.v @@ -41,7 +41,7 @@ module vsql //~ /* Identifier */ ::= //~ -> column_name //~ -//~ /* Expr */ ::= +//~ /* GeneralValueSpecification */ ::= //~ -> host_parameter_name //~ //~ /* Identifier */ ::= @@ -50,6 +50,32 @@ module vsql //~ /* Identifier */ ::= //~ -> sequence_generator_name +// HostParameterName is :foo. The colon is not included in the name. Parameters +// are case sensitive. +struct HostParameterName { + name string +} + +fn (e HostParameterName) pstr(params map[string]Value) string { + p := params[e.name] + + if p.typ.typ != .is_numeric && (p.typ.uses_string() || p.typ.uses_time()) { + return '\'${p.str()}\'' + } + + return p.str() +} + +fn (e HostParameterName) eval(mut conn Connection, data Row, params map[string]Value) !Value { + return params[e.name] or { return sqlstate_42p02(e.name) } +} + +fn (e HostParameterName) eval_type(conn &Connection, data Row, params map[string]Value) !Type { + p := params[e.name] or { return sqlstate_42p02(e.name) } + + return eval_as_type(conn, data, p, params) +} + fn parse_table_name(identifier IdentifierChain) !Identifier { return new_table_identifier(identifier.identifier) } @@ -74,8 +100,8 @@ fn parse_column_name(column_name IdentifierChain) !Identifier { return new_column_identifier(column_name.identifier) } -fn parse_host_parameter_name(name IdentifierChain) !Expr { - return Parameter{name.identifier} +fn parse_host_parameter_name(name IdentifierChain) !GeneralValueSpecification { + return HostParameterName{name.identifier} } fn parse_correlation_name(identifier IdentifierChain) !Identifier { diff --git a/vsql/std_value_expression_primary.v b/vsql/std_value_expression_primary.v index b2e9a64..456aaa6 100644 --- a/vsql/std_value_expression_primary.v +++ b/vsql/std_value_expression_primary.v @@ -12,7 +12,7 @@ module vsql //~ -> expr //~ //~ /* Expr */ ::= -//~ +//~ -> nonparenthesized_value_expression_primary_1 //~ | -> identifier_to_expr //~ | //~ | @@ -27,3 +27,7 @@ fn parse_expr(e Expr) !Expr { fn parse_identifier_to_expr(name Identifier) !Expr { return name } + +fn parse_nonparenthesized_value_expression_primary_1(e UnsignedValueSpecification) !Expr { + return e +} diff --git a/vsql/std_value_specification_and_target_specification.v b/vsql/std_value_specification_and_target_specification.v index ae13b78..3e0767d 100644 --- a/vsql/std_value_specification_and_target_specification.v +++ b/vsql/std_value_specification_and_target_specification.v @@ -6,32 +6,107 @@ module vsql //~ //~ /* Expr */ ::= //~ -//~ | +//~ | -> value_specification_2 //~ -//~ /* Expr */ ::= -//~ -> value_to_expr -//~ | +//~ /* UnsignedValueSpecification */ ::= +//~ -> unsigned_value_specification_1 +//~ | -> unsigned_value_specification_2 //~ -//~ /* Expr */ ::= +//~ /* GeneralValueSpecification */ ::= //~ //~ | CURRENT_CATALOG -> current_catalog //~ | CURRENT_SCHEMA -> current_schema //~ //~ /* Expr */ ::= //~ -//~ | +//~ | -> simple_value_specification_2 //~ -//~ /* Expr */ ::= +//~ /* GeneralValueSpecification */ ::= //~ -fn parse_current_catalog() !Expr { - return CurrentCatalogExpr{} +type UnsignedValueSpecification = GeneralValueSpecification | Value + +fn (e UnsignedValueSpecification) pstr(params map[string]Value) string { + return match e { + Value, GeneralValueSpecification { e.pstr(params) } + } +} + +fn (e UnsignedValueSpecification) eval_type(conn &Connection, data Row, params map[string]Value) !Type { + return match e { + Value { eval_as_type(conn, data, e, params)! } + GeneralValueSpecification { e.eval_type(conn, data, params)! } + } +} + +fn (e UnsignedValueSpecification) eval(mut conn Connection, data Row, params map[string]Value) !Value { + return match e { + Value { eval_as_value(mut conn, data, e, params)! } + GeneralValueSpecification { e.eval(mut conn, data, params)! } + } +} + +fn (e UnsignedValueSpecification) is_agg(conn &Connection, row Row, params map[string]Value) !bool { + return false } -fn parse_current_schema() !Expr { - return CurrentSchemaExpr{} +fn (e UnsignedValueSpecification) resolve_identifiers(conn &Connection, tables map[string]Table) !Expr { + return e } -fn parse_value_to_expr(v Value) !Expr { +type GeneralValueSpecification = CurrentCatalog | CurrentSchema | HostParameterName + +// CURRENT_CATALOG +struct CurrentCatalog { +} + +// CURRENT_SCHEMA +struct CurrentSchema { +} + +fn (e GeneralValueSpecification) pstr(params map[string]Value) string { + return match e { + HostParameterName { e.pstr(params) } + CurrentCatalog { 'CURRENT_CATALOG' } + CurrentSchema { 'CURRENT_SCHEMA' } + } +} + +fn (e GeneralValueSpecification) eval_type(conn &Connection, data Row, params map[string]Value) !Type { + return match e { + HostParameterName { e.eval_type(conn, data, params)! } + CurrentCatalog, CurrentSchema { new_type('CHARACTER VARYING', 0, 0) } + } +} + +fn (e GeneralValueSpecification) eval(mut conn Connection, data Row, params map[string]Value) !Value { + return match e { + HostParameterName { e.eval(mut conn, data, params)! } + CurrentCatalog { new_varchar_value(conn.current_catalog) } + CurrentSchema { new_varchar_value(conn.current_schema) } + } +} + +fn parse_current_catalog() !GeneralValueSpecification { + return CurrentCatalog{} +} + +fn parse_current_schema() !GeneralValueSpecification { + return CurrentSchema{} +} + +fn parse_unsigned_value_specification_1(v Value) !UnsignedValueSpecification { return v } + +fn parse_unsigned_value_specification_2(v GeneralValueSpecification) !UnsignedValueSpecification { + return v +} + +fn parse_value_specification_2(e GeneralValueSpecification) !Expr { + return UnsignedValueSpecification(e) +} + +fn parse_simple_value_specification_2(e GeneralValueSpecification) !Expr { + return UnsignedValueSpecification(e) +} diff --git a/vsql/value.v b/vsql/value.v index 246e31e..872f322 100644 --- a/vsql/value.v +++ b/vsql/value.v @@ -286,6 +286,14 @@ fn (v Value) as_numeric() !big.Integer { return big.integer_from_string(strconv.f64_to_str_l(v.f64_value()).split('.')[0]) } +fn (v Value) pstr(params map[string]Value) string { + if v.typ.typ != .is_numeric && (v.typ.uses_string() || v.typ.uses_time()) { + return '\'${v.str()}\'' + } + + return v.str() +} + // The string representation of this value. Different types will have different // formatting. pub fn (v Value) str() string {