diff --git a/docs/custom-functions.rst b/docs/custom-functions.rst index 245ffbf..effcdcc 100644 --- a/docs/custom-functions.rst +++ b/docs/custom-functions.rst @@ -7,7 +7,7 @@ You can create custom functions to use in expressions: // no_pennies will round to 0.05 denominations. db.register_function('no_pennies(float) float', fn (a []vsql.Value) !vsql.Value { - amount := math.round(a[0].f64_value / 0.05) * 0.05 + amount := math.round(a[0].f64_value() / 0.05) * 0.05 return vsql.new_double_precision_value(amount) }) ! diff --git a/docs/snippets.rst b/docs/snippets.rst index b55948f..7c7b406 100644 --- a/docs/snippets.rst +++ b/docs/snippets.rst @@ -281,6 +281,9 @@ .. |v.Type.not_null| replace:: Is NOT NULL? +.. |v.Type.scale| replace:: + The scale is only for numeric types. + .. |v.Type.size| replace:: The size specified for the type. diff --git a/examples/custom-functions.v b/examples/custom-functions.v index 3c68cab..c252e78 100644 --- a/examples/custom-functions.v +++ b/examples/custom-functions.v @@ -12,7 +12,7 @@ fn example() ! { // no_pennies will round to 0.05 denominations. db.register_function('no_pennies(float) float', fn (a []vsql.Value) !vsql.Value { - amount := math.round(a[0].f64_value / 0.05) * 0.05 + amount := math.round(a[0].f64_value() / 0.05) * 0.05 return vsql.new_double_precision_value(amount) })! diff --git a/vsql/agg.v b/vsql/agg.v index 9769a94..60ded4e 100644 --- a/vsql/agg.v +++ b/vsql/agg.v @@ -20,15 +20,15 @@ fn func_min(values []Value) !Value { return new_null_value(.is_double_precision) } - mut min := values[0].f64_value + mut min := values[0].f64_value() for value in values { // If any values are NULL, the result is also NULL. if value.is_null { return new_null_value(.is_double_precision) } - if value.f64_value < min { - min = value.f64_value + if value.f64_value() < min { + min = value.f64_value() } } @@ -41,15 +41,15 @@ fn func_max(values []Value) !Value { return new_null_value(.is_double_precision) } - mut max := values[0].f64_value + mut max := values[0].f64_value() for value in values { // If any values are NULL, the result is also NULL. if value.is_null { return new_null_value(.is_double_precision) } - if value.f64_value > max { - max = value.f64_value + if value.f64_value() > max { + max = value.f64_value() } } @@ -69,7 +69,7 @@ fn func_sum(values []Value) !Value { return new_null_value(.is_double_precision) } - sum += value.f64_value + sum += value.f64_value() } return new_double_precision_value(sum) @@ -88,7 +88,7 @@ fn func_avg(values []Value) !Value { return new_null_value(.is_double_precision) } - sum += value.f64_value + sum += value.f64_value() } return new_double_precision_value(sum / values.len) diff --git a/vsql/cast.v b/vsql/cast.v index f28afd1..dd2f94b 100644 --- a/vsql/cast.v +++ b/vsql/cast.v @@ -115,213 +115,213 @@ fn cast_passthru(conn &Connection, v Value, to Type) !Value { } fn cast_bigint_to_smallint(conn &Connection, v Value, to Type) !Value { - check_integer_range(v.int_value, .is_smallint)! + check_integer_range(v.int_value(), .is_smallint)! - return new_smallint_value(i16(v.int_value)) + return new_smallint_value(i16(v.int_value())) } fn cast_bigint_to_integer(conn &Connection, v Value, to Type) !Value { - check_integer_range(v.int_value, .is_integer)! + check_integer_range(v.int_value(), .is_integer)! - return new_integer_value(int(v.int_value)) + return new_integer_value(int(v.int_value())) } fn cast_bigint_to_real(conn &Connection, v Value, to Type) !Value { - return new_real_value(f32(v.int_value)) + return new_real_value(f32(v.int_value())) } fn cast_bigint_to_double_precision(conn &Connection, v Value, to Type) !Value { - return new_double_precision_value(f64(v.int_value)) + return new_double_precision_value(f64(v.int_value())) } fn cast_smallint_to_integer(conn &Connection, v Value, to Type) !Value { - return new_integer_value(int(v.int_value)) + return new_integer_value(int(v.int_value())) } fn cast_smallint_to_bigint(conn &Connection, v Value, to Type) !Value { - return new_bigint_value(int(v.int_value)) + return new_bigint_value(int(v.int_value())) } fn cast_smallint_to_real(conn &Connection, v Value, to Type) !Value { - return new_real_value(f32(v.int_value)) + return new_real_value(f32(v.int_value())) } fn cast_smallint_to_double_precision(conn &Connection, v Value, to Type) !Value { - return new_double_precision_value(f64(v.int_value)) + return new_double_precision_value(f64(v.int_value())) } fn cast_integer_to_smallint(conn &Connection, v Value, to Type) !Value { - check_integer_range(v.int_value, .is_smallint)! + check_integer_range(v.int_value(), .is_smallint)! - return new_smallint_value(i16(v.int_value)) + return new_smallint_value(i16(v.int_value())) } fn cast_integer_to_bigint(conn &Connection, v Value, to Type) !Value { - return new_bigint_value(int(v.int_value)) + return new_bigint_value(int(v.int_value())) } fn cast_integer_to_real(conn &Connection, v Value, to Type) !Value { - return new_real_value(f32(v.int_value)) + return new_real_value(f32(v.int_value())) } fn cast_integer_to_double_precision(conn &Connection, v Value, to Type) !Value { - return new_double_precision_value(f64(v.int_value)) + return new_double_precision_value(f64(v.int_value())) } fn cast_real_to_smallint(conn &Connection, v Value, to Type) !Value { - check_floating_range(v.f64_value, .is_smallint)! + check_floating_range(v.f64_value(), .is_smallint)! - return new_smallint_value(i16(v.f64_value)) + return new_smallint_value(i16(v.f64_value())) } fn cast_real_to_integer(conn &Connection, v Value, to Type) !Value { - check_floating_range(v.f64_value, .is_integer)! + check_floating_range(v.f64_value(), .is_integer)! - return new_integer_value(int(v.f64_value)) + return new_integer_value(int(v.f64_value())) } fn cast_real_to_bigint(conn &Connection, v Value, to Type) !Value { - check_floating_range(v.f64_value, .is_bigint)! + check_floating_range(v.f64_value(), .is_bigint)! - return new_bigint_value(i64(v.f64_value)) + return new_bigint_value(i64(v.f64_value())) } fn cast_real_to_double_precision(conn &Connection, v Value, to Type) !Value { - return new_double_precision_value(f64(v.f64_value)) + return new_double_precision_value(f64(v.f64_value())) } fn cast_double_precision_to_smallint(conn &Connection, v Value, to Type) !Value { - check_floating_range(v.f64_value, .is_smallint)! + check_floating_range(v.f64_value(), .is_smallint)! - return new_smallint_value(i16(v.f64_value)) + return new_smallint_value(i16(v.f64_value())) } fn cast_double_precision_to_integer(conn &Connection, v Value, to Type) !Value { - check_floating_range(v.f64_value, .is_integer)! + check_floating_range(v.f64_value(), .is_integer)! - return new_integer_value(int(v.f64_value)) + return new_integer_value(int(v.f64_value())) } fn cast_double_precision_to_bigint(conn &Connection, v Value, to Type) !Value { - check_floating_range(v.f64_value, .is_bigint)! + check_floating_range(v.f64_value(), .is_bigint)! - return new_bigint_value(i64(v.f64_value)) + return new_bigint_value(i64(v.f64_value())) } fn cast_double_precision_to_real(conn &Connection, v Value, to Type) !Value { - return new_real_value(f32(v.f64_value)) + return new_real_value(f32(v.f64_value())) } fn cast_varchar_to_varchar(conn &Connection, v Value, to Type) !Value { - if to.size > 0 && v.string_value.len > to.size { + if to.size > 0 && v.string_value().len > to.size { return sqlstate_22001(to) } - return new_varchar_value(v.string_value, to.size) + return new_varchar_value(v.string_value(), to.size) } fn cast_varchar_to_character(conn &Connection, v Value, to Type) !Value { - if to.size > 0 && v.string_value.len > to.size { + if to.size > 0 && v.string_value().len > to.size { return sqlstate_22001(to) } - return new_character_value(v.string_value, to.size) + return new_character_value(v.string_value(), to.size) } fn cast_character_to_varchar(conn &Connection, v Value, to Type) !Value { - if to.size > 0 && v.string_value.len > to.size { + if to.size > 0 && v.string_value().len > to.size { return sqlstate_22001(to) } - return new_varchar_value(v.string_value, to.size) + return new_varchar_value(v.string_value(), to.size) } fn cast_character_to_character(conn &Connection, v Value, to Type) !Value { - if to.size > 0 && v.string_value.len > to.size { + if to.size > 0 && v.string_value().len > to.size { return sqlstate_22001(to) } - return new_character_value(v.string_value, to.size) + return new_character_value(v.string_value(), to.size) } // '2022-06-30' => '2022-06-30 00:00:00.000000' fn cast_date_to_timestamp_without(conn &Connection, v Value, to Type) !Value { - return new_timestamp_value(v.time_value.str_full_timestamp(to.size, false, true)) + return new_timestamp_value(v.time_value().str_full_timestamp(to.size, false, true)) } // '2022-06-30' => '2022-06-30 00:00:00.000000+05:00' fn cast_date_to_timestamp_with(conn &Connection, v Value, to Type) !Value { - return new_timestamp_value(v.time_value.str_full_timestamp(to.size, false, true) + + return new_timestamp_value(v.time_value().str_full_timestamp(to.size, false, true) + time_zone_value(conn)) } // '12:34:56.000000+0500' => '12:34:56.000000' fn cast_time_with_to_time_without(conn &Connection, v Value, to Type) !Value { - return new_time_value(v.time_value.str_full_time(to.size, false, true)) + return new_time_value(v.time_value().str_full_time(to.size, false, true)) } // '12:34:56.999999' => '12:34:56.999999+0500' fn cast_time_without_to_time_with(conn &Connection, v Value, to Type) !Value { - return new_time_value(v.time_value.str_full_time(to.size, false, true) + time_zone_value(conn)) + return new_time_value(v.time_value().str_full_time(to.size, false, true) + time_zone_value(conn)) } // '2022-06-30 12:34:56.999999+0500' => '2022-06-30' fn cast_timestamp_with_to_date(conn &Connection, v Value, to Type) !Value { - return new_date_value(v.time_value.str_date()) + return new_date_value(v.time_value().str_date()) } // '2022-06-30 12:34:56.999999+0500' => '12:34:56.999999+0500' fn cast_timestamp_with_to_time_with(conn &Connection, v Value, to Type) !Value { - return new_time_value(v.time_value.str_full_time(to.size, true, true)) + return new_time_value(v.time_value().str_full_time(to.size, true, true)) } // '2022-06-30 12:34:56.999999+0500' => '12:34:56.999999' fn cast_timestamp_with_to_time_without(conn &Connection, v Value, to Type) !Value { - return new_time_value(v.time_value.str_full_time(to.size, false, true)) + return new_time_value(v.time_value().str_full_time(to.size, false, true)) } // '2022-06-30 12:34:56.999999+0500' => '2022-06-30 12:34:56.999999' fn cast_timestamp_with_to_timestamp_without(conn &Connection, v Value, to Type) !Value { - return new_timestamp_value(v.time_value.str_full_timestamp(to.size, false, true)) + return new_timestamp_value(v.time_value().str_full_timestamp(to.size, false, true)) } // '12:34:56.999999+0500' => '12:34:56.999999+0500' fn cast_time_with_to_time_with(conn &Connection, v Value, to Type) !Value { - return new_time_value(v.time_value.str_full_time(to.size, true, true)) + return new_time_value(v.time_value().str_full_time(to.size, true, true)) } // '12:34:56.999999' => '12:34:56.999999' fn cast_time_without_to_time_without(conn &Connection, v Value, to Type) !Value { - return new_time_value(v.time_value.str_full_time(to.size, false, true)) + return new_time_value(v.time_value().str_full_time(to.size, false, true)) } // '2022-06-30 12:34:56.999999+0500' => '2022-06-30 12:34:56.999999+0500' fn cast_timestamp_with_to_timestamp_with(conn &Connection, v Value, to Type) !Value { - return new_timestamp_value(v.time_value.str_full_timestamp(to.size, true, true)) + return new_timestamp_value(v.time_value().str_full_timestamp(to.size, true, true)) } // '2022-06-30 12:34:56.999999' => '2022-06-30' fn cast_timestamp_without_to_date(conn &Connection, v Value, to Type) !Value { - return new_date_value(v.time_value.str_date()) + return new_date_value(v.time_value().str_date()) } // '2022-06-30 12:34:56.999999' => '12:34:56.999999+0500' fn cast_timestamp_without_to_time_with(conn &Connection, v Value, to Type) !Value { - return new_time_value(v.time_value.str_full_time(to.size, false, true) + time_zone_value(conn)) + return new_time_value(v.time_value().str_full_time(to.size, false, true) + time_zone_value(conn)) } // '2022-06-30 12:34:56.999999' => '12:34:56.999999' fn cast_timestamp_without_to_time_without(conn &Connection, v Value, to Type) !Value { - return new_time_value(v.time_value.str_full_time(to.size, false, true)) + return new_time_value(v.time_value().str_full_time(to.size, false, true)) } // '2022-06-30 12:34:56.999999' => '2022-06-30 12:34:56.999999+0500' fn cast_timestamp_without_to_timestamp_with(conn &Connection, v Value, to Type) !Value { - return new_timestamp_value(v.time_value.str_full_timestamp(to.size, false, true) + + return new_timestamp_value(v.time_value().str_full_timestamp(to.size, false, true) + time_zone_value(conn)) } // '2022-06-30 12:34:56.999999' => '2022-06-30 12:34:56.999999' fn cast_timestamp_without_to_timestamp_without(conn &Connection, v Value, to Type) !Value { - return new_timestamp_value(v.time_value.str_full_timestamp(to.size, false, true)) + return new_timestamp_value(v.time_value().str_full_timestamp(to.size, false, true)) } diff --git a/vsql/connection.v b/vsql/connection.v index 33d9a95..4778327 100644 --- a/vsql/connection.v +++ b/vsql/connection.v @@ -332,11 +332,11 @@ pub fn (mut c Connection) register_function(prototype string, func fn ([]Value) mut arg_types := []Type{} for arg in raw_args { if arg.trim_space() != '' { - arg_types << new_type(arg.trim_space().to_upper(), 0) + arg_types << new_type(arg.trim_space().to_upper(), 0, 0) } } - return_type := new_type(parts[2].trim_space().to_upper(), 0) + return_type := new_type(parts[2].trim_space().to_upper(), 0, 0) c.register_func(Func{function_name, arg_types, false, func, return_type})! } diff --git a/vsql/eval.v b/vsql/eval.v index 657f871..2f25180 100644 --- a/vsql/eval.v +++ b/vsql/eval.v @@ -111,10 +111,10 @@ fn eval_as_type(conn &Connection, data Row, e Expr, params map[string]Value) !Ty return func.return_type } CountAllExpr, NextValueExpr { - return new_type('INTEGER', 0) + return new_type('INTEGER', 0, 0) } BetweenExpr, NullExpr, TruthExpr, LikeExpr, SimilarExpr { - return new_type('BOOLEAN', 0) + return new_type('BOOLEAN', 0, 0) } Parameter { p := params[e.name] or { return sqlstate_42p02(e.name) } @@ -151,22 +151,22 @@ fn eval_as_type(conn &Connection, data Row, e Expr, params map[string]Value) !Ty return sqlstate_42601('invalid expression provided: ${e.str()}') } CurrentDateExpr { - return new_type('DATE', 0) + return new_type('DATE', 0, 0) } CurrentTimeExpr { - return new_type('TIME WITH TIME ZONE', 0) + return new_type('TIME WITH TIME ZONE', 0, 0) } CurrentTimestampExpr { - return new_type('TIMESTAMP WITH TIME ZONE', 0) + return new_type('TIMESTAMP WITH TIME ZONE', 0, 0) } LocalTimeExpr { - return new_type('TIME WITHOUT TIME ZONE', 0) + return new_type('TIME WITHOUT TIME ZONE', 0, 0) } LocalTimestampExpr { - return new_type('TIMESTAMP WITHOUT TIME ZONE', 0) + return new_type('TIMESTAMP WITHOUT TIME ZONE', 0, 0) } SubstringExpr, TrimExpr, CurrentCatalogExpr, CurrentSchemaExpr { - return new_type('CHARACTER VARYING', 0) + return new_type('CHARACTER VARYING', 0, 0) } UntypedNullExpr { return error('cannot determine type of untyped NULL') @@ -317,7 +317,7 @@ fn eval_as_bool(mut conn Connection, data Row, e Expr, params map[string]Value) v := eval_as_value(mut conn, data, e, params)! if v.typ.typ == .is_boolean { - return v.bool_value == .is_true + return v.bool_value() == .is_true } return sqlstate_42804('in expression', 'BOOLEAN', v.typ.str()) @@ -429,21 +429,21 @@ fn eval_cast(mut conn Connection, data Row, e CastExpr, params map[string]Value) fn eval_truth(mut conn Connection, data Row, e TruthExpr, params map[string]Value) !Value { value := eval_as_value(mut conn, data, e.expr, params)! - result := match value.bool_value { + result := match value.bool_value() { .is_true { - match e.value.bool_value { + match e.value.bool_value() { .is_true { new_boolean_value(true) } .is_false, .is_unknown { new_boolean_value(false) } } } .is_false { - match e.value.bool_value { + match e.value.bool_value() { .is_true, .is_unknown { new_boolean_value(false) } .is_false { new_boolean_value(true) } } } .is_unknown { - match e.value.bool_value { + match e.value.bool_value() { .is_true, .is_false { new_boolean_value(false) } .is_unknown { new_boolean_value(true) } } @@ -462,16 +462,16 @@ fn eval_trim(mut conn Connection, data Row, e TrimExpr, params map[string]Value) character := eval_as_value(mut conn, data, e.character, params)! if e.specification == 'LEADING' { - return new_varchar_value(source.string_value.trim_left(character.string_value), + return new_varchar_value(source.string_value().trim_left(character.string_value()), 0) } if e.specification == 'TRAILING' { - return new_varchar_value(source.string_value.trim_right(character.string_value), + return new_varchar_value(source.string_value().trim_right(character.string_value()), 0) } - return new_varchar_value(source.string_value.trim(character.string_value), 0) + return new_varchar_value(source.string_value().trim(character.string_value()), 0) } fn eval_like(mut conn Connection, data Row, e LikeExpr, params map[string]Value) !Value { @@ -479,7 +479,7 @@ fn eval_like(mut conn Connection, data Row, e LikeExpr, params map[string]Value) right := eval_as_value(mut conn, data, e.right, params)! // Make sure we escape any regexp characters. - escaped_regex := right.string_value.replace('+', '\\+').replace('?', '\\?').replace('*', + escaped_regex := right.string_value().replace('+', '\\+').replace('?', '\\?').replace('*', '\\*').replace('|', '\\|').replace('.', '\\.').replace('(', '\\(').replace(')', '\\)').replace('[', '\\[').replace('{', '\\{').replace('_', '.').replace('%', '.*') @@ -487,7 +487,7 @@ fn eval_like(mut conn Connection, data Row, e LikeExpr, params map[string]Value) mut re := regex.regex_opt('^${escaped_regex}$') or { return error('cannot compile regexp: ^${escaped_regex}$: ${err}') } - result := re.matches_string(left.string_value) + result := re.matches_string(left.string_value()) if e.not { return new_boolean_value(!result) @@ -501,7 +501,7 @@ fn eval_substring(mut conn Connection, data Row, e SubstringExpr, params map[str from := int((eval_as_value(mut conn, data, e.from, params)!).as_int() - 1) if e.using == 'CHARACTERS' { - characters := value.string_value.runes() + characters := value.string_value().runes() if from >= characters.len || from < 0 { return new_varchar_value('', 0) @@ -515,16 +515,16 @@ fn eval_substring(mut conn Connection, data Row, e SubstringExpr, params map[str return new_varchar_value(characters[from..from + @for].string(), 0) } - if from >= value.string_value.len || from < 0 { + if from >= value.string_value().len || from < 0 { return new_varchar_value('', 0) } - mut @for := value.string_value.len - from + mut @for := value.string_value().len - from if e.@for !is NoExpr { @for = int((eval_as_value(mut conn, data, e.@for, params)!).as_int()) } - return new_varchar_value(value.string_value.substr(from, from + @for), 0) + return new_varchar_value(value.string_value().substr(from, from + @for), 0) } fn eval_binary(mut conn Connection, data Row, e BinaryExpr, params map[string]Value) !Value { @@ -583,12 +583,12 @@ fn eval_similar(mut conn Connection, data Row, e SimilarExpr, params map[string] left := eval_as_value(mut conn, data, e.left, params)! right := eval_as_value(mut conn, data, e.right, params)! - regexp := '^${right.string_value.replace('.', '\\.').replace('_', '.').replace('%', + regexp := '^${right.string_value().replace('.', '\\.').replace('_', '.').replace('%', '.*')}$' mut re := regex.regex_opt(regexp) or { return error('cannot compile regexp: ${regexp}: ${err}') } - result := re.matches_string(left.string_value) + result := re.matches_string(left.string_value()) if e.not { return new_boolean_value(!result) diff --git a/vsql/funcs.v b/vsql/funcs.v index c5fcd55..6124256 100644 --- a/vsql/funcs.v +++ b/vsql/funcs.v @@ -11,10 +11,10 @@ struct Func { } fn register_builtin_funcs(mut conn Connection) ! { - double_precision := Type{SQLType.is_double_precision, 0, false} - integer := Type{SQLType.is_integer, 0, false} - varchar := Type{SQLType.is_varchar, 0, false} - character := Type{SQLType.is_character, 0, false} + double_precision := Type{SQLType.is_double_precision, 0, 0, false} + integer := Type{SQLType.is_integer, 0, 0, false} + varchar := Type{SQLType.is_varchar, 0, 0, false} + character := Type{SQLType.is_character, 0, 0, false} // Scalar functions. conn.register_func(Func{'ABS', [double_precision], false, func_abs, double_precision})! diff --git a/vsql/math.v b/vsql/math.v index 89eb37e..05a8dc8 100644 --- a/vsql/math.v +++ b/vsql/math.v @@ -6,95 +6,95 @@ import math // ABS(DOUBLE PRECISION) DOUBLE PRECISION fn func_abs(args []Value) !Value { - return new_double_precision_value(math.abs(args[0].f64_value)) + return new_double_precision_value(math.abs(args[0].f64_value())) } // SIN(DOUBLE PRECISION) DOUBLE PRECISION fn func_sin(args []Value) !Value { - return new_double_precision_value(math.sin(args[0].f64_value)) + return new_double_precision_value(math.sin(args[0].f64_value())) } // COS(DOUBLE PRECISION) DOUBLE PRECISION fn func_cos(args []Value) !Value { - return new_double_precision_value(math.cos(args[0].f64_value)) + return new_double_precision_value(math.cos(args[0].f64_value())) } // TAN(DOUBLE PRECISION) DOUBLE PRECISION fn func_tan(args []Value) !Value { - return new_double_precision_value(math.tan(args[0].f64_value)) + return new_double_precision_value(math.tan(args[0].f64_value())) } // SINH(DOUBLE PRECISION) DOUBLE PRECISION fn func_sinh(args []Value) !Value { - return new_double_precision_value(math.sinh(args[0].f64_value)) + return new_double_precision_value(math.sinh(args[0].f64_value())) } // COSH(DOUBLE PRECISION) DOUBLE PRECISION fn func_cosh(args []Value) !Value { - return new_double_precision_value(math.cosh(args[0].f64_value)) + return new_double_precision_value(math.cosh(args[0].f64_value())) } // TANH(DOUBLE PRECISION) DOUBLE PRECISION fn func_tanh(args []Value) !Value { - return new_double_precision_value(math.tanh(args[0].f64_value)) + return new_double_precision_value(math.tanh(args[0].f64_value())) } // ASIN(DOUBLE PRECISION) DOUBLE PRECISION fn func_asin(args []Value) !Value { - return new_double_precision_value(math.asin(args[0].f64_value)) + return new_double_precision_value(math.asin(args[0].f64_value())) } // ACOS(DOUBLE PRECISION) DOUBLE PRECISION fn func_acos(args []Value) !Value { - return new_double_precision_value(math.acos(args[0].f64_value)) + return new_double_precision_value(math.acos(args[0].f64_value())) } // ATAN(DOUBLE PRECISION) DOUBLE PRECISION fn func_atan(args []Value) !Value { - return new_double_precision_value(math.atan(args[0].f64_value)) + return new_double_precision_value(math.atan(args[0].f64_value())) } // MOD(DOUBLE PRECISION, DOUBLE PRECISION) DOUBLE PRECISION fn func_mod(args []Value) !Value { - return new_double_precision_value(math.fmod(args[0].f64_value, args[1].f64_value)) + return new_double_precision_value(math.fmod(args[0].f64_value(), args[1].f64_value())) } // LOG(DOUBLE PRECISION) DOUBLE PRECISION fn func_log(args []Value) !Value { - return new_double_precision_value(math.log2(args[0].f64_value)) + return new_double_precision_value(math.log2(args[0].f64_value())) } // LOG10(DOUBLE PRECISION) DOUBLE PRECISION fn func_log10(args []Value) !Value { - return new_double_precision_value(math.log10(args[0].f64_value)) + return new_double_precision_value(math.log10(args[0].f64_value())) } // LN(DOUBLE PRECISION) DOUBLE PRECISION fn func_ln(args []Value) !Value { - return new_double_precision_value(math.log(args[0].f64_value)) + return new_double_precision_value(math.log(args[0].f64_value())) } // EXP(DOUBLE PRECISION) DOUBLE PRECISION fn func_exp(args []Value) !Value { - return new_double_precision_value(math.exp(args[0].f64_value)) + return new_double_precision_value(math.exp(args[0].f64_value())) } // SQRT(DOUBLE PRECISION) DOUBLE PRECISION fn func_sqrt(args []Value) !Value { - return new_double_precision_value(math.sqrt(args[0].f64_value)) + return new_double_precision_value(math.sqrt(args[0].f64_value())) } // POWER(DOUBLE PRECISION, DOUBLE PRECISION) DOUBLE PRECISION fn func_power(args []Value) !Value { - return new_double_precision_value(math.pow(args[0].f64_value, args[1].f64_value)) + return new_double_precision_value(math.pow(args[0].f64_value(), args[1].f64_value())) } // FLOOR(DOUBLE PRECISION) DOUBLE PRECISION fn func_floor(args []Value) !Value { - return new_double_precision_value(math.floor(args[0].f64_value)) + return new_double_precision_value(math.floor(args[0].f64_value())) } // CEIL(DOUBLE PRECISION) DOUBLE PRECISION fn func_ceil(args []Value) !Value { - return new_double_precision_value(math.ceil(args[0].f64_value)) + return new_double_precision_value(math.ceil(args[0].f64_value())) } diff --git a/vsql/operators.v b/vsql/operators.v index 5cad030..e07f0d7 100644 --- a/vsql/operators.v +++ b/vsql/operators.v @@ -90,15 +90,15 @@ fn unary_passthru(conn &Connection, v Value) !Value { } fn unary_negate_bigint(conn &Connection, v Value) !Value { - return new_bigint_value(-v.int_value) + return new_bigint_value(-v.int_value()) } fn unary_negate_double_precision(conn &Connection, v Value) !Value { - return new_double_precision_value(-v.f64_value) + return new_double_precision_value(-v.f64_value()) } fn unary_not_boolean(conn &Connection, v Value) !Value { - return match v.bool_value { + return match v.bool_value() { .is_true { new_boolean_value(false) } .is_false { new_boolean_value(true) } .is_unknown { new_unknown_value() } @@ -106,73 +106,73 @@ fn unary_not_boolean(conn &Connection, v Value) !Value { } fn binary_double_precision_plus_double_precision(conn &Connection, a Value, b Value) !Value { - return new_double_precision_value(a.f64_value + b.f64_value) + return new_double_precision_value(a.f64_value() + b.f64_value()) } fn binary_integer_plus_integer(conn &Connection, a Value, b Value) !Value { - return new_integer_value(int(a.int_value + b.int_value)) + return new_integer_value(int(a.int_value() + b.int_value())) } fn binary_bigint_plus_bigint(conn &Connection, a Value, b Value) !Value { - return new_bigint_value(a.int_value + b.int_value) + return new_bigint_value(a.int_value() + b.int_value()) } fn binary_double_precision_minus_double_precision(conn &Connection, a Value, b Value) !Value { - return new_double_precision_value(a.f64_value - b.f64_value) + return new_double_precision_value(a.f64_value() - b.f64_value()) } fn binary_integer_minus_integer(conn &Connection, a Value, b Value) !Value { - return new_integer_value(int(a.int_value - b.int_value)) + return new_integer_value(int(a.int_value() - b.int_value())) } fn binary_bigint_minus_bigint(conn &Connection, a Value, b Value) !Value { - return new_bigint_value(a.int_value - b.int_value) + return new_bigint_value(a.int_value() - b.int_value()) } fn binary_double_precision_multiply_double_precision(conn &Connection, a Value, b Value) !Value { - return new_double_precision_value(a.f64_value * b.f64_value) + return new_double_precision_value(a.f64_value() * b.f64_value()) } fn binary_integer_multiply_integer(conn &Connection, a Value, b Value) !Value { - return new_integer_value(int(a.int_value * b.int_value)) + return new_integer_value(int(a.int_value() * b.int_value())) } fn binary_bigint_multiply_bigint(conn &Connection, a Value, b Value) !Value { - return new_bigint_value(a.int_value * b.int_value) + return new_bigint_value(a.int_value() * b.int_value()) } fn binary_double_precision_divide_double_precision(conn &Connection, a Value, b Value) !Value { - if b.f64_value == 0 { + if b.f64_value() == 0 { return sqlstate_22012() // division by zero } - return new_double_precision_value(a.f64_value / b.f64_value) + return new_double_precision_value(a.f64_value() / b.f64_value()) } fn binary_integer_divide_integer(conn &Connection, a Value, b Value) !Value { - if b.int_value == 0 { + if b.int_value() == 0 { return sqlstate_22012() // division by zero } - return new_integer_value(int(a.int_value / b.int_value)) + return new_integer_value(int(a.int_value() / b.int_value())) } fn binary_bigint_divide_bigint(conn &Connection, a Value, b Value) !Value { - if b.int_value == 0 { + if b.int_value() == 0 { return sqlstate_22012() // division by zero } - return new_bigint_value(a.int_value / b.int_value) + return new_bigint_value(a.int_value() / b.int_value()) } fn binary_varchar_concat_varchar(conn &Connection, a Value, b Value) !Value { - return new_varchar_value(a.string_value + b.string_value, 0) + return new_varchar_value(a.string_value() + b.string_value(), 0) } fn binary_boolean_and_boolean(conn &Connection, a Value, b Value) !Value { - match a.bool_value { + match a.bool_value() { .is_true { - return match b.bool_value { + return match b.bool_value() { .is_true { new_boolean_value(true) } .is_false { new_boolean_value(false) } .is_unknown { new_unknown_value() } @@ -182,7 +182,7 @@ fn binary_boolean_and_boolean(conn &Connection, a Value, b Value) !Value { return new_boolean_value(false) } .is_unknown { - return match b.bool_value { + return match b.bool_value() { .is_true { new_unknown_value() } .is_false { new_boolean_value(false) } .is_unknown { new_unknown_value() } @@ -192,19 +192,19 @@ fn binary_boolean_and_boolean(conn &Connection, a Value, b Value) !Value { } fn binary_boolean_or_boolean(conn &Connection, a Value, b Value) !Value { - match a.bool_value { + match a.bool_value() { .is_true { return new_boolean_value(true) } .is_false { - return match b.bool_value { + return match b.bool_value() { .is_true { new_boolean_value(true) } .is_false { new_boolean_value(false) } .is_unknown { new_unknown_value() } } } .is_unknown { - return match b.bool_value { + return match b.bool_value() { .is_true { new_boolean_value(true) } .is_false { new_unknown_value() } .is_unknown { new_unknown_value() } @@ -214,73 +214,73 @@ fn binary_boolean_or_boolean(conn &Connection, a Value, b Value) !Value { } fn binary_float_equal_float(conn &Connection, a Value, b Value) !Value { - return new_boolean_value(a.f64_value == b.f64_value) + return new_boolean_value(a.f64_value() == b.f64_value()) } fn binary_int_equal_int(conn &Connection, a Value, b Value) !Value { - return new_boolean_value(a.int_value == b.int_value) + return new_boolean_value(a.int_value() == b.int_value()) } fn binary_string_equal_string(conn &Connection, a Value, b Value) !Value { - return new_boolean_value(a.string_value == b.string_value) + return new_boolean_value(a.string_value() == b.string_value()) } fn binary_float_not_equal_float(conn &Connection, a Value, b Value) !Value { - return new_boolean_value(a.f64_value != b.f64_value) + return new_boolean_value(a.f64_value() != b.f64_value()) } fn binary_int_not_equal_int(conn &Connection, a Value, b Value) !Value { - return new_boolean_value(a.int_value != b.int_value) + return new_boolean_value(a.int_value() != b.int_value()) } fn binary_string_not_equal_string(conn &Connection, a Value, b Value) !Value { - return new_boolean_value(a.string_value != b.string_value) + return new_boolean_value(a.string_value() != b.string_value()) } fn binary_float_less_float(conn &Connection, a Value, b Value) !Value { - return new_boolean_value(a.f64_value < b.f64_value) + return new_boolean_value(a.f64_value() < b.f64_value()) } fn binary_int_less_int(conn &Connection, a Value, b Value) !Value { - return new_boolean_value(a.int_value < b.int_value) + return new_boolean_value(a.int_value() < b.int_value()) } fn binary_string_less_string(conn &Connection, a Value, b Value) !Value { - return new_boolean_value(a.string_value < b.string_value) + return new_boolean_value(a.string_value() < b.string_value()) } fn binary_float_greater_float(conn &Connection, a Value, b Value) !Value { - return new_boolean_value(a.f64_value > b.f64_value) + return new_boolean_value(a.f64_value() > b.f64_value()) } fn binary_int_greater_int(conn &Connection, a Value, b Value) !Value { - return new_boolean_value(a.int_value > b.int_value) + return new_boolean_value(a.int_value() > b.int_value()) } fn binary_string_greater_string(conn &Connection, a Value, b Value) !Value { - return new_boolean_value(a.string_value > b.string_value) + return new_boolean_value(a.string_value() > b.string_value()) } fn binary_float_less_equal_float(conn &Connection, a Value, b Value) !Value { - return new_boolean_value(a.f64_value <= b.f64_value) + return new_boolean_value(a.f64_value() <= b.f64_value()) } fn binary_int_less_equal_int(conn &Connection, a Value, b Value) !Value { - return new_boolean_value(a.int_value <= b.int_value) + return new_boolean_value(a.int_value() <= b.int_value()) } fn binary_string_less_equal_string(conn &Connection, a Value, b Value) !Value { - return new_boolean_value(a.string_value <= b.string_value) + return new_boolean_value(a.string_value() <= b.string_value()) } fn binary_float_greater_equal_float(conn &Connection, a Value, b Value) !Value { - return new_boolean_value(a.f64_value >= b.f64_value) + return new_boolean_value(a.f64_value() >= b.f64_value()) } fn binary_int_greater_equal_int(conn &Connection, a Value, b Value) !Value { - return new_boolean_value(a.int_value >= b.int_value) + return new_boolean_value(a.int_value() >= b.int_value()) } fn binary_string_greater_equal_string(conn &Connection, a Value, b Value) !Value { - return new_boolean_value(a.string_value >= b.string_value) + return new_boolean_value(a.string_value() >= b.string_value()) } diff --git a/vsql/parse.v b/vsql/parse.v index b007b27..6457978 100644 --- a/vsql/parse.v +++ b/vsql/parse.v @@ -96,43 +96,43 @@ fn parse_column_definition2(column_name Identifier, data_type Type, constraint b } fn parse_bigint() !Type { - return new_type('BIGINT', 0) + return new_type('BIGINT', 0, 0) } fn parse_integer() !Type { - return new_type('INTEGER', 0) + return new_type('INTEGER', 0, 0) } fn parse_smallint() !Type { - return new_type('SMALLINT', 0) + return new_type('SMALLINT', 0, 0) } fn parse_varchar(length string) !Type { - return new_type('CHARACTER VARYING', length.int()) + return new_type('CHARACTER VARYING', length.int(), 0) } fn parse_character_n(length string) !Type { - return new_type('CHARACTER', length.int()) + return new_type('CHARACTER', length.int(), 0) } fn parse_character() !Type { - return new_type('CHARACTER', 1) + return new_type('CHARACTER', 1, 0) } fn parse_double_precision() !Type { - return new_type('DOUBLE PRECISION', 0) + return new_type('DOUBLE PRECISION', 0, 0) } fn parse_float_n(length string) !Type { - return new_type('FLOAT', length.int()) + return new_type('FLOAT', length.int(), 0) } fn parse_float() !Type { - return new_type('FLOAT', 0) + return new_type('FLOAT', 0, 0) } fn parse_real() !Type { - return new_type('REAL', 0) + return new_type('REAL', 0, 0) } fn parse_drop_table_statement(table_name Identifier) !Stmt { @@ -332,7 +332,7 @@ fn parse_comparison(expr Expr, comp ComparisonPredicatePart2) !Expr { } fn parse_boolean_type() !Type { - return new_type('BOOLEAN', 0) + return new_type('BOOLEAN', 0, 0) } fn parse_true() !Value { @@ -704,10 +704,10 @@ fn parse_int_value(x string) !Value { fn parse_timestamp_prec_tz_type(prec string, tz bool) !Type { if tz { - return new_type('TIMESTAMP WITH TIME ZONE', prec.int()) + return new_type('TIMESTAMP WITH TIME ZONE', prec.int(), 0) } - return new_type('TIMESTAMP WITHOUT TIME ZONE', prec.int()) + return new_type('TIMESTAMP WITHOUT TIME ZONE', prec.int(), 0) } fn parse_timestamp_prec_type(prec string) !Type { @@ -726,10 +726,10 @@ fn parse_timestamp_type() !Type { fn parse_time_prec_tz_type(prec string, tz bool) !Type { if tz { - return new_type('TIME WITH TIME ZONE', prec.int()) + return new_type('TIME WITH TIME ZONE', prec.int(), 0) } - return new_type('TIME WITHOUT TIME ZONE', prec.int()) + return new_type('TIME WITHOUT TIME ZONE', prec.int(), 0) } fn parse_time_type() !Type { @@ -745,19 +745,19 @@ fn parse_time_tz_type(tz bool) !Type { } fn parse_date_type() !Type { - return new_type('DATE', 0) + return new_type('DATE', 0, 0) } fn parse_timestamp_literal(v Value) !Value { - return new_timestamp_value(v.string_value) + return new_timestamp_value(v.string_value()) } fn parse_time_literal(v Value) !Value { - return new_time_value(v.string_value) + return new_time_value(v.string_value()) } fn parse_date_literal(v Value) !Value { - return new_date_value(v.string_value) + return new_date_value(v.string_value()) } fn parse_current_date() !Expr { diff --git a/vsql/planner.v b/vsql/planner.v index 4e24a0d..514eb54 100644 --- a/vsql/planner.v +++ b/vsql/planner.v @@ -346,6 +346,6 @@ fn (p Plan) explain(elapsed_parse time.Duration) Result { } return new_result([ - Column{Identifier{ sub_entity_name: 'EXPLAIN' }, new_type('VARCHAR', 0), false}, + Column{Identifier{ sub_entity_name: 'EXPLAIN' }, new_type('VARCHAR', 0, 0), false}, ], rows, elapsed_parse, 0) } diff --git a/vsql/result.v b/vsql/result.v index 04a2e37..be76121 100644 --- a/vsql/result.v +++ b/vsql/result.v @@ -42,7 +42,7 @@ pub fn new_result(columns Columns, rows []Row, elapsed_parse time.Duration, elap fn new_result_msg(msg string, elapsed_parse time.Duration, elapsed_exec time.Duration) Result { return new_result([ - Column{Identifier{ sub_entity_name: 'msg' }, new_type('VARCHAR', 0), false}, + Column{Identifier{ sub_entity_name: 'msg' }, new_type('VARCHAR', 0, 0), false}, ], [ Row{ data: { diff --git a/vsql/row.v b/vsql/row.v index 74054a5..9e5ce04 100644 --- a/vsql/row.v +++ b/vsql/row.v @@ -42,7 +42,7 @@ pub fn (r Row) get_null(name string) !bool { pub fn (r Row) get_f64(name string) !f64 { value := r.get(name)! if value.typ.uses_f64() { - return value.f64_value + return value.f64_value() } return error("cannot use get_f64('${name}') when type is ${value.typ}") @@ -55,7 +55,7 @@ pub fn (r Row) get_f64(name string) !f64 { pub fn (r Row) get_int(name string) !int { value := r.get(name)! if value.typ.uses_int() { - return int(value.int_value) + return int(value.int_value()) } return error("cannot use get_int('${name}') when type is ${value.typ}") @@ -84,7 +84,7 @@ pub fn (r Row) get_bool(name string) !Boolean { match value.typ.typ { .is_boolean { - return value.bool_value + return value.bool_value() } else { return error("cannot use get_bool('${name}') when type is ${value.typ}") @@ -215,29 +215,29 @@ fn (r Row) bytes(t Table) []u8 { if !v.is_null || col.typ.typ == .is_boolean { match col.typ.typ { .is_boolean { - buf.write_u8(u8(v.bool_value)) + buf.write_u8(u8(v.bool_value())) } .is_bigint { - buf.write_i64(v.int_value) + buf.write_i64(v.int_value()) } .is_double_precision { - buf.write_f64(v.f64_value) + buf.write_f64(v.f64_value()) } .is_integer { - buf.write_i32(int(v.int_value)) + buf.write_i32(int(v.int_value())) } .is_real { - buf.write_f32(f32(v.f64_value)) + buf.write_f32(f32(v.f64_value())) } .is_smallint { - buf.write_i16(i16(v.int_value)) + buf.write_i16(i16(v.int_value())) } .is_varchar, .is_character { - buf.write_string4(v.string_value) + buf.write_string4(v.string_value()) } .is_date, .is_time_with_time_zone, .is_time_without_time_zone, .is_timestamp_with_time_zone, .is_timestamp_without_time_zone { - buf.write_u8s(v.time_value.bytes()) + buf.write_u8s(v.time_value().bytes()) } } } @@ -282,49 +282,49 @@ fn new_row_from_bytes(t Table, data []u8, tid int) Row { match col.typ.typ { .is_boolean { unsafe { - v.bool_value = Boolean(buf.read_u8()) - if v.bool_value == .is_unknown { + v.v.bool_value = Boolean(buf.read_u8()) + if v.bool_value() == .is_unknown { v.is_null = true } } } .is_bigint { - v.int_value = buf.read_i64() + v.v.int_value = buf.read_i64() } .is_double_precision { - v.f64_value = buf.read_f64() + v.v.f64_value = buf.read_f64() } .is_integer { - v.int_value = buf.read_i32() + v.v.int_value = buf.read_i32() } .is_real { - v.f64_value = buf.read_f32() + v.v.f64_value = buf.read_f32() } .is_smallint { - v.int_value = buf.read_i16() + v.v.int_value = buf.read_i16() } .is_varchar, .is_character { - v.string_value = buf.read_string4() + v.v.string_value = buf.read_string4() } .is_date { - typ := Type{.is_date, col.typ.size, col.not_null} - v.time_value = new_time_from_bytes(typ, buf.read_u8s(8)) + typ := Type{.is_date, col.typ.size, col.typ.scale, col.not_null} + v.v.time_value = new_time_from_bytes(typ, buf.read_u8s(8)) } .is_time_with_time_zone { - typ := Type{.is_time_with_time_zone, col.typ.size, col.not_null} - v.time_value = new_time_from_bytes(typ, buf.read_u8s(10)) + typ := Type{.is_time_with_time_zone, col.typ.size, col.typ.scale, col.not_null} + v.v.time_value = new_time_from_bytes(typ, buf.read_u8s(10)) } .is_time_without_time_zone { - typ := Type{.is_time_without_time_zone, col.typ.size, col.not_null} - v.time_value = new_time_from_bytes(typ, buf.read_u8s(8)) + typ := Type{.is_time_without_time_zone, col.typ.size, col.typ.scale, col.not_null} + v.v.time_value = new_time_from_bytes(typ, buf.read_u8s(8)) } .is_timestamp_with_time_zone { - typ := Type{.is_timestamp_with_time_zone, col.typ.size, col.not_null} - v.time_value = new_time_from_bytes(typ, buf.read_u8s(10)) + typ := Type{.is_timestamp_with_time_zone, col.typ.size, col.typ.scale, col.not_null} + v.v.time_value = new_time_from_bytes(typ, buf.read_u8s(10)) } .is_timestamp_without_time_zone { - typ := Type{.is_timestamp_without_time_zone, col.typ.size, col.not_null} - v.time_value = new_time_from_bytes(typ, buf.read_u8s(8)) + typ := Type{.is_timestamp_without_time_zone, col.typ.size, col.typ.scale, col.not_null} + v.v.time_value = new_time_from_bytes(typ, buf.read_u8s(8)) } } } @@ -344,13 +344,13 @@ fn (mut r Row) object_key(t Table) ![]u8 { col := t.column(col_name)! match col.typ.typ { .is_bigint { - pk.write_i64(r.data[col_name].int_value) + pk.write_i64(r.data[col_name].int_value()) } .is_integer { - pk.write_i32(int(r.data[col_name].int_value)) + pk.write_i32(int(r.data[col_name].int_value())) } .is_smallint { - pk.write_i16(i16(r.data[col_name].int_value)) + pk.write_i16(i16(r.data[col_name].int_value())) } else { return error('cannot use ${col.typ.str()} in PRIMARY KEY') diff --git a/vsql/sql_test.v b/vsql/sql_test.v index ba81d1e..cb6ec96 100644 --- a/vsql/sql_test.v +++ b/vsql/sql_test.v @@ -65,7 +65,7 @@ fn get_tests() ![]SQLTest { params[parts[1]] = new_varchar_value(parts[2][1..parts[2].len - 1], 0) } else if parts[2] == 'NULL' { - typ := new_type(parts[3], 0) + typ := new_type(parts[3], 0, 0) params[parts[1]] = new_null_value(typ.typ) } else { params[parts[1]] = new_double_precision_value(parts[2].f64()) diff --git a/vsql/strings.v b/vsql/strings.v index 56f962c..cfbdad9 100644 --- a/vsql/strings.v +++ b/vsql/strings.v @@ -4,27 +4,27 @@ module vsql // POSITION(CHARACTER VARYING IN CHARACTER VARYING) INTEGER fn func_position(args []Value) !Value { - index := args[1].string_value.index(args[0].string_value) or { -1 } + index := args[1].string_value().index(args[0].string_value()) or { -1 } return new_integer_value(index + 1) } // CHAR_LENGTH(CHARACTER VARYING) INTEGER fn func_char_length(args []Value) !Value { - return new_integer_value(args[0].string_value.runes().len) + return new_integer_value(args[0].string_value().runes().len) } // OCTET_LENGTH(CHARACTER VARYING) INTEGER fn func_octet_length(args []Value) !Value { - return new_integer_value(args[0].string_value.len) + return new_integer_value(args[0].string_value().len) } // UPPER(CHARACTER VARYING) CHARACTER VARYING fn func_upper(args []Value) !Value { - return new_varchar_value(args[0].string_value.to_upper(), 0) + return new_varchar_value(args[0].string_value().to_upper(), 0) } // LOWER(CHARACTER VARYING) CHARACTER VARYING fn func_lower(args []Value) !Value { - return new_varchar_value(args[0].string_value.to_lower(), 0) + return new_varchar_value(args[0].string_value().to_lower(), 0) } diff --git a/vsql/table.v b/vsql/table.v index 92ca258..17148de 100644 --- a/vsql/table.v +++ b/vsql/table.v @@ -115,7 +115,7 @@ fn (t Table) bytes() []u8 { b.write_u8(col.typ.number()) b.write_bool(col.not_null) b.write_i32(col.typ.size) - b.write_i16(0) // precision + b.write_i16(col.typ.scale) } return b.bytes() @@ -138,14 +138,14 @@ fn new_table_from_bytes(data []u8, tid int, catalog_name string) Table { column_type := b.read_u8() is_not_null := b.read_bool() size := b.read_i32() - b.read_i16() // precision + scale := b.read_i16() columns << Column{Identifier{ catalog_name: catalog_name schema_name: table_name.schema_name entity_name: table_name.entity_name sub_entity_name: column_name - }, type_from_number(column_type, size), is_not_null} + }, type_from_number(column_type, size, scale), is_not_null} } return Table{tid, table_name, columns, primary_key, false} diff --git a/vsql/type.v b/vsql/type.v index 93f8a77..f9207db 100644 --- a/vsql/type.v +++ b/vsql/type.v @@ -15,6 +15,10 @@ mut: // // snippet: v.Type.size size int + // The scale is only for numeric types. + // + // snippet: v.Type.scale + scale i16 // Is NOT NULL? // // snippet: v.Type.not_null @@ -61,48 +65,48 @@ fn (t SQLType) str() string { } } -fn new_type(name string, size int) Type { +fn new_type(name string, size int, scale i16) Type { name_without_size := name.split('(')[0] return match name_without_size { 'BIGINT' { - Type{.is_bigint, size, false} + Type{.is_bigint, size, scale, false} } 'BOOLEAN' { - Type{.is_boolean, size, false} + Type{.is_boolean, size, scale, false} } 'CHARACTER VARYING', 'CHAR VARYING', 'VARCHAR' { - Type{.is_varchar, size, false} + Type{.is_varchar, size, scale, false} } 'CHARACTER', 'CHAR' { - Type{.is_character, size, false} + Type{.is_character, size, scale, false} } 'DOUBLE PRECISION', 'FLOAT' { - Type{.is_double_precision, size, false} + Type{.is_double_precision, size, scale, false} } 'REAL' { - Type{.is_real, size, false} + Type{.is_real, size, scale, false} } 'INT', 'INTEGER' { - Type{.is_integer, size, false} + Type{.is_integer, size, scale, false} } 'SMALLINT' { - Type{.is_smallint, size, false} + Type{.is_smallint, size, scale, false} } 'DATE' { - Type{.is_date, 0, false} + Type{.is_date, size, scale, false} } 'TIME', 'TIME WITHOUT TIME ZONE' { - Type{.is_time_without_time_zone, size, false} + Type{.is_time_without_time_zone, size, scale, false} } 'TIME WITH TIME ZONE' { - Type{.is_time_with_time_zone, size, false} + Type{.is_time_with_time_zone, size, scale, false} } 'TIMESTAMP', 'TIMESTAMP WITHOUT TIME ZONE' { - Type{.is_timestamp_without_time_zone, size, false} + Type{.is_timestamp_without_time_zone, size, scale, false} } 'TIMESTAMP WITH TIME ZONE' { - Type{.is_timestamp_with_time_zone, size, false} + Type{.is_timestamp_with_time_zone, size, scale, false} } else { panic(name_without_size) @@ -243,7 +247,7 @@ fn (t Type) number() u8 { } } -fn type_from_number(number u8, size int) Type { +fn type_from_number(number u8, size int, scale i16) Type { return new_type(match number { 0 { 'BOOLEAN' } 1 { 'BIGINT' } @@ -259,5 +263,5 @@ fn type_from_number(number u8, size int) Type { 11 { 'TIMESTAMP(${size}) WITH TIME ZONE' } 12 { 'TIMESTAMP(${size}) WITHOUT TIME ZONE' } else { panic(number) } - }, 0) + }, size, scale) } diff --git a/vsql/value.v b/vsql/value.v index 72393c7..4906b9e 100644 --- a/vsql/value.v +++ b/vsql/value.v @@ -41,6 +41,15 @@ pub mut: // // snippet: v.Value.is_null is_null bool + v InternalValue + // If is_coercible is true the value comes from an ambigious type (like a + // numerical constant) that can be corerced to another type if needed in an + // expression. + is_coercible bool +} + +union InternalValue { +mut: // BOOLEAN bool_value Boolean // DOUBLE PRECISION and REAL @@ -53,10 +62,6 @@ pub mut: // TIME(n) WITH TIME ZONE and TIME(n) WITHOUT TIME ZONE // TIMESTAMP(n) WITH TIME ZONE and TIMESTAMP(n) WITHOUT TIME ZONE time_value Time - // If is_coercible is true the value comes from an ambigious type (like a - // numerical constant) that can be corerced to another type if needed in an - // expression. - is_coercible bool } // new_null_value creates a NULL value of a specific type. In SQL, all NULL @@ -65,7 +70,7 @@ pub mut: // snippet: v.new_null_value pub fn new_null_value(typ SQLType) Value { return Value{ - typ: Type{typ, 0, false} + typ: Type{typ, 0, 0, false} is_null: true } } @@ -76,8 +81,10 @@ pub fn new_null_value(typ SQLType) Value { // snippet: v.new_boolean_value pub fn new_boolean_value(b bool) Value { return Value{ - typ: Type{.is_boolean, 0, false} - bool_value: if b { .is_true } else { .is_false } + typ: Type{.is_boolean, 0, 0, false} + v: InternalValue{ + bool_value: if b { .is_true } else { .is_false } + } } } @@ -87,8 +94,10 @@ pub fn new_boolean_value(b bool) Value { // snippet: v.new_unknown_value pub fn new_unknown_value() Value { return Value{ - typ: Type{.is_boolean, 0, false} - bool_value: .is_unknown + typ: Type{.is_boolean, 0, 0, false} + v: InternalValue{ + bool_value: .is_unknown + } } } @@ -97,8 +106,10 @@ pub fn new_unknown_value() Value { // snippet: v.new_double_precision_value pub fn new_double_precision_value(x f64) Value { return Value{ - typ: Type{.is_double_precision, 0, false} - f64_value: x + typ: Type{.is_double_precision, 0, 0, false} + v: InternalValue{ + f64_value: x + } } } @@ -107,8 +118,10 @@ pub fn new_double_precision_value(x f64) Value { // snippet: v.new_integer_value pub fn new_integer_value(x int) Value { return Value{ - typ: Type{.is_integer, 0, false} - int_value: x + typ: Type{.is_integer, 0, 0, false} + v: InternalValue{ + int_value: x + } } } @@ -117,8 +130,10 @@ pub fn new_integer_value(x int) Value { // snippet: v.new_bigint_value pub fn new_bigint_value(x i64) Value { return Value{ - typ: Type{.is_bigint, 0, false} - int_value: x + typ: Type{.is_bigint, 0, 0, false} + v: InternalValue{ + int_value: x + } } } @@ -127,8 +142,10 @@ pub fn new_bigint_value(x i64) Value { // snippet: v.new_real_value pub fn new_real_value(x f32) Value { return Value{ - typ: Type{.is_real, 0, false} - f64_value: x + typ: Type{.is_real, 0, 0, false} + v: InternalValue{ + f64_value: x + } } } @@ -137,8 +154,10 @@ pub fn new_real_value(x f32) Value { // snippet: v.new_smallint_value pub fn new_smallint_value(x i16) Value { return Value{ - typ: Type{.is_smallint, 0, false} - int_value: x + typ: Type{.is_smallint, 0, 0, false} + v: InternalValue{ + int_value: x + } } } @@ -147,8 +166,10 @@ pub fn new_smallint_value(x i16) Value { // snippet: v.new_varchar_value pub fn new_varchar_value(x string, size int) Value { return Value{ - typ: Type{.is_varchar, size, false} - string_value: x + typ: Type{.is_varchar, size, 0, false} + v: InternalValue{ + string_value: x + } } } @@ -160,8 +181,10 @@ pub fn new_character_value(x string, size int) Value { // TODO(elliotchance): Doesn't handle size < x.len return Value{ - typ: Type{.is_character, size, false} - string_value: x + strings.repeat(` `, size - x.len) + typ: Type{.is_character, size, 0, false} + v: InternalValue{ + string_value: x + strings.repeat(` `, size - x.len) + } } } @@ -173,7 +196,9 @@ pub fn new_timestamp_value(ts string) !Value { return Value{ typ: t.typ - time_value: t + v: InternalValue{ + time_value: t + } } } @@ -185,7 +210,9 @@ pub fn new_time_value(ts string) !Value { return Value{ typ: t.typ - time_value: t + v: InternalValue{ + time_value: t + } } } @@ -197,7 +224,9 @@ pub fn new_date_value(ts string) !Value { return Value{ typ: t.typ - time_value: t + v: InternalValue{ + time_value: t + } } } @@ -215,10 +244,10 @@ fn f64_string(x f64) string { // OFFSET). fn (v Value) as_int() i64 { if v.typ.uses_int() { - return v.int_value + return v.int_value() } - return i64(v.f64_value) + return i64(v.f64_value()) } // The string representation of this value. Different types will have different @@ -232,20 +261,20 @@ pub fn (v Value) str() string { return match v.typ.typ { .is_boolean { - v.bool_value.str() + v.bool_value().str() } .is_double_precision, .is_real { - f64_string(v.f64_value) + f64_string(v.f64_value()) } .is_bigint, .is_integer, .is_smallint { - v.int_value.str() + v.int_value().str() } .is_varchar, .is_character { - v.string_value + v.string_value() } .is_date, .is_time_with_time_zone, .is_time_without_time_zone, .is_timestamp_with_time_zone, .is_timestamp_without_time_zone { - v.time_value.str() + v.time_value().str() } } } @@ -279,26 +308,26 @@ pub fn (v Value) cmp(v2 Value) !(int, bool) { // TODO(elliotchance): BOOLEAN shouldn't be compared this way. if v.typ.uses_int() { if v2.typ.uses_int() { - return cmp_value(v.int_value, v2.int_value) + return cmp_value(v.int_value(), v2.int_value()) } if v2.typ.uses_f64() { - return cmp_value(v.int_value, v2.f64_value) + return cmp_value(v.int_value(), v2.f64_value()) } } if v.typ.uses_f64() { if v2.typ.uses_int() { - return cmp_value(v.f64_value, v2.int_value) + return cmp_value(v.f64_value(), v2.int_value()) } if v2.typ.uses_f64() { - return cmp_value(v.f64_value, v2.f64_value) + return cmp_value(v.f64_value(), v2.f64_value()) } } if v.typ.uses_string() && v2.typ.uses_string() { - return cmp_value(v.string_value, v2.string_value) + return cmp_value(v.string_value(), v2.string_value()) } return error('cannot compare ${v.typ} and ${v2.typ}') @@ -315,3 +344,33 @@ fn cmp_value[A, B](lhs A, rhs B) (int, bool) { return 0, false } + +pub fn (v Value) bool_value() Boolean { + unsafe { + return v.v.bool_value + } +} + +pub fn (v Value) int_value() i64 { + unsafe { + return v.v.int_value + } +} + +pub fn (v Value) f64_value() f64 { + unsafe { + return v.v.f64_value + } +} + +pub fn (v Value) string_value() string { + unsafe { + return v.v.string_value + } +} + +pub fn (v Value) time_value() Time { + unsafe { + return v.v.time_value + } +} diff --git a/vsql/values.v b/vsql/values.v index 14fe3a5..c1ed406 100644 --- a/vsql/values.v +++ b/vsql/values.v @@ -77,7 +77,7 @@ fn (o &ValuesOperation) columns() Columns { fn (mut o ValuesOperation) execute(_ []Row) ![]Row { mut offset := 0 if o.offset !is NoExpr { - offset = int((eval_as_value(mut o.conn, Row{}, o.offset, o.params)!).f64_value) + offset = int((eval_as_value(mut o.conn, Row{}, o.offset, o.params)!).f64_value()) } mut rows := []Row{}