redtux has asked for the wisdom of the Perl Monks concerning the following question:

This is something that has bugged me a for aa whil, under what circumstances is the no strict 'refs' error triggered. I have the following concrete example.

this works

my $transref_chksql= <<~ 'SQLSTR'; SELECT CASE WHEN EXISTS (SELECT * FROM pg_class WHERE relkind = 'S' AND relname= 'encode_transref_seqm') THEN 'transref_seq_add' ELSE 'ignore' END SQLSTR my $transseqchk->{transchk}= ($dbh->selectrow_array($transref_chksql))[0]; my %actionsw; $actionsw{transref_seq_add}->{cmd}=sub{ (my $encode_transref_seqmsql= <<~ 'SQLSTR'); CREATE SEQUENCE IF NOT EXISTS transref_seqm Start 0 minvalue 0 OWNED BY encodes.fileid SQLSTR $dbh->do($encode_transref_seqmsql); }; if ($actionsw{$transseqchk->{transchk}}->{cmd}){ &{$actionsw{$transseqchk->{transchk}}->{cmd}}; }
This triggers strict 'refs'
my %transseqchk; my $transref_chksql= <<~ 'SQLSTR'; SELECT CASE WHEN EXISTS (SELECT * FROM pg_class WHERE relkind = 'S' AND relname= 'encode_transref_seqm') THEN 'transref_seq_add' ELSE 'ignore' END SQLSTR my $transseqchk->{transchk}= ($dbh->selectrow_array($transref_chksql))[0]; $transseqchk->{transref_seq_add}->{cmd}=sub{ (my $encode_transref_seqmsql= <<~ 'SQLSTR'); CREATE SEQUENCE IF NOT EXISTS transref_seqm Start 0 minvalue 0 OWNED BY encodes.fileid SQLSTR $dbh->do($encode_transref_seqmsql); }; if ($transseqchk->{transchk}->{cmd}){ &{$transseqchk->{transchk}->{cmd}}; }
The only difference is a further level of hash in the working example

Replies are listed 'Best First'.
Re: When is strict 'refs triggered
by choroba (Cardinal) on May 22, 2020 at 14:05 UTC
    It's not possible for us to run your example, as you didn't provide the code to populate the database.

    Moreover, the code is not the same. In the "works" case, you're using $transseqchk->{transchk} as the key in %actionsw, but it contains a hash reference, so the if condition is false and the code dereference is not executed.

    Update: If you're curious how I discovered it, here's the code I used. I mocked the database as I guessed it's irrelevant to the question.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      In the original code the sub routine using %actionsw does work (just dropped sequence and reran a few times)

      DB creation

      DB create line (in psql)

      sudo su postgres

      /usr/pgsql-11/bin/psql template1

      CREATE USER usevideo blah etc;

      CREATE DATABASE usevideos WITH OWNER = usevideo ENCODING = 'UTF8' LC_COLLATE = 'en_GB.UTF-8' LC_CTYPE = 'en_GB.UTF-8' TABLESPACE = pg_default CONNECTION LIMIT = -1;

      The db connection line is

      use DBI qw(:sql_types); my $dbh=DBI->connect('dbi:Pg:dbname=usevideos;host=192.168.1.3','dbuser','dbpass',{AutoCommit=>1,RaiseError=>1,PrintError=>0});

Re: When is strict 'refs triggered
by tobyink (Canon) on May 23, 2020 at 06:40 UTC

    This bit is weird and suggests you don't know how lexical variables work:

    my $transseqchk->{transchk}=

    And when you combine it with this, it suggests you don't fully understand the difference between hashes and hashrefs:

    my %transseqchk;

    To answer the question in the title, strict refs is triggered when you try to treat a non-reference (such as a string) as a reference.

    perl -E'use strict; my $x = "foo"; $$x' perl -E'use strict; my $x = "foo"; @$x' perl -E'use strict; my $x = "foo"; %$x' perl -E'use strict; my $x = "foo"; &$x' perl -E'use strict; my $x = "foo"; $x->[0]' perl -E'use strict; my $x = "foo"; $x->{bar}' perl -E'use strict; my $x = "foo"; $x->()'
      re my $transseqchk->{transchk}=, I was using auto-vivification for $transseqchk. the %transseqchk is old code which I've deleted.