From 2b8ca4a67f414eec8e04db1ae443f29612073a04 Mon Sep 17 00:00:00 2001 From: Nicolas Boisselier Date: Sun, 20 Nov 2016 04:19:19 +0000 Subject: [PATCH] a lot --- bin/dbq | 66 ++++++----- etc/dbq.php | 5 +- etc/dbq/local.php | 12 ++ etc/profile.d/docker.sh | 6 +- etc/profile.d/functions | 37 ++++++ etc/profile.d/virtualbox.sh | 30 +++++ etc/vim/source/html.no | 4 +- etc/vim/source/vars.vim | 18 +++ etc/vim/source/vars.vim.bak | 11 ++ etc/vim/{stats => stats.TODEL}/let.g | 0 etc/vim/{stats => stats.TODEL}/let.v | 0 etc/vim/{stats => stats.TODEL}/set.all | 0 etc/vim/{stats => stats.TODEL}/setglob.all | 0 etc/vim/{stats => stats.TODEL}/setloc.all | 0 etc/vim/{ => templates}/template.html | 0 etc/vimrc | 10 -- lib/php/config.php | 24 ++-- lib/php/db.php | 66 ++++++++--- lib/php/db/table.php | 125 ++++++++++++++++----- lib/php/db/types/sqlite.php | 2 +- lib/php/out.php | 58 +++++++++- share/db/local.db | Bin 0 -> 53248 bytes share/db/update.sh | 18 +++ 23 files changed, 391 insertions(+), 101 deletions(-) create mode 100644 etc/dbq/local.php create mode 100644 etc/profile.d/virtualbox.sh create mode 100644 etc/vim/source/vars.vim create mode 100644 etc/vim/source/vars.vim.bak rename etc/vim/{stats => stats.TODEL}/let.g (100%) rename etc/vim/{stats => stats.TODEL}/let.v (100%) rename etc/vim/{stats => stats.TODEL}/set.all (100%) rename etc/vim/{stats => stats.TODEL}/setglob.all (100%) rename etc/vim/{stats => stats.TODEL}/setloc.all (100%) rename etc/vim/{ => templates}/template.html (100%) create mode 100644 share/db/local.db create mode 100755 share/db/update.sh diff --git a/bin/dbq b/bin/dbq index e7ff28ce..d1533afa 100755 --- a/bin/dbq +++ b/bin/dbq @@ -33,23 +33,6 @@ my %PARAM = ( 'rows_head_char' => "\r", ); -$PARAM{'format'} = 'csv' unless -t STDOUT; -%PARAM = map {$_=>$PARAM{$_}} grep {$PARAM{$_} ne ''} keys %PARAM; - -# DBQ -if ($ENV{$UC_NAME}) { - for (split(' ',$ENV{$UC_NAME})) { - /^(\w+)=(.*?)$/ and $PARAM{$1} = $2; - } -} - -# DBQ_PARAMS -if ($ENV{$UC_NAME.'_PARAMS'}) { - for (split(' ',$ENV{$UC_NAME.'_PARAMS'})) { - /^(\w+)=(.*?)$/ and $PARAM{$1} = $2; - } -} - my %CMD_ALIASE = ( # NB 09.04.16 'd' => 'db', # NB 09.04.16 't' => 'table', @@ -100,6 +83,27 @@ get_options(\%Opt,\@CURL_OPT); # ################################################################################# +# +# Params +# +$PARAM{'format'} = 'csv' if $Opt{pipe}; +%PARAM = map {$_=>$PARAM{$_}} grep {$PARAM{$_} ne ''} keys %PARAM; + +# DBQ +if ($ENV{$UC_NAME}) { + for (split(' ',$ENV{$UC_NAME})) { + /^(\w+)=(.*?)$/ and $PARAM{$1} = $2; + } +} + +# DBQ_PARAMS +if ($ENV{$UC_NAME.'_PARAMS'}) { + for (split(' ',$ENV{$UC_NAME.'_PARAMS'})) { + /^(\w+)=(.*?)$/ and $PARAM{$1} = $2; + } +} + + # # Get URL # @@ -127,7 +131,7 @@ $url =~ m@^ssh://(.*)$@ and $Opt{ssh} = $1; #exec('ssh',$Opt{ssh},". /etc/profile && $NAME",map{s/"/\\"/g;'"'.$_.'"'} grep {$_ !~ /^(-+ssh|$Opt{ssh})/} @EXEC) if $Opt{ssh}; exec('ssh', - -t STDOUT ? '-t' : '-q', + $Opt{pipe} ? '-q' : '-t', #'-q', $Opt{ssh}, '/usr/bin/env', @@ -178,9 +182,6 @@ while (my ($k,$v) = each %PARAM) { $keys{$k} = $v; } -# NB 19.04.16 use Data::Dumper; die Dumper(\%keys); -# NB 19.04.16 $keys{table} = $1 if $keys{db} and $keys{db} =~ s/:(.*)$//; - ################################################################################# # # Parser @@ -369,7 +370,7 @@ sub help { close $in; # Output - open(STDOUT,"|perl -pe 's/\.$$//g'".(($ENV{PAGER}||'') eq 'less' ? "|less -FRi" : "")); + open(STDOUT,"|perl -pe 's/\.$$//g'".(($ENV{PAGER}||'') eq 'less' ? "|less -FRi" : "")); my $opts = { -input => $in_file, -ouput => \*STDOUT, @@ -395,7 +396,7 @@ sub version { print "$NAME: version [$VERSION]\n"; exit 0; } #------------------------------------------------------------------------------ sub get_options { - my $hash = $_[0]; #shift @_; + my $Opt = $_[0]; #shift @_; my $default = $_[1]; #shift @_; use Getopt::Long qw(:config no_ignore_case no_auto_abbrev); @@ -415,13 +416,15 @@ sub get_options { $main::_DATA_ .= $_; } - GetOptions($hash,@Opt) || exit -1; + GetOptions($Opt,@Opt) || exit -1; + + help() if $Opt->{'help'} or $_[0]{'man'}; + version() if $Opt->{'version'}; - help() if $hash->{'help'} or $_[0]{'man'}; - version() if $hash->{'version'}; + $main::VERBOSE = $VERBOSE = $Opt->{'verbose'} if defined $_[0]{'verbose'}; + $main::DEBUG = $DEBUG = $Opt->{'debug'} if defined $_[0]{'debug'}; - $main::VERBOSE = $VERBOSE = $hash->{'verbose'} if defined $_[0]{'verbose'}; - $main::DEBUG = $DEBUG = $hash->{'debug'} if defined $_[0]{'debug'}; + $Opt{pipe} = -t STDOUT ? 0 : 1 unless defined $Opt{pipe}; } @@ -467,8 +470,15 @@ Quick usage: $NAME [URL|EXEC] [CURL_OPTIONS] [key=value]... Curl / Php query wrapper +Value understand patterns: + + - *PATTERN* + - ~REGEX + - ![PATTERN|REGEX] + =head1 OPTIONS + option[pipe|p!] Define pipe context output. Default (dynamic) option[cut=s] Parse output to cut, imply format=csv and header=0 option[ssh=s] SERVER Run the script on that server option[verbose|v+] Verbose mode: increase the verbosity level. diff --git a/etc/dbq.php b/etc/dbq.php index be2771a0..82c0efd2 100644 --- a/etc/dbq.php +++ b/etc/dbq.php @@ -65,7 +65,7 @@ if (!empty($DIR_SQLITE)) { } # -# Sqlite all Attach db type=sqlite +# ALL - Attach all sqlite databases # #return; $DBQ['all'] = [ @@ -106,6 +106,9 @@ foreach ($DBQ as $id => $db) { } conf_merge($DBQ['nb'],$DBQ['all']); +# +# Functions +# function conf_merge(&$c1,&$c2) { // .* diff --git a/etc/dbq/local.php b/etc/dbq/local.php new file mode 100644 index 00000000..bc08c1aa --- /dev/null +++ b/etc/dbq/local.php @@ -0,0 +1,12 @@ + [ + 'type' => 'sqlite', + 'name' => 'local', + 'host' => nb::ROOT_DIR.'/share/db/local.db', + ], +]; +?> diff --git a/etc/profile.d/docker.sh b/etc/profile.d/docker.sh index 1d84132a..edc10081 100644 --- a/etc/profile.d/docker.sh +++ b/etc/profile.d/docker.sh @@ -18,9 +18,9 @@ if [ -z "$MYVIMRC" ]; then fi -docker_machine_shared() { - VBoxManage showvminfo "$DOCKER_MACHINE_NAME" | perl -ne "print qq|\$2\t\$1\n| if /^Name: '(.*?)', Host path: '(.*?)'/" -} +if which docker-compose > /dev/null; then + true +fi docker_build() { diff --git a/etc/profile.d/functions b/etc/profile.d/functions index cc0b8eea..4fabb36b 100644 --- a/etc/profile.d/functions +++ b/etc/profile.d/functions @@ -634,3 +634,40 @@ find_sort_mtime() { # strftime "%a %b %e %H:%M:%S %Y" } +shell_functions2sql() { + local t="$1"; shift + local f + ( + for f in `shell_functions`; do + type "$f" || continue + done + ) | perl -MData::Dumper -e ' +BEGIN{$t=shift @ARGV and print qq|PRAGMA encoding="UTF-8";\n| +."DROP TABLE IF EXISTS $t;\n" +."CREATE TABLE $t (name VARCHAR(255) PRIMARY KEY,code BLOB);\n" +and $t="INSERT INTO $t "; +$|=1; +} +$_=join("",<>);@_=(map{s/^\s*(.*?)\s*$/$1/m;$_}split(/^(.*?) is a function$/m,$_)); +0&&die Dumper(\\@_); +0&&die Dumper($_[2]); +$q=chr(39); +while (@_) { + $k=shift @_; + next unless $k; + $v=shift @_; + $v =~ s/$q/$q.$q/ge; + print $t.qq|VALUES ($q$k$q,$q$v$q);\n|; +} +' "$t" +} + +shell_replace() { + perl -ne 'if (/^.{1,3}>SHELL_REPLACE (.*)$/ .. /^.{1,3} /dev/null || return 0 + +virtualbox_shared() { + local machine="$1"; shift + [ -z "$machine" -a -n "$DOCKER_MACHINE_NAME" ] && machine="$DOCKER_MACHINE_NAME" + [ -z "$machine" -o "$machine" = '-h' -o "$machine" = '--help' ] && echo "Usage: $FUNCNAME MACHINE_NAME" 1>&2 && return + VBoxManage showvminfo "$machine" | perl -ne "print qq|\$2\t\$1\n| if /^Name: '(.*?)', Host path: '(.*?)'/" +} + +virtualbox_add_shared() { + local machine="$1"; shift + local path="$1"; shift + local share="$1"; shift + virtualbox_shared "$machine" | grep -q "^$path" && echo "$path: share already exists!'" 1>&2 && return 1 + + if virtualbox_shared "$machine" | grep -q "^$path"; then + echo "$path: share already exists!'" 1>&2 + else + docker-machine stop "$machine" + VBoxManage sharedfolder add "$machine" --name "$share" --hostpath "$path"--automount 2>/dev/null || : + docker-machine start "$machine" + fi + + eval $(docker-machine env "$machine") && docker-machine ssh "$machine" \ + 'printf "test -e $path || mkdir -p $path\nmount -t vboxsf -o rw,user $share $path\n | sudo tee /mnt/sda1/var/lib/boot2docker/bootlocal.sh && sudo sh /mnt/sda1/var/lib/boot2docker/bootlocal.sh' +} diff --git a/etc/vim/source/html.no b/etc/vim/source/html.no index 485cdd38..314cd89e 100644 --- a/etc/vim/source/html.no +++ b/etc/vim/source/html.no @@ -1,6 +1,6 @@ """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" " NB 04.09.06 HTML plugin -" :let g:html_authorname = 'Nicolas' +" :let g:html_authorname = 'Nicolas Boisselier' " :let g:html_tag_case = 'l' -" :let g:html_template = '~/.vim/template.html' +" :let g:html_template = $VIMHOME . '/templates/template.html' """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" diff --git a/etc/vim/source/vars.vim b/etc/vim/source/vars.vim new file mode 100644 index 00000000..2358b046 --- /dev/null +++ b/etc/vim/source/vars.vim @@ -0,0 +1,18 @@ +" +">SHELL_REPLACE dbq t=mime orderby=id rows.fields=id,cmd_check out=cust cust="@id@ : @cmd_check@" sep=, preff=' \' quote_escape="'" quote="'" open='let mimeCheck = {\n' close='\}\n' +let mimeCheck = { + \'bash' : 'bash -c' + \,'erb' : 'sh -c \"cat | erb -x - | ruby -c\" <' + \,'html' : 'xmllint --noout --html' + \,'json' : 'ruby -rjson -e ''puts JSON.parse(File.read(ARGV[0]))''' + \,'perl' : 'perl -c -w' + \,'php' : 'php --define error_reporting=22519 --define display_errors=1 --define log_errors=1 --define html_errors=0' + \,'puppet' : 'perl -e ''system qq/puppet parser validate $ARGV[0] && puppet-lint --no-selector_inside_resource-check --no-autoloader_layout-check --no-hard_tabs-check --no-80chars-check $ARGV[0]/''' + \,'python' : 'python -m py_compile' + \,'ruby' : 'ruby -c' + \,'sh' : 'sh -c' + \,'yaml' : 'ruby -ryaml -e ''puts YAML.load_file(ARGV[0])''' +\} +"SHELL_REPLACE dbq t=mime rows.fields=id,cmd_check out=cust cust="@id@ : @cmd_check@" sep=, preff=' \' open='let mimeCheck = {\n' close='\}\n' +" +let mimeCheck = { +\} +" +"pdo) and $this->type) $this->pdo = $this->type.':'; + # Extract args from pdo + foreach ($this->pdo2h($this->pdo) as $k=>$v) { + $this->$k = $v; + } + if (empty($this->type)) $this->type = strtolower(preg_replace('/^([^:]+):.*$/','\1',$this->pdo)); if (!$this->type) return false; if ($this->conf_type('use_path')) { + if ($p = $this->p('db.host')) $this->host = $p; if (empty($this->host)) $this->host = preg_replace('/^\w+:/','',$this->pdo); + # Add file if (trim($this->pdo,'pdo:'.$this->type)=='') $this->pdo .= $this->host; } else { - # Extract args from pdo - foreach ($this->pdo2h($this->pdo) as $k=>$v) { - $this->$k = $v; - } +# NB 19.11.16 # Extract args from pdo +# NB 19.11.16 foreach ($this->pdo2h($this->pdo) as $k=>$v) { +# NB 19.11.16 $this->$k = $v; +# NB 19.11.16 } # NB 26.10.16 if (preg_match_all("/[:;](\w+)=([^;]+)/",$this->pdo,$m,PREG_SET_ORDER)) { # NB 26.10.16 foreach ($m as $param) { @@ -233,14 +241,8 @@ class Db extends nb { if (empty($this->row_parse) and $this->conf_type('row_parse')) { $this->row_parse = $this->conf_type('row_parse'); } - } - public function disconnect() { - if (empty($this->conn)) return null; - #$this->conn->exec('COMMIT'); - $this->method('disconnect'); -# NB 09.09.16 return $this->conn->close(); - } + } # < if else 'use_path' public function connect() { if (!empty($this->conn)) return false; @@ -259,9 +261,11 @@ class Db extends nb { } catch (PDOException $e) { $msg = 'Connection failed:'; + foreach(['name','host','file'] as $p) { if (!empty($this->$p)) $msg .= " $p=".$this->$p; } + $msg .= "\n ".$e->getMessage(); #throw new Exception($msg, (int)$e->getCode()); self::bye($msg); @@ -286,6 +290,13 @@ class Db extends nb { return true; } + public function disconnect() { + if (empty($this->conn)) return null; + #$this->conn->exec('COMMIT'); + $this->method('disconnect'); +# NB 09.09.16 return $this->conn->close(); + } + function exec($sql) { try { @@ -484,6 +495,9 @@ class Db extends nb { $sql = $this->method('tables'); if ($sql and !empty($this->conn)) { +#bye([">>",$this->tables,$sql]); +#$sql = "SELECT 'shell_functions','table';"; +#$sql = "SELECT name,type FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type IN('table','view') AND name NOT LIKE 'sqlite_%'"; foreach ($this->conn->query($sql,PDO::FETCH_ASSOC) as $row) { $name = current($row); @@ -723,6 +737,21 @@ class Db extends nb { return $dbs; } + /** + * @copyright NB 19.11.16 + * Return a db hash to create a new instance from $conf + */ + public static function conf_param_db($id) { + if (!isset($id)) $id = self::p('db'); + + if (!$id or !preg_match('/^(\w+):(.*)/',$id,$m)) return []; + $conf = [$id => []]; + + $conf[$id] = $conf[$id] + self::pdo2h($id); + + return $conf; + } + /** * @copyright NB 12.08.16 * Return a db hash to create a new instance from $conf @@ -734,11 +763,15 @@ class Db extends nb { # Load databases $conf = self::is_hash($conf) ? $conf : self::conf_load($conf); + /* + # NB 19.11.16: TODEL - replaced with conf_param_db # Check db=pdo if ($id and preg_match('/^(\w+):(.*)/',$id,$m)) { if (empty($conf[$id])) $conf[$id] = []; $conf[$id] = $conf[$id] + self::pdo2h($id); } + */ + $conf += self::conf_param_db($id); if (!$conf) return false; @@ -819,17 +852,25 @@ class Db extends nb { */ public static function pdo2h($pdo) { $hash = []; + if (preg_match('/^(\w+):(.*)/',$pdo,$m)) { $hash['type'] = $m[1]; $pdo = $m[2]; } + # YES - 'use_path' while (preg_match('/^(\w+)=([^;]*)(?:;?)(.*?)$/',$pdo,$m)) { if ($m[1] == 'dbname') $m[1] = 'name'; $hash[$m[1]] = $m[2]; $pdo = $m[3]; } + # NO - 'use_path' + if ($pdo) { + $hash['host'] = $pdo; + unset($pdo); + } + return $hash; } @@ -1089,9 +1130,6 @@ class Db extends nb { return $return; } - public function fct() { - } - public function databases() { if (!isset($this->databases)) { diff --git a/lib/php/db/table.php b/lib/php/db/table.php index 2656fc75..1cab6d88 100644 --- a/lib/php/db/table.php +++ b/lib/php/db/table.php @@ -744,8 +744,38 @@ Class Table extends nb { return true; } + private function rows_parsers(&$row,&$opt=[]) { + $parser = isset($opt['parser']) ? $opt['parser'] : true; + $call = null; + + if ($parser) $this->db()->table_row_decrypt($this,$row); + if ($parser and !empty($this->db()->row_parse)) { + $call = $this->db()->row_parse; $call($row); + } + + if ($parser and !empty($this->row_parse_pre)) { + $call = $this->row_parse_pre; $call($row); + } + + if ($opt['is_html'] and !$opt['use_out']) { + foreach ($row as $k=>$v) { + if (!isset($this->extras[$k])) $row[$k] = out::format($v); + } + + } + + if ($parser and !empty($this->row_parse_post)) { + $call = $this->row_parse_post; $call($row); + } + + return $call; + } + public function rows(&$opt=[],$opt_by_val=null) { + # + # Run query + # $this->create_temporary(); if ($opt_by_val !== null) $opt = $opt_by_val; @@ -754,39 +784,43 @@ Class Table extends nb { if (!$format) bye("Parameter `format` missing!"); list($sql,$where,$limit,$select_count) = $this->rows_sql($opt); - $st = $this->db()->conn->prepare($sql); + $st = $this->db()->conn->prepare($sql);#,[PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT]); $st->execute(); + # # Fields - $fields = []; + # if (!DB_TABLE_QUERY_NAME) { + $fields = []; foreach ($this->db()->fields($st) as $f) { $fields[$f->name] = $f; } $this->fields = $fields; } #debug($fields); #bye($this->name); - if (!isset($opt['is_html'])) $opt['is_html'] = preg_match('/^(table|div)$/',$format) - ? ( $this->p('header')!=="0") - : false - ; - - if ($opt['is_html'] and !$this->p('action') and !$this->p('inc')) { - echo $this->html_menu(); - } - - if ($opt['is_html']) { - echo '
'.NB_EOL; - if (!$this->p('inc')) echo $this->form_hidden(); + # + # Fields filter + # + $fields = $this->fields(); + $fields_filter = []; + if ($this->p('rows.fields')) { + $fields_filter = preg_split('/[^\w_]/',$this->p('rows.fields')); + foreach ($fields as $k => $field) { + if (!in_array($k,$fields_filter) and !isset($this->extras[$k])) unset($fields[$k]); + } } + # # Use the module out when format unknow + # $out_conf = null; + $opt['use_out'] = false; if ($this->p('out') or !preg_match('/^('.join('|', [ 'table','sql','div','wp','_csv','_xml','_json','_yaml' ] # local ).')$/',$format)) { + $opt['use_out'] = true; if (!($out_conf = out::types($format))) $this->bye("Unknow format `$format`"); out::type($format); self::$params += array_values(out::types()); @@ -796,19 +830,42 @@ Class Table extends nb { } + # + # Html + # + if (!isset($opt['is_html'])) $opt['is_html'] = preg_match('/^(table|div)$/',$format) + ? ( $this->p('header')!=="0") + : false + ; + + if ($opt['is_html'] and !$this->p('action') and !$this->p('inc')) { + echo $this->html_menu(); + } + + if ($opt['is_html']) { + echo '
'.NB_EOL; + if (!$this->p('inc')) echo $this->form_hidden(); + } + if ($opt['is_html']) out::type('html'); - $count = 0; + + # + # Rows + # # Parser on/off (default: on) if (!isset($opt['parser'])) $opt['parser'] = true; $parser = $opt['parser']; #bye($parser); + $count = 0; while ($row = $st->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT)) { $count++; $call = null; + $call = $this->rows_parsers($row,$opt); + /* if ($parser) $this->db()->table_row_decrypt($this,$row); if ($parser and !empty($this->db()->row_parse)) { $call = $this->db()->row_parse; $call($row); @@ -828,12 +885,22 @@ Class Table extends nb { if ($parser and !empty($this->row_parse_post)) { $call = $this->row_parse_post; $call($row); } + */ # # Close previous # # NB 27.09.16 if ($out_conf and $count !== 1) out::row_end($out_conf); + # + # Fields filter + # + if ($fields_filter) { + foreach (array_keys($row) as $k) { + if (!in_array($k,$fields_filter)) unset($row[$k]); + } + } + # # Preffix # @@ -847,20 +914,22 @@ Class Table extends nb { if ($call) { foreach (array_keys($row) as $name) { - if (!$this->fields($name)) { - $this->fields[$name] = new Field($name); - $this->fields[$name]->dyn = true; - #$fields[$name] = $this->fields[$name]; +# NB 19.11.16 if (!$this->fields($name)) { + if (!isset($fields[$name])) { + $fields[$name] = new Field($name); + $fields[$name]->dyn = true; +# NB 19.11.16 $this->fields[$name] = $fields[$name]; } } } if ($out_conf) { - out::head($out_conf,array_keys($this->fields()),[$row]); +# NB 19.11.16 out::head($out_conf,array_keys($this->fields()),[$row]); + out::head($out_conf,array_keys($fields),[$row]); } else { - #bye([$this->fields(),$row]); - echo $this->{"rows_begin_$format"}($this->fields(),$opt); +# NB 19.11.16 echo $this->{"rows_begin_$format"}($this->fields(),$opt); + echo $this->{"rows_begin_$format"}($fields,$opt); } } @@ -870,8 +939,11 @@ Class Table extends nb { # $count_fields = 0; - foreach ($this->fields() as $f => $field) { +# NB 19.11.16 foreach ($this->fields() as $f => $field) { +# NB 19.11.16 $row[$f] = $field->out(isset($row[$f]) ? $row[$f] : ''); + foreach ($fields as $f => $field) { $row[$f] = $field->out(isset($row[$f]) ? $row[$f] : ''); +# NB 19.11.16 $row[$f] = $this->field($f)->out(isset($row[$f]) ? $row[$f] : ''); $count_fields++; } @@ -925,7 +997,8 @@ Class Table extends nb { } # < is_html if ($count === 0 and $this->p('header') === 'force') { - echo $this->{"rows_begin_$format"}($this->fields()); +# NB 19.11.16 echo $this->{"rows_begin_$format"}($this->fields()); + echo $this->{"rows_begin_$format"}($fields); } if ($out_conf) { @@ -1160,7 +1233,7 @@ Class Table extends nb { return $html; } - public function rows_end_table($opt=[]) { + public function rows_end_table() { $html = ''; $html .= ''.NB_EOL; $html .= ''.NB_EOL; @@ -1198,7 +1271,7 @@ Class Table extends nb { return $html; } - public function rows_end_div($opt=[]) { + public function rows_end_div() { return '
'.NB_EOL; } diff --git a/lib/php/db/types/sqlite.php b/lib/php/db/types/sqlite.php index 48d95ac3..5edb1b94 100644 --- a/lib/php/db/types/sqlite.php +++ b/lib/php/db/types/sqlite.php @@ -71,7 +71,7 @@ $DB_TYPES['sqlite'] = array ( $sql = "SELECT name,type FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type IN('table','view') AND name NOT LIKE 'sqlite_%'"; $dbs = $Db->databases(); - if (count($dbs)<2) return $sql; + if (count($dbs)<=1) return $sql; # Handle attach mechnisum $all = ''; diff --git a/lib/php/out.php b/lib/php/out.php index 6b76e8a2..e2ef91eb 100644 --- a/lib/php/out.php +++ b/lib/php/out.php @@ -20,9 +20,61 @@ Class Out extends Nb { 'end' => 'out_human_end', ], - 'sql' => array(), # Code still in db/table.php ! + 'sql' => [], # Code still in db/table.php ! - 'shell' => array( + 'cust' => [ + 'cust' => self::p('cust',"CHANGE ME"), + 'at' => self::p('at','@'), + 'open' => self::p('open',''), + 'close' => self::p('close',''), + + 'quote' => self::p('quote',"'"), + 'quote_escape' => self::p('quote_escape','\\'), + + 'eol' => self::p('eol',"\n"), + 'sep' => self::p('sep',''), + 'preff' => self::p('preff',''), + 'suff' => self::p('suff',''), + + 'end' => function($o) { if (isset($o['count']) and $o['close']) echo $o['close']; }, + 'row' => function(&$o,&$r) { + static $count=0; + if (!$count) { + foreach ($o as $k=>$v) { + if (is_scalar($v)) $o[$k] = str_replace('\n',"\n",$v); + } + if ($o['open']) echo $o['open']; + } + $count++; $o['count'] = $count; + echo $o['preff'] + .($count>1 ? $o['sep'] : '') + .preg_replace_callback('/'.$o['at'].'([\w_]+)(?::([-\+]?\d+))?'.$o['at'].'/',function($m) use ($o,$r,$count){ + + #bye($m); + $k = $m[1]; + $size = empty($m[2]) ? 0 : (int)$m[2]; + $v = $r[$k]; + + if (!empty($o['quote'])) $v = $o['quote'] . + str_replace($o['quote'],$o['quote_escape'].$o['quote'],$v) . $o['quote'] + ; + + if ($size) { + $align = $size>0 ? STR_PAD_LEFT : STR_PAD_RIGHT; + $size = abs($size); + if ($count>1) $size -= mb_strlen($o['sep'],out::$charset); + $v = out::mb_str_pad($v, $size, ' ',$align); + } + + return $v; + + },$o['cust']) + .$o['suff'] + ; + } + ], + + 'shell' => [ 'preff' => self::p('preff',''), 'suff' => self::p('suff',''), 'row' => function(&$o,&$r) { @@ -33,7 +85,7 @@ Class Out extends Nb { } if ($line) echo join(' ',$line)."\n"; } - ), + ], 'sh' => array( 'preff' => self::p('preff',""), diff --git a/share/db/local.db b/share/db/local.db new file mode 100644 index 0000000000000000000000000000000000000000..c138a646dfcdbd58a461a04857188d75181875c2 GIT binary patch literal 53248 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 L#OOuc*+u^wFBGS^ literal 0 HcmV?d00001 diff --git a/share/db/update.sh b/share/db/update.sh new file mode 100755 index 00000000..32fec4f5 --- /dev/null +++ b/share/db/update.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash --login +set -e +cd "$(dirname "$0")" + +( + +cat << EOF +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +EOF + +shell_functions2sql shell_function + +cat << EOF +COMMIT; +EOF +) | sqlite3 local.db.tmp && mv local.db.tmp local.db + -- 2.47.3