this should non-"=" searches on fields that require SQL type binding...
[freeside.git] / FS / FS / Record.pm
index db94003..aef550d 100644 (file)
@@ -6,6 +6,7 @@ use vars qw( $AUTOLOAD @ISA @EXPORT_OK $DEBUG
              %virtual_fields_cache $nowarn_identical $no_update_diff );
 use Exporter;
 use Carp qw(carp cluck croak confess);
+use Scalar::Util qw( blessed );
 use File::CounterFile;
 use Locale::Country;
 use DBI qw(:sql_types);
@@ -15,7 +16,7 @@ use FS::CurrentUser;
 use FS::Schema qw(dbdef);
 use FS::SearchCache;
 use FS::Msgcat qw(gettext);
-use FS::Conf;
+#use FS::Conf; #dependency loop bs, in install_callback below instead
 
 use FS::part_virtual_field;
 
@@ -24,7 +25,8 @@ use Tie::IxHash;
 @ISA = qw(Exporter);
 
 #export dbdef for now... everything else expects to find it here
-@EXPORT_OK = qw(dbh fields hfields qsearch qsearchs dbdef jsearch str2time_sql);
+@EXPORT_OK = qw(dbh fields hfields qsearch qsearchs dbdef jsearch
+                str2time_sql str2time_sql_closing );
 
 $DEBUG = 0;
 $me = '[FS::Record]';
@@ -38,6 +40,8 @@ my $rsa_encrypt;
 my $rsa_decrypt;
 
 FS::UID->install_callback( sub {
+  eval "use FS::Conf;";
+  die $@ if $@;
   $conf = new FS::Conf; 
   $File::CounterFile::DEFAULT_DIR = $conf->base_dir . "/counters.". datasrc;
 } );
