2012-05-09 2 views
2

Новорожденный разработчик Perl здесь. Я размахивал своим мозгом и искал по сети, пытаясь понять это ... раздраженно, я прихожу к вам, ищущий ясности.Как передать массив Perl в виде скаляра в подпрограмму?

Я следующий код (только соответствующие части оставили в), а остальные работают):

my @arrMissingTids; 
@arrMissingTids = %hshTids; 

my $missingtid; 
foreach $missingtid (@arrMissingTids) { 
    print "$missingtid\n"; 
} 

Это хорошо работает, возвращая значения, я хочу быть в массиве:

500000246,500000235,500000185,500000237,500000227,500000252 

Однако, когда я передаю это подпрограмме и включаю ее в имя переменной, она не содержит список, как написано выше, а скорее номер 1. Код для этого ниже:

myqry(@arrMissingTids); 

sub myqry($) { 

    my $missingtids = @_; 

    $sql = "select 
     i.tid i_tid, i.name i_name 
     from 
     instrument i 
     where i.tid in ($missingtids)"; 

    print "$sql/n"; 
} 

печати $ SQL возвращает следующее:

Select i.tid i_tid, i.name i_name from instrument i where i.tid in (1) 

Когда я хочу, чтобы вернуть следующее:

Select i.tid i_tid, i.name i_name from instrument i where i.tid in (500000246,500000235,500000185,500000237,500000227,500000252) 

Заранее спасибо за любые указатели в правильном направлении!

+8

[Почему прототипы функций Perl-плохо?] (http://stackoverflow.com/questions/297034/why-are-perl-5s-function-prototypes-bad) – daxim

+5

Я чувствую себя вынужденным упомянуть, что построение sql-запроса путем интерполяции является угрозой безопасности. http://bobby-tables.com/ –

+0

это из-за '($)', см. мой ответ;) – delicateLatticeworkFever

ответ

1

Проблема прямо здесь:

my $missingtids = @_; 

Вы звоните массив @_ в скалярном контексте.Это означает, что вы назначаете $missingtids количество элементов в @_. Один из способов обойти это было бы передать ссылку на массив:

sub myqry { 

    my $missingtids_ref = shift; 
    my @[email protected]$missingtids_ref; 

    $sql = "select 
     i.tid i_tid, i.name i_name 
     from 
     instrument i 
     where i.tid in (" . join(",",@missingtids) . ")"; 

    print "$sql/n"; 
} 

Для получения дополнительной информации, посмотрите на perldoc perlref и perldoc perldata.

+1

Принимая это как ответ, поскольку он был первым и решил проблему ... отличная, отличная помощь на всем протяжении. Я очень ценю все отзывы! –

+0

Downvoter: Помогите объяснить? –

-1

непроверенная, но, вероятно, правы:

myqry(\@arrMissingTids); 

sub myqry($) { 

    my $missingtids = shift; # or $_[0] 

    $sql = "select 
     i.tid i_tid, i.name i_name 
     from 
     instrument i 
     where i.tid in (" . join(',', @{$missingtids}) . ")"; 

    print "$sql/n"; 
} 

Конечно, вы могли бы передать сам массив вместо ссылки, но тогда вам нужно будет изменить прототип и переписать ссылки на массивы. Но вышеизложенное должно заставить вас идти.

+4

Лучше не использовать прототип функции. Почти во всех случаях ломается гораздо больше, чем решает. Просто избегайте их. – LeoNerd

+1

или, по крайней мере, использовать прототип '(\ @)' для принудительного преобразования массивов в arrayrefs, а не для принудительного скалярного контекста, который почти наверняка не является тем, что здесь требуется. –

+0

Да, это не сработает из-за '($)'. – delicateLatticeworkFever

0

Итак, вы хотите, чтобы создать строку

... in (1,2,3,4) 

Используйте join

myqry(join(',', @arrMissingTids)) 

Но это скорее наизнанку. Это было бы лучше:

sub myqry { 
    my $missingtids = join(',', @_); 

    return "select 
     i.tid i_tid, i.name i_name 
     from 
     instrument i 
     where i.tid in ($missingtids) 
    "; 
} 

myqry(@arrMissingTids); 
7

Здесь есть три проблемы. Первый использует прототип функции, просто оставьте его, см. Why are Perl 5's function prototypes bad?.

Второе - это несоответствие типов в вызове функции и на стороне получателя самой функции. Либо используйте массивы как раз, либо ссылки массива оба раза.

Третье, что обработка данных как часть SQL-запроса, возможно открытие ворот для SQL injection attack. Это безопасно смягчается путем сборки строки запроса с помощью заполнителей для использования с DBI.

myqry(@arrMissingTids); 
sub myqry { 
    my @missingtids = @_; 
    $sql = "select 
     i.tid i_tid, i.name i_name 
     from 
     instrument i 
     where i.tid in (" . join(',', ('?') x @missingtids) . ")"; 
    print "$sql\n"; 
    # $dbh->selectall_arrayref($sql, {}, @missingtids) 
} 

myqry(\@arrMissingTids); 
sub myqry { 
    my @missingtids = @{ shift() }; 
    $sql = "select 
     i.tid i_tid, i.name i_name 
     from 
     instrument i 
     where i.tid in (" . join(',', ('?') x @missingtids) . ")"; 
    print "$sql\n"; 
    # $dbh->selectall_arrayref($sql, {}, @missingtids) 
} 
+0

очень ясно, спасибо Daxim –

+0

Изменен код для работы с заполнителями базы данных. Хорошо напомнил, [Джоэл] (http://stackoverflow.com/users/468327/joel-berger)! – daxim

+0

Спасибо Daxim. Я ценю этот маленький уголок о передаче SQL. По крутой кривой обучения, оцените всю помощь. –

5

Если кто-то не упомянуть еще, прототип здесь является вопрос:

sub myqry($) { 

Рассмотрим это:

sub test1($) { 
    print "$_\n" foreach @_; 
} 

sub test2 { 
    print "$_\n" foreach @_; 
} 

my @args = ('a', 'b', 'c'); 

test1(@args); 
test2(@args);  

и выход:

3 
a 
b 
c 

К настоящему времени вы поняли, что массив в скалярном контексте - это просто количество элементов, например:

my $n = @args; 

$n равен 3. Передавая массив в подпрограмму, которая уменьшает его скаляр, вы в конечном итоге с одной арг, число элементов в массиве. Тогда вы сделаете это:

my $missingtids = @_; 

, который всегда будет просто один из-за ($) в определении подпункта (массив уже был сокращен до одного элемента). Следовательно, вы получаете .

$ 0,02: IMO прототипы в Perl это плохая идея;)

+0

, возможно, укажите прототип '(\ @)'? –

+0

Я не использую их сам, но это выглядит лучше, чем '($)'. – delicateLatticeworkFever

0

Спасибо за помощь. После того, как все сказано и сделано, я в конечном итоге избавиться от прототипа и с помощью этого кода, который работал отлично и кусочки от всей помощи выше:

myqry(@arrTids); 

sub myqry { 
    $missingtids = join(",",@_); 

    .rest of code... 
} 
Смежные вопросы