diff --git a/Changes b/Changes index a37f5e5..7ec7d6e 100644 --- a/Changes +++ b/Changes @@ -1,5 +1,8 @@ Revision history for SQL-Inserter +0.04 2023-12-17 + - Add last_insert_id. + 0.03 2023-10-29 - Add support for Oracle Database. diff --git a/README.pod b/README.pod index 2cb6cd1..ac0782c 100644 --- a/README.pod +++ b/README.pod @@ -4,7 +4,7 @@ SQL::Inserter - Efficient buffered DBI inserter and fast INSERT SQL builder =head1 VERSION -Version 0.03 +Version 0.04 =head1 SYNOPSIS @@ -17,21 +17,22 @@ Version 0.03 buffer => 100? # Default buffer is 100 rows ); - # Fastest method: pass single or multiple rows of data as an array + # Pass single or multiple rows of data as an array (fastest method): $sql->insert($col1_row1, $col2_row1, $col1_row2...); - # You can manually flush the buffer at any time with no argument on insert - # (otherwise there is auto-flush on the object's destruction) - $sql->insert(); - - # Alternative, pass a single row as a hash, allows SQL code passed as - # references instead of values (no need to define cols in constructor) + # Alternatively, pass a single row as a hash, allows SQL code passed as + # references instead of values (no need to define cols in constructor): $sql->insert({ column1 => $data1, column2 => \'NOW()', ... }); + # Since the inserts are buffered, they might not have been executed yet. + # You can manually flush the buffer at any time with no argument on insert + # (otherwise there is auto-flush on the object's destruction): + $sql->insert(); + # There are also functions to just get the SQL statement and its bind vars # similar to SQL::Abstract or SQL::Maker insert, but with much less overhead: my ($sql, @bind) = simple_insert($table, {col1=>$val...}); @@ -179,6 +180,19 @@ from the very first hash), and after flushing the buffer you can switch to array =back +=head2 last_insert_id + + # MySQL + my $id = $sql->last_insert_id; + + # Depending on the driver you might need parameters + my $id = $sql->last_insert_id($catalog, $schema, $table, $field, \%attr); + +Returns the id of the last insert row, if available, after emptying the buffer. + +Convenience wrapper around L's database handle method of the same name. See +that method's documentation for details and caveats depending on your DB driver. + =head1 ATTRIBUTES =head2 C diff --git a/lib/SQL/Inserter.pm b/lib/SQL/Inserter.pm index b58e1c0..7500d0b 100644 --- a/lib/SQL/Inserter.pm +++ b/lib/SQL/Inserter.pm @@ -13,11 +13,11 @@ SQL::Inserter - Efficient buffered DBI inserter and fast INSERT SQL builder =head1 VERSION -Version 0.03 +Version 0.04 =cut -our $VERSION = '0.03'; +our $VERSION = '0.04'; our @EXPORT_OK = qw(simple_insert multi_insert_sql); @@ -32,21 +32,22 @@ our @EXPORT_OK = qw(simple_insert multi_insert_sql); buffer => 100? # Default buffer is 100 rows ); - # Fastest method: pass single or multiple rows of data as an array + # Pass single or multiple rows of data as an array (fastest method): $sql->insert($col1_row1, $col2_row1, $col1_row2...); - # You can manually flush the buffer at any time with no argument on insert - # (otherwise there is auto-flush on the object's destruction) - $sql->insert(); - - # Alternative, pass a single row as a hash, allows SQL code passed as - # references instead of values (no need to define cols in constructor) + # Alternatively, pass a single row as a hash, allows SQL code passed as + # references instead of values (no need to define cols in constructor): $sql->insert({ column1 => $data1, column2 => \'NOW()', ... }); + # Since the inserts are buffered, they might not have been executed yet. + # You can manually flush the buffer at any time with no argument on insert + # (otherwise there is auto-flush on the object's destruction): + $sql->insert(); + # There are also functions to just get the SQL statement and its bind vars # similar to SQL::Abstract or SQL::Maker insert, but with much less overhead: my ($sql, @bind) = simple_insert($table, {col1=>$val...}); @@ -263,6 +264,29 @@ sub insert { return $ret; } +=head2 last_insert_id + + # MySQL + my $id = $sql->last_insert_id; + + # Depending on the driver you might need parameters + my $id = $sql->last_insert_id($catalog, $schema, $table, $field, \%attr); + +Returns the id of the last insert row, if available, after emptying the buffer. + +Convenience wrapper around L's database handle method of the same name. See +that method's documentation for details and caveats depending on your DB driver. + +=cut + +sub last_insert_id { + my $self = shift; + + $self->_empty_buffer() if $self->{buffer_counter}; + + return $self->{dbh}->last_insert_id(@_); +} + =head1 ATTRIBUTES =head2 C diff --git a/t/simple.t b/t/simple.t index 0ef217b..84f8b5d 100644 --- a/t/simple.t +++ b/t/simple.t @@ -8,8 +8,9 @@ my @execute = (); my $dbh = mock {} => ( add => [ - prepare => sub { my $self = shift; push @prepare, @_ ; return $self}, - execute => sub { shift; @execute = @_ ; return 1}, + prepare => sub {my $self = shift; push @prepare, @_ ; return $self}, + execute => sub {shift; @execute = @_ ; return 1}, + last_insert_id => sub {1}, ] ); @@ -197,4 +198,18 @@ subtest 'new' => sub { ok(!$sql->{oracle}, "Oracle not detected"); }; +subtest 'last_insert_id' => sub { + @execute = (); + @prepare = (); + my $sql = SQL::Inserter->new(dbh=>$dbh,table=>'table',cols=>[qw/col1 col2/],buffer=>3); + $sql->last_insert_id; + is([@prepare],[], "No prepared statement"); + is($sql->insert(1,2),0, "No execute"); + is($sql->{row_total}, undef, "No row_total"); + + is($sql->last_insert_id, 1, "Last insert id"); + is([@execute],[1,2], "Last execute bind vars"); + is($sql->{row_total}, 1, "1 execute"); +}; + done_testing;