@@ -294,10 +298,17 @@ sub qsearch {
   foreach my $field (
     grep defined( $record->{$_} ) && $record->{$_} ne '', @real_fields
   ) {
-    if ( $record->{$field} =~ /^\d+(\.\d+)?$/
-         && dbdef->table($table)->column($field)->type =~ /(int|(big)?serial)/i
-    ) {
+    my $value = $record->{$field};
+    $value = $value->{'value'} if ref($value);
+    my $type = dbdef->table($table)->column($field)->type;
+    if ( $type =~ /(int|(big)?serial)/i && $value =~ /^\d+(\.\d+)?$/ ) {
       $sth->bind_param($bind++, $record->{$field}, { TYPE => SQL_INTEGER } );
+    } elsif (    ( $type =~ /(numeric)/i     && $value =~ /^[+-]?\d+(\.\d+)?$/)
+              || ( $type =~ /(real|float4)/i
+                     && $value =~ /[-+]?\d*\.?\d+([eE][-+]?\d+)?/
+                 )
+            ) {
+      $sth->bind_param($bind++, $record->{$field}, { TYPE => SQL_FLOAT } );
     } else {
       $sth->bind_param($bind++, $record->{$field}, { TYPE => SQL_VARCHAR } );
     }
@@ -654,11 +665,11 @@ sub AUTOLOAD {
   $field =~ s/.*://;
   if ( defined($value) ) {
     confess "errant AUTOLOAD $field for $self (arg $value)"
-      unless ref($self) && $self->can('setfield');
+      unless blessed($self) && $self->can('setfield');
     $self->setfield($field,$value);
   } else {
     confess "errant AUTOLOAD $field for $self (no args)"
-      unless ref($self) && $self->can('getfield');
+      unless blessed($self) && $self->can('getfield');
     $self->getfield($field);
   }    
 }
@@ -780,7 +791,6 @@ sub insert {
 
   
   # Encrypt before the database
-  my $conf = new FS::Conf;
   if ($conf->exists('encryption') && defined(eval '@FS::'. $table . '::encrypted_fields')) {
     foreach my $field (eval '@FS::'. $table . '::encrypted_fields') {
       $self->{'saved'} = $self->getfield($field);
@@ -1058,7 +1068,6 @@ sub replace {
   return $error if $error;
   
   # Encrypt for replace
-  my $conf = new FS::Conf;
   my $saved = {};
   if ($conf->exists('encryption') && defined(eval '@FS::'. $new->table . '::encrypted_fields')) {
     foreach my $field (eval '@FS::'. $new->table . '::encrypted_fields') {
@@ -1278,7 +1287,6 @@ sub _h_statement {
 
   # If we're encrypting then don't ever store the payinfo or CVV2 in the history....
   # You can see if it changed by the paymask...
-  my $conf = new FS::Conf;
   if ($conf->exists('encryption') ) {
     @fields = grep  $_ ne 'payinfo' && $_ ne 'cvv2', @fields;
   }
@@ -1343,10 +1351,10 @@ null.  If there is an error, returns the error, otherwise returns false.
 
 sub ut_float {
   my($self,$field)=@_ ;
-  ($self->getfield($field) =~ /^(\d+\.\d+)$/ ||
-   $self->getfield($field) =~ /^(\d+)$/ ||
-   $self->getfield($field) =~ /^(\d+\.\d+e\d+)$/ ||
-   $self->getfield($field) =~ /^(\d+e\d+)$/)
+  ($self->getfield($field) =~ /^\s*(\d+\.\d+)\s*$/ ||
+   $self->getfield($field) =~ /^\s*(\d+)\s*$/ ||
+   $self->getfield($field) =~ /^\s*(\d+\.\d+e\d+)\s*$/ ||
+   $self->getfield($field) =~ /^\s*(\d+e\d+)\s*$/)
     or return "Illegal or empty (float) $field: ". $self->getfield($field);
   $self->setfield($field,$1);
   '';
@@ -1379,10 +1387,10 @@ false.
 
 sub ut_sfloat {
   my($self,$field)=@_ ;
-  ($self->getfield($field) =~ /^(-?\d+\.\d+)$/ ||
-   $self->getfield($field) =~ /^(-?\d+)$/ ||
-   $self->getfield($field) =~ /^(-?\d+\.\d+[eE]-?\d+)$/ ||
-   $self->getfield($field) =~ /^(-?\d+[eE]-?\d+)$/)
+  ($self->getfield($field) =~ /^\s*(-?\d+\.\d+)\s*$/ ||
+   $self->getfield($field) =~ /^\s*(-?\d+)\s*$/ ||
+   $self->getfield($field) =~ /^\s*(-?\d+\.\d+[eE]-?\d+)\s*$/ ||
+   $self->getfield($field) =~ /^\s*(-?\d+[eE]-?\d+)\s*$/)
     or return "Illegal or empty (float) $field: ". $self->getfield($field);
   $self->setfield($field,$1);
   '';
@@ -1413,7 +1421,7 @@ returns the error, otherwise returns false.
 
 sub ut_snumber {
   my($self, $field) = @_;
-  $self->getfield($field) =~ /^(-?)\s*(\d+)$/
+  $self->getfield($field) =~ /^\s*(-?)\s*(\d+)\s*$/
     or return "Illegal or empty (numeric) $field: ". $self->getfield($field);
   $self->setfield($field, "$1$2");
   '';
@@ -1428,7 +1436,7 @@ returns the error, otherwise returns false.
 
 sub ut_snumbern {
   my($self, $field) = @_;
-  $self->getfield($field) =~ /^(-?)\s*(\d*)$/
+  $self->getfield($field) =~ /^\s*(-?)\s*(\d*)\s*$/
     or return "Illegal (numeric) $field: ". $self->getfield($field);
   if ($1) {
     return "Illegal (numeric) $field: ". $self->getfield($field)
@@ -1447,7 +1455,7 @@ is an error, returns the error, otherwise returns false.
 
 sub ut_number {
   my($self,$field)=@_;
-  $self->getfield($field) =~ /^(\d+)$/
+  $self->getfield($field) =~ /^\s*(\d+)\s*$/
     or return "Illegal or empty (numeric) $field: ". $self->getfield($field);
   $self->setfield($field,$1);
   '';
@@ -1462,7 +1470,7 @@ an error, returns the error, otherwise returns false.
 
 sub ut_numbern {
   my($self,$field)=@_;
-  $self->getfield($field) =~ /^(\d*)$/
+  $self->getfield($field) =~ /^\s*(\d*)\s*$/
     or return "Illegal (numeric) $field: ". $self->getfield($field);
   $self->setfield($field,$1);
   '';
@@ -1478,7 +1486,7 @@ is an error, returns the error, otherwise returns false.
 sub ut_money {
   my($self,$field)=@_;
   $self->setfield($field, 0) if $self->getfield($field) eq '';
-  $self->getfield($field) =~ /^(\-)? ?(\d*)(\.\d{2})?$/
+  $self->getfield($field) =~ /^\s*(\-)?\s*(\d*)(\.\d{2})?\s*$/
     or return "Illegal (money) $field: ". $self->getfield($field);
   #$self->setfield($field, "$1$2$3" || 0);
   $self->setfield($field, ( ($1||''). ($2||''). ($3||'') ) || 0);
@@ -1915,7 +1923,7 @@ sub ut_agentnum_acl {
 
   if ( $self->$field() ) {
 
-    return "Access deined"
+    return "Access denied"
       unless $curuser->agentnum($self->$field());
 
   } else {
@@ -2033,7 +2041,6 @@ sub encrypt {
   my ($self, $value) = @_;
   my $encrypted;
 
-  my $conf = new FS::Conf;
   if ($conf->exists('encryption')) {
     if ($self->is_encrypted($value)) {
       # Return the original value if it isn't plaintext.
@@ -2082,7 +2089,6 @@ You should generally not have to worry about calling this, as the system handles
 sub decrypt {
   my ($self,$value) = @_;
   my $decrypted = $value; # Will return the original value if it isn't encrypted or can't be decrypted.
-  my $conf = new FS::Conf;
   if ($conf->exists('encryption') && $self->is_encrypted($value)) {
     $self->loadRSA;
     if (ref($rsa_decrypt) =~ /::RSA/) {
@@ -2099,7 +2105,6 @@ sub loadRSA {
     #Initialize the Module
     $rsa_module = 'Crypt::OpenSSL::RSA'; # The Default
 
-    my $conf = new FS::Conf;
     if ($conf->exists('encryptionmodule') && $conf->config_binary('encryptionmodule') ne '') {
       $rsa_module = $conf->config('encryptionmodule');
     }