2021-07-23 12:33:55 +03:00
|
|
|
module mysql
|
|
|
|
|
|
|
|
import orm
|
|
|
|
import time
|
|
|
|
|
2022-04-15 18:25:45 +03:00
|
|
|
type Prims = f32 | f64 | i16 | i64 | i8 | int | string | u16 | u32 | u64 | u8
|
2021-07-23 12:33:55 +03:00
|
|
|
|
|
|
|
// sql expr
|
|
|
|
|
|
|
|
pub fn (db Connection) @select(config orm.SelectConfig, data orm.QueryData, where orm.QueryData) ?[][]orm.Primitive {
|
|
|
|
query := orm.orm_select_gen(config, '`', false, '?', 0, where)
|
|
|
|
mut ret := [][]orm.Primitive{}
|
|
|
|
mut stmt := db.init_stmt(query)
|
2022-05-13 06:56:21 +03:00
|
|
|
stmt.prepare()?
|
2021-07-23 12:33:55 +03:00
|
|
|
|
2022-05-13 06:56:21 +03:00
|
|
|
mysql_stmt_binder(mut stmt, where)?
|
|
|
|
mysql_stmt_binder(mut stmt, data)?
|
2022-06-16 20:19:49 +03:00
|
|
|
|
2021-07-23 12:33:55 +03:00
|
|
|
if data.data.len > 0 || where.data.len > 0 {
|
2022-05-13 06:56:21 +03:00
|
|
|
stmt.bind_params()?
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
|
|
|
|
2022-05-13 06:56:21 +03:00
|
|
|
mut status := stmt.execute()?
|
2021-07-23 12:33:55 +03:00
|
|
|
num_fields := stmt.get_field_count()
|
|
|
|
metadata := stmt.gen_metadata()
|
|
|
|
fields := stmt.fetch_fields(metadata)
|
2022-06-16 20:19:49 +03:00
|
|
|
mut dataptr := []&u8{}
|
2021-07-23 12:33:55 +03:00
|
|
|
|
|
|
|
for i in 0 .. num_fields {
|
|
|
|
f := unsafe { fields[i] }
|
|
|
|
match FieldType(f.@type) {
|
|
|
|
.type_tiny {
|
2022-06-16 20:19:49 +03:00
|
|
|
dataptr << unsafe { malloc(1) }
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
|
|
|
.type_short {
|
2022-06-16 20:19:49 +03:00
|
|
|
dataptr << unsafe { malloc(2) }
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
|
|
|
.type_long {
|
2022-06-16 20:19:49 +03:00
|
|
|
dataptr << unsafe { malloc(4) }
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
|
|
|
.type_longlong {
|
2022-06-16 20:19:49 +03:00
|
|
|
dataptr << unsafe { malloc(8) }
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
|
|
|
.type_float {
|
2022-06-16 20:19:49 +03:00
|
|
|
dataptr << unsafe { malloc(4) }
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
|
|
|
.type_double {
|
2022-06-16 20:19:49 +03:00
|
|
|
dataptr << unsafe { malloc(8) }
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
2022-07-19 18:29:09 +03:00
|
|
|
.type_time, .type_date, .type_datetime, .type_time2, .type_datetime2 {
|
|
|
|
dataptr << unsafe { malloc(sizeof(C.MYSQL_TIME)) }
|
|
|
|
}
|
2022-06-16 20:19:49 +03:00
|
|
|
.type_string, .type_blob {
|
|
|
|
dataptr << unsafe { malloc(512) }
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
2022-07-19 18:29:09 +03:00
|
|
|
.type_var_string {
|
|
|
|
dataptr << unsafe { malloc(2) }
|
|
|
|
}
|
2021-07-23 12:33:55 +03:00
|
|
|
else {
|
2022-07-19 18:29:09 +03:00
|
|
|
return error('\'${FieldType(f.@type)}\' is not yet implemented. Please create a new issue at https://github.com/vlang/v/issues/new')
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lens := []u32{len: int(num_fields), init: 0}
|
2022-06-16 20:19:49 +03:00
|
|
|
stmt.bind_res(fields, dataptr, lens, num_fields)
|
2021-07-23 12:33:55 +03:00
|
|
|
|
|
|
|
mut row := 0
|
2022-08-25 08:52:13 +03:00
|
|
|
mut types := config.types.clone()
|
2022-07-19 18:29:09 +03:00
|
|
|
mut field_types := []FieldType{}
|
2022-06-16 20:19:49 +03:00
|
|
|
if config.is_count {
|
|
|
|
types = [orm.type_idx['u64']]
|
|
|
|
}
|
2021-07-23 12:33:55 +03:00
|
|
|
|
2022-07-19 18:29:09 +03:00
|
|
|
for i, mut mysql_bind in stmt.res {
|
|
|
|
f := unsafe { fields[i] }
|
|
|
|
field_types << FieldType(f.@type)
|
|
|
|
match types[i] {
|
|
|
|
orm.string {
|
|
|
|
mysql_bind.buffer_type = C.MYSQL_TYPE_BLOB
|
|
|
|
mysql_bind.buffer_length = FieldType.type_blob.get_len()
|
|
|
|
}
|
|
|
|
orm.time {
|
|
|
|
match FieldType(f.@type) {
|
|
|
|
.type_long {
|
|
|
|
mysql_bind.buffer_type = C.MYSQL_TYPE_LONG
|
|
|
|
}
|
|
|
|
.type_time, .type_date, .type_datetime {
|
|
|
|
mysql_bind.buffer_type = C.MYSQL_TYPE_BLOB
|
|
|
|
mysql_bind.buffer_length = FieldType.type_blob.get_len()
|
|
|
|
}
|
|
|
|
.type_string, .type_blob {}
|
|
|
|
else {
|
|
|
|
return error('Unknown type ${f.@type}')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
stmt.bind_result_buffer()?
|
|
|
|
stmt.store_result()?
|
2021-07-23 12:33:55 +03:00
|
|
|
for {
|
2022-05-13 06:56:21 +03:00
|
|
|
status = stmt.fetch_stmt()?
|
2021-07-23 12:33:55 +03:00
|
|
|
|
|
|
|
if status == 1 || status == 100 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
row++
|
2022-06-16 20:19:49 +03:00
|
|
|
|
2022-07-19 18:29:09 +03:00
|
|
|
data_list := buffer_to_primitive(dataptr, types, field_types)?
|
2021-07-23 12:33:55 +03:00
|
|
|
ret << data_list
|
|
|
|
}
|
|
|
|
|
2022-05-13 06:56:21 +03:00
|
|
|
stmt.close()?
|
2021-07-23 12:33:55 +03:00
|
|
|
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
// sql stmt
|
|
|
|
|
|
|
|
pub fn (db Connection) insert(table string, data orm.QueryData) ? {
|
2022-07-19 18:29:09 +03:00
|
|
|
mut converted_primitive_array := db.factory_orm_primitive_converted_from_sql(table,
|
|
|
|
data)?
|
|
|
|
|
2022-07-27 00:59:32 +03:00
|
|
|
converted_primitive_data := orm.QueryData{
|
2022-07-19 18:29:09 +03:00
|
|
|
fields: data.fields
|
|
|
|
data: converted_primitive_array
|
|
|
|
types: []
|
|
|
|
kinds: []
|
|
|
|
is_and: []
|
|
|
|
}
|
|
|
|
|
2022-07-27 00:59:32 +03:00
|
|
|
query, converted_data := orm.orm_stmt_gen(table, '`', .insert, false, '?', 1, converted_primitive_data,
|
|
|
|
orm.QueryData{})
|
2022-07-19 18:29:09 +03:00
|
|
|
mysql_stmt_worker(db, query, converted_data, orm.QueryData{})?
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn (db Connection) update(table string, data orm.QueryData, where orm.QueryData) ? {
|
2022-07-27 00:59:32 +03:00
|
|
|
query, _ := orm.orm_stmt_gen(table, '`', .update, false, '?', 1, data, where)
|
2022-05-13 06:56:21 +03:00
|
|
|
mysql_stmt_worker(db, query, data, where)?
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn (db Connection) delete(table string, where orm.QueryData) ? {
|
2022-07-27 00:59:32 +03:00
|
|
|
query, _ := orm.orm_stmt_gen(table, '`', .delete, false, '?', 1, orm.QueryData{},
|
|
|
|
where)
|
2022-05-13 06:56:21 +03:00
|
|
|
mysql_stmt_worker(db, query, orm.QueryData{}, where)?
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn (db Connection) last_id() orm.Primitive {
|
2021-10-13 21:24:07 +03:00
|
|
|
query := 'SELECT last_insert_id();'
|
2021-07-23 12:33:55 +03:00
|
|
|
id := db.query(query) or {
|
|
|
|
Result{
|
|
|
|
result: 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return orm.Primitive(id.rows()[0].vals[0].int())
|
|
|
|
}
|
|
|
|
|
|
|
|
// table
|
|
|
|
pub fn (db Connection) create(table string, fields []orm.TableField) ? {
|
2022-07-27 00:59:32 +03:00
|
|
|
query := orm.orm_table_gen(table, '`', true, 0, fields, mysql_type_from_v, false) or {
|
2021-07-23 12:33:55 +03:00
|
|
|
return err
|
|
|
|
}
|
2022-05-13 06:56:21 +03:00
|
|
|
mysql_stmt_worker(db, query, orm.QueryData{}, orm.QueryData{})?
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn (db Connection) drop(table string) ? {
|
|
|
|
query := 'DROP TABLE `$table`;'
|
2022-05-13 06:56:21 +03:00
|
|
|
mysql_stmt_worker(db, query, orm.QueryData{}, orm.QueryData{})?
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn mysql_stmt_worker(db Connection, query string, data orm.QueryData, where orm.QueryData) ? {
|
|
|
|
mut stmt := db.init_stmt(query)
|
2022-05-13 06:56:21 +03:00
|
|
|
stmt.prepare()?
|
|
|
|
mysql_stmt_binder(mut stmt, data)?
|
|
|
|
mysql_stmt_binder(mut stmt, where)?
|
2021-07-23 12:33:55 +03:00
|
|
|
if data.data.len > 0 || where.data.len > 0 {
|
2022-05-13 06:56:21 +03:00
|
|
|
stmt.bind_params()?
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
2022-05-13 06:56:21 +03:00
|
|
|
stmt.execute()?
|
|
|
|
stmt.close()?
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn mysql_stmt_binder(mut stmt Stmt, d orm.QueryData) ? {
|
|
|
|
for data in d.data {
|
|
|
|
stmt_binder_match(mut stmt, data)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn stmt_binder_match(mut stmt Stmt, data orm.Primitive) {
|
|
|
|
match data {
|
|
|
|
bool {
|
|
|
|
stmt.bind_bool(&data)
|
|
|
|
}
|
|
|
|
i8 {
|
|
|
|
stmt.bind_i8(&data)
|
|
|
|
}
|
|
|
|
i16 {
|
|
|
|
stmt.bind_i16(&data)
|
|
|
|
}
|
|
|
|
int {
|
|
|
|
stmt.bind_int(&data)
|
|
|
|
}
|
|
|
|
i64 {
|
|
|
|
stmt.bind_i64(&data)
|
|
|
|
}
|
2022-04-15 20:31:10 +03:00
|
|
|
u8 {
|
2022-04-15 14:58:56 +03:00
|
|
|
stmt.bind_u8(&data)
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
|
|
|
u16 {
|
|
|
|
stmt.bind_u16(&data)
|
|
|
|
}
|
|
|
|
u32 {
|
|
|
|
stmt.bind_u32(&data)
|
|
|
|
}
|
|
|
|
u64 {
|
|
|
|
stmt.bind_u64(&data)
|
|
|
|
}
|
|
|
|
f32 {
|
|
|
|
stmt.bind_f32(unsafe { &f32(&data) })
|
|
|
|
}
|
|
|
|
f64 {
|
|
|
|
stmt.bind_f64(unsafe { &f64(&data) })
|
|
|
|
}
|
|
|
|
string {
|
|
|
|
stmt.bind_text(data)
|
|
|
|
}
|
|
|
|
time.Time {
|
2022-06-16 20:19:49 +03:00
|
|
|
unix := int(data.unix)
|
|
|
|
stmt_binder_match(mut stmt, unix)
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
|
|
|
orm.InfixType {
|
|
|
|
stmt_binder_match(mut stmt, data.right)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-19 18:29:09 +03:00
|
|
|
fn buffer_to_primitive(data_list []&u8, types []int, field_types []FieldType) ?[]orm.Primitive {
|
2021-07-23 12:33:55 +03:00
|
|
|
mut res := []orm.Primitive{}
|
|
|
|
|
|
|
|
for i, data in data_list {
|
|
|
|
mut primitive := orm.Primitive(0)
|
|
|
|
match types[i] {
|
2022-06-16 20:19:49 +03:00
|
|
|
orm.type_idx['i8'] {
|
|
|
|
primitive = *(unsafe { &i8(data) })
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
2022-06-16 20:19:49 +03:00
|
|
|
orm.type_idx['i16'] {
|
|
|
|
primitive = *(unsafe { &i16(data) })
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
2022-06-16 20:19:49 +03:00
|
|
|
orm.type_idx['int'], orm.serial {
|
|
|
|
primitive = *(unsafe { &int(data) })
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
2022-06-16 20:19:49 +03:00
|
|
|
orm.type_idx['i64'] {
|
|
|
|
primitive = *(unsafe { &i64(data) })
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
2022-07-06 13:32:30 +03:00
|
|
|
orm.type_idx['u8'] {
|
2022-06-16 20:19:49 +03:00
|
|
|
primitive = *(unsafe { &u8(data) })
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
2022-06-16 20:19:49 +03:00
|
|
|
orm.type_idx['u16'] {
|
|
|
|
primitive = *(unsafe { &u16(data) })
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
2022-06-16 20:19:49 +03:00
|
|
|
orm.type_idx['u32'] {
|
|
|
|
primitive = *(unsafe { &u32(data) })
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
2022-06-16 20:19:49 +03:00
|
|
|
orm.type_idx['u64'] {
|
|
|
|
primitive = *(unsafe { &u64(data) })
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
2022-06-16 20:19:49 +03:00
|
|
|
orm.type_idx['f32'] {
|
|
|
|
primitive = *(unsafe { &f32(data) })
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
2022-06-16 20:19:49 +03:00
|
|
|
orm.type_idx['f64'] {
|
|
|
|
primitive = *(unsafe { &f64(data) })
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
2022-06-16 20:19:49 +03:00
|
|
|
orm.type_idx['bool'] {
|
|
|
|
primitive = *(unsafe { &bool(data) })
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
|
|
|
orm.string {
|
|
|
|
primitive = unsafe { cstring_to_vstring(&char(data)) }
|
|
|
|
}
|
|
|
|
orm.time {
|
2022-07-19 18:29:09 +03:00
|
|
|
match field_types[i] {
|
|
|
|
.type_long {
|
|
|
|
timestamp := *(unsafe { &int(data) })
|
|
|
|
primitive = time.unix(timestamp)
|
|
|
|
}
|
|
|
|
.type_datetime {
|
|
|
|
string_time := unsafe { cstring_to_vstring(&char(data)) }
|
|
|
|
primitive = time.parse(string_time)?
|
|
|
|
}
|
|
|
|
else {}
|
|
|
|
}
|
2021-07-23 12:33:55 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
return error('Unknown type ${types[i]}')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
res << primitive
|
|
|
|
}
|
|
|
|
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mysql_type_from_v(typ int) ?string {
|
|
|
|
str := match typ {
|
2022-07-06 13:32:30 +03:00
|
|
|
orm.type_idx['i8'], orm.type_idx['u8'] {
|
2021-07-23 12:33:55 +03:00
|
|
|
'TINYINT'
|
|
|
|
}
|
2022-06-16 20:19:49 +03:00
|
|
|
orm.type_idx['i16'], orm.type_idx['u16'] {
|
2021-07-23 12:33:55 +03:00
|
|
|
'SMALLINT'
|
|
|
|
}
|
2022-06-16 20:19:49 +03:00
|
|
|
orm.type_idx['int'], orm.type_idx['u32'], orm.time {
|
2021-07-23 12:33:55 +03:00
|
|
|
'INT'
|
|
|
|
}
|
2022-06-16 20:19:49 +03:00
|
|
|
orm.type_idx['i64'], orm.type_idx['u64'] {
|
2021-07-23 12:33:55 +03:00
|
|
|
'BIGINT'
|
|
|
|
}
|
2022-06-16 20:19:49 +03:00
|
|
|
orm.type_idx['f32'] {
|
2021-07-23 12:33:55 +03:00
|
|
|
'FLOAT'
|
|
|
|
}
|
2022-06-16 20:19:49 +03:00
|
|
|
orm.type_idx['f64'] {
|
2021-07-23 12:33:55 +03:00
|
|
|
'DOUBLE'
|
|
|
|
}
|
|
|
|
orm.string {
|
|
|
|
'TEXT'
|
|
|
|
}
|
2022-06-16 20:19:49 +03:00
|
|
|
orm.serial {
|
2021-07-23 12:33:55 +03:00
|
|
|
'SERIAL'
|
|
|
|
}
|
2022-06-16 20:19:49 +03:00
|
|
|
orm.type_idx['bool'] {
|
|
|
|
'BOOLEAN'
|
|
|
|
}
|
2021-07-23 12:33:55 +03:00
|
|
|
else {
|
|
|
|
''
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if str == '' {
|
|
|
|
return error('Unknown type $typ')
|
|
|
|
}
|
|
|
|
return str
|
|
|
|
}
|
2022-07-19 18:29:09 +03:00
|
|
|
|
|
|
|
fn (db Connection) factory_orm_primitive_converted_from_sql(table string, data orm.QueryData) ?[]orm.Primitive {
|
|
|
|
mut map_val := db.get_table_data_type_map(table)?
|
|
|
|
|
|
|
|
// adapt v type to sql time
|
|
|
|
mut converted_data := []orm.Primitive{}
|
|
|
|
for i, field in data.fields {
|
|
|
|
match data.data[i].type_name() {
|
|
|
|
'time.Time' {
|
|
|
|
if map_val[field] == 'datetime' {
|
|
|
|
converted_data << orm.Primitive((data.data[i] as time.Time).str())
|
|
|
|
} else {
|
|
|
|
converted_data << data.data[i]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
converted_data << data.data[i]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return converted_data
|
|
|
|
}
|
|
|
|
|
|
|
|
fn (db Connection) get_table_data_type_map(table string) ?map[string]string {
|
|
|
|
data_type_querys := "SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '$table'"
|
|
|
|
mut map_val := map[string]string{}
|
|
|
|
|
|
|
|
results := db.query(data_type_querys)?
|
|
|
|
db.use_result()
|
|
|
|
|
|
|
|
for row in results.rows() {
|
|
|
|
map_val[row.vals[0]] = row.vals[1]
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe { results.free() }
|
|
|
|
return map_val
|
|
|
|
}
|