--- /dev/null
+!CNF3.3
+<<<CONST
+ TZ = Australia/Sydney
+>>>
+<<<ARGUMENTS
+ -DB = lifelog
+ -DB_CREDENTIALS = lifelog/lifelog
+ -DB_SQL_SOURCE = DBI:Pg:host=localhost;port=5432;
+ -table="GOLD_PRICE"
+ -action="insert"
+>>>
+<<@<%LOG>
+ directory = "apps"
+ file = sql.log
+ # Should it mirror to console too?
+ console = 1
+ # Disable/enable output to file at all?
+ enabled = 1
+ # Tail size cut, set to 0 if no tail cutting is desired.
+ tail = 1000
+>>
+
+###
+# sql.pl Usage examples
+
+
+# SQL select table in this files CNF arguments default, return values date and value column.
+# There is no -print option, so it will return in delimited comma format.
+perl apps/sql.pl -action=select --col_value --col_date
+
+# SQL default action is insert into table, and we assume timestamps is now by date inserting value 69.
+perl apps/sql.pl --col_value=69
+
+# SQL select in order by date and present with -print in the CNF data format,
+# the default table set in this configuration.
+perl apps/sql.pl -action=select -where="value!=0 order by date desc" --print
+
+# SQL select only the latest record value.
+perl apps/sql.pl -action=select -where="order by date desc limit 1" --col_value
+
+###
+
+<<GOLD_PRICE<DATA> __HAS_HEADER__ __SQL_TABLE__ __SQL_POSTGRES___
+date _DATE_`value _NUM_~
+>>
+
--- /dev/null
+2025-10-31 07:16:31.825 AEDT - Plugin instructed -> ARGUMENTS
+2025-10-31 07:16:32.075 AEDT - Selected GOLD_PRICE: SELECT "date","value" FROM GOLD_PRICE WHERE value!=0
+2025-10-31 07:19:18.453 AEDT - Plugin instructed -> ARGUMENTS
+2025-10-31 07:19:45.317 AEDT - Plugin instructed -> ARGUMENTS
+2025-10-31 07:19:45.514 AEDT - Selected GOLD_PRICE: SELECT "date","value" FROM GOLD_PRICE WHERE value!=0
+2025-10-31 07:20:51.277 AEDT - Plugin instructed -> ARGUMENTS
+2025-10-31 07:20:51.470 AEDT - Selected GOLD_PRICE: SELECT "date","value" FROM GOLD_PRICE WHERE value!=0
+2025-10-31 07:21:02.294 AEDT - Plugin instructed -> ARGUMENTS
+2025-10-31 07:21:02.461 AEDT - Selected GOLD_PRICE: SELECT "date","value" FROM GOLD_PRICE WHERE value!=0 limit 1
+2025-10-31 07:21:24.509 AEDT - Plugin instructed -> ARGUMENTS
+2025-10-31 07:23:55.017 AEDT - Plugin instructed -> ARGUMENTS
+2025-10-31 07:24:20.214 AEDT - Plugin instructed -> ARGUMENTS
+2025-10-31 07:24:20.378 AEDT - Selected GOLD_PRICE: SELECT "date","value" FROM GOLD_PRICE WHERE value!=0 order by date desc
+2025-10-31 07:24:35.898 AEDT - Plugin instructed -> ARGUMENTS
+2025-10-31 07:24:36.075 AEDT - Selected GOLD_PRICE: SELECT "date","value" FROM GOLD_PRICE WHERE value!=0 order by date desc limit 1
+2025-10-31 07:34:35.984 AEDT - Plugin instructed -> ARGUMENTS
+2025-10-31 07:34:36.154 AEDT - Selected GOLD_PRICE: SELECT "date","value" FROM GOLD_PRICE WHERE value!=0 order by date desc limit 1
+2025-10-31 07:56:34.019 AEDT - Plugin instructed -> ARGUMENTS
+2025-10-31 07:56:34.230 AEDT - Selected GOLD_PRICE: SELECT "date","value" FROM GOLD_PRICE
+2025-10-31 08:28:53.013 AEDT - Plugin instructed -> ARGUMENTS
+2025-10-31 08:28:53.248 AEDT - Selected GOLD_PRICE: SELECT "date","value" FROM GOLD_PRICE
+2025-10-31 08:30:09.241 AEDT - Plugin instructed -> ARGUMENTS
+2025-10-31 08:30:09.460 AEDT - Selected GOLD_PRICE: SELECT "date","value" FROM GOLD_PRICE
--- /dev/null
+#!/usr/bin/env perl
+use 5.38.0;
+use warnings; use strict;
+ no warnings('once');
+use Syntax::Keyword::Try;
+use Benchmark;
+use lib "tests";
+use lib "system/modules";
+
+require CNFParser;
+require CNFSQL;
+
+our $CNF = CNFParser->new('apps/sql.cnf');
+my $arguments = $CNF->property(CNFParser::APP_ARGS());
+my $db = CNFSQL::_connectDB(CNFSQL::_credentialsToArray($arguments->{DB_CREDENTIALS}),
+ $arguments->{DB_SQL_SOURCE},$arguments->{DB});
+our $SQL = $CNF->SQL();
+$SQL->initDatabase($db,1);
+my %schema = $SQL->schema();
+
+my $action = $arguments->{action};
+my $table = $arguments->{table};
+die "Config error: Table $table not found in database -> ".$arguments->{DB} if not exists $schema{$table};
+
+my $table_spec = $CNF->data()->{$table};
+my $now = CNFDateTime->now(TZ=>$CNF->{TZ});
+my %MHDR = %CNFMeta::TABLE_HEADER;
+my @header = CNFMeta::_deRefArray($$table_spec->{header});
+my @col_names = CNFMeta::_deRefArray($header[$MHDR{COL_NAMES}]);
+my @col_types = CNFMeta::_deRefArray($header[$MHDR{COL_TYPES}]);
+my $fld_names = ${$header[$MHDR{F_NAMES}]};
+my $fld_values = ${$header[$MHDR{F_VALUES}]};
+my $fld_updates = ${$header[$MHDR{F_UPDATES}]};
+my $fld_where = ${$header[$MHDR{F_WHERE}]};
+my $prime_key = ${$header[$MHDR{ID_PRIMARY}]};
+my $id_type = ${$header[$MHDR{ID_TYPE}]};
+
+my $tbl_stm_name = $table;
+$prime_key ="" if ! $prime_key;
+
+$fld_where = $arguments->{where} if not $fld_where;
+$fld_where = "" if not $fld_where;
+
+my ($s_sqlSEL, $s_sqlINS, $s_sqlUPD)=(
+ "SELECT $prime_key $fld_names FROM $tbl_stm_name WHERE $fld_where",
+ "INSERT INTO $tbl_stm_name ($fld_names) VALUES ($fld_values);",
+ "UPDATE $tbl_stm_name SET $fld_updates WHERE $fld_where;"
+ );
+$s_sqlSEL = "SELECT $prime_key $fld_names FROM $tbl_stm_name" if !$fld_where;
+
+sub outputFetch($sqlSEL,$cols){
+ if(!$cols){
+ my $hdr;
+ foreach(@col_names){
+ $hdr .= "$_`"
+ }
+ $hdr =~ s/`$/~\n/g;
+ print $hdr;
+ while(my @sel = $sqlSEL->fetchrow_array()){
+
+ my $row;
+ foreach(@sel){
+ $row .= "$_`"
+ }
+ $row =~ s/`$/~\n/g;
+ print $row;
+
+ }
+ }else{
+ my @cols = @$cols;
+ while(my @sel = $sqlSEL->fetchrow_array()){
+ my $row;
+ foreach(@cols){
+ $row .= "\"".$sel[$_]."\","
+ }
+ $row =~ s/,$//g;
+ say $row
+ }
+ }
+}
+
+if($action eq 'insert'){
+ my @values; my $i=0;
+ foreach my $col_name(@col_names){
+ my $arg_name = "col_".(lc $col_name);
+ my $cur = $arguments->{$arg_name};
+ if(!$cur){
+ if($col_types[$i++] == $CNFMeta::CNF_DATA_TYPES{DATE}) {
+ $values[@values] = $now->toDateTimeFormatWithZone();
+ }else{
+ die "Error: For action [$action] the argument value is not set with --$arg_name, table is $table and database -> ".$arguments->{DB}
+ }
+ }else{
+ $values[@values] = $cur
+ }
+ }
+ my $sqlINS = $db -> prepare($s_sqlINS);
+ if(defined $sqlINS -> execute(@values)){
+ $CNF -> log("Inserted into $table:".join(',',@values));
+ }else{
+ $CNF -> error("Failed inserted into $table:".join(', ',@values));
+ }
+}elsif($action eq 'select'){
+ my $sqlSEL = $db -> prepare($s_sqlSEL);
+ if(defined $sqlSEL -> execute()){
+ $CNF -> log("Selected $table: $s_sqlSEL");
+ if($arguments->{print}){
+ outputFetch($sqlSEL, undef);
+ }else{
+ my @cols; my $i=0;
+ foreach my $col_name(@col_names){
+ my $arg_name = "col_".(lc $col_name);
+ my $cur = $arguments->{$arg_name};
+ if($cur){
+ $cols[@cols] = $i
+ }
+ $i++;
+ }
+ outputFetch($sqlSEL,\@cols);
+ }
+ }else{
+ $CNF -> error("Failed select $table: $s_sqlSEL");
+ }
+}