make << work with appending arrays; PostgreSQL driver
parent
fcf8909c75
commit
8f10e37370
|
@ -236,6 +236,7 @@ typedef map map_string;
|
||||||
//============================== HELPER C MACROS =============================*/
|
//============================== HELPER C MACROS =============================*/
|
||||||
|
|
||||||
#define _PUSH(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array__push(arr, &tmp);}
|
#define _PUSH(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array__push(arr, &tmp);}
|
||||||
|
#define _PUSH_MANY(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array__push_many(arr, tmp.data, tmp.len);}
|
||||||
#define _IN(typ, val, arr) array_##typ##_contains(arr, val)
|
#define _IN(typ, val, arr) array_##typ##_contains(arr, val)
|
||||||
#define ALLOC_INIT(type, ...) (type *)memdup((type[]){ __VA_ARGS__ }, sizeof(type))
|
#define ALLOC_INIT(type, ...) (type *)memdup((type[]){ __VA_ARGS__ }, sizeof(type))
|
||||||
#define UTF8_CHAR_LEN( byte ) (( 0xE5000000 >> (( byte >> 3 ) & 0x1e )) & 3 ) + 1
|
#define UTF8_CHAR_LEN( byte ) (( 0xE5000000 >> (( byte >> 3 ) & 0x1e )) & 3 ) + 1
|
||||||
|
|
|
@ -48,21 +48,9 @@ mut:
|
||||||
assigned_type string
|
assigned_type string
|
||||||
left_type string
|
left_type string
|
||||||
tmp_cnt int
|
tmp_cnt int
|
||||||
// TODO all these options are copy-pasted from the V struct. Create a Settings struct instead?
|
|
||||||
// is_test bool
|
|
||||||
is_script bool
|
is_script bool
|
||||||
pref *Preferences // Setting and Preferences shared from V struct
|
pref *Preferences // Setting and Preferences shared from V struct
|
||||||
// is_live bool
|
|
||||||
// is_so bool
|
|
||||||
// is_prof bool
|
|
||||||
// translated bool
|
|
||||||
// is_prod bool
|
|
||||||
// is_verbose bool
|
|
||||||
// obfuscate bool
|
|
||||||
// is_play bool
|
|
||||||
// is_repl bool
|
|
||||||
builtin_pkg bool
|
builtin_pkg bool
|
||||||
// build_mode BuildMode
|
|
||||||
vh_lines []string
|
vh_lines []string
|
||||||
inside_if_expr bool
|
inside_if_expr bool
|
||||||
is_struct_init bool
|
is_struct_init bool
|
||||||
|
@ -92,19 +80,9 @@ fn (c mut V) new_parser(path string, run Pass) Parser {
|
||||||
table: c.table
|
table: c.table
|
||||||
cur_fn: EmptyFn
|
cur_fn: EmptyFn
|
||||||
cgen: c.cgen
|
cgen: c.cgen
|
||||||
// is_test: c.pref.is_test
|
|
||||||
is_script: (c.pref.is_script && path == c.dir)
|
is_script: (c.pref.is_script && path == c.dir)
|
||||||
pref: c.pref
|
pref: c.pref
|
||||||
// is_so: c.is_so
|
|
||||||
os: c.os
|
os: c.os
|
||||||
// is_prof: c.is_prof
|
|
||||||
// is_prod: c.is_prod
|
|
||||||
// is_play: c.is_play
|
|
||||||
// translated: c.translated
|
|
||||||
// obfuscate: c.obfuscate
|
|
||||||
// is_verbose: c.is_verbose
|
|
||||||
// build_mode: c.build_mode
|
|
||||||
// is_repl: c.is_repl
|
|
||||||
run: run
|
run: run
|
||||||
vroot: c.vroot
|
vroot: c.vroot
|
||||||
}
|
}
|
||||||
|
@ -148,7 +126,7 @@ fn (p mut Parser) parse() {
|
||||||
p.fgenln('\n')
|
p.fgenln('\n')
|
||||||
p.builtin_pkg = p.pkg == 'builtin'
|
p.builtin_pkg = p.pkg == 'builtin'
|
||||||
p.can_chash = p.pkg == 'gg' || p.pkg == 'glm' || p.pkg == 'gl' ||
|
p.can_chash = p.pkg == 'gg' || p.pkg == 'glm' || p.pkg == 'gl' ||
|
||||||
p.pkg == 'http' || p.pkg == 'glfw' // TODO tmp remove
|
p.pkg == 'http' || p.pkg == 'glfw' || p.pkg=='ui' // TODO tmp remove
|
||||||
// Import pass - the first and the smallest pass that only analyzes imports
|
// Import pass - the first and the smallest pass that only analyzes imports
|
||||||
p.table.register_package(p.pkg)
|
p.table.register_package(p.pkg)
|
||||||
if p.run == RUN_IMPORTS {
|
if p.run == RUN_IMPORTS {
|
||||||
|
@ -1151,8 +1129,7 @@ fn (p mut Parser) var_decl() {
|
||||||
p.statements()
|
p.statements()
|
||||||
p.genln('$typ $name = *($typ*) $tmp . data;')
|
p.genln('$typ $name = *($typ*) $tmp . data;')
|
||||||
if !p.returns && p.prev_tok2 != CONTINUE && p.prev_tok2 != BREAK {
|
if !p.returns && p.prev_tok2 != CONTINUE && p.prev_tok2 != BREAK {
|
||||||
println(p.prev_tok2)
|
p.error('`or` block must return/continue/break/panic')
|
||||||
p.error('`or` statement must return/continue/break')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.register_var(Var {
|
p.register_var(Var {
|
||||||
|
@ -1820,13 +1797,21 @@ fn (p mut Parser) expression() string {
|
||||||
if !p.expr_var.is_mut && !p.pref.translated {
|
if !p.expr_var.is_mut && !p.pref.translated {
|
||||||
p.error('`$p.expr_var.name` is immutable (can\'t <<)')
|
p.error('`$p.expr_var.name` is immutable (can\'t <<)')
|
||||||
}
|
}
|
||||||
p.check_types(p.expression(), tmp_typ)
|
expr_type := p.expression()
|
||||||
|
// Two arrays of the same type?
|
||||||
|
push_array := typ == expr_type
|
||||||
|
if push_array {
|
||||||
|
p.cgen.set_placeholder(ph, '_PUSH_MANY(&' )
|
||||||
|
p.gen('), $tmp, $typ)')
|
||||||
|
} else {
|
||||||
|
p.check_types(expr_type, tmp_typ)
|
||||||
// Pass tmp var info to the _PUSH macro
|
// Pass tmp var info to the _PUSH macro
|
||||||
p.gen('), $tmp, $tmp_typ)')
|
|
||||||
// Prepend tmp initialisation and push call
|
// Prepend tmp initialisation and push call
|
||||||
// Don't dereference if it's already a mutable array argument (`fn foo(mut []int)`)
|
// Don't dereference if it's already a mutable array argument (`fn foo(mut []int)`)
|
||||||
push_call := if typ.contains('*'){'_PUSH('} else { '_PUSH(&'} // p.cgen.set_placeholder(ph, '_PUSH(&')
|
push_call := if typ.contains('*'){'_PUSH('} else { '_PUSH(&'}
|
||||||
p.cgen.set_placeholder(ph, push_call)
|
p.cgen.set_placeholder(ph, push_call)
|
||||||
|
p.gen('), $tmp, $tmp_typ)')
|
||||||
|
}
|
||||||
return 'void'
|
return 'void'
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -437,6 +437,9 @@ fn (p mut Parser) _check_types(got, expected string, throw bool) bool {
|
||||||
if got=='byteptr' && expected=='byte*' {
|
if got=='byteptr' && expected=='byte*' {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if got=='byte*' && expected=='byteptr' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
if got=='int' && expected=='byte*' {
|
if got=='int' && expected=='byte*' {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,13 +69,6 @@ fn array_repeat(val voidptr, nr_repeats, elm_size int) array {
|
||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a mut array) append_array(b array) {
|
|
||||||
for i := 0; i < b.len; i++ {
|
|
||||||
val := b[i]
|
|
||||||
a._push(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn (a mut array) sort_with_compare(compare voidptr) {
|
pub fn (a mut array) sort_with_compare(compare voidptr) {
|
||||||
C.qsort(a.data, a.len, a.element_size, compare)
|
C.qsort(a.data, a.len, a.element_size, compare)
|
||||||
}
|
}
|
||||||
|
@ -178,6 +171,7 @@ fn (arr mut array) _push(val voidptr) {
|
||||||
arr.len++
|
arr.len++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `val` is array.data
|
||||||
pub fn (arr mut array) _push_many(val voidptr, size int) {
|
pub fn (arr mut array) _push_many(val voidptr, size int) {
|
||||||
if arr.len >= arr.cap - size {
|
if arr.len >= arr.cap - size {
|
||||||
cap := (arr.len + size) * 2
|
cap := (arr.len + size) * 2
|
||||||
|
|
|
@ -141,7 +141,7 @@ fn test_slice() {
|
||||||
fn test_push_many() {
|
fn test_push_many() {
|
||||||
mut a := [1, 2, 3]
|
mut a := [1, 2, 3]
|
||||||
b := [4, 5, 6]
|
b := [4, 5, 6]
|
||||||
a._push_many(b.data, b.len)
|
a << b
|
||||||
assert a.len == 6
|
assert a.len == 6
|
||||||
assert a[0] == 1
|
assert a[0] == 1
|
||||||
assert a[3] == 4
|
assert a[3] == 4
|
||||||
|
|
|
@ -567,7 +567,7 @@ fn (ctx &GG) _draw_text(_x, _y int, utext ustring, cfg gx.TextCfg) {
|
||||||
// #free(runes.data);
|
// #free(runes.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (ctx &GG) draw_text_def(x, y int, text string) {
|
pub fn (ctx &GG) draw_text_def(x, y int, text string) {
|
||||||
cfg := gx.TextCfg {
|
cfg := gx.TextCfg {
|
||||||
color: gx.Black,
|
color: gx.Black,
|
||||||
size: DEFAULT_FONT_SIZE,
|
size: DEFAULT_FONT_SIZE,
|
||||||
|
|
38
vlib/os/os.v
38
vlib/os/os.v
|
@ -108,12 +108,7 @@ fn parse_windows_cmd_line(cmd byteptr) []string {
|
||||||
//pub fn read_file(path string) ?string {
|
//pub fn read_file(path string) ?string {
|
||||||
pub fn read_file(path string) ?string {
|
pub fn read_file(path string) ?string {
|
||||||
mut res := ''
|
mut res := ''
|
||||||
mut mode := 'r'
|
mut mode := 'rb'
|
||||||
777 // TODO
|
|
||||||
// Need 'rb' on windows to avoid the \r\n mess.
|
|
||||||
$if windows {
|
|
||||||
mode = 'rb'
|
|
||||||
}
|
|
||||||
cpath := path.cstr()
|
cpath := path.cstr()
|
||||||
fp := C.fopen(cpath, mode.cstr())
|
fp := C.fopen(cpath, mode.cstr())
|
||||||
if isnil(fp) {
|
if isnil(fp) {
|
||||||
|
@ -132,31 +127,6 @@ pub fn read_file(path string) ?string {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_file_opt(path string) ?string {
|
|
||||||
mut res := ''
|
|
||||||
mut mode := 'r'
|
|
||||||
777 // TODO
|
|
||||||
// Need 'rb' on windows to avoid the \r\n mess.
|
|
||||||
$if windows {
|
|
||||||
mode = 'rb'
|
|
||||||
}
|
|
||||||
cpath := path.cstr()
|
|
||||||
fp := C.fopen(cpath, mode.cstr())
|
|
||||||
if isnil(fp) {
|
|
||||||
return error('failed to open file "$path"')
|
|
||||||
}
|
|
||||||
C.fseek(fp, 0, SEEK_END)
|
|
||||||
fsize := C.ftell(fp)
|
|
||||||
// C.fseek(fp, 0, SEEK_SET) // same as C.rewind(fp) below
|
|
||||||
C.rewind(fp)
|
|
||||||
mut str := malloc(fsize + 1)
|
|
||||||
C.fread(str, fsize, 1, fp)
|
|
||||||
C.fclose(fp)
|
|
||||||
str[fsize] = 0
|
|
||||||
res = tos(str, fsize)
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// file_size returns the size of the file located in `path`.
|
// file_size returns the size of the file located in `path`.
|
||||||
pub fn file_size(path string) int {
|
pub fn file_size(path string) int {
|
||||||
s := C.stat{}
|
s := C.stat{}
|
||||||
|
@ -208,7 +178,7 @@ fn read_ulines(path string) []ustring {
|
||||||
pub fn open(path string) ?File {
|
pub fn open(path string) ?File {
|
||||||
cpath := path.cstr()
|
cpath := path.cstr()
|
||||||
file := File {
|
file := File {
|
||||||
cfile: C.fopen(cpath, 'r')
|
cfile: C.fopen(cpath, 'rb')
|
||||||
}
|
}
|
||||||
if isnil(file.cfile) {
|
if isnil(file.cfile) {
|
||||||
return error('failed to open file "$path"')
|
return error('failed to open file "$path"')
|
||||||
|
@ -220,7 +190,7 @@ pub fn open(path string) ?File {
|
||||||
pub fn create(path string) ?File {
|
pub fn create(path string) ?File {
|
||||||
cpath := path.cstr()
|
cpath := path.cstr()
|
||||||
file := File {
|
file := File {
|
||||||
cfile: C.fopen(cpath, 'w')
|
cfile: C.fopen(cpath, 'wb')
|
||||||
}
|
}
|
||||||
if isnil(file.cfile) {
|
if isnil(file.cfile) {
|
||||||
return error('failed to create file "$path"')
|
return error('failed to create file "$path"')
|
||||||
|
@ -231,7 +201,7 @@ pub fn create(path string) ?File {
|
||||||
pub fn open_append(path string) ?File {
|
pub fn open_append(path string) ?File {
|
||||||
cpath := path.cstr()
|
cpath := path.cstr()
|
||||||
file := File {
|
file := File {
|
||||||
cfile: C.fopen(cpath, 'a')
|
cfile: C.fopen(cpath, 'ab')
|
||||||
}
|
}
|
||||||
if isnil(file.cfile) {
|
if isnil(file.cfile) {
|
||||||
return error('failed to create file "$path"')
|
return error('failed to create file "$path"')
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
module pg
|
||||||
|
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
#flag -lpq
|
||||||
|
#flag linux -I/usr/include/postgresql
|
||||||
|
#include <libpq-fe.h>
|
||||||
|
|
||||||
|
struct DB {
|
||||||
|
mut:
|
||||||
|
conn *C.PGconn
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Row {
|
||||||
|
pub:
|
||||||
|
vals []string
|
||||||
|
}
|
||||||
|
|
||||||
|
import const (
|
||||||
|
CONNECTION_OK
|
||||||
|
)
|
||||||
|
|
||||||
|
struct C.PGResult { }
|
||||||
|
|
||||||
|
fn C.PQconnectdb(a byteptr) *C.PGconn
|
||||||
|
fn C.PQerrorMessage(voidptr) byteptr
|
||||||
|
|
||||||
|
pub fn connect(dbname, user string) DB {
|
||||||
|
conninfo := 'host=localhost user=$user dbname=$dbname'
|
||||||
|
conn:=C.PQconnectdb(conninfo.cstr())
|
||||||
|
status := C.PQstatus(conn)
|
||||||
|
if status != CONNECTION_OK {
|
||||||
|
error_msg := C.PQerrorMessage(conn)
|
||||||
|
eprintln('Connection to a PG database failed: ' + string(error_msg))
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
return DB {conn: conn}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn res_to_rows(res voidptr) []pg.Row {
|
||||||
|
nr_rows := C.PQntuples(res)
|
||||||
|
nr_cols := C.PQnfields(res)
|
||||||
|
mut rows := []pg.Row
|
||||||
|
for i := 0; i < nr_rows; i++ {
|
||||||
|
mut row := Row{}
|
||||||
|
for j := 0; j < nr_cols; j++ {
|
||||||
|
val := C.PQgetvalue(res, i, j)
|
||||||
|
row.vals << string(val)
|
||||||
|
}
|
||||||
|
rows << row
|
||||||
|
}
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (db DB) q_int(query string) int {
|
||||||
|
rows := db.exec(query)
|
||||||
|
if rows.len == 0 {
|
||||||
|
println('q_int "$query" not found')
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
row := rows[0]
|
||||||
|
if row.vals.len == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
val := row.vals[0]
|
||||||
|
return val.int()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (db DB) q_string(query string) string {
|
||||||
|
rows := db.exec(query)
|
||||||
|
if rows.len == 0 {
|
||||||
|
println('q_string "$query" not found')
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
row := rows[0]
|
||||||
|
if row.vals.len == 0 {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
val := row.vals[0]
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (db DB) q_strings(query string) []pg.Row {
|
||||||
|
return db.exec(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (db DB) exec(query string) []pg.Row {
|
||||||
|
res := C.PQexec(db.conn, query.cstr())
|
||||||
|
e := string(C.PQerrorMessage(db.conn))
|
||||||
|
if e != '' {
|
||||||
|
println('pg exec error:')
|
||||||
|
println(e)
|
||||||
|
return res_to_rows(res)
|
||||||
|
}
|
||||||
|
return res_to_rows(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
pub fn (db DB) exec_param2(query string, param, param2 string) []pg.Row {
|
||||||
|
mut param_vals := [2]byteptr
|
||||||
|
param_vals[0] = param.str
|
||||||
|
param_vals[1] = param2.str
|
||||||
|
res := C.PQexecParams(db.conn, query.str, 2, 0, param_vals, 0, 0, 0)
|
||||||
|
return res_to_rows(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (db DB) exec_param(query string, param string) []pg.Row {
|
||||||
|
mut param_vals := [1]byteptr
|
||||||
|
param_vals[0] = param.str
|
||||||
|
res := C.PQexecParams(db.conn, query.str, 1, 0, param_vals, 0, 0, 0)
|
||||||
|
return res_to_rows(res)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
module pg
|
||||||
|
|
||||||
|
#flag -I/usr/include/postgresql
|
||||||
|
// #flag `pkg-config --cflags libpq`
|
|
@ -0,0 +1,2 @@
|
||||||
|
module pg
|
||||||
|
|
|
@ -18,11 +18,13 @@ pub fn new_builder(initial_size int) Builder {
|
||||||
|
|
||||||
pub fn (b mut Builder) write(s string) {
|
pub fn (b mut Builder) write(s string) {
|
||||||
b.buf._push_many(s.str, s.len)
|
b.buf._push_many(s.str, s.len)
|
||||||
|
//b.buf << []byte(s) // TODO
|
||||||
b.len += s.len
|
b.len += s.len
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (b mut Builder) writeln(s string) {
|
pub fn (b mut Builder) writeln(s string) {
|
||||||
b.buf._push_many(s.str, s.len)
|
b.buf._push_many(s.str, s.len)
|
||||||
|
//b.buf << []byte(s) // TODO
|
||||||
b.buf << `\n`
|
b.buf << `\n`
|
||||||
b.len += s.len + 1
|
b.len += s.len + 1
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue