From 5df3d8ac7577ff7ed23c44f4f51346cb73a67648 Mon Sep 17 00:00:00 2001 From: Louis Schmieder Date: Thu, 16 Jun 2022 19:19:49 +0200 Subject: [PATCH] orm: mysql fixes (#14772) --- vlib/mysql/orm.v | 117 ++++++++++++++++++++----------------------- vlib/mysql/stmt.c.v | 4 +- vlib/orm/orm.v | 1 + vlib/orm/orm_test.v | 16 ++++-- vlib/pg/orm.v | 2 +- vlib/sqlite/orm.v | 1 + vlib/v/checker/orm.v | 9 +++- 7 files changed, 80 insertions(+), 70 deletions(-) diff --git a/vlib/mysql/orm.v b/vlib/mysql/orm.v index 35a57f6c9..febe9de76 100644 --- a/vlib/mysql/orm.v +++ b/vlib/mysql/orm.v @@ -15,6 +15,7 @@ pub fn (db Connection) @select(config orm.SelectConfig, data orm.QueryData, wher mysql_stmt_binder(mut stmt, where)? mysql_stmt_binder(mut stmt, data)? + if data.data.len > 0 || where.data.len > 0 { stmt.bind_params()? } @@ -24,52 +25,48 @@ pub fn (db Connection) @select(config orm.SelectConfig, data orm.QueryData, wher metadata := stmt.gen_metadata() fields := stmt.fetch_fields(metadata) - mut dataptr := []Prims{} + mut dataptr := []&u8{} for i in 0 .. num_fields { f := unsafe { fields[i] } match FieldType(f.@type) { .type_tiny { - dataptr << u8(0) + dataptr << unsafe { malloc(1) } } .type_short { - dataptr << u16(0) + dataptr << unsafe { malloc(2) } } .type_long { - dataptr << u32(0) + dataptr << unsafe { malloc(4) } } .type_longlong { - dataptr << u64(0) + dataptr << unsafe { malloc(8) } } .type_float { - dataptr << f32(0) + dataptr << unsafe { malloc(4) } } .type_double { - dataptr << f64(0) + dataptr << unsafe { malloc(8) } } - .type_string { - dataptr << '' + .type_string, .type_blob { + dataptr << unsafe { malloc(512) } } else { - dataptr << u8(0) + dataptr << &u8(0) } } } - mut vptr := []&char{} - - for d in dataptr { - vptr << d.get_data_ptr() - } - - unsafe { dataptr.free() } - lens := []u32{len: int(num_fields), init: 0} - stmt.bind_res(fields, vptr, lens, num_fields) + stmt.bind_res(fields, dataptr, lens, num_fields) stmt.bind_result_buffer()? stmt.store_result()? mut row := 0 + mut types := config.types + if config.is_count { + types = [orm.type_idx['u64']] + } for { status = stmt.fetch_stmt()? @@ -78,7 +75,8 @@ pub fn (db Connection) @select(config orm.SelectConfig, data orm.QueryData, wher break } row++ - data_list := buffer_to_primitive(vptr, config.types)? + + data_list := buffer_to_primitive(dataptr, types)? ret << data_list } @@ -184,7 +182,8 @@ fn stmt_binder_match(mut stmt Stmt, data orm.Primitive) { stmt.bind_text(data) } time.Time { - stmt.bind_int(&int(data.unix)) + unix := int(data.unix) + stmt_binder_match(mut stmt, unix) } orm.InfixType { stmt_binder_match(mut stmt, data.right) @@ -192,50 +191,50 @@ fn stmt_binder_match(mut stmt Stmt, data orm.Primitive) { } } -fn buffer_to_primitive(data_list []&char, types []int) ?[]orm.Primitive { +fn buffer_to_primitive(data_list []&u8, types []int) ?[]orm.Primitive { mut res := []orm.Primitive{} for i, data in data_list { mut primitive := orm.Primitive(0) match types[i] { - 5 { - primitive = *(&i8(data)) + orm.type_idx['i8'] { + primitive = *(unsafe { &i8(data) }) } - 6 { - primitive = *(&i16(data)) + orm.type_idx['i16'] { + primitive = *(unsafe { &i16(data) }) } - 7, -1 { - primitive = *(&int(data)) + orm.type_idx['int'], orm.serial { + primitive = *(unsafe { &int(data) }) } - 8 { - primitive = *(&i64(data)) + orm.type_idx['i64'] { + primitive = *(unsafe { &i64(data) }) } - 9 { - primitive = *(&u8(data)) + orm.type_idx['byte'] { + primitive = *(unsafe { &u8(data) }) } - 10 { - primitive = *(&u16(data)) + orm.type_idx['u16'] { + primitive = *(unsafe { &u16(data) }) } - 11 { - primitive = *(&u32(data)) + orm.type_idx['u32'] { + primitive = *(unsafe { &u32(data) }) } - 12 { - primitive = *(&u64(data)) + orm.type_idx['u64'] { + primitive = *(unsafe { &u64(data) }) } - 13 { - primitive = *(&f32(data)) + orm.type_idx['f32'] { + primitive = *(unsafe { &f32(data) }) } - 14 { - primitive = *(&f64(data)) + orm.type_idx['f64'] { + primitive = *(unsafe { &f64(data) }) } - 15 { - primitive = *(&bool(data)) + orm.type_idx['bool'] { + primitive = *(unsafe { &bool(data) }) } orm.string { primitive = unsafe { cstring_to_vstring(&char(data)) } } orm.time { - timestamp := *(&int(data)) + timestamp := *(unsafe { &int(data) }) primitive = time.unix(timestamp) } else { @@ -250,30 +249,33 @@ fn buffer_to_primitive(data_list []&char, types []int) ?[]orm.Primitive { fn mysql_type_from_v(typ int) ?string { str := match typ { - 5, 9, 16 { + orm.type_idx['i8'], orm.type_idx['byte'] { 'TINYINT' } - 6, 10 { + orm.type_idx['i16'], orm.type_idx['u16'] { 'SMALLINT' } - 7, 11, orm.time { + orm.type_idx['int'], orm.type_idx['u32'], orm.time { 'INT' } - 8, 12 { + orm.type_idx['i64'], orm.type_idx['u64'] { 'BIGINT' } - 13 { + orm.type_idx['f32'] { 'FLOAT' } - 14 { + orm.type_idx['f64'] { 'DOUBLE' } orm.string { 'TEXT' } - -1 { + orm.serial { 'SERIAL' } + orm.type_idx['bool'] { + 'BOOLEAN' + } else { '' } @@ -283,14 +285,3 @@ fn mysql_type_from_v(typ int) ?string { } return str } - -fn (p Prims) get_data_ptr() &char { - return match p { - string { - p.str - } - else { - &char(&p) - } - } -} diff --git a/vlib/mysql/stmt.c.v b/vlib/mysql/stmt.c.v index 97ea72674..8ed0a7e47 100644 --- a/vlib/mysql/stmt.c.v +++ b/vlib/mysql/stmt.c.v @@ -210,14 +210,14 @@ pub fn (mut stmt Stmt) bind(typ int, buffer voidptr, buf_len u32) { } } -pub fn (mut stmt Stmt) bind_res(fields &C.MYSQL_FIELD, dataptr []&char, lens []u32, num_fields int) { +pub fn (mut stmt Stmt) bind_res(fields &C.MYSQL_FIELD, dataptr []&u8, lens []u32, num_fields int) { for i in 0 .. num_fields { len := FieldType(unsafe { fields[i].@type }).get_len() stmt.res << C.MYSQL_BIND{ buffer_type: unsafe { fields[i].@type } buffer: dataptr[i] length: &lens[i] - buffer_length: &len + buffer_length: len } } } diff --git a/vlib/orm/orm.v b/vlib/orm/orm.v index 4e5d62633..53a2cd87c 100644 --- a/vlib/orm/orm.v +++ b/vlib/orm/orm.v @@ -20,6 +20,7 @@ pub const ( ] string = ast.string_type_idx time = -2 + serial = -1 type_idx = { 'i8': ast.i8_type_idx 'i16': ast.i16_type_idx diff --git a/vlib/orm/orm_test.v b/vlib/orm/orm_test.v index d6c20f418..3602a0383 100644 --- a/vlib/orm/orm_test.v +++ b/vlib/orm/orm_test.v @@ -1,7 +1,8 @@ // import os // import term -import time +// import mysql // import pg +import time import sqlite struct Module { @@ -33,9 +34,17 @@ struct TestTime { fn test_orm() { db := sqlite.connect(':memory:') or { panic(err) } - // db.exec('drop table if exists User') + db.exec('drop table if exists User') // db := pg.connect(host: 'localhost', port: 5432, user: 'louis', password: 'abc', dbname: 'orm') or { panic(err) } + /* + mut db := mysql.Connection{ + host: '127.0.0.1' + username: 'root' + password: 'pw' + dbname: 'v' + } + db.connect() or { panic(err) }*/ sql db { create table Module @@ -268,7 +277,7 @@ fn test_orm() { assert updated_oldest.age == 31 // Remove this when pg is used - db.exec('insert into User (name, age) values (NULL, 31)') + // db.exec('insert into User (name, age) values (NULL, 31)') null_user := sql db { select from User where id == 5 } @@ -319,6 +328,7 @@ fn test_orm() { } assert data.len == 1 + assert tnow.unix == data[0].create.unix mod := Module{} diff --git a/vlib/pg/orm.v b/vlib/pg/orm.v index 70a4c363f..7fd5250de 100644 --- a/vlib/pg/orm.v +++ b/vlib/pg/orm.v @@ -205,7 +205,7 @@ fn pg_type_from_v(typ int) ?string { orm.string { 'TEXT' } - -1 { + orm.serial { 'SERIAL' } else { diff --git a/vlib/sqlite/orm.v b/vlib/sqlite/orm.v index e01b2d369..e80eb8eae 100644 --- a/vlib/sqlite/orm.v +++ b/vlib/sqlite/orm.v @@ -20,6 +20,7 @@ pub fn (db DB) @select(config orm.SelectConfig, data orm.QueryData, where orm.Qu mut ret := [][]orm.Primitive{} if config.is_count { + eprintln(config) // 2. Get count of returned values & add it to ret array step := stmt.step() if step !in [sqlite_row, sqlite_ok, sqlite_done] { diff --git a/vlib/v/checker/orm.v b/vlib/v/checker/orm.v index 4ece16177..2cf26f5d5 100644 --- a/vlib/v/checker/orm.v +++ b/vlib/v/checker/orm.v @@ -22,7 +22,7 @@ fn (mut c Checker) sql_expr(mut node ast.SqlExpr) ast.Type { return ast.void_type } info := sym.info as ast.Struct - fields := c.fetch_and_verify_orm_fields(info, node.table_expr.pos, sym.name) + mut fields := c.fetch_and_verify_orm_fields(info, node.table_expr.pos, sym.name) mut sub_structs := map[int]ast.SqlExpr{} for f in fields.filter((c.table.type_symbols[int(it.typ)].kind == .struct_ || (c.table.sym(it.typ).kind == .array @@ -81,6 +81,13 @@ fn (mut c Checker) sql_expr(mut node ast.SqlExpr) ast.Type { sub_structs[int(typ)] = n } + if node.is_count { + fields = [ + ast.StructField{ + typ: ast.int_type + }, + ] + } node.fields = fields node.sub_structs = sub_structs.move() if node.has_where { -- 2.30.2