mehfatitem
mehfatitem

Reputation: 147

Pass multiple arrays in Perl, string parameter

I'm beginner in Perl programming, and I want to learn about OOP in Perl. I develop a simple application about sql creator, but I have a problem. I think the problem is passing multiple parameters.

package SqlCreator;

use warnings;
use strict;

sub new {
    my ($class, %args) = @_;
    return bless \%args, $class;
}

sub editArray {
    my (@array) = @_;
    my $text = '';
    my $arraySize = scalar @array;
    for(my $i = 1; $i<$arraySize; $i++) {
        $text .= "'" . $array[$i] . "'". ",";
    }
    my $length = length $text;
    $text = substr($text, 0, $length-1);
    return $text;
}

sub createInsertColumn {
    my (@column ) = @_;
    my $sql = '';
    $sql .= ' (';
    $sql .= editArray(@column);
    $sql .= ')';
    return $sql;
}

sub createInsertValue{
    my (@value) = @_;
    my $sql = '';
    $sql .= ' VALUES (';
    $sql .= editArray(@value);
    $sql .= ')';
    return $sql;
}

sub createInsertSql{
    my ($table, @column, @value) = @_;
    my $sql = 'INSERT INTO ' . $table;
    $sql .= createInsertColumn(@column);
    $sql .= createInsertValue(@value);
    return $sql;
}
1;

use warnings;
use strict;

use SqlCreator;

my $object = SqlCreator->new;

my @column = ('name', 'gender', 'age');
my @value = ('Mehmed Fatih Temiz', 'male', 28);

my $sql = $object->createInsertSql('person', @column, @value);

print $sql;

This is my sample code. If you solve the problem, please help me.

Upvotes: 0

Views: 266

Answers (1)

ikegami
ikegami

Reputation: 385655

You can't pass arrays to subs, only scalars. When you do

my $sql = $object->createInsertSql(
    'person', @column, @value );

you are passing the following to the method:

$object, 'person', $column[0], $column[1], ..., $value[0], $value[1], ...

Inside the method, you have

my ( $table, @column, @value ) = @_;

First of all, you forgot to account for the invocant. There should be a leading $self parameter.

Secondly, there's no way to know how many of the scalars to add to @column and how many to add to @value, so all but the first are added to @column.

This means you were effectively doing the following:

my $table  = $object;
my @column = ( 'person', $column[0], $column[1], ..., $value[0], $value[1], ... );
my @value  = ();

If you want to pass an array, pass a reference to it instead.

my $sql = $object->createInsertSql( 'person', \@column, \@value );

The sub becomes

sub createInsertSql {
    my ( $self, $table, $column, $value ) = @_;
    my $sql = 'INSERT INTO '.$table;           # XXX Injection bug
    $sql .= createInsertColumn(@$column);
    $sql .= createInsertValue(@$value);
    return $sql;
}

By the way, your code is full of injection errors. You aren't properly converting text into SQL identifiers and SQL string literals.

Fixed:

package SqlCreator;

use warnings;
use strict;

sub new {
    my ( $class, %args ) = @_;
    return bless \%args, $class;
}

sub createInsertSql{
    my ( $self, $table, $cols, $vals ) = @_;

    my $dbh = $self->{dbh};

    return sprintf(
        'INSERT INTO %s ( %s ) VALUES ( %s )'
        $dbh->quote_identifier($table),
        ( join ', ', map { $dbh->quote_identifier($_) } @$cols ),
        ( join ', ', map { $dbh->quote($_)            } @$vals ),
    );
}

1;

use warnings;
use strict;

use DBI        qw( );
use SqlCreator qw( );

my $dbh = DBI->connect(...);

my $sql_creator = SqlCreator->new( dbh => $dbh );

my @cols = ( 'name', 'gender', 'age' );
my @vals = ( 'Mehmed Fatih Temiz', 'male', 28 );

my $sql = $sql_creator->createInsertSql( 'person' , \@cols , \@vals );
print "$sql\n";

Upvotes: 7

Related Questions