| 1 | ################################# | ############################################ | 
| 2 | # | # | 
| 3 | #  $Id$ | #  $Id$ | 
| 4 | # | # | 
| 5 | #  $Log$ | #  $Log$ | 
| 6 |  | #  Revision 1.32  2003/04/08 22:52:22  joko | 
| 7 |  | #  modified 'querySchema': better behaviour regarding filtering result | 
| 8 |  | # | 
| 9 |  | #  Revision 1.31  2003/04/05 21:24:09  joko | 
| 10 |  | #  modified 'sub getChildNodes': now contains code from 'querySchema' | 
| 11 |  | # | 
| 12 |  | #  Revision 1.30  2003/03/27 15:31:14  joko | 
| 13 |  | #  fixes to modules regarding new namespace(s) below Data::Mungle::* | 
| 14 |  | # | 
| 15 |  | #  Revision 1.29  2003/02/21 01:47:18  joko | 
| 16 |  | #  purged old code | 
| 17 |  | #  minor cosmetics | 
| 18 |  | # | 
| 19 |  | #  Revision 1.28  2003/02/20 20:20:26  joko | 
| 20 |  | #  tried to get auto-disconnect working again - failed with that | 
| 21 |  | # | 
| 22 |  | #  Revision 1.27  2003/01/31 06:30:59  joko | 
| 23 |  | #  + enabled 'sendQuery' | 
| 24 |  | # | 
| 25 |  | #  Revision 1.26  2003/01/30 22:29:47  joko | 
| 26 |  | #  + fixed module usage (removed dependency on 'libp.pm') | 
| 27 |  | # | 
| 28 |  | #  Revision 1.25  2003/01/19 02:30:05  joko | 
| 29 |  | #  + fix: modified call to '_initSchema' | 
| 30 |  | # | 
| 31 |  | #  Revision 1.24  2002/12/22 14:13:01  joko | 
| 32 |  | #  + sub dropDb | 
| 33 |  | # | 
| 34 |  | #  Revision 1.23  2002/12/19 16:31:53  joko | 
| 35 |  | #  +- renamed sub to 'rebuildDb' | 
| 36 |  | # | 
| 37 |  | #  Revision 1.22  2002/12/18 22:28:16  jonen | 
| 38 |  | #  + added extended logging at 'getObjectByGuid()' | 
| 39 |  | # | 
| 40 |  | #  Revision 1.21  2002/12/16 22:20:49  jonen | 
| 41 |  | #  + fixed bug at 'getObjectByGuid()' | 
| 42 |  | # | 
| 43 |  | #  Revision 1.20  2002/12/16 20:49:17  jonen | 
| 44 |  | #  + added sub 'getObjectByGuid()' | 
| 45 |  | #  + added functionality to use 'getObjectByGuid' at 'getObjectAsHash()' | 
| 46 |  | # | 
| 47 |  | #  Revision 1.19  2002/12/16 06:46:09  joko | 
| 48 |  | #  + attempt to introduce a generic '_patchSchema' - cancelled! | 
| 49 |  | # | 
| 50 |  | #  Revision 1.18  2002/12/13 21:48:07  joko | 
| 51 |  | #  + fix to 'sub sendQuery' | 
| 52 |  | # | 
| 53 |  | #  Revision 1.17  2002/12/12 02:51:09  joko | 
| 54 |  | #  + cosmetics | 
| 55 |  | # | 
| 56 |  | #  Revision 1.16  2002/12/11 06:54:10  joko | 
| 57 |  | #  + fix: encapsulated object-loading inside an 'eval' | 
| 58 |  | # | 
| 59 |  | #  Revision 1.15  2002/12/05 13:55:21  joko | 
| 60 |  | #  + now utilizing 'expand' instead of 'var_deref' | 
| 61 |  | #  + played around with having fresh-objects - no progress.... | 
| 62 |  | # | 
| 63 |  | #  Revision 1.14  2002/12/05 09:40:30  jonen | 
| 64 |  | #  + added option->{destroy} at getObject for unloading all instance | 
| 65 |  | # | 
| 66 |  | #  Revision 1.13  2002/12/05 07:59:04  joko | 
| 67 |  | #  + now using Tie::SecureHash as a base for the COREHANDLE | 
| 68 |  | #  + former public COREHANDLE becomes private _COREHANDLE now | 
| 69 |  | #  + sub getCOREHANDLE | 
| 70 |  | # | 
| 71 |  | #  Revision 1.12  2002/12/04 11:34:49  joko | 
| 72 |  | #  - $schema_tangram doesn't have to be in class? | 
| 73 |  | # | 
| 74 |  | #  Revision 1.11  2002/12/04 08:54:08  jonen | 
| 75 |  | #  + untested bugfix: undef($object) after transform to hash at getObjectAsHash | 
| 76 |  | # | 
| 77 |  | #  Revision 1.10  2002/12/03 15:53:23  joko | 
| 78 |  | #  + small bugfix regarding object hierarchy | 
| 79 |  | # | 
| 80 |  | #  Revision 1.9  2002/12/03 05:29:40  joko | 
| 81 |  | #  + sub getObject | 
| 82 |  | #  + sub getObjectAsHash | 
| 83 |  | # | 
| 84 |  | #  Revision 1.8  2002/12/01 22:25:51  joko | 
| 85 |  | #  + now utilizing metadata from storage locator when connecting to DBI in "raw"-mode | 
| 86 |  | # | 
| 87 |  | #  Revision 1.7  2002/12/01 04:46:19  joko | 
| 88 |  | #  + sub eraseAll | 
| 89 |  | # | 
| 90 |  | #  Revision 1.6  2002/11/29 05:02:30  joko | 
| 91 |  | #  - sub getNewPerlObjectByPkgName (moved to libp.pm) | 
| 92 |  | #  + sub getMetaInfo | 
| 93 |  | #  - sub existsChildNode (moved to Abstract.pm) | 
| 94 |  | #  + sub getListUnfiltered | 
| 95 |  | #  + sub getListFiltered | 
| 96 |  | #  + sub createCursor | 
| 97 |  | #  + sub createSet | 
| 98 |  | #  + sub sendQuery | 
| 99 |  | # | 
| 100 |  | #  Revision 1.5  2002/11/17 06:35:18  joko | 
| 101 |  | #  + locator metadata can now be reached via ->{locator} | 
| 102 |  | #  - getChildNodes is now wrapped via COREHANDLE | 
| 103 |  | # | 
| 104 | #  Revision 1.4  2002/10/25 11:44:44  joko | #  Revision 1.4  2002/10/25 11:44:44  joko | 
| 105 | #  + sub _initSchema | #  + sub _initSchema | 
| 106 | #  + sub existsChildNode | #  + sub existsChildNode | 
| 119 | #  Revision 1.1  2002/10/10 03:44:07  cvsjoko | #  Revision 1.1  2002/10/10 03:44:07  cvsjoko | 
| 120 | #  + new | #  + new | 
| 121 | # | # | 
| 122 | # | ############################################ | 
| 123 | ################################# |  | 
| 124 |  |  | 
| 125 | package Data::Storage::Handler::Tangram; | package Data::Storage::Handler::Tangram; | 
| 126 |  |  | 
| 127 | use strict; | use strict; | 
| 128 | use warnings; | use warnings; | 
| 129 |  |  | 
| 130 |  | use base ("Data::Storage::Handler"); | 
| 131 | use base ("Data::Storage::Handler::Abstract"); | use base ("Data::Storage::Handler::Abstract"); | 
| 132 |  |  | 
| 133 | use Tangram; |  | 
| 134 | use Data::Dumper; | use Data::Dumper; | 
| 135 |  | use Tangram; | 
| 136 |  |  | 
| 137 |  | use DesignPattern::Object; | 
| 138 |  | use Data::Storage::Result::Tangram; | 
| 139 |  | use Data::Mungle::Compare::Struct qw( isEmpty ); | 
| 140 |  | use Data::Mungle::Transform::Deep qw( expand ); | 
| 141 |  |  | 
| 142 | # get logger instance | # get logger instance | 
| 143 | my $logger = Log::Dispatch::Config->instance; | my $logger = Log::Dispatch::Config->instance; | 
| 144 |  |  | 
| 145 |  |  | 
| 146 | our $metainfo = { | # this holds the complete instantiated schema from tangram | 
| 147 | 'disconnectMethod' => 'disconnect', | my $schema_tangram; | 
|  | }; |  | 
| 148 |  |  | 
| 149 | sub getNewPerlObjectByPkgName { | sub getMetaInfo { | 
| 150 | my $pkgname = shift; | my $self = shift; | 
| 151 | my $args = shift; | $logger->debug( __PACKAGE__ . "->getMetaInfo()"  ); | 
| 152 | $logger->debug( __PACKAGE__ . "->getNewPerlObjectByPkgName( pkgname $pkgname args $args )" ); | return { | 
| 153 | my $evstring = "use $pkgname;"; | 'disconnectMethod' => 'disconnect', | 
| 154 | eval($evstring); | }; | 
|  | $@ && $logger->error( __PACKAGE__ . ':' . __LINE__ . " Error in eval: " .  $@ ); |  | 
|  | return $pkgname->new($args); |  | 
| 155 | } | } | 
| 156 |  |  | 
| 157 | sub _initSchema { | sub _initSchema { | 
| 158 | my $self = shift; | my $self = shift; | 
| 159 | $logger->debug( __PACKAGE__ . "->_initSchema()" ); | $logger->debug( __PACKAGE__ . "->_initSchema()" ); | 
| 160 | #if (!$self->{schema_tangram}) { | #if (!$schema_tangram) { | 
| 161 | my $obj = getNewPerlObjectByPkgName($self->{schema}, { EXPORT_OBJECTS => $self->{classnames} } ); | #my $obj = getNewPerlObjectByPkgName($self->{locator}->{schema}, { EXPORT_OBJECTS => $self->{locator}->{classnames}, want_transactions => $self->{locator}->{want_transactions} } ); | 
| 162 | $self->{schema_tangram} = $obj->getSchema(); | my $obj = DesignPattern::Object->fromPackage($self->{locator}->{schema}, { 'EXPORT_OBJECTS' => $self->{locator}->{classnames}, 'want_transactions' => $self->{locator}->{want_transactions} } ); | 
| 163 |  | $schema_tangram = $obj->getSchema(); | 
| 164 | #} | #} | 
| 165 | if (!$self->{schema_tangram}) { | if (!$schema_tangram) { | 
| 166 | $logger->error( __PACKAGE__ . "->_initSchema: No Schema available for $self->{schema}" ); | $logger->error( __PACKAGE__ . "->_initSchema: No Schema available for $self->{schema}" ); | 
| 167 | return 0; | return 0; | 
| 168 | } | } | 
| 169 |  | #$self->_patchSchema(); | 
| 170 | return 1; | return 1; | 
| 171 | } | } | 
| 172 |  |  | 
| 173 |  | sub _patchSchema { | 
| 174 |  | my $self = shift; | 
| 175 |  | foreach (keys %{$schema_tangram->{classes}}) { | 
| 176 |  | next if $schema_tangram->{classes}->{$_}->{abstract}; | 
| 177 |  | #next if ($_ ne 'TsBankAccount'); | 
| 178 |  | #$_ ne 'AbstractAccount' && | 
| 179 |  | print "class: $_", "\n"; | 
| 180 |  | #print Dumper($schema_tangram->{classes}->{$_}); | 
| 181 |  | # create new string property named 'guid' | 
| 182 |  | my $tstring = Tangram::String->new(); | 
| 183 |  | $tstring->{name} = $tstring->{col} = 'guid'; | 
| 184 |  | # inject property into schema | 
| 185 |  | #$schema_tangram->{classes}->{$_}->{root}->{SPECS}->[0]->{fields}->{string}->{$tstring->{name}} = $tstring; | 
| 186 |  | print Dumper($schema_tangram->{classes}->{$_}->{root}->{SPECS}->[0]->{fields}); | 
| 187 |  | } | 
| 188 |  | } | 
| 189 |  |  | 
| 190 | sub connect { | sub connect { | 
| 191 |  |  | 
| 192 | my $self = shift; | my $self = shift; | 
| 193 |  |  | 
| 194 | my $dsn = shift; | my $dsn = shift; | 
| 195 | $dsn ||= $self->{dbi}->{dsn}; |  | 
| 196 |  | #print Dumper($self); | 
| 197 |  | #exit; | 
| 198 |  |  | 
| 199 |  | # TODO: re-enable | 
| 200 |  | $dsn ||= $self->{locator}->{dbi}->{dsn}; | 
| 201 | $logger->debug( __PACKAGE__ . "->connect( dsn $dsn )" ); | $logger->debug( __PACKAGE__ . "->connect( dsn $dsn )" ); | 
| 202 |  |  | 
| 203 | #my $storage = Tangram::Relational->connect( $schema, $dsn ); | #my $storage = Tangram::Relational->connect( $schema, $dsn ); | 
| 209 | #      return; | #      return; | 
| 210 | #    } | #    } | 
| 211 |  |  | 
| 212 | return unless $self->_initSchema(); | #return unless $self->_initSchema(); | 
| 213 |  | $self->_initSchema(); | 
| 214 |  |  | 
| 215 |  | # create the main tangram storage object | 
| 216 | #$self->{COREHANDLE} = Tangram::Relational->connect( $schema, $dsn ); | #$self->{COREHANDLE} = Tangram::Relational->connect( $schema, $dsn ); | 
| 217 | $self->{COREHANDLE} = Tangram::Relational->connect( $self->{schema_tangram}, $dsn ); | $self->{_COREHANDLE} = Tangram::Relational->connect( $schema_tangram, $dsn ); | 
| 218 |  |  | 
| 219 |  | #print "connect", "\n"; | 
| 220 |  | #my $core = $self->{_COREHANDLE}; | 
| 221 |  | #print Dumper($core); | 
| 222 |  |  | 
| 223 |  | # some attempts for configuring the wrapped underlying dbi..... | 
| 224 | #$self->{STORAGEHANDLE_UNDERLYING} = $self->getUnderlyingStorage(); | #$self->{STORAGEHANDLE_UNDERLYING} = $self->getUnderlyingStorage(); | 
| 225 | #$self->{STORAGEHANDLE_UNDERLYING}->_configureCOREHANDLE(); | #$self->{STORAGEHANDLE_UNDERLYING}->_configureCOREHANDLE(); | 
| 226 | #$self->_configureUnderlyingStorage; | #$self->_configureUnderlyingStorage; | 
| 227 |  |  | 
| 228 |  | # ..... encapsulation wins! | 
| 229 | $self->configureCOREHANDLE(); | $self->configureCOREHANDLE(); | 
| 230 |  |  | 
| 231 |  | $self->{locator}->{status}->{connected} = 1; | 
| 232 |  |  | 
| 233 | return 1; | return 1; | 
| 234 |  |  | 
| 235 | } | } | 
| 237 | sub getChildNodes { | sub getChildNodes { | 
| 238 |  |  | 
| 239 | my $self = shift; | my $self = shift; | 
| 240 | my @nodes; | my $mode = shift; | 
| 241 |  | my $filter = shift; | 
| 242 |  |  | 
| 243 |  | $mode ||= 'core'; | 
| 244 |  | $filter ||= 'all'; | 
| 245 |  |  | 
| 246 |  | $logger->debug( __PACKAGE__ . "->getChildNodes($mode)" ); | 
| 247 |  |  | 
| 248 | $logger->debug( __PACKAGE__ . "->getChildNodes()" ); | if ($mode eq 'core') { | 
| 249 |  |  | 
| 250 | # create new DBI - Data::Storage - object from already connected DBI::db - handle inside the current COREHANDLE | my @nodes; | 
| 251 | #my $loc = new Data::Storage::Locator( type => "DBI", dbi => { db => $self->{COREHANDLE}->{db} }); |  | 
| 252 | #my $loc = new Data::Storage::Locator( type => "DBI", COREHANDLE => $self->{COREHANDLE}->{db} ); | # create new DBI - Data::Storage - object from already connected DBI::db - handle inside the current COREHANDLE | 
| 253 | my $storage = $self->_getSubLayerHandle(); | #my $loc = new Data::Storage::Locator( type => "DBI", dbi => { db => $self->{COREHANDLE}->{db} }); | 
| 254 | #$storage->_configureCOREHANDLE(); | #my $loc = new Data::Storage::Locator( type => "DBI", COREHANDLE => $self->{COREHANDLE}->{db} ); | 
| 255 |  |  | 
| 256 |  | # todo: should we retrieve information from the schema here | 
| 257 |  | # rather than poorly getting table names from underlying dbi? | 
| 258 |  | my $storage = $self->_getSubLayerHandle(); | 
| 259 |  | @nodes = @{$storage->getChildNodes()}; | 
| 260 |  | #$storage->_configureCOREHANDLE(); | 
| 261 |  | #print "getchildnodes\n"; | 
| 262 |  | #print Dumper($self); | 
| 263 |  | #if (my $result = $self->sendCommand( 'SHOW TABLES;' ) ) { | 
| 264 |  |  | 
| 265 |  | # TODO: REVIEW | 
| 266 |  | #$storage->disconnect(); | 
| 267 |  |  | 
| 268 |  | $self->{meta}->{childnodes} = \@nodes; | 
| 269 |  |  | 
| 270 | #if (my $result = $self->sendCommand( 'SHOW TABLES;' ) ) { | return \@nodes; | 
|  | if (my $result = $storage->sendCommand( 'SHOW TABLES;' ) ) { |  | 
|  | while ( my $row = $result->_getNextEntry() ) { |  | 
|  | push @nodes, $row; |  | 
|  | } |  | 
|  | } |  | 
| 271 |  |  | 
| 272 | $storage->disconnect(); | } elsif ($mode eq 'root') { | 
| 273 |  |  | 
| 274 |  | # FIXME: this will return *all* known classes to 'Class::Tangram', | 
| 275 |  | # which might not be what you expect since more than one instance | 
| 276 |  | # of Tangram may be in memory and Class::Tangram seems to | 
| 277 |  | # offer no methods to determine this or filter its result(s) according | 
| 278 |  | # to a specific database. | 
| 279 |  | my @object_names = Class::Tangram::known_classes(); | 
| 280 |  | my @concret_names; | 
| 281 |  | my $o_cnt; | 
| 282 |  | foreach (sort @object_names) { | 
| 283 |  | push @concret_names, $_  if (!Class::Tangram::class_is_abstract($_)); | 
| 284 |  | $o_cnt++; | 
| 285 |  | } | 
| 286 |  |  | 
| 287 |  | if ($filter eq 'all') { | 
| 288 |  | return \@object_names; | 
| 289 |  | } elsif ($filter eq 'concrete') { | 
| 290 |  | return \@concret_names; | 
| 291 |  | } | 
| 292 |  |  | 
| 293 | $self->{meta}->{childnodes} = \@nodes; | } | 
| 294 |  |  | 
|  | return \@nodes; |  | 
| 295 |  |  | 
| 296 | } | } | 
| 297 |  |  | 
|  |  |  | 
|  | sub existsChildNode { |  | 
|  | my $self = shift; |  | 
|  | my $nodename = shift; |  | 
|  | $logger->debug( __PACKAGE__ . "->getChildNode( nodename $nodename )" ); |  | 
|  | $self->getChildNodes() unless $self->{meta}->{childnodes}; |  | 
|  | return grep $nodename, @{$self->{meta}->{childnodes}}; |  | 
|  | } |  | 
|  |  |  | 
|  |  |  | 
| 298 | sub testIntegrity { | sub testIntegrity { | 
| 299 |  |  | 
| 300 | my $self = shift; | my $self = shift; | 
| 313 | return; | return; | 
| 314 | } | } | 
| 315 |  |  | 
| 316 |  | $self->{locator}->{status}->{integrity} = 1; | 
| 317 | return 1; | return 1; | 
| 318 |  |  | 
| 319 | } | } | 
| 325 |  |  | 
| 326 | $logger->debug( __PACKAGE__ . "->_getSubLayerHandle()" ); | $logger->debug( __PACKAGE__ . "->_getSubLayerHandle()" ); | 
| 327 |  |  | 
|  | use Data::Dumper; |  | 
| 328 | #print Dumper($self); | #print Dumper($self); | 
| 329 | #exit; |  | 
|  |  |  | 
| 330 | # hack, make more generic! | # hack, make more generic! | 
| 331 | if (!$self->{dataStorageLayer}) { | if (!$self->{dataStorageLayer}) { | 
| 332 | $logger->debug( __PACKAGE__ . "->_getSubLayerHandle() creating new dataStorageLayer" ); | $logger->debug( __PACKAGE__ . "->_getSubLayerHandle() creating new dataStorageLayer" ); | 
| 333 | #my $loc = Data::Storage::Locator->new( type => "DBI", dbi => $self->{dbi}, COREHANDLE => $self->{COREHANDLE}->{db} ); | #my $loc = Data::Storage::Locator->new( type => "DBI", dbi => $self->{dbi}, COREHANDLE => $self->{COREHANDLE}->{db} ); | 
| 334 | my $loc = Data::Storage::Locator->new( type => "DBI", dbi => $self->{dbi} ); | my $loc = Data::Storage::Locator->new( { type => "DBI", dbi => $self->{locator}->{dbi} } ); | 
| 335 | $self->{dataStorageLayer} = Data::Storage->new( $loc, { protected => 1 } ); | $self->{dataStorageLayer} = Data::Storage->new( $loc, { protected => 1 } ); | 
| 336 | #$self->{STORAGE_UNDER_THE_HOOD}->{STORAGEHANDLE}->_configureCOREHANDLE(); | #$self->{STORAGE_UNDER_THE_HOOD}->{STORAGEHANDLE}->_configureCOREHANDLE(); | 
| 337 | #$self->{STORAGE_UNDER_THE_HOOD}->_configureCOREHANDLE(); | #$self->{STORAGE_UNDER_THE_HOOD}->_configureCOREHANDLE(); | 
| 355 | foreach my $key (keys %{$self->{dbi}}) { | foreach my $key (keys %{$self->{dbi}}) { | 
| 356 | my $val = $self->{dbi}->{$key}; | my $val = $self->{dbi}->{$key}; | 
| 357 | print "entry: $key; $val", "\n"; | print "entry: $key; $val", "\n"; | 
| 358 | $self->{COREHANDLE}->{db}->{$key} = $val; | $self->{_COREHANDLE}->{db}->{$key} = $val; | 
| 359 | } | } | 
| 360 | #print Dumper($self->{COREHANDLE}->{db}); | #print Dumper($self->{COREHANDLE}->{db}); | 
| 361 | } | } | 
| 368 | $logger->debug( __PACKAGE__ . "->configureCOREHANDLE" ); | $logger->debug( __PACKAGE__ . "->configureCOREHANDLE" ); | 
| 369 |  |  | 
| 370 | #my $subLayer = $self->_getSubLayerHandle(); | #my $subLayer = $self->_getSubLayerHandle(); | 
| 371 |  | #print Dumper($self); | 
| 372 |  | #exit; | 
| 373 |  |  | 
| 374 | # apply configured modifications | # apply configured modifications | 
| 375 | if (exists $self->{dbi}->{trace_level} && exists $self->{dbi}->{trace_file}) { | if (exists $self->{dbi}->{trace_level} && exists $self->{dbi}->{trace_file}) { | 
| 376 | $self->{COREHANDLE}->{db}->trace($self->{dbi}->{trace_level}, $self->{dbi}->{trace_file}); | $self->{_COREHANDLE}->{db}->trace($self->{dbi}->{trace_level}, $self->{dbi}->{trace_file}); | 
| 377 | } | } | 
| 378 | if (exists $self->{dbi}->{RaiseError}) { | if (exists $self->{dbi}->{RaiseError}) { | 
| 379 | $self->{COREHANDLE}->{db}->{RaiseError} = $self->{dbi}->{RaiseError}; | $self->{_COREHANDLE}->{db}->{RaiseError} = $self->{dbi}->{RaiseError}; | 
| 380 | } | } | 
| 381 | if (exists $self->{dbi}->{PrintError}) { | if (exists $self->{dbi}->{PrintError}) { | 
| 382 | $self->{COREHANDLE}->{db}->{PrintError} = $self->{dbi}->{PrintError}; | $self->{_COREHANDLE}->{db}->{PrintError} = $self->{dbi}->{PrintError}; | 
| 383 | } | } | 
| 384 | if (exists $self->{dbi}->{HandleError}) { | if (exists $self->{dbi}->{HandleError}) { | 
| 385 | $self->{COREHANDLE}->{db}->{HandleError} = $self->{dbi}->{HandleError}; | $self->{_COREHANDLE}->{db}->{HandleError} = $self->{dbi}->{HandleError}; | 
| 386 | } | } | 
| 387 |  |  | 
| 388 | } | } | 
| 389 |  |  | 
| 390 | sub deploySchema { | sub deploySchema { | 
| 391 | my $self = shift; | my $self = shift; | 
| 392 | #my $dsn = $self->{locator}->{dbi}->{dsn}; | my $args = shift; | 
| 393 | my $dsn = $self->{dbi}->{dsn}; |  | 
| 394 |  | my $dsn = $self->{locator}->{dbi}->{dsn}; | 
| 395 |  |  | 
| 396 | $logger->debug( __PACKAGE__ . "->deploySchema( dsn $dsn )" ); | $logger->debug( __PACKAGE__ . "->deploySchema( dsn $dsn )" ); | 
| 397 |  |  | 
| 398 | my $ok; | my $ok; | 
| 399 | if ( my $dbh = DBI->connect($dsn, '', '', { | if ( my $dbh = DBI->connect($dsn, '', '', $self->{locator}->{dbi} ) ) { | 
|  | PrintError => 0, |  | 
|  | } ) ) { |  | 
|  |  |  | 
| 400 | return unless $self->_initSchema(); | return unless $self->_initSchema(); | 
| 401 |  | $ok = Tangram::Relational->deploy($schema_tangram, $dbh ); | 
|  | $ok = Tangram::Relational->deploy($self->{schema_tangram}, $dbh ); |  | 
| 402 | $dbh->disconnect(); | $dbh->disconnect(); | 
| 403 | } | } | 
| 404 | return $ok; | return $ok; | 
| 407 | sub retreatSchema { | sub retreatSchema { | 
| 408 |  |  | 
| 409 | my $self = shift; | my $self = shift; | 
| 410 | #my $dsn = $self->{locator}->{dbi}->{dsn}; | my $dsn = $self->{locator}->{dbi}->{dsn}; | 
|  | my $dsn = $self->{dbi}->{dsn}; |  | 
| 411 |  |  | 
| 412 | $logger->debug( __PACKAGE__ . "->retreatSchema( dsn $dsn )" ); | $logger->debug( __PACKAGE__ . "->retreatSchema( dsn $dsn )" ); | 
| 413 |  |  | 
| 414 | my $ok; | my $ok; | 
| 415 | if ( my $dbh = DBI->connect($dsn, '', '', { | if ( my $dbh = DBI->connect($dsn, '', '', $self->{locator}->{dbi} ) ) { | 
|  | #PrintError => 0, |  | 
|  | #RaiseError => 0, |  | 
|  | } ) ) { |  | 
| 416 |  |  | 
| 417 | return unless $self->_initSchema(); | return unless $self->_initSchema(); | 
| 418 |  |  | 
| 419 | #use Data::Dumper; print Dumper($self); | #use Data::Dumper; print Dumper($self); | 
| 420 | $self->{dataStorageLayer}->removeLogDispatchHandler("Tangram11"); | $self->{dataStorageLayer}->removeLogDispatchHandler("Tangram11"); | 
| 421 |  |  | 
| 422 | $ok = Tangram::Relational->retreat($self->{schema_tangram}, $dbh ); | $ok = Tangram::Relational->retreat($schema_tangram, $dbh ); | 
| 423 | $ok = 2;    # answer is "maybe" for now since Tangram::Relational->retreat doesn't seem to return a valid status |  | 
| 424 | # idea: test this by checking for count of tables in database - | # answer "$ok=2" means "maybe" for now - we have to patch this to a constant here because... | 
| 425 | #          problem with this: there may be some left not having been included to the schema | # - ... Tangram::Relational->retreat doesn't seem to return a valid status | 
| 426 |  | # - possible improvement: | 
| 427 |  | #   - test this by checking for count of tables in database | 
| 428 |  | #   - problem with this: there may be some left not having been included to the schema | 
| 429 |  | #   - maybe better: use "->getChildNodes"? | 
| 430 |  | $ok = 2; | 
| 431 |  |  | 
| 432 | $dbh->disconnect(); | $dbh->disconnect(); | 
| 433 |  |  | 
| 434 | } | } | 
| 435 | return $ok; | return $ok; | 
| 436 | } | } | 
| 437 |  |  | 
| 438 | sub rebuildDbAndSchema { | sub rebuildDb { | 
| 439 | my $self = shift; | my $self = shift; | 
| 440 | $logger->info( __PACKAGE__ . "->rebuildDbAndSchema()" ); | $logger->info( __PACKAGE__ . "->rebuildDb()" ); | 
| 441 | my @results; | my @results; | 
| 442 |  |  | 
| 443 | # sum up results (bool (0/1)) in array | # sum up results (bool (0/1)) in array | 
| 455 | return $res; | return $res; | 
| 456 | } | } | 
| 457 |  |  | 
| 458 |  | sub getListUnfiltered { | 
| 459 |  | my $self = shift; | 
| 460 |  | my $nodename = shift; | 
| 461 |  | my @results; | 
| 462 |  | $logger->debug( __PACKAGE__ . "->getListUnfiltered( nodename => '" . $nodename . "' )" ); | 
| 463 |  | # get set of objects from odbms by object name | 
| 464 |  | my $object_set = $self->{_COREHANDLE}->remote($nodename); | 
| 465 |  | @results = $self->{_COREHANDLE}->select($object_set); | 
| 466 |  | return \@results; | 
| 467 |  | } | 
| 468 |  |  | 
| 469 |  | sub getListFiltered { | 
| 470 |  | my $self = shift; | 
| 471 |  |  | 
| 472 |  | # redirect to unfiltered mode | 
| 473 |  | #return $self->getListUnfiltered(@_); | 
| 474 |  |  | 
| 475 |  | my $nodename = shift; | 
| 476 |  | my $filters = shift; | 
| 477 |  | my @results; | 
| 478 |  | $logger->debug( __PACKAGE__ . "->getListFiltered( nodename => '" . $nodename . "' )" ); | 
| 479 |  |  | 
| 480 |  | #print Dumper($filters); | 
| 481 |  |  | 
| 482 |  | my @tfilters; | 
| 483 |  |  | 
| 484 |  | foreach my $filter (@$filters) { | 
| 485 |  |  | 
| 486 |  | # get filter - TODO: for each filter | 
| 487 |  | #my $filter = $filters->[0]; | 
| 488 |  |  | 
| 489 |  | # build filter | 
| 490 |  | my $lexpr = $filter->{key}; | 
| 491 |  | #my $op = $filter->{op}; | 
| 492 |  | my $op = '='; | 
| 493 |  | my $rexpr = $filter->{val}; | 
| 494 |  | my $tight = 100; | 
| 495 |  |  | 
| 496 |  | #  my $tfilter = Tangram::Filter->new( | 
| 497 |  | #    expr => "t1.$lexpr $op '$rexpr'", | 
| 498 |  | #    tight => $tight, | 
| 499 |  | #    objects => $objects, | 
| 500 |  | #  ); | 
| 501 |  |  | 
| 502 |  | # HACK: build eval-string (sorry) to get filtered list - please give advice here | 
| 503 |  | push @tfilters, '$remote->{' . $filter->{key} . '}' . " $filter->{op} '$filter->{val}'"; | 
| 504 |  |  | 
| 505 |  | } | 
| 506 |  |  | 
| 507 |  | my $tfilter = join(' & ', @tfilters); | 
| 508 |  |  | 
| 509 |  | # get set of objects from odbms by object name | 
| 510 |  | my $remote = $self->{_COREHANDLE}->remote($nodename); | 
| 511 |  |  | 
| 512 |  | # was: | 
| 513 |  | #@results = $self->{COREHANDLE}->select($object_set, $tfilter); | 
| 514 |  |  | 
| 515 |  | # is: | 
| 516 |  | # HACK: build eval-string (sorry) to get filtered list - please give advice here | 
| 517 |  | my $evalstring = 'return $self->{_COREHANDLE}->select($remote, ' . $tfilter . ');'; | 
| 518 |  |  | 
| 519 |  | #print "eval: $evalstring", "\n"; | 
| 520 |  |  | 
| 521 |  | # get filtered list/set | 
| 522 |  | @results = eval($evalstring); | 
| 523 |  | die $@ if $@; | 
| 524 |  |  | 
| 525 |  | return \@results; | 
| 526 |  | } | 
| 527 |  |  | 
| 528 |  | sub createCursor { | 
| 529 |  | my $self = shift; | 
| 530 |  | my $node = shift; | 
| 531 |  | my $cmdHandle = $self->{_COREHANDLE}->cursor($node); | 
| 532 |  | my $result = Data::Storage::Result::Tangram->new( RESULTHANDLE => $cmdHandle ); | 
| 533 |  | return $result; | 
| 534 |  | } | 
| 535 |  |  | 
| 536 |  | sub createSet { | 
| 537 |  | my $self = shift; | 
| 538 |  | #print "-" x 80, "\n"; | 
| 539 |  | #print Dumper(@_); | 
| 540 |  | my @objects = @_; | 
| 541 |  | my $rh = Set::Object->new(); | 
| 542 |  | foreach (@objects) { | 
| 543 |  | if (!isEmpty($_)) { | 
| 544 |  | #print Dumper($_); | 
| 545 |  | $rh->insert($_); | 
| 546 |  | } | 
| 547 |  | } | 
| 548 |  | #print Dumper($rh->members()); | 
| 549 |  | my $result = Data::Storage::Result::Tangram->new( RESULTHANDLE => $rh ); | 
| 550 |  | return $result; | 
| 551 |  | } | 
| 552 |  |  | 
| 553 |  | sub sendQuery { | 
| 554 |  | my $self = shift; | 
| 555 |  | my $query = shift; | 
| 556 |  | #my $sql = "SELECT cs FROM $self->{metainfo}->{$descent}->{node} WHERE $self->{metainfo}->{$descent}->{IdentProvider}->{arg}='$self->{entry}->{source}->{ident}';"; | 
| 557 |  | #my $result = $self->{metainfo}->{$descent}->{storage}->sendCommand($sql); | 
| 558 |  |  | 
| 559 |  | #print Dumper($query); | 
| 560 |  |  | 
| 561 |  | # HACK: special case: querying by id does not translate into a common tangram query | 
| 562 |  | # just load the object by given id(ent) | 
| 563 |  | if ($query->{criterias} && ($query->{criterias}->[0]->{key} eq 'id' && $query->{criterias}->[0]->{op} eq 'eq')) { | 
| 564 |  | #print "LOAD!!!", "\n"; | 
| 565 |  | #exit; | 
| 566 |  | #return Set::Object->new( $self->{COREHANDLE}->load($query->{criterias}->[0]->{val}) ); | 
| 567 |  | my $ident = $query->{criterias}->[0]->{val}; | 
| 568 |  | #print "load obj", "\n"; | 
| 569 |  | #return $self->createSet() if $ident == 5; | 
| 570 |  | $self->{_COREHANDLE}->unload($ident); | 
| 571 |  | my $object = $self->{_COREHANDLE}->load($ident); | 
| 572 |  | #print "get id", "\n"; | 
| 573 |  | my $oid = $self->{_COREHANDLE}->id($object); | 
| 574 |  | #print Dumper($object); | 
| 575 |  | #print "oid: $oid", "\n"; | 
| 576 |  | return $self->createSet($object); | 
| 577 |  | #return $self->createSet( $self->{COREHANDLE}->load('300090018') ); | 
| 578 |  | } | 
| 579 |  |  | 
| 580 |  | my $list = $self->getListFiltered($query->{node}, $query->{criterias}); | 
| 581 |  | #return $self->createSet($object); | 
| 582 |  | #return $self->createSet($list); | 
| 583 |  | return $self->createSet(@$list); | 
| 584 |  |  | 
| 585 |  | #die("This should not be reached for now - redirect to \$self->getListFiltered() here!"); | 
| 586 |  |  | 
| 587 |  |  | 
| 588 |  |  | 
| 589 |  |  | 
| 590 |  | # try a generic tangram query here | 
| 591 |  | # TODO: try to place an oql on top of that (search.cpan.org!) | 
| 592 |  | my @crits; | 
| 593 |  | foreach (@{$query->{criterias}}) { | 
| 594 |  | my $op = ''; | 
| 595 |  | $op = '=' if lc $_->{op} eq 'eq'; | 
| 596 |  | push @crits, "$_->{key}$op'$_->{val}'"; | 
| 597 |  | } | 
| 598 |  | my $subnodes = {}; | 
| 599 |  | map { $subnodes->{$_}++ } @{$query->{subnodes}}; | 
| 600 |  | # HACK: this is hardcoded ;(    expand possibilities! | 
| 601 |  | #my $crit = join(' AND ', @crits); | 
| 602 |  | #my $sql = hash2Sql($query->{node}, $subnodes, 'SELECT', $crit); | 
| 603 |  | #return $self->sendCommand($sql); | 
| 604 |  | #my $h = $self->{COREHANDLE}->remote($query->{node}); | 
| 605 |  | #my $res = $self->{COREHANDLE}->select($h, $h->{); | 
| 606 |  | return $self->createCursor($query->{node}); | 
| 607 |  | } | 
| 608 |  |  | 
| 609 |  | sub eraseAll { | 
| 610 |  | my $self = shift; | 
| 611 |  | my $classname = shift; | 
| 612 |  | my $remote = $self->{_COREHANDLE}->remote($classname); | 
| 613 |  | my @objs = $self->{_COREHANDLE}->select($remote); | 
| 614 |  | $self->{_COREHANDLE}->erase(@objs); | 
| 615 |  | } | 
| 616 |  |  | 
| 617 |  | sub createDb { | 
| 618 |  | my $self = shift; | 
| 619 |  | my $storage = $self->_getSubLayerHandle(); | 
| 620 |  | return $storage->createDb(); | 
| 621 |  | } | 
| 622 |  |  | 
| 623 |  | sub getObject { | 
| 624 |  | my $self = shift; | 
| 625 |  | my $oid = shift; | 
| 626 |  | my $options = shift; | 
| 627 |  |  | 
| 628 |  | # TODO: create a deep_unload method (currently _all_ objects are unloaded) | 
| 629 |  | # unload($oid) will only unload object, not deep object hashes | 
| 630 |  | $self->{_COREHANDLE}->unload() if ($options->{destroy}); | 
| 631 |  |  | 
| 632 |  | # TODO: review this | 
| 633 |  | #if (!$self->{COREHANDLE}) { return; } | 
| 634 |  |  | 
| 635 |  | # TODO: review this | 
| 636 |  | my $object = eval('$self->{_COREHANDLE}->load($oid);'); | 
| 637 |  | print $@, "\n" if $@; | 
| 638 |  |  | 
| 639 |  | return $object if $object; | 
| 640 |  | } | 
| 641 |  |  | 
| 642 |  | sub getObjectByGuid { | 
| 643 |  | my $self = shift; | 
| 644 |  | my $guid = shift; | 
| 645 |  | my $options = shift; | 
| 646 |  |  | 
| 647 |  | # Guid and Classname is needed | 
| 648 |  | if(!$guid || !$options->{classname}) { | 
| 649 |  | $logger->error( __PACKAGE__ . "->getObjectByGuid: No 'guid' OR no Classname in options hash was given but needed!" ); | 
| 650 |  | return; | 
| 651 |  | } | 
| 652 |  |  | 
| 653 |  | # TODO: create a deep_unload method (currently _all_ objects are unloaded) | 
| 654 |  | # unload($oid) will only unload object, not deep object hashes | 
| 655 |  | $self->{_COREHANDLE}->unload() if ($options->{destroy}); | 
| 656 |  |  | 
| 657 |  | # search for object with given Classname and Guid | 
| 658 |  | my $obj_tmp = $self->{_COREHANDLE}->remote($options->{classname}); | 
| 659 |  | my @result = $self->{_COREHANDLE}->select($obj_tmp, $obj_tmp->{guid} eq $guid); | 
| 660 |  |  | 
| 661 |  | # we searched for global unique identifer of some object, | 
| 662 |  | # so I think we can trust there would be only one result | 
| 663 |  | if($result[0]) { | 
| 664 |  | return $result[0]; | 
| 665 |  | } else { | 
| 666 |  | $logger->error( __PACKAGE__ . "->getObjectByGuid: No Object with Classname $options->{classname} and GUID $guid found!" ); | 
| 667 |  | return; | 
| 668 |  | } | 
| 669 |  |  | 
| 670 |  | } | 
| 671 |  |  | 
| 672 |  | sub getObjectAsHash { | 
| 673 |  | my $self = shift; | 
| 674 |  | my $oid = shift; | 
| 675 |  | my $options = shift; | 
| 676 |  | my $obj; | 
| 677 |  |  | 
| 678 |  | if($options->{guid}) { | 
| 679 |  | $obj = $self->getObjectByGuid($oid, $options); | 
| 680 |  | } else { | 
| 681 |  | $obj = $self->getObject($oid, $options); | 
| 682 |  | } | 
| 683 |  |  | 
| 684 |  | # build options (a callback to unload autovivified objects) for 'expand' | 
| 685 |  | # TODO: use $logger to write to debug here! | 
| 686 |  | my $cb; # = sub {}; | 
| 687 |  |  | 
| 688 |  | # deactivated way to get rid of used instances, if requested | 
| 689 |  | =pod | 
| 690 |  | if ($options->{destroy}) { | 
| 691 |  | $options->{cb}->{destroy} = sub { | 
| 692 |  | print "================ DESTROY", "\n"; | 
| 693 |  | my $object = shift; | 
| 694 |  | #print Dumper($object); | 
| 695 |  | $self->{_COREHANDLE}->unload($object); | 
| 696 |  | #undef($object); | 
| 697 |  | }; | 
| 698 |  | } | 
| 699 |  | =cut | 
| 700 |  |  | 
| 701 |  | my $hash = expand($obj, $options); | 
| 702 |  |  | 
| 703 |  | # old (unsuccessful) attempts to get rid of used instances, if requested | 
| 704 |  |  | 
| 705 |  | # V1: | 
| 706 |  | #$options->{cb}->{destroy}->($obj); | 
| 707 |  | #$self->{_COREHANDLE}->unload($obj); | 
| 708 |  |  | 
| 709 |  | # V2: | 
| 710 |  | #$obj->clear_refs; | 
| 711 |  | #$self->{COREHANDLE}->unload($obj) if($options->{destroy}); | 
| 712 |  | #$obj->DESTROY; | 
| 713 |  | #undef($obj) if($options->{destroy}); | 
| 714 |  |  | 
| 715 |  | return $hash; | 
| 716 |  | } | 
| 717 |  |  | 
| 718 |  | sub getSchema { | 
| 719 |  | return $schema_tangram; | 
| 720 |  | } | 
| 721 |  |  | 
| 722 |  | sub getCOREHANDLE { | 
| 723 |  | my $self = shift; | 
| 724 |  | return $self->{_COREHANDLE}; | 
| 725 |  | } | 
| 726 |  |  | 
| 727 |  | sub dropDb { | 
| 728 |  | my $self = shift; | 
| 729 |  | my $storage = $self->_getSubLayerHandle(); | 
| 730 |  | return $storage->dropDb(); | 
| 731 |  | } | 
| 732 |  |  | 
| 733 |  | sub testAvailability { | 
| 734 |  | my $self = shift; | 
| 735 |  | my $storage = $self->_getSubLayerHandle(); | 
| 736 |  | return $storage->testAvailability(); | 
| 737 |  | } | 
| 738 |  |  | 
| 739 |  | sub disconnect2 { | 
| 740 |  | my $self = shift; | 
| 741 |  | my $storage = $self->_getSubLayerHandle(); | 
| 742 |  | print "DISC!", "\n"; | 
| 743 |  |  | 
| 744 |  | my $storage_ll = $storage->{_COREHANDLE}; | 
| 745 |  | $storage_ll->disconnect(); | 
| 746 |  |  | 
| 747 |  | print Dumper($storage); | 
| 748 |  | exit; | 
| 749 |  |  | 
| 750 |  | #$self->{_COREHANDLE} | 
| 751 |  | #$storage->disconnect(); | 
| 752 |  | $self->{dataStorageLayer}->disconnect(); | 
| 753 |  | } | 
| 754 |  |  | 
| 755 | 1; | 1; | 
| 756 |  | __END__ |