File Coverage

blib/lib/JLdap.pm
Criterion Covered Total %
statement 9 687 1.3
branch 0 232 0.0
condition 0 51 0.0
subroutine 3 27 11.1
pod 0 24 0.0
total 12 1021 1.1


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             package JLdap;
4              
5             require 5.002;
6              
7 1     1   438 use Net::LDAP::Entry;
  1         2783  
  1         31  
8 1     1   7 no warnings qw (uninitialized);
  1         6  
  1         44  
9              
10             #use Fcntl;
11              
12             ##++
13             ## Global Variables. Declare lock constants manually, instead of
14             ## importing them from Fcntl.
15             ##
16 1     1   6 use vars qw ($VERSION);
  1         1  
  1         9137  
17             ##--
18              
19             $JLdap::VERSION = '0.24';
20              
21             #my $NUMERICTYPES = '^(NUMBER|FLOAT|DOUBLE|INT|INTEGER|NUM)$'; #20000224
22             #my $STRINGTYPES = '^(VARCHAR|CHAR|VARCHAR|DATE|LONG|BLOB|MEMO)$';
23              
24             ##++
25             ## Public Methods and Constructor
26             ##--
27              
28             sub new
29             {
30 0     0 0   my $class = shift;
31 0           my $self;
32              
33 0           $self = {
34             commands => 'select|update|delete|alter|insert|create|drop|primary_key_info',
35             column => '[A-Za-z0-9\~\x80-\xFF][\w\x80-\xFF]+',
36             _select => '[\w\x80-\xFF\*,\s\~]+',
37             path => '[\w\x80-\xFF\-\/\.\:\~\\\\]+',
38             table => '',
39             timestamp => 0,
40             fields => {},
41             use_fields => '',
42             key_fields => '',
43             order => [],
44             types => {},
45             lengths => {},
46             scales => {},
47             defaults => {},
48             records => [],
49             errors => {},
50             lasterror => 0, #JWT: ADDED FOR ERROR-CONTROL
51             lastmsg => '',
52             CaseTableNames => 0, #JWT: 19990991 TABLE-NAME CASE-SENSITIVITY?
53             LongTruncOk => 0, #JWT: 19991104: ERROR OR NOT IF TRUNCATION.
54             RaiseError => 0, #JWT: 20000114: ADDED DBI RAISEERROR HANDLING.
55             silent => 0,
56             ldap_dbh => 0,
57             ldap_sizelimit => 0, #JWT: LIMIT #RECORDS FETCHED, IF SET.
58             ldap_timelimit => 0, #JWT: LIMIT #RECORDS FETCHED, IF SET.
59             ldap_deref => 0, #JWT: LIMIT #RECORDS FETCHED, IF SET.
60             ldap_typesonly => 0,
61             ldap_callback => 0,
62             ldap_scope => 0,
63             ldap_inseparator => '|',
64             ldap_outseparator => '|',
65             ldap_firstonly => 0,
66             ldap_nullsearchvalue => ' ', #ADDED 20040330 TO FOR BACKWARD COMPATABILITY.
67             ldap_appendbase2ins => 0, #ADDED 20060719 FOR BACKWARD COMPAT. - 0.08+ NO LONGER APPENDS BASE TO ALWAYSINSERT PER REQUEST.
68             dirty => 0, #JWT: 20000229: PREVENT NEEDLESS RECOMMITS.
69             tindx => 0 #REPLACES GLOBAL VARIABLE.
70             };
71              
72 0           bless $self, $class;
73              
74 0           for (my $i=0;$i
75             {
76 0           $self->{$_[$i]} = $_[$i+1];
77             }
78              
79 0           $self->initialize;
80 0           return $self;
81             }
82             sub initialize
83             {
84 0     0 0   my $self = shift;
85              
86 0           $self->define_errors;
87             }
88              
89             sub sql
90             {
91 0     0 0   my ($self, $csr, $query) = @_;
92              
93 0           my ($command, $status, $base, $fields);
94             #print STDERR "-sql1($command,$status,$base,$fields)";
95 0 0         return wantarray ? () : -514 unless ($query);
    0          
96 0           $self->{lasterror} = 0;
97 0           $self->{lastmsg} = '';
98 0           $query =~ s/\n/ /gso;
99 0           $query =~ s/^\s*(.*?)\s*$/$1/;
100 0 0         $query = 'select tables' if ($query =~ /^show\s+tables$/i);
101 0 0         $query = 'select tables' if ($query =~ /^select\s+TABLE_NAME\s+from\s+USER_TABLES$/i); #ORACLE-COMPATABILITY.
102 0           $command = '';
103              
104 0 0         if ($query =~ /^($self->{commands})/io)
105             {
106 0           $command = $1;
107 0           $command =~ tr/A-Z/a-z/; #ADDED 19991202!
108 0           $status = $self->$command ($csr, $query);
109 0 0         if (!defined($status)) #NEXT 5 ADDED PER PATCH REQUEST 20091101:
    0          
110             {
111 0           $self->display_error(-599);
112 0 0         return wantarray ? () : -599;
113             }
114             elsif (ref ($status) eq 'ARRAY') #SELECT RETURNED OK (LIST OF RECORDS).
115             {
116 0 0         return wantarray ? @$status : $status;
117             }
118             else
119             {
120 0 0         if ($status < 0)
121             { #SQL RETURNED AN ERROR!
122             #print STDERR "-sql6 status=$status=\n";
123 0           $self->display_error ($status);
124             #return ($status);
125 0 0         return wantarray ? () : $status;
126             }
127             else
128             { #SQL RETURNED OK.
129             #print STDERR "-sql7 status=$status= at=$@= cash=$_= bang=$!= query=$?=\n";
130 0 0         return wantarray ? ($status) : $status;
131             }
132             }
133             }
134             else
135             {
136 0 0         return wantarray ? () : -514;
137             }
138             }
139              
140             sub select
141             {
142 0     0 0   my ($self, $csr, $query) = @_;
143              
144 0           my (@ordercols) = ();
145 0           $regex = $self->{_select};
146 0           $path = $self->{path};
147 0           my (@rtnvals) = ();
148              
149 0           my $distinct;
150 0 0         $distinct = 1 if ($query =~ s/select\s+distinct(\s+\w|\s*\(|\s+\*)/select $1/i);
151 0           my ($dbh) = $csr->FETCH('ldap_dbh');
152 0           my ($tablehash);
153              
154 0 0         if ($query =~ /^select tables$/io)
    0          
155             {
156 0           $tablehash = $dbh->FETCH('ldap_tablenames');
157 0           $self->{use_fields} = 'TABLE_NAME'; #ADDED 20000224 FOR DBI!
158 0           $values_or_error = [];
159 0           for ($i=0;$i<=$#{$tablehash};$i++)
  0            
160             {
161 0           push (@$values_or_error,[$tablehash->[$i]]);
162             }
163 0           unshift (@$values_or_error, ($#{$tablehash}+1));
  0            
164 0           return $values_or_error;
165             }
166             elsif ($query =~ /^select\s+ # Keyword
167             ($regex)\s+ # Columns
168             from\s+ # 'from'
169             ($path)(.*)$/iox)
170             {
171 0           ($attbs, $table, $extra) = ($1, $2, $3);
172              
173 0 0         $table =~ tr/A-Z/a-z/ unless ($self->{CaseTableNames}); #JWT:TABLE-NAMES ARE NOW CASE-INSENSITIVE!
174 0           $self->{file} = $table;
175 0 0         if ($extra =~ s/([\s|\)]+)order\s+by\s*(.*)/$1/i)
176             {
177 0           $orderclause = $2;
178 0           @ordercols = split(/,/,$orderclause);
179 0           $descorder = ($ordercols[$#ordercols] =~ s/(\w+\W+)desc(?:end|ending)?$/$1/i); #MODIFIED 20000721 TO ALLOW "desc|descend|descending"!
180 0           for $i (0..$#ordercols)
181             {
182 0           $ordercols[$i] =~ s/\s//igo; #CASE-INSENSITIVITY ADDED NEXT 2: 20050416 PER PATCH BY jmorano
183 0           $ordercols[$i] =~ s/[\(\)]+//igo;
184             }
185             }
186 0           $tablehash = $dbh->FETCH('ldap_tables');
187 0 0         return (-524) unless ($tablehash->{$table});
188              
189 0           my ($base, $objfilter, $dnattbs, $allattbs, $alwaysinsert) = split(/\:/o ,$tablehash->{$table});
190 0 0 0       $attbs = $allattbs if ($allattbs && $attbs =~ s/\*//o);
191 0           $attbs =~ s/\s//go;
192 0           $attbs =~ tr/A-Z/a-z/;
193 0 0         @{$self->{order}} = split(/,/o, $attbs) unless ($attbs eq '*');
  0            
194 0           my $fieldnamehash = ();
195 0           my $attbcnt = 0;
196 0           foreach my $i (@{$self->{order}})
  0            
197             {
198 0           $fieldnamehash{$i} = $attbcnt++;
199             }
200 0           my ($ldap) = $csr->FETCH('ldap_ldap');
201 0   0       $objfilter ||= 'objectclass=*';
202 0 0         $objfilter = "($objfilter)" unless ($objfilter =~ /^\(/o);
203             #print "
-where=$extra=\n";
204 0 0         if ($extra =~ /^\s+where\s*(.+)$/io)
205             {
206 0           $filter = $self->parse_expression($1);
207 0 0         $filter = '('.$filter.')' unless ($filter =~ /^\(/o);
208 0           $filter = "(&$objfilter$filter)";
209             }
210             else
211             {
212 0           $filter = $objfilter;
213             }
214             #print "
-filter =$filter=\n";
215 0           my $data;
216 0           my (@searchops) = (
217             'base' => $base,
218             'filter' => $filter,
219             'attrs' => [split(/\,/o, $attbs)]
220             );
221 0           foreach my $i (qw(ldap_sizelimit ldap_timelimit deref typesonly
222             callback))
223             {
224 0           $j = $i;
225 0           $j =~ s/^ldap_//o;
226 0 0         push (@searchops, ($j, $self->{$i})) if ($self->{$i});
227             }
228 0   0       push (@searchops, ('scope', ($self->{ldap_scope} || 'one')));
229             #print "--- ATTBS =$attbs=\n";
230             #print "--- SEARCH OPS =".join('|',@searchops)."=\n";
231 0 0         $data = $ldap->search(@searchops)
232             or return($self->ldap_error($@,"Search failed to return object: filter=$filter (".$data->error().")"));
233             #print "--- data=$data=\n";
234 0           my ($j) = 0;
235 0           my (@varlist) = ();
236 0           while (my $entry = $data->shift_entry())
237             {
238 0           $dn = $entry->dn();
239 0 0         next unless ($dn =~ /$base$/i); #CASE-INSENSITIVITY ADDED NEXT 2: 20050416 PER PATCH BY jmorano
240 0           @attributes = $entry->attributes;
241 0 0         unless ($attbcnt)
242             {
243 0           $attbs = join(',',@attributes);
244 0           $attbcnt = 0;
245 0           @{$self->{order}} = @attributes;
  0            
246 0           foreach my $i (@{$self->{order}})
  0            
247             {
248 0           $fieldnamehash{$i} = $attbcnt++;
249             }
250             }
251 0           $varlist[$j] = [];
252 0           for (my $i=0;$i<$attbcnt;$i++)
253             {
254 0           $varlist[$j][$i] = '';
255             }
256 0           $i = 0;
257 0           foreach my $attr (@{$self->{order}})
  0            
258             {
259             # $valuesref = $entry->get($attr); #CHGD. TO NEXT PER PATCH REQUEST 20091101:
260 0           $valuesref = $entry->get_value($attr, asref => 1);
261 0 0 0       if ($self->{ldap_firstonly} && $self->{ldap_firstonly} <= scalar (@{$valuesref}))
  0            
262             {
263             #$varlist[$j][$fieldnamehash{$attr}] = join($self->{ldap_outseparator}, $valuesref->[0]); #CHGD. 20010829 TO NEXT.
264 0           $varlist[$j][$fieldnamehash{$attr}] = join($self->{ldap_outseparator}, @{$valuesref}[0..($self->{ldap_firstonly}-1)]);
  0            
265             }
266             else
267             {
268 0   0       $varlist[$j][$fieldnamehash{$attr}] = join($self->{ldap_outseparator}, @$valuesref) || '';
269             }
270 0 0         unless ($valuesref[0])
271             {
272 0 0         $varlist[$j][$fieldnamehash{dn}] = $dn if ($attr eq 'dn');
273             }
274 0           $i++;
275             }
276 0           ++$j;
277             }
278 0           $self->{use_fields} = $attbs;
279 0 0         if ($distinct) #THIS MAKES "DISTINCT" WORK.
280             {
281 0           my (%disthash);
282 0           for (my $i=0;$i<=$#varlist;$i++)
283             {
284 0           ++$disthash{join("\x02",@{$varlist[$i]})};
  0            
285             }
286 0           @varlist = ();
287 0           foreach my $i (keys(%disthash))
288             {
289 0           push (@varlist, [split(/\x02/o, $i, -1)]);
290             }
291             }
292 0 0         if ($#ordercols >= 0) #SORT 'EM!
293             {
294 0           my @SV;
295 0           for (my $i=0;$i<=$#varlist;$i++)
296             {
297 0           $SV[$i] = '';
298 0           foreach my $j (@ordercols)
299             {
300 0           $SV[$i] .= $varlist[$i][$fieldnamehash{$j}] . "\x01";
301             }
302             }
303 0           @sortvector = &sort_elements(\@SV);
304 0 0         @sortvector = reverse(@sortvector) if ($descorder);
305 0           @SV = ();
306 0           while (@sortvector)
307             {
308 0           push (@SV, $varlist[shift(@sortvector)]);
309             }
310 0           @varlist = @SV;
311 0           @SV = ();
312             }
313 0           return [($#attributes+1), @varlist];
314             }
315             else #INVALID SELECT STATEMENT!
316             {
317 0           return (-503);
318             }
319             }
320              
321             sub sort_elements
322             {
323 0     0 0   my (@elements, $line, @sortlist, @sortedlist, $j, $t, $argcnt, $linedata,
324             $vectorid, @sortvector);
325              
326 0           my ($lo) = 0;
327 0           my ($hi) = 0;
328 0 0         $lo = shift unless (ref($_[0]));
329 0 0         $hi = shift unless (ref($_[0]));
330              
331 0 0 0       if ($lo || $hi)
332             {
333 0           for ($j=0;$j<=$#{$_[0]};$j++)
  0            
334             {
335 0           $sortvector[$j] = $j;
336             }
337             }
338 0   0       $hi ||= $#{$_[0]};
  0            
339 0           $argcnt = scalar(@_);
340 0           for (my $i=$lo;$i<=$hi;$i++)
341             {
342 0           $line = $_[0][$i];
343 0           for ($j=1;$j<$argcnt;$j++)
344             {
345 0           $line .= "\x02" . $_[$j][$i];
346             }
347 0           $line .= "\x04".$i;
348 0           push (@sortlist, $line);
349             }
350              
351 0           @sortedlist = sort @sortlist;
352 0           $i = $lo;
353 0           foreach $line (@sortedlist)
354             {
355 0           ($linedata,$vectorid) = split(/\x04/o, $line);
356 0           (@elements) = split(/\x02/o, $linedata);
357 0 0         $t = $#elements unless $t;
358 0           for ($j=$t;$j>=1;$j--)
359             {
360             #push (@{$_[$j]}, $elements[$j]);
361 0           ${$_[$j]}[$i] = $elements[$j];
  0            
362             }
363 0           $sortvector[$i] = $vectorid;
364 0           $elements[0] =~ s/\s+//go;
365 0           ${$_[0]}[$i] = $elements[$j];
  0            
366 0           ++$i;
367             }
368 0           return @sortvector;
369             }
370              
371             sub ldap_error
372             {
373 0     0 0   my ($self,$errcode,$errmsg,$warn) = @_;
374              
375 0   0       $err = $errcode || -1;
376 0           $errdetails = $errmsg;
377 0 0         $err = -1 * $err if ($err > 0);
378 0 0 0       return ($err) unless (defined($warn) && $warn);
379              
380             # print "Content-type: text/html\nWindow-target: _parent", "\n\n"
381             # if (defined($warn) && $warn == 1);
382              
383 0           return ($self->display_error($errcode));
384             }
385              
386             sub display_error
387             {
388 0     0 0   my ($self, $error) = @_;
389              
390 0   0       $other = $@ || $! || 'None';
391              
392 0 0         print STDERR <{silent});
393              
394             Oops! The following error occurred when processing your request:
395              
396             $self->{errors}->{$error} ($errdetails)
397              
398             Here's some more information to help you:
399              
400             file: $self->{file}
401             $other
402              
403             Error_Message
404              
405             #JWT: ADDED FOR ERROR-CONTROL.
406              
407 0           $self->{lasterror} = $error;
408 0           $self->{lastmsg} = "$error:" . $self->{errors}->{$error};
409 0 0         $self->{lastmsg} .= '('.$errdetails.')' if ($errdetails); #20000114
410              
411 0           $errdetails = ''; #20000114
412 0 0         die $self->{lastmsg} if ($self->{RaiseError}); #20000114.
413              
414             #return (1);
415 0           return ($error);
416             }
417              
418             sub commit
419             {
420 0     0 0   my ($self) = @_;
421 0           my ($status) = 1;
422 0           my ($dbh) = $self->FETCH('ldap_dbh');
423 0           my ($autocommit) = $dbh->FETCH('AutoCommit');
424              
425 0 0         $status = $dbh->commit() unless ($autocommit);
426              
427 0 0         $self->{dirty} = 0 if ($status > 0);
428 0 0         return undef if ($status <= 0); #ADDED 20000103
429 0           return $status;
430             }
431              
432             ##++
433             ## Private Methods
434             ##--
435              
436             sub define_errors
437             {
438 0     0 0   my $self = shift;
439 0           my $errors;
440              
441 0           $errors = {};
442              
443 0           $errors->{'-501'} = 'Could not open specified database.';
444 0           $errors->{'-502'} = 'Specified column(s) not found.';
445 0           $errors->{'-503'} = 'Incorrect format in [select] statement.';
446 0           $errors->{'-504'} = 'Incorrect format in [update] statement.';
447 0           $errors->{'-505'} = 'Incorrect format in [delete] statement.';
448 0           $errors->{'-506'} = 'Incorrect format in [add/drop column] statement.';
449 0           $errors->{'-507'} = 'Incorrect format in [alter table] statement.';
450 0           $errors->{'-508'} = 'Incorrect format in [insert] command.';
451 0           $errors->{'-509'} = 'The no. of columns does not match no. of values.';
452 0           $errors->{'-510'} = 'A severe error! Check your query carefully.';
453 0           $errors->{'-511'} = 'Cannot write the database to output file.';
454 0           $errors->{'-512'} = 'Unmatched quote in expression.';
455 0           $errors->{'-513'} = 'Need to open the database first!';
456 0           $errors->{'-514'} = 'Please specify a valid query.';
457             # $errors->{'-515'} = 'Cannot get lock on database file.';
458             # $errors->{'-516'} = 'Cannot delete temp. lock file.';
459 0           $errors->{'-517'} = "Built-in function failed ($@).";
460 0           $errors->{'-518'} = "Unique Key Constraint violated."; #JWT.
461 0           $errors->{'-519'} = "Field would have to be truncated."; #JWT.
462 0           $errors->{'-520'} = "Can not create existing table (drop first!)."; #20000225 JWT.
463 0           $errors->{'-521'} = "Can not change datatype on non-empty table."; #20000323 JWT.
464 0           $errors->{'-522'} = "Can not decrease field-size on non-empty table."; #20000323 JWT.
465 0           $errors->{'-523'} = "Update Failed to commit changes."; #20000323 JWT.
466 0           $errors->{'-524'} = "No such table."; #20000323 JWT.
467 0           $errors->{'-599'} = 'General error.';
468              
469 0           $self->{errors} = $errors;
470              
471 0           return (1);
472             }
473              
474             sub parse_expression
475             {
476 0     0 0   my ($self, $s) = @_;
477              
478 0           $s =~ s/\s+$//o; #STRIP OFF LEADING AND TRAILING WHITESPACE.
479 0           $s =~ s/^\s+//o;
480 0 0         return unless ($s);
481              
482              
483 0           my $relop = '(?:<|=|>|<=|>=|!=|like|not\s+like|is\s+not|is)';
484 0           my %boolopsym = ('and' => '&', 'or' => '|');
485              
486 0           my $indx = 0;
487              
488 0           my @P = ();
489 0           my @T3 = (); #PROTECTS MULTI-WAY RELOP EXPRESSIONS, IE. (A AND B AND C)
490 0           my $t3indx = 0;
491 0           @T = ();
492 0           my @QS = ();
493              
494 0           $s=~s|\\\'|\x04|go; #PROTECT "\'" IN QUOTES.
495 0           $s=~s|\\\"|\x02|go; #PROTECT "\"" IN QUOTES.
496              
497             #THIS NEXT LOOP STRIPS OUT AND SAVES ALL QUOTED STRING LITERALS
498             #TO PREVENT THEM FROM INTERFEARING WITH OTHER REGICES, IE. DON'T
499             #WANT OPERATORS IN STRINGS TO BE TREATED AS OPERATORS!
500              
501 0           $indx++ while ($s =~ s/([\'\"])([^\1]*?)\1/
502 0           $QS[$indx] = $2; "\$QS\[$indx]"/e);
  0            
503              
504 0           for (my $i=0;$i<=$#QS;$i++) #ESCAPE LDAP SPECIAL-CHARACTERS.
505             {
506 0           $QS[$i] =~ s/\\x([\da-fA-F][\da-fA-F])/\x05$1/g; #PROTECT PERL HEX TO LDAP HEX (\X## => \##).
507             #$QS[$i] =~ s/([\*\(\)\+\\\<\>])/\\$1/g; #CHGD. TO NEXT. 20020409!
508 0           $QS[$i] =~ s/([\*\(\)\\])/"\\".unpack('H2',$1)/eg;
  0            
509             #$QS[$i] =~ s/\\x(\d\d)/\\$1/g; #CONVERT PERL HEX TO LDAP HEX (\X## => \##).
510 0           $QS[$i] =~ s/\x05([\da-fA-F][\da-fA-F])/\\$1/go; #CONVERT PERL HEX TO LDAP HEX (\X## => \##).
511             }
512             #print STDERR "-parse_expression: QS list=".join('|',@QS)."= SSSS=$s=\n";
513 0           $indx = 0;
514              
515             #I TRIED TO ALLOWING ATTRIBUTES TO BE COMPARED W/OTHER ATTRIBUTES, BUT
516             #(20020409), BUT APPARENTLY LDAP ONLY ALLOWS STRING CONSTANTS ON RHS OF OPERATORS!
517              
518             # $indx++ while ($s =~ s/(\w+)\s*($relop)\s*(\$QS\[\d*\]|\w+)/ #THIS WAS TRIED TO COMPARE ATTRIBUTES WITH ATTRIBUTES, BUT APPARENTLY DOESN'T WORK IN LDAP!
519 0           $indx++ while ($s =~ s/(\w+)\s*($relop)\s*(\$QS\[\d*\])/
520 0           my ($one, $two, $three) = ($1, $2, $3);
521 0           my ($regex) = 0;
522 0           my ($opr) = $two;
523             #CONVERT "NOT LIKE" AND "IS NOT" TO "!( = ).
524              
525 0 0         if ($two =~ m!(?:not\s+like|is\s+not)!io)
    0          
526             {
527 0           $two = '=';
528 0           $regex = 2;
529             }
530             elsif ($two =~ m!(?:like|is)!io) #CONVERT "LIKE" AND "IS" TO "=".
531             {
532 0           $two = '=';
533 0           $regex = 1;
534             }
535 0           $P[$indx] = $one.$two.$three; #SAVE EXPRESSION.
536            
537             #CONVERT SQL WILDCARDS INTO LDAP WILDCARDS IN OPERAND.
538            
539 0           my ($qsindx);
540 0 0         if ($three =~ m!\$QS\[(\d+)\]!)
541             {
542 0           $qsindx = $1;
543 0 0         if ($regex > 0)
544             {
545 0 0         if ($opr !~ m!is!io)
546             {
547 0           $QS[$qsindx] =~ s!\%!\*!go; #FIX WILDCARD. NOTE - NO FIX FOR "_"!
548             }
549             }
550 0 0         $QS[$qsindx] = $self->{ldap_nullsearchvalue} unless (length($QS[$qsindx]));
551             }
552 0 0 0       $P[$indx] = "!($P[$indx])" if ($regex == 2 || $opr eq '!=' || ($opr eq '=' && !length($QS[$qsindx]))); #INVERT EXPRESSION IF "NOT"!
      0        
      0        
553 0           $P[$indx] =~ s!\!\=!\=!o; #AFTER INVERSION, FIX "!=" (NOT VALID IN LDAP!)
554 0           "\$P\[$indx]";
555             /ei); #CASE-INSENSITIVITY ADDED NEXT 2: 20050416 PER PATCH BY jmorano
556 0           $self->{tindx} = 0;
557 0           $s = &parseParins($self, $s);
558              
559 0           for (my $i=0;$i<=$#T;$i++)
560             {
561             # 1 while ($T[$i] =~ s/(.+?)\s*\band\b\s*(.+)/\&\($1\)\($2\)/i);
562 0           1 while ($T[$i] =~ s/([^\(\)]+)\s*\band\b\s*([^\(\)]+)(?:and|or)?/\&\($1\)\($2\)/i);
563 0           1 while ($T[$i] =~ s/([^\(\)]+)\s*\bor\b\s*([^\(\)]+)(?:and|or)?/\|\($1\)\($2\)/i);
564             }
565 0           $s =~ s/AND/and/igo;
566 0           $s =~ s/OR/or/igo;
567             # 1 while ($s =~ s/(.+?)\s*\band\b\s*(.+)/\(\&\($1\)\($2\)\)/i); #CASE-INSENSITIVITY ADDED NEXT 2: 20050416 PER PATCH BY jmorano
568 0           1 while ($s =~ s/([^\(\)]+)\s*\band\b\s*([^\(\)]+)(?:and|or)?/\&\($1\)\($2\)/i); #CASE-INSENSITIVITY ADDED NEXT 2: 20050416 PER PATCH BY jmorano
569 0           1 while ($s =~ s/([^\(\)]+)\s*\bor\b\s*([^\(\)]+)(?:and|or)?/\|\($1\)\($2\)/i); #CASE-INSENSITIVITY ADDED NEXT 2: 20050416 PER PATCH BY jmorano
570 0           1 while ($s =~ s/\bnot\b\s*([^\s\)]+)?/\!\($1\)/);
571 0           1 while ($s =~ s/\$T\[(\d+)\]/$T[$1]/g);
572 0           $s =~ s/(\w+)\s+is\s+not\s+null?/$1\=\*/gi;
573 0           $s =~ s/(\w+)\s+is\s+null?/\!\($1\=\*\)/gi;
574              
575             #CONVERT SQL WILDCARDS TO PERL REGICES.
576              
577 0           1 while ($s =~ s/\$P\[(\d+)\]/$P[$1]/g);
578 0           $s =~ s/ +//go;
579 0           1 while ($s =~ s/\$QS\[(\d+)\]/$QS[$1]/g);
580 0           $s =~ s/\x04/\'/go; #UNPROTECT AND UNESCAPE QUOTES WITHIN QUOTES.
581 0 0         $s = '(' . $s . ')' unless ($s =~ /^\(/o);
582 0           return $s;
583             }
584              
585             sub parseParins
586             {
587 0     0 0   my $self = shift;
588 0           my $s = shift;
589              
590 0           $self->{tindx}++ while ($s =~ s/\(([^\(\)]+)\)/
591 0           $T[$self->{tindx}] = &parseParins($self, $1); "\$T\[$self->{tindx}]"
  0            
592             /e);
593 0           return $s;
594             }
595              
596             sub rollback
597             {
598 0     0 0   my ($self) = @_;
599              
600 0           my ($status) = 1;
601 0           my ($dbh) = $self->FETCH('ldap_dbh');
602 0           my ($autocommit) = $dbh->FETCH('AutoCommit');
603              
604 0 0         $status = $dbh->rollback() unless ($autocommit);
605              
606 0 0         $self->{dirty} = 0 if ($status > 0);
607 0           return $status;
608             }
609              
610             sub update
611             {
612 0     0 0   my ($self, $csr, $query) = @_;
613 0           my ($i, $path, $regex, $table, $extra, @attblist, $filter, $all_columns);
614 0           my $status = 0;
615 0           my ($psuedocols) = "CURVAL|NEXTVAL|ROWNUM";
616             #print STDERR "-update10 sql=$query=\n";
617             ##++
618             ## Hack to allow parenthesis to be escaped!
619             ##--
620              
621 0           $query =~ s/\\([()])/sprintf ("%%\0%d: ", ord ($1))/ge;
  0            
622 0           $path = $self->{path};
623 0           $regex = $self->{column};
624              
625 0 0         if ($query =~ /^update\s+($path)\s+set\s+(.+)$/i)
626             {
627 0           ($table, $extra) = ($1, $2);
628             #print STDERR "-update20: table=$table= extra=$extra=\n";
629             #ADDED IF-STMT 20010418 TO CATCH
630             #PARENTHESIZED SET-CLAUSES (ILLEGAL IN ORACLE & CAUSE WIERD PARSING ERRORS!)
631              
632 0 0         if ($extra =~ /^\(.+\)\s*where/io)
633             {
634 0           $errdetails = 'parenthesis around SET clause?';
635 0           return (-504);
636             }
637 0 0         $table =~ tr/A-Z/a-z/ unless ($self->{CaseTableNames}); #JWT:TABLE-NAMES ARE NOW CASE-INSENSITIVE!
638 0           $self->{file} = $table;
639              
640 0           my ($dbh) = $csr->FETCH('ldap_dbh');
641 0           my ($ldap) = $csr->FETCH('ldap_ldap');
642 0           my ($tablehash) = $dbh->FETCH('ldap_tables');
643 0 0         return (-524) unless ($tablehash->{$table});
644 0           my ($base, $objfilter, $dnattbs, $allattbs, $alwaysinsert) = split(/\:/,$tablehash->{$table});
645              
646 0           $all_columns = {};
647              
648 0           $extra =~ s/\\\\/\x02/go; #PROTECT "\\"
649             #1$extra =~ s/\'\'/\x03\x03/go; #PROTECT '', AND \'.
650 0           $extra =~ s/\\\'/\x03/go; #PROTECT '', AND \'.
651              
652 0           $extra =~ s/^\s+//o; #STRIP OFF SURROUNDING SPACES.
653 0           $extra =~ s/\s+$//o;
654              
655             #NOW TEMPORARILY PROTECT COMMAS WITHIN (), IE. FN(ARG1,ARG2).
656              
657 0           $column = $self->{column};
658 0           $extra =~ s/($column\s*\=\s*)\'(.*?)\'(,|$)/
659 0           my ($one,$two,$three) = ($1,$2,$3);
660 0           $two =~ s|\,|\x05|go;
661 0           $two =~ s|\(|\x06|go;
662 0           $two =~ s|\)|\x07|go;
663 0           $one."'".$two."'".$three;
664             /eg;
665              
666 0           1 while ($extra =~ s/\(([^\(\)]*)\)/
667 0           my ($args) = $1;
668 0           $args =~ s|\,|\x05|go;
669 0           "\x06$args\x07";
670             /eg);
671 0           @expns = split(',',$extra);
672             #print STDERR "-update50: extra=$extra= expns=".join('|',@expns)."=\n";
673 0           for ($i=0;$i<=$#expns;$i++) #PROTECT "WHERE" IN QUOTED VALUES.
674             {
675 0           $expns[$i] =~ s/\x05/\,/go;
676 0           $expns[$i] =~ s/\x06/\(/go;
677 0           $expns[$i] =~ s/\x07/\)/go;
678 0           $expns[$i] =~ s/\=\s*'([^']*?)where([^']*?)'/\='$1\x05$2'/gi;
679 0           $expns[$i] =~ s/\'(.*?)\'/my ($j)=$1;
  0            
680 0           $j=~s|where|\x05|gio;
681 0           "'$j'"
682             /eg;
683             }
684 0           $extra = $expns[$#expns]; #EXTRACT WHERE-CLAUSE, IF ANY.
685 0 0         $filter = ($extra =~ s/(.*)where(.+)$/where$1/i) ? $2 : '';
686 0           $filter =~ s/\s+//o;
687 0           $expns[$#expns] =~ s/\s*where(.+)$//io; #20000108 REP. PREV. LINE 2FIX BUG IF LAST COLUMN CONTAINS SINGLE QUOTES.
688 0           $column = $self->{column};
689 0   0       $objfilter ||= 'objectclass=*';
690 0 0         $objfilter = "($objfilter)" unless ($objfilter =~ /^\(/o);
691 0 0         if ($filter)
692             {
693             #print STDERR "--update: BEF parse_expn: filter=$filter=\n";
694 0           $filter = $self->parse_expression ($filter);
695             #print STDERR "--update: AFT parse_expn: filter=$filter= objfilter=$objfilter=\n";
696 0 0         $filter = '('.$filter.')' unless ($filter =~ /^\(/o);
697 0           $filter = "(&$objfilter$filter)";
698             }
699             else
700             {
701 0           $filter = "$objfilter";
702             }
703 0           $filter =~ s/\x03/\\\'/go; #UNPROTECT '', AND \'. #NEXT 2 ADDED 20091101:
704 0           $filter =~ s/\x02/\\\\/go; #UNPROTECT "\\".
705             # $alwaysinsert .= ',' . $base; #CHGD TO NEXT 200780719 PER REQUEST.
706 0 0         $alwaysinsert .= ',' . $base if ($self->{ldap_appendbase2ins});
707 0           $alwaysinsert =~ s/\\\\/\x02/go; #PROTECT "\\"
708 0           $alwaysinsert =~ s/\\\,/\x03/go; #PROTECT "\,"
709 0           $alwaysinsert =~ s/\\\=/\x04/go; #PROTECT "\="
710 0           my ($i1, $col, $vals, $j, @l);
711 0           for ($i=0;$i<=$#expns;$i++) #EXTRACT FIELD NAMES AND
712             #VALUES FROM EACH EXPRESSION.
713             {
714 0           $expns[$i] =~ s/\x03/\\\'/go; #UNPROTECT '', AND \'.
715 0           $expns[$i] =~ s/\x02/\\\\/go; #UNPROTECT "\\".
716 0           $expns[$i] =~ s!\s*($column)\s*=\s*(.+)$!
717 0           my ($var) = $1;
718 0           my ($val) = $2;
719            
720 0 0         $val = &pscolfn($self,$val) if ($val =~ "$column\.$psuedocols");
721 0           $var =~ tr/A-Z/a-z/;
722 0           $val =~ s|%\0(\d+): |pack("C",$1)|ge;
  0            
723 0           $val =~ s/^\'//o; #NEXT 2 ADDED 20010530 TO STRIP EXCESS QUOTES.
724 0           $val =~ s/([^\\\'])\'$/$1/;
725 0           $val =~ s/\'$//o;
726 0           $all_columns->{$var} = $val;
727 0           @_ = split(/\,\s*/o, $alwaysinsert);
728 0           while (@_)
729             {
730 0           ($col, $vals) = split(/\=/o, shift);
731 0 0         next unless ($col eq $var);
732 0           $vals =~ s/\x04/\\\=/go; #UNPROTECT "\="
733 0           $vals =~ s/\x03/\\\,/go; #UNPROTECT "\,"
734 0           $vals =~ s/\x02/\\\\/go; #UNPROTECT "\\"
735 0           @l = split(/\Q$self->{ldap_inseparator}\E/, $vals);
736 0           VALUE: for (my $j=0;$j<=$#l;$j++)
737             {
738 0 0         next if ($all_columns->{$var} =~ /\b$l[$j]\b/);
739             $all_columns->{$var} .= $self->{ldap_inseparator}
740 0 0         if ($all_columns->{$var});
741 0           $all_columns->{$var} .= $l[$j];
742             }
743             }
744 0           $all_columns->{$var} =~ s/\x02/\\\\/go;
745             # $all_columns->{$var} =~ s/\x03/\'/go; #20091030: REPL. W.NEXT LINE TO KEEP ESCAPE SLASH "\" - RETAIN ORIG. COMMENT:
746 0           $all_columns->{$var} =~ s/\x03/\\\'/go; #20000108 REPL. PREV. LINE - NO NEED TO DOUBLE QUOTES (WE ESCAPE THEM) - THIS AIN'T ORACLE.
747             !e;
748             }
749              
750 0           delete $all_columns->{dn}; #DO NOT ALLOW DN TO BE CHANGED DIRECTLY!
751             #foreach my $xxx (sort keys %{$all_columns}) { print STDERR "---data($xxx)=".$all_columns->{$xxx}."=\n"; };
752 0           my ($data);
753 0           my (@searchops) = (
754             'base' => $base,
755             'filter' => $filter,
756             );
757 0           foreach my $i (qw(ldap_sizelimit ldap_timelimit deref typesonly
758             callback))
759             {
760 0           $j = $i;
761 0           $j =~ s/^ldap_//o;
762 0 0         push (@searchops, ($j, $self->{$i})) if ($self->{$i});
763             }
764 0   0       push (@searchops, ('scope', ($self->{ldap_scope} || 'one')));
765             #print STDERR "-update: filter=$filter= searchops=".join('|',@searchops)."=\n";
766 0 0         $data = $ldap->search(@searchops)
767             or return($self->ldap_error($@,"Search failed to return object: filter=$filter (".$data->error().")"));
768             #print STDERR "-update: got thru search; data=$data=\n";
769 0           my (@varlist) = ();
770 0           $dbh = $csr->FETCH('ldap_dbh');
771 0           my ($autocommit) = $dbh->FETCH('AutoCommit');
772 0 0         my ($commitqueue) = $dbh->FETCH('ldap_commitqueue') unless ($autocommit);
773 0           my (@dnattbs) = split(/\,/o, $dnattbs);
774 0           my ($changedn);
775             #print STDERR "-update: going into loop!\n";
776 0           while (my $entry = $data->shift_entry())
777             {
778             #print STDERR "----update: in loop entry=$entry=\n";
779 0           $dn = $entry->dn();
780 0           $dn =~ s/\\/\x02/go; #PROTECT "\";
781 0           $dn =~ s/\\\,/\x03/go; #PROTECT "\,";
782 0           $changedn = 0;
783 0           I: foreach my $i (@dnattbs)
784             {
785 0           foreach my $j (keys %$all_columns)
786             {
787 0 0         if ($i eq $j)
788             {
789 0           $dn =~ s/(\b$i\=)([^\,]+)/$1$all_columns->{$j}/;
790 0           $changedn = 1;
791 0           next I;
792             }
793             }
794             }
795 0           $dn =~ s/(?:\,\s*)$base$//;
796 0           $dn =~ s/\x03/\\\,/go; #UNPROTECT "\,";
797 0           $dn =~ s/\x02/\\/go; #UNPROTECT "\";
798 0           foreach my $i (keys %$all_columns)
799             {
800 0           $all_columns->{$i} =~ s/(?:\\|\')\'/\'/go; #1UNESCAPE QUOTES IN VALUES.
801 0           @_ = split(/\Q$self->{ldap_inseparator}\E/, $all_columns->{$i});
802 0 0         if (!@_)
    0          
803             {
804 0           push (@attblist, ($i, ''));
805             }
806             elsif (@_ == 1)
807             {
808 0           push (@attblist, ($i, shift));
809             }
810             else
811             {
812 0           push (@attblist, ($i, [@_]));
813             }
814             }
815 0           $r1 = $entry->replace(@attblist);
816             #print STDERR "-update: r1=$r1= attblist=".join('|',@attblist)."=\n";
817 0 0         if ($r1 > 0)
818             {
819 0 0         if ($autocommit)
820             {
821 0           $r2 = $entry->update($ldap); #COMMIT!!!
822 0 0         if ($r2->is_error)
823             {
824 0           $errdetails = $r2->code . ': ' . $r2->error;
825 0           return (-523);
826             }
827 0 0         if ($changedn)
828             {
829 0           $r2 = $ldap->moddn($entry, newrdn => $dn);
830 0 0         if ($r2->is_error)
831             {
832 0           $errdetails = "Could not change dn - "
833             . $r2->code . ': ' . $r2->error . '!';
834 0           return (-523);
835             }
836             }
837             }
838             else
839             {
840 0           push (@{$commitqueue}, (\$entry, \$ldap));
  0            
841 0 0         push (@{$commitqueue}, "dn=$dn") if ($changedn);
  0            
842             }
843 0           ++$status;
844             }
845             else
846             {
847             #return($self->ldap_error($@,"Search failed to return object: filter=$filter (".$data->error().")"));
848 0           $errdetails = $data->code . ': ' . $data->error;
849 0           return (-523);
850             }
851             }
852 0           return ($status);
853             }
854             else
855             {
856 0           return (-504);
857             }
858             }
859              
860             sub delete
861             {
862 0     0 0   my ($self, $csr, $query) = @_;
863 0           my ($path, $table, $filter, $wherepart);
864 0           my $status = 0;
865              
866 0           $path = $self->{path};
867 0 0         if ($query =~ /^delete\s+from\s+($path)(?:\s+where\s+(.+))?$/io)
868             {
869 0           $table = $1;
870 0           $wherepart = $2;
871 0 0         $table =~ tr/A-Z/a-z/ unless ($self->{CaseTableNames}); #JWT:TABLE-NAMES ARE NOW CASE-INSENSITIVE!
872 0           $self->{file} = $table;
873              
874 0           my ($dbh) = $csr->FETCH('ldap_dbh');
875 0           my ($ldap) = $csr->FETCH('ldap_ldap');
876 0           my ($tablehash) = $dbh->FETCH('ldap_tables');
877 0 0         return (-524) unless ($tablehash->{$table});
878 0           my ($base, $objfilter, $dnattbs, $allattbs, $alwaysinsert) = split(/\:/,$tablehash->{$table});
879 0   0       $objfilter ||= 'objectclass=*';
880 0 0         $objfilter = "($objfilter)" unless ($objfilter =~ /^\(/o);
881 0 0         if ($wherepart =~ /\S/o)
882             {
883 0           $filter = $self->parse_expression ($wherepart);
884 0 0         $filter = '('.$filter.')' unless ($filter =~ /^\(/o);
885 0           $filter = "(&$objfilter$filter)";
886             }
887             else
888             {
889 0           $filter = "$objfilter";
890             }
891 0 0         $filter = '('.$filter.')' unless ($filter =~ /^\(/o);
892              
893 0 0         $data = $ldap->search(
894             base => $base,
895             filter => $filter,
896             ) or return ($self->ldap_error($@,"Search failed to return object: filter=$filter (".$data->error().")"));
897 0           my ($j) = 0;
898 0           my (@varlist) = ();
899 0           $dbh = $csr->FETCH('ldap_dbh');
900 0           my ($autocommit) = $dbh->FETCH('AutoCommit');
901 0 0         my ($commitqueue) = $dbh->FETCH('ldap_commitqueue') unless ($autocommit);
902 0           while (my $entry = $data->shift_entry())
903             {
904 0           $dn = $entry->dn();
905 0 0         next unless ($dn =~ /$base$/i); #CASE-INSENSITIVITY ADDED NEXT 2: 20050416 PER PATCH BY jmorano
906 0           $r1 = $entry->delete();
907 0 0         if ($autocommit)
908             {
909 0           $r2 = $entry->update($ldap); #COMMIT!!!
910 0 0         if ($r2->is_error)
911             {
912 0           $errdetails = $r2->code . ': ' . $r2->error;
913 0           return (-523);
914             }
915             }
916             else
917             {
918 0           push (@{$commitqueue}, (\$entry, \$ldap));
  0            
919             }
920 0           ++$status;
921             }
922              
923 0           return $status;
924             }
925             else
926             {
927 0           return (-505);
928             }
929             }
930              
931             sub primary_key_info
932             {
933 0     0 0   my ($self, $csr, $query) = @_;
934 0           my $table = $query;
935 0           $table =~ s/^.*\s+(\w+)$/$1/;
936 0 0         $table =~ tr/A-Z/a-z/ unless ($self->{CaseTableNames}); #JWT:TABLE-NAMES ARE NOW CASE-INSENSITIVE!
937 0           $self->{file} = $table;
938 0           my ($dbh) = $csr->FETCH('ldap_dbh');
939 0           my $tablehash = $dbh->FETCH('ldap_tables');
940 0 0         return -524 unless ($tablehash->{$table});
941              
942 0           undef %{ $self->{types} };
  0            
943 0           undef %{ $self->{lengths} };
  0            
944 0           $self->{use_fields} = 'CAT,SCHEMA,TABLE_NAME,PRIMARY_KEY';
945 0           $self->{order} = [ 'CAT', 'SCHEMA', 'TABLE_NAME', 'PRIMARY_KEY' ];
946 0           $self->{fields}->{CAT} = 1;
947 0           $self->{fields}->{SCHEMA} = 1;
948 0           $self->{fields}->{TABLE_NAME} = 1;
949 0           $self->{fields}->{PRIMARY_KEY} = 1;
950 0           undef @{ $self->{records} };
  0            
951 0           my (@keyfields) = split(/\,\s*/o, $self->{key_fields}); #JWT: PREVENT DUP. KEYS.
952 0           ${$self->{types}}{CAT} = 'VARCHAR';
  0            
953 0           ${$self->{types}}{SCHEMA} = 'VARCHAR';
  0            
954 0           ${$self->{types}}{TABLE_NAME} = 'VARCHAR';
  0            
955 0           ${$self->{types}}{PRIMARY_KEY} = 'VARCHAR';
  0            
956 0           ${$self->{lengths}}{CAT} = 50;
  0            
957 0           ${$self->{lengths}}{SCHEMA} = 50;
  0            
958 0           ${$self->{lengths}}{TABLE_NAME} = 50;
  0            
959 0           ${$self->{lengths}}{PRIMARY_KEY} = 50;
  0            
960 0           ${$self->{defaults}}{CAT} = undef;
  0            
961 0           ${$self->{defaults}}{SCHEMA} = undef;
  0            
962 0           ${$self->{defaults}}{TABLE_NAME} = undef;
  0            
963 0           ${$self->{defaults}}{PRIMARY_KEY} = undef;
  0            
964 0           ${$self->{scales}}{PRIMARY_KEY} = 50;
  0            
965 0           ${$self->{scales}}{PRIMARY_KEY} = 50;
  0            
966 0           ${$self->{scales}}{PRIMARY_KEY} = 50;
  0            
967 0           ${$self->{scales}}{PRIMARY_KEY} = 50;
  0            
968 0           my $results;
969 0           my $keycnt = scalar(@keyfields);
970 0           while (@keyfields)
971             {
972 0           push (@{$results}, [0, 0, $table, shift(@keyfields)]);
  0            
973             }
974 0           unshift (@$results, $keycnt);
975 0           return $results;
976             }
977              
978             sub alter #SQL COMMAND NOT IMPLEMENTED.
979             {
980 0     0 0   $@ = 'SQL "alter" command is not (yet) implemented!';
981 0           return 0;
982             }
983              
984             sub insert
985             {
986             #my ($self, $query) = @_;
987 0     0 0   my ($self, $csr, $query) = @_;
988 0           my ($i, $path, $table, $columns, $values, $status);
989              
990 0           $path = $self->{path};
991 0 0         if ($query =~ /^insert\s+into\s+ # Keyword
992             ($path)\s* # Table
993             (?:\((.+?)\)\s*)? # Keys
994             values\s* # 'values'
995             \((.+)\)$/ixo)
996             { #JWT: MAKE COLUMN LIST OPTIONAL!
997              
998 0           ($table, $columns, $values) = ($1, $2, $3);
999 0           my ($dbh) = $csr->FETCH('ldap_dbh');
1000 0           my ($tablehash) = $dbh->FETCH('ldap_tables');
1001 0 0         $table =~ tr/A-Z/a-z/ unless ($self->{CaseTableNames}); #JWT:TABLE-NAMES ARE NOW CASE-INSENSITIVE!
1002 0           $self->{file} = $table;
1003 0 0         return (-524) unless ($tablehash->{$table});
1004 0           my ($base, $objfilter, $dnattbs, $allattbs, $alwaysinsert) = split(/\:/,$tablehash->{$table});
1005 0           $columns =~ s/\s//go;
1006 0   0       $columns ||= $allattbs;
1007 0 0         $columns = join(',', @{ $self->{order} }) unless ($columns =~ /\S/o); #JWT
  0            
1008              
1009 0 0         unless ($columns =~ /\S/o)
1010             {
1011 0           return ($self->display_error (-509));
1012             }
1013 0           $values =~ s/\\\\/\x02/go; #PROTECT "\\"
1014 0           $values =~ s/\\\'/\x03/go; #PROTECT '', AND \'.
1015              
1016 0           $values =~ s/\'(.*?)\'/
1017 0           my ($j)=$1;
1018 0           $j=~s|,|\x04|go; #PROTECT "," IN QUOTES.
1019 0           "'$j'"
1020             /eg;
1021 0           @values = split(/,/o, $values);
1022 0           $values = '';
1023 0           for $i (0..$#values)
1024             {
1025 0           $values[$i] =~ s/^\s+//o; #STRIP LEADING & TRAILING SPACES.
1026 0           $values[$i] =~ s/\s+$//o;
1027 0           $values[$i] =~ s/\x03/\'/go; #RESTORE PROTECTED SINGLE QUOTES HERE.
1028 0           $values[$i] =~ s/\x02/\\/go; #RESTORE PROTECTED SLATS HERE.
1029 0           $values[$i] =~ s/\x04/,/go; #RESTORE PROTECTED COMMAS HERE.
1030             }
1031 0           chop($values);
1032              
1033 0           $status = $self->insert_data ($csr, $base, $dnattbs, $alwaysinsert, $columns, @values);
1034              
1035 0           return $status;
1036             }
1037             else
1038             {
1039 0           return (-508);
1040             }
1041             }
1042              
1043             sub insert_data
1044             {
1045 0     0 0   my ($self, $csr, $base, $dnattbs, $alwaysinsert, $column_string, @values) = @_;
1046 0           my (@columns, @attblist, $loop, $column, $j, $k);
1047 0           $column_string =~ tr/A-Z/a-z/;
1048 0           $dnattbs =~ tr/A-Z/a-z/;
1049 0           @columns = split (/\,/o, $column_string);
1050              
1051 0 0         if ($#columns = $#values)
1052             {
1053 0           my $dn = '';
1054 0           my @t = split(/,/o, $dnattbs);
1055 0           while (@t)
1056             {
1057 0           $j = shift (@t);
1058 0           J1: for (my $i=0;$i<=$#columns;$i++)
1059             {
1060 0 0         if ($columns[$i] eq $j)
1061             {
1062 0           $dn .= $columns[$i] . '=';
1063 0 0         if ($values[$i] =~ /\Q$self->{ldap_inseparator}\E/)
1064             {
1065 0           $dn .= (split(/\Q$self->{ldap_inseparator}\E/,$values[$i]))[0];
1066             }
1067             else
1068             {
1069 0           $dn .= $values[$i];
1070             }
1071 0           $dn .= ', ';
1072 0           last J1;
1073             }
1074             }
1075             }
1076 0           $dn =~ s/\'//go;
1077 0           $dn .= $base;
1078 0           for (my $i=0;$i<=$#columns;$i++)
1079             {
1080 0           @l = split(/\Q$self->{ldap_inseparator}\E/,$values[$i]);
1081 0           while (@l)
1082             {
1083 0           $j = shift(@l);
1084 0           $j =~ s/^\'//o;
1085 0           $j =~ s/([^\\\'])\'$/$1/;
1086 0 0 0       unless (!length($j) || $j eq "'" || $columns[$i] eq 'dn')
      0        
1087             {
1088 0 0         $j = "'" if ($j eq "''");
1089 0           push (@attblist, $columns[$i]);
1090 0           push (@attblist, $j);
1091             }
1092             }
1093             }
1094             # $alwaysinsert .= ',' . $base; #CHGD TO NEXT 200780719 PER REQUEST.
1095 0 0         $alwaysinsert .= ',' . $base if ($self->{ldap_appendbase2ins});
1096 0           my ($i1, $found, $col, $vals, $j);
1097 0           @_ = split(/\,\s*/o, $alwaysinsert);
1098 0           while (@_)
1099             {
1100 0           ($col, $vals) = split(/\=/o, shift);
1101 0           @l = split(/\Q$self->{ldap_inseparator}\E/, $vals);
1102 0           VALUE: for (my $i=0;$i<=$#l;$i++)
1103             {
1104 0           for ($j=0;$j<=$#attblist;$j+=2)
1105             {
1106 0 0         if ($attblist[$j] eq $col)
1107             {
1108 0 0         next VALUE if ($attblist[$j+1] eq $l[$i]);
1109             }
1110             }
1111 0           push (@attblist, $col);
1112 0           push (@attblist, $l[$i]);
1113             }
1114             }
1115 0           my ($ldap) = $csr->FETCH('ldap_ldap');
1116              
1117 0           my $entry = Net::LDAP::Entry->new;
1118 0           $entry->dn($dn);
1119              
1120 0           my $result = $entry->add(@attblist);
1121 0           $_ = $entry->dn();
1122              
1123 0           my ($dbh) = $csr->FETCH('ldap_dbh');
1124 0           my ($autocommit) = $dbh->FETCH('AutoCommit');
1125 0 0         if ($autocommit)
1126             {
1127 0           $r2 = $entry->update($ldap); #COMMIT!!!
1128 0 0         if ($r2->is_error)
1129             {
1130 0           $errdetails = $r2->code . ': ' . $r2->error;
1131 0           return (-523);
1132             }
1133             }
1134             else
1135             {
1136 0           my ($commitqueue) = $dbh->FETCH('ldap_commitqueue');
1137 0           push (@{$commitqueue}, (\$entry, \$ldap));
  0            
1138             }
1139              
1140 0           return (1);
1141             }
1142             else
1143             {
1144 0           $errdetails = "$#columns != $#values"; #20000114
1145 0           return (-509);
1146             }
1147             }
1148              
1149             sub create #SQL COMMAND NOT IMPLEMENTED.
1150             {
1151 0     0 0   $@ = 'SQL "create" command is not (yet) implemented!';
1152 0           return 0;
1153             }
1154              
1155             sub drop #SQL COMMAND NOT IMPLEMENTED.
1156             {
1157 0     0 0   $@ = 'SQL "drop" command is not (yet) implemented!';
1158 0           return 0;
1159             }
1160              
1161             sub pscolfn
1162             {
1163 0     0 0   my ($self,$id) = @_;
1164 0 0         return $id unless ($id =~ /CURVAL|NEXTVAL|ROWNUM/);
1165 0           my ($value) = '';
1166 0           my ($seq_file,$col) = split(/\./o, $id);
1167 0           $seq_file = $self->get_path_info($seq_file) . '.seq';
1168              
1169 0 0         $seq_file =~ tr/A-Z/a-z/ unless ($self->{CaseTableNames}); #JWT:TABLE-NAMES ARE NOW CASE-INSENSITIVE!
1170 0 0         open (FILE, "<$seq_file") || return (-511);
1171 0           $x = ;
1172             #chomp($x);
1173 0           $x =~ s/\s+$//o; #20000113
1174 0           ($incval, $startval) = split(/\,/o, $x);
1175 0           close (FILE);
1176 0 0         if ($id =~ /NEXTVAL/o)
1177             {
1178 0 0         open (FILE, ">$seq_file") || return (-511);
1179 0   0       $incval += ($startval || 1);
1180 0           print FILE "$incval,$startval\n";
1181 0           close (FILE);
1182             }
1183 0           $value = $incval;
1184 0           return $value;
1185             }
1186              
1187             sub SYSTIME
1188             {
1189 0     0 0   return time;
1190             }
1191              
1192             sub NUM
1193             {
1194 0     0 0   return shift;
1195             }
1196              
1197             sub NULL
1198             {
1199 0     0 0   return '';
1200             }
1201              
1202             1;