SQLite.pm 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. package Trog::SQLite;
  2. use strict;
  3. use warnings;
  4. no warnings 'experimental';
  5. use feature qw{signatures};
  6. use POSIX qw{floor};
  7. use DBI;
  8. use DBD::SQLite;
  9. use File::Slurper qw{read_text};
  10. my $dbh = {};
  11. # Ensure the db schema is OK, and give us a handle
  12. sub dbh {
  13. my ($schema,$dbname) = @_;
  14. return $dbh->{$schema} if $dbh->{$schema};
  15. my $qq = read_text($schema);
  16. my $db = DBI->connect("dbi:SQLite:dbname=$dbname","","");
  17. $db->{sqlite_allow_multiple_statements} = 1;
  18. $db->do($qq) or die "Could not ensure database consistency";
  19. $db->{sqlite_allow_multiple_statements} = 0;
  20. $dbh->{$schema} = $db;
  21. # Turn on fkeys
  22. $db->do("PRAGMA foreign_keys = ON");
  23. return $db;
  24. }
  25. =head2 bulk_insert(DBI $dbh, STRING $table, ARRAYREF $keys, MIXED @values)
  26. Upsert the values into specified table with provided keys.
  27. values will be N-tuples based on the number and ordering of the keys.
  28. Essentially works around the 999 named param limit and executes by re-using prepared statements.
  29. This results in a quick insert/update of lots of data, such as when building an index or importing data.
  30. Dies on failure.
  31. Doesn't escape the table name or keys, so don't be a maroon and let users pass data to this
  32. =cut
  33. sub bulk_insert ($dbh, $table, $keys, $ACTION='IGNORE', @values) {
  34. die "keys must be nonempty ARRAYREF" unless ref $keys eq 'ARRAY' && @$keys;
  35. die "#Values must be a multiple of #keys" if @values % @$keys;
  36. my ($smt,$query) = ('','');
  37. while (@values) {
  38. #Must have even multiple of #keys, so floor divide and chop remainder
  39. my $nkeys = scalar(@$keys);
  40. my $limit = floor( 999 / $nkeys );
  41. $limit = $limit - ( $limit % $nkeys);
  42. $smt = '' if scalar(@values) < $limit;
  43. my @params = splice(@values,0,$limit);
  44. if (!$smt) {
  45. my @value_tuples;
  46. my @huh = map { '?' } @params;
  47. while (@huh) {
  48. push(@value_tuples, "(".join(',',(splice(@huh,0,$nkeys))).")");
  49. }
  50. $query = "INSERT OR $ACTION INTO $table (".join(',',@$keys).") VALUES ".join(',',@value_tuples);
  51. $smt = $dbh->prepare($query);
  52. }
  53. $smt->execute(@params);
  54. }
  55. }
  56. 1;