SQLite.pm 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  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 auth database consistency";
  19. $db->{sqlite_allow_multiple_statements} = 0;
  20. $dbh->{$schema} = $db;
  21. return $db;
  22. }
  23. =head2 bulk_insert(DBI $dbh, STRING $table, ARRAYREF $keys, MIXED @values)
  24. Upsert the values into specified table with provided keys.
  25. values will be N-tuples based on the number and ordering of the keys.
  26. Essentially works around the 999 named param limit and executes by re-using prepared statements.
  27. This results in a quick insert/update of lots of data, such as when building an index or importing data.
  28. Dies on failure.
  29. Doesn't escape the table name or keys, so don't be a maroon and let users pass data to this
  30. =cut
  31. sub bulk_insert ($dbh, $table, $keys, $ACTION='IGNORE', @values) {
  32. die "keys must be nonempty ARRAYREF" unless ref $keys eq 'ARRAY' && @$keys;
  33. die "#Values must be a multiple of #keys" if @values % @$keys;
  34. my ($smt,$query) = ('','');
  35. while (@values) {
  36. #Must have even multiple of #keys, so floor divide and chop remainder
  37. my $nkeys = scalar(@$keys);
  38. my $limit = floor( 999 / $nkeys );
  39. $limit = $limit - ( $limit % $nkeys);
  40. $smt = '' if scalar(@values) < $limit;
  41. my @params = splice(@values,0,$limit);
  42. if (!$smt) {
  43. my @value_tuples;
  44. my @huh = map { '?' } @params;
  45. while (@huh) {
  46. push(@value_tuples, "(".join(',',(splice(@huh,0,$nkeys))).")");
  47. }
  48. $query = "INSERT OR $ACTION INTO $table (".join(',',@$keys).") VALUES ".join(',',@value_tuples);
  49. $smt = $dbh->prepare($query);
  50. }
  51. $smt->execute(@params);
  52. }
  53. }
  54. 1;