+sub selectall_ids {
+ $main::lxdebug->enter_sub(2);
+
+ my ($form, $dbh, $query, $key_col) = splice(@_, 0, 4);
+
+ my $sth = prepare_execute_query($form, $dbh, $query, @_);
+
+ my @ids;
+ while (my $ref = $sth->fetchrow_arrayref()) {
+ push @ids, $ref->[$key_col];
+ }
+
+ $sth->finish;
+
+ $main::lxdebug->leave_sub(2);
+
+ return @ids;
+}
+
+sub create_sort_spec {
+ $main::lxdebug->enter_sub(2);
+
+ my %params = @_;
+
+ # Safety check:
+ $params{defs} || die;
+ $params{default} || die;
+
+ # The definition of valid columns to sort by.
+ my $defs = $params{defs};
+
+ # The column name to sort by. Use the default column name if none was given.
+ my %result = ( 'column' => $params{column} || $params{default} );
+
+ # Overwrite the column name with the default column name if the other one is not valid.
+ $result{column} = $params{default} unless ($defs->{ $result{column} });
+
+ # The sort direction. true means 'sort ascending', false means 'sort descending'.
+ $result{dir} = defined $params{dir} ? $params{dir}
+ : defined $params{default_dir} ? $params{default_dir}
+ : 1;
+ $result{dir} = $result{dir} ? 1 : 0;
+ my $asc_desc = $result{dir} ? 'ASC' : 'DESC';
+
+ # Create the SQL code.
+ my $cols = $defs->{ $result{column} };
+ $result{sql} = join ', ', map { "${_} ${asc_desc}" } @{ ref $cols eq 'ARRAY' ? $cols : [ $cols ] };
+
+ $main::lxdebug->leave_sub(2);
+
+ return %result;
+}
+
+sub does_table_exist {
+ $main::lxdebug->enter_sub(2);
+
+ my $dbh = shift;
+ my $table = shift;
+
+ my $result = 0;
+
+ if ($dbh) {
+ my $sth = $dbh->table_info('', '', $table, 'TABLE');
+ if ($sth) {
+ $result = $sth->fetchrow_hashref();
+ $sth->finish();
+ }
+ }
+
+ $main::lxdebug->leave_sub(2);
+
+ return $result;
+}
+
+# add token to values.
+# usage:
+# add_token(
+# \@where_tokens,
+# \@where_values,
+# col => 'id',
+# val => [ 23, 34, 17 ]
+# esc => \&conf_i
+# )
+# will append to the given arrays:
+# -> 'id IN (?, ?, ?)'
+# -> (conv_i(23), conv_i(34), conv_i(17))
+#
+# features:
+# - don't care if one or multiple values are given. singlewill result in 'col = ?'
+# - pass escape routines
+# - expand for future method
+# - no need to type "push @where_tokens, 'id = ?'" over and over again
+sub add_token {
+ my $tokens = shift() || [];
+ my $values = shift() || [];
+ my %params = @_;
+ my $col = $params{col};
+ my $val = $params{val};
+ my $escape = $params{esc} || sub { $_ };
+ my $method = $params{esc} =~ /^start|end|substr$/ ? 'ILIKE' : $params{method} || '=';
+
+ $val = [ $val ] unless ref $val eq 'ARRAY';
+
+ my %escapes = (
+ id => \&conv_i,
+ bool => \&conv_b,
+ date => \&conv_date,
+ start => sub { trim($_[0]) . '%' },
+ end => sub { '%' . trim($_[0]) },
+ substr => sub { like($_[0]) },
+ );
+
+ my $_long_token = sub {
+ my $op = shift;
+ sub {
+ my $col = shift;
+ return scalar @_ ? join ' OR ', ("$col $op ?") x scalar @_,
+ : undef;
+ }
+ };
+
+ my %methods = (
+ '=' => sub {
+ my $col = shift;
+ return scalar @_ > 1 ? sprintf '%s IN (%s)', $col, join ', ', ("?") x scalar @_
+ : scalar @_ == 1 ? sprintf '%s = ?', $col
+ : undef;
+ },
+ map({ $_ => $_long_token->($_) } qw(LIKE ILIKE >= <= > <)),
+ );
+
+ $method = $methods{$method} || $method;
+ $escape = $escapes{$escape} || $escape;
+
+ my $token = $method->($col, @{ $val });
+ my @vals = map { $escape->($_) } @{ $val };
+
+ return unless $token;
+
+ push @{ $tokens }, $token;
+ push @{ $values }, @vals;
+
+ return ($token, @vals);
+}
+
+sub like {
+ my ($string) = @_;
+
+ return "%" . SL::Util::trim($string // '') . "%";
+}
+
+sub role_is_superuser {
+ my ($dbh, $login) = @_;
+ my ($is_superuser) = $dbh->selectrow_array(qq|SELECT usesuper FROM pg_user WHERE usename = ?|, undef, $login);
+
+ return $is_superuser;
+}
+
+sub check_trgm {
+ my ($dbh) = @_;
+
+ my $version = $dbh->selectrow_array(qq|SELECT installed_version FROM pg_available_extensions WHERE name = 'pg_trgm'|);
+
+ return !!$version;
+}
